4 * Copyright (C) 2005 Mike Baker
5 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
6 * Copyrigth (C) 2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include <sys/ioctl.h>
34 #include <mtd/mtd-user.h>
35 #include <linux/bcm963xx_tag.h>
40 ssize_t
pread(int fd
, void *buf
, size_t count
, off_t offset
);
41 ssize_t
pwrite(int fd
, const void *buf
, size_t count
, off_t offset
);
43 #define CRC_START 0xFFFFFFFF
45 static uint32_t strntoul(char *str
, char **endptr
, int base
, size_t len
) {
49 newstr
= calloc(len
+ 1, sizeof(char));
51 strncpy(newstr
, str
, len
);
52 res
= strtoul(newstr
, endptr
, base
);
58 uint32_t compute_crc32(uint32_t crc
, off_t start
, size_t compute_len
, int fd
)
60 uint8_t readbuf
[1024];
64 /* Read a buffer's worth of bytes */
65 while (fd
&& (compute_len
>= sizeof(readbuf
))) {
66 res
= pread(fd
, readbuf
, sizeof(readbuf
), offset
);
67 crc
= crc32(crc
, readbuf
, res
);
68 compute_len
= compute_len
- res
;
72 /* Less than buffer-size bytes remains, read compute_len bytes */
73 if (fd
&& (compute_len
> 0)) {
74 res
= pread(fd
, readbuf
, compute_len
, offset
);
75 crc
= crc32(crc
, readbuf
, res
);
82 trx_fixup(int fd
, const char *name
)
84 struct mtd_info_user mtdInfo
;
90 uint32_t cfelen
, imagelen
, imagestart
, rootfslen
;
91 uint32_t imagecrc
, rootfscrc
, headercrc
;
93 cfelen
= imagelen
= imagestart
= imagecrc
= rootfscrc
= headercrc
= rootfslen
= 0;
96 if (ioctl(fd
, MEMGETINFO
, &mtdInfo
) < 0) {
97 fprintf(stderr
, "Failed to get mtd info\n");
102 if (mtdInfo
.size
<= 0) {
103 fprintf(stderr
, "Invalid MTD device size\n");
107 bfd
= mtd_open(name
, true);
108 ptr
= mmap(NULL
, len
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, bfd
, 0);
109 if (!ptr
|| (ptr
== (void *) -1)) {
114 tag
= (struct bcm_tag
*) (ptr
);
116 cfelen
= strntoul(&tag
->cfe_length
[0], NULL
, 10, IMAGE_LEN
);
118 fprintf(stderr
, "Non-zero CFE length. This is currently unsupported.\n");
122 headercrc
= compute_crc32(CRC_START
, offset
, offsetof(struct bcm_tag
, header_crc
), fd
);
123 if (headercrc
!= *(uint32_t *)(&tag
->header_crc
)) {
124 fprintf(stderr
, "Tag verify failed. This may not be a valid image.\n");
128 sprintf(&tag
->root_length
[0], "%u", 0);
129 strncpy(&tag
->total_length
[0], &tag
->kernel_length
[0], IMAGE_LEN
);
131 imagestart
= sizeof(tag
);
132 memcpy(&tag
->image_crc
, &tag
->kernel_crc
, sizeof(uint32_t));
133 memcpy(&tag
->fskernel_crc
, &tag
->kernel_crc
, sizeof(uint32_t));
134 rootfscrc
= CRC_START
;
135 memcpy(&tag
->rootfs_crc
, &rootfscrc
, sizeof(uint32_t));
136 headercrc
= crc32(CRC_START
, tag
, offsetof(struct bcm_tag
, header_crc
));
137 memcpy(&tag
->header_crc
, &headercrc
, sizeof(uint32_t));
139 msync(ptr
, sizeof(struct bcm_tag
), MS_SYNC
|MS_INVALIDATE
);
147 fprintf(stderr
, "Error fixing up imagetag header\n");
153 trx_check(int imagefd
, const char *mtd
, char *buf
, int *len
)
155 struct bcm_tag
*tag
= (const struct bcm_tag
*) buf
;
160 if (strcmp(mtd
, "linux") != 0)
163 *len
= read(imagefd
, buf
, sizeof(struct bcm_tag
));
164 if (*len
< sizeof(struct bcm_tag
)) {
165 fprintf(stdout
, "Could not get image header, file too small (%d bytes)\n", *len
);
168 headerCRC
= crc32buf(buf
, offsetof(struct bcm_tag
, header_crc
));
169 if (*(uint32_t *)(&tag
->header_crc
) != headerCRC
) {
172 fprintf(stderr
, "Bad header CRC got %08x, calculated %08x\n",
173 *(uint32_t *)(&tag
->header_crc
), headerCRC
);
174 fprintf(stderr
, "This is not the correct file format; refusing to flash.\n"
175 "Please specify the correct file or use -f to force.\n");
180 /* check if image fits to mtd device */
181 fd
= mtd_check_open(mtd
);
183 fprintf(stderr
, "Could not open mtd device: %s\n", mtd
);
187 imageLen
= strntoul(&tag
->total_length
[0], NULL
, 10, IMAGE_LEN
);
189 if(mtdsize
< imageLen
) {
190 fprintf(stderr
, "Image too big for partition: %s\n", mtd
);
200 mtd_fixtrx(const char *mtd
, size_t offset
)
207 uint32_t cfelen
, imagelen
, imagestart
, rootfslen
;
208 uint32_t imagecrc
, rootfscrc
, headercrc
;
209 cfelen
= imagelen
= imagestart
= imagecrc
= rootfscrc
= headercrc
= rootfslen
= 0;
212 fprintf(stderr
, "Trying to fix trx header in %s at 0x%x...\n", mtd
, offset
);
214 block_offset
= offset
& ~(erasesize
- 1);
215 offset
-= block_offset
;
217 fd
= mtd_check_open(mtd
);
219 fprintf(stderr
, "Could not open mtd device: %s\n", mtd
);
223 if (block_offset
+ erasesize
> mtdsize
) {
224 fprintf(stderr
, "Offset too large, device size 0x%x\n", mtdsize
);
228 buf
= malloc(erasesize
);
234 res
= pread(fd
, buf
, erasesize
, block_offset
);
235 if (res
!= erasesize
) {
240 tag
= (struct bcm_tag
*) (buf
+ offset
);
242 cfelen
= strntoul(tag
->cfe_length
, NULL
, 10, IMAGE_LEN
);
244 fprintf(stderr
, "Non-zero CFE length. This is currently unsupported.\n");
249 fprintf(stderr
, "Verifying we actually have an imagetag.\n");
252 headercrc
= compute_crc32(CRC_START
, offset
, offsetof(struct bcm_tag
, header_crc
), fd
);
253 if (headercrc
!= *(uint32_t *)(&tag
->header_crc
)) {
254 fprintf(stderr
, "Tag verify failed. This may not be a valid image.\n");
259 fprintf(stderr
, "Checking current fixed status.\n");
262 rootfslen
= strntoul(&tag
->root_length
[0], NULL
, 10, IMAGE_LEN
);
263 if (rootfslen
== 0) {
265 fprintf(stderr
, "Header already fixed, exiting\n");
271 fprintf(stderr
, "Setting root length to 0.\n");
274 sprintf(&tag
->root_length
[0], "%u", 0);
275 strncpy(&tag
->total_length
[0], &tag
->kernel_length
[0], IMAGE_LEN
);
278 fprintf(stderr
, "Recalculating CRCs.\n");
281 imagestart
= sizeof(tag
);
282 memcpy(&tag
->image_crc
, &tag
->kernel_crc
, sizeof(uint32_t));
283 memcpy(&tag
->fskernel_crc
, &tag
->kernel_crc
, sizeof(uint32_t));
284 rootfscrc
= CRC_START
;
285 memcpy(&tag
->rootfs_crc
, &rootfscrc
, sizeof(uint32_t));
286 headercrc
= crc32(CRC_START
, tag
, offsetof(struct bcm_tag
, header_crc
));
287 memcpy(&tag
->header_crc
, &headercrc
, sizeof(uint32_t));
290 fprintf(stderr
, "Erasing imagetag block\n");
293 if (mtd_erase_block(fd
, block_offset
)) {
294 fprintf(stderr
, "Can't erase block at 0x%x (%s)\n", block_offset
, strerror(errno
));
299 fprintf(stderr
, "New image crc32: 0x%x, rewriting block\n",
300 *(uint32_t *)(&tag
->image_crc
));
301 fprintf(stderr
, "New header crc32: 0x%x, rewriting block\n", headercrc
);
304 if (pwrite(fd
, buf
, erasesize
, block_offset
) != erasesize
) {
305 fprintf(stderr
, "Error writing block (%s)\n", strerror(errno
));
310 fprintf(stderr
, "Done.\n");