OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * imagetag.c |
||
3 | * |
||
4 | * Copyright (C) 2005 Mike Baker |
||
5 | * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name> |
||
6 | * Copyrigth (C) 2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> |
||
7 | * |
||
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. |
||
12 | * |
||
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. |
||
17 | * |
||
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. |
||
21 | */ |
||
22 | |||
23 | #include <stdio.h> |
||
24 | #include <stdlib.h> |
||
25 | #include <stddef.h> |
||
26 | #include <unistd.h> |
||
27 | #include <fcntl.h> |
||
28 | #include <sys/mman.h> |
||
29 | #include <sys/stat.h> |
||
30 | #include <string.h> |
||
31 | #include <errno.h> |
||
32 | |||
33 | #include <sys/ioctl.h> |
||
34 | #include <mtd/mtd-user.h> |
||
35 | |||
36 | #include "mtd.h" |
||
37 | #include "crc32.h" |
||
38 | |||
39 | #define TAGVER_LEN 4 /* Length of Tag Version */ |
||
40 | #define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */ |
||
41 | #define SIG1_LEN 20 /* Company Signature 1 Length */ |
||
42 | #define SIG2_LEN 14 /* Company Signature 2 Length */ |
||
43 | #define BOARDID_LEN 16 /* Length of BoardId */ |
||
44 | #define ENDIANFLAG_LEN 2 /* Endian Flag Length */ |
||
45 | #define CHIPID_LEN 6 /* Chip Id Length */ |
||
46 | #define IMAGE_LEN 10 /* Length of Length Field */ |
||
47 | #define ADDRESS_LEN 12 /* Length of Address field */ |
||
48 | #define DUALFLAG_LEN 2 /* Dual Image flag Length */ |
||
49 | #define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */ |
||
50 | #define RSASIG_LEN 20 /* Length of RSA Signature in tag */ |
||
51 | #define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */ |
||
52 | #define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */ |
||
53 | #define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */ |
||
54 | #define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */ |
||
55 | |||
56 | #define NUM_PIRELLI 2 |
||
57 | #define IMAGETAG_CRC_START 0xFFFFFFFF |
||
58 | |||
59 | #define PIRELLI_BOARDS { \ |
||
60 | "AGPF-S0", \ |
||
61 | "DWV-S0", \ |
||
62 | } |
||
63 | /* |
||
64 | * The broadcom firmware assumes the rootfs starts the image, |
||
65 | * therefore uses the rootfs start (flash_image_address) |
||
66 | * to determine where to flash the image. Since we have the kernel first |
||
67 | * we have to give it the kernel address, but the crc uses the length |
||
68 | * associated with this address (root_length), which is added to the kernel |
||
69 | * length (kernel_length) to determine the length of image to flash and thus |
||
70 | * needs to be rootfs + deadcode (jffs2 EOF marker) |
||
71 | */ |
||
72 | |||
73 | struct bcm_tag { |
||
74 | /* 0-3: Version of the image tag */ |
||
75 | char tag_version[TAGVER_LEN]; |
||
76 | /* 4-23: Company Line 1 */ |
||
77 | char sig_1[SIG1_LEN]; |
||
78 | /* 24-37: Company Line 2 */ |
||
79 | char sig_2[SIG2_LEN]; |
||
80 | /* 38-43: Chip this image is for */ |
||
81 | char chip_id[CHIPID_LEN]; |
||
82 | /* 44-59: Board name */ |
||
83 | char board_id[BOARDID_LEN]; |
||
84 | /* 60-61: Map endianness -- 1 BE 0 LE */ |
||
85 | char big_endian[ENDIANFLAG_LEN]; |
||
86 | /* 62-71: Total length of image */ |
||
87 | char total_length[IMAGE_LEN]; |
||
88 | /* 72-83: Address in memory of CFE */ |
||
89 | char cfe__address[ADDRESS_LEN]; |
||
90 | /* 84-93: Size of CFE */ |
||
91 | char cfe_length[IMAGE_LEN]; |
||
92 | /* 94-105: Address in memory of image start |
||
93 | * (kernel for OpenWRT, rootfs for stock firmware) |
||
94 | */ |
||
95 | char flash_image_start[ADDRESS_LEN]; |
||
96 | /* 106-115: Size of rootfs */ |
||
97 | char root_length[IMAGE_LEN]; |
||
98 | /* 116-127: Address in memory of kernel */ |
||
99 | char kernel_address[ADDRESS_LEN]; |
||
100 | /* 128-137: Size of kernel */ |
||
101 | char kernel_length[IMAGE_LEN]; |
||
102 | /* 138-139: Unused at the moment */ |
||
103 | char dual_image[DUALFLAG_LEN]; |
||
104 | /* 140-141: Unused at the moment */ |
||
105 | char inactive_flag[INACTIVEFLAG_LEN]; |
||
106 | /* 142-161: RSA Signature (not used; some vendors may use this) */ |
||
107 | char rsa_signature[RSASIG_LEN]; |
||
108 | /* 162-191: Compilation and related information (not used in OpenWrt) */ |
||
109 | char information1[TAGINFO1_LEN]; |
||
110 | /* 192-195: Version flash layout */ |
||
111 | char flash_layout_ver[FLASHLAYOUTVER_LEN]; |
||
112 | /* 196-199: kernel+rootfs CRC32 */ |
||
113 | __u32 fskernel_crc; |
||
114 | /* 200-215: Unused except on Alice Gate where is is information */ |
||
115 | char information2[TAGINFO2_LEN]; |
||
116 | /* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */ |
||
117 | __u32 image_crc; |
||
118 | /* 220-223: CRC32 of rootfs partition */ |
||
119 | __u32 rootfs_crc; |
||
120 | /* 224-227: CRC32 of kernel partition */ |
||
121 | __u32 kernel_crc; |
||
122 | /* 228-231: Image sequence number */ |
||
123 | char image_sequence[4]; |
||
124 | /* 222-235: Openwrt: real rootfs length */ |
||
125 | __u32 real_rootfs_length; |
||
126 | /* 236-239: CRC32 of header excluding last 20 bytes */ |
||
127 | __u32 header_crc; |
||
128 | /* 240-255: Unused at present */ |
||
129 | char reserved2[16]; |
||
130 | }; |
||
131 | ssize_t pread(int fd, void *buf, size_t count, off_t offset); |
||
132 | ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); |
||
133 | |||
134 | #define CRC_START 0xFFFFFFFF |
||
135 | |||
136 | static uint32_t strntoul(char *str, char **endptr, int base, size_t len) { |
||
137 | char *newstr; |
||
138 | uint32_t res = 0; |
||
139 | |||
140 | newstr = calloc(len + 1, sizeof(char)); |
||
141 | if (newstr) { |
||
142 | strncpy(newstr, str, len); |
||
143 | res = strtoul(newstr, endptr, base); |
||
144 | free(newstr); |
||
145 | } |
||
146 | return res; |
||
147 | } |
||
148 | |||
149 | uint32_t compute_crc32(uint32_t crc, off_t start, size_t compute_len, int fd) |
||
150 | { |
||
151 | uint8_t readbuf[1024]; |
||
152 | ssize_t res; |
||
153 | off_t offset = start; |
||
154 | |||
155 | /* Read a buffer's worth of bytes */ |
||
156 | while (fd && (compute_len >= sizeof(readbuf))) { |
||
157 | res = pread(fd, readbuf, sizeof(readbuf), offset); |
||
158 | crc = crc32(crc, readbuf, res); |
||
159 | compute_len = compute_len - res; |
||
160 | offset += res; |
||
161 | } |
||
162 | |||
163 | /* Less than buffer-size bytes remains, read compute_len bytes */ |
||
164 | if (fd && (compute_len > 0)) { |
||
165 | res = pread(fd, readbuf, compute_len, offset); |
||
166 | crc = crc32(crc, readbuf, res); |
||
167 | } |
||
168 | |||
169 | return crc; |
||
170 | } |
||
171 | |||
172 | int |
||
173 | trx_fixup(int fd, const char *name) |
||
174 | { |
||
175 | struct mtd_info_user mtdInfo; |
||
176 | unsigned long len; |
||
177 | void *ptr, *scan; |
||
178 | int bfd; |
||
179 | struct bcm_tag *tag; |
||
180 | ssize_t res; |
||
181 | uint32_t cfelen, imagelen, imagestart, rootfslen; |
||
182 | uint32_t imagecrc, rootfscrc, headercrc; |
||
183 | uint32_t offset = 0; |
||
184 | cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0; |
||
185 | |||
186 | |||
187 | if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) { |
||
188 | fprintf(stderr, "Failed to get mtd info\n"); |
||
189 | goto err; |
||
190 | } |
||
191 | |||
192 | len = mtdInfo.size; |
||
193 | if (mtdInfo.size <= 0) { |
||
194 | fprintf(stderr, "Invalid MTD device size\n"); |
||
195 | goto err; |
||
196 | } |
||
197 | |||
198 | bfd = mtd_open(name, true); |
||
199 | ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0); |
||
200 | if (!ptr || (ptr == (void *) -1)) { |
||
201 | perror("mmap"); |
||
202 | goto err1; |
||
203 | } |
||
204 | |||
205 | tag = (struct bcm_tag *) (ptr); |
||
206 | |||
207 | cfelen = strntoul(&tag->cfe_length[0], NULL, 10, IMAGE_LEN); |
||
208 | if (cfelen) { |
||
209 | fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n"); |
||
210 | exit(1); |
||
211 | } |
||
212 | |||
213 | headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd); |
||
214 | if (headercrc != *(uint32_t *)(&tag->header_crc)) { |
||
215 | fprintf(stderr, "Tag verify failed. This may not be a valid image.\n"); |
||
216 | exit(1); |
||
217 | } |
||
218 | |||
219 | sprintf(&tag->root_length[0], "%u", 0); |
||
220 | strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN); |
||
221 | |||
222 | imagestart = sizeof(tag); |
||
223 | memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t)); |
||
224 | memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t)); |
||
225 | rootfscrc = CRC_START; |
||
226 | memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t)); |
||
227 | headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc)); |
||
228 | memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t)); |
||
229 | |||
230 | msync(ptr, sizeof(struct bcm_tag), MS_SYNC|MS_INVALIDATE); |
||
231 | munmap(ptr, len); |
||
232 | close(bfd); |
||
233 | return 0; |
||
234 | |||
235 | err1: |
||
236 | close(bfd); |
||
237 | err: |
||
238 | fprintf(stderr, "Error fixing up imagetag header\n"); |
||
239 | return -1; |
||
240 | } |
||
241 | |||
242 | |||
243 | int |
||
244 | trx_check(int imagefd, const char *mtd, char *buf, int *len) |
||
245 | { |
||
246 | struct bcm_tag *tag = (const struct bcm_tag *) buf; |
||
247 | int fd; |
||
248 | uint32_t headerCRC; |
||
249 | uint32_t imageLen; |
||
250 | |||
251 | if (strcmp(mtd, "linux") != 0) |
||
252 | return 1; |
||
253 | |||
254 | *len = read(imagefd, buf, sizeof(struct bcm_tag)); |
||
255 | if (*len < sizeof(struct bcm_tag)) { |
||
256 | fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len); |
||
257 | return 0; |
||
258 | } |
||
259 | headerCRC = crc32buf(buf, offsetof(struct bcm_tag, header_crc)); |
||
260 | if (*(uint32_t *)(&tag->header_crc) != headerCRC) { |
||
261 | |||
262 | if (quiet < 2) { |
||
263 | fprintf(stderr, "Bad header CRC got %08x, calculated %08x\n", |
||
264 | *(uint32_t *)(&tag->header_crc), headerCRC); |
||
265 | fprintf(stderr, "This is not the correct file format; refusing to flash.\n" |
||
266 | "Please specify the correct file or use -f to force.\n"); |
||
267 | } |
||
268 | return 0; |
||
269 | } |
||
270 | |||
271 | /* check if image fits to mtd device */ |
||
272 | fd = mtd_check_open(mtd); |
||
273 | if(fd < 0) { |
||
274 | fprintf(stderr, "Could not open mtd device: %s\n", mtd); |
||
275 | exit(1); |
||
276 | } |
||
277 | |||
278 | imageLen = strntoul(&tag->total_length[0], NULL, 10, IMAGE_LEN); |
||
279 | |||
280 | if(mtdsize < imageLen) { |
||
281 | fprintf(stderr, "Image too big for partition: %s\n", mtd); |
||
282 | close(fd); |
||
283 | return 0; |
||
284 | } |
||
285 | |||
286 | close(fd); |
||
287 | return 1; |
||
288 | } |
||
289 | |||
290 | int |
||
291 | mtd_fixtrx(const char *mtd, size_t offset, size_t data_size) |
||
292 | { |
||
293 | int fd; |
||
294 | struct bcm_tag *tag; |
||
295 | char *buf; |
||
296 | ssize_t res; |
||
297 | size_t block_offset; |
||
298 | uint32_t cfelen, imagelen, imagestart, rootfslen; |
||
299 | uint32_t imagecrc, rootfscrc, headercrc; |
||
300 | cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0; |
||
301 | |||
302 | if (data_size) |
||
303 | fprintf(stderr, "Specifying data size in unsupported for imagetag\n"); |
||
304 | |||
305 | if (quiet < 2) |
||
306 | fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset); |
||
307 | |||
308 | block_offset = offset & ~(erasesize - 1); |
||
309 | offset -= block_offset; |
||
310 | |||
311 | fd = mtd_check_open(mtd); |
||
312 | if(fd < 0) { |
||
313 | fprintf(stderr, "Could not open mtd device: %s\n", mtd); |
||
314 | exit(1); |
||
315 | } |
||
316 | |||
317 | if (block_offset + erasesize > mtdsize) { |
||
318 | fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize); |
||
319 | exit(1); |
||
320 | } |
||
321 | |||
322 | buf = malloc(erasesize); |
||
323 | if (!buf) { |
||
324 | perror("malloc"); |
||
325 | exit(1); |
||
326 | } |
||
327 | |||
328 | res = pread(fd, buf, erasesize, block_offset); |
||
329 | if (res != erasesize) { |
||
330 | perror("pread"); |
||
331 | exit(1); |
||
332 | } |
||
333 | |||
334 | tag = (struct bcm_tag *) (buf + offset); |
||
335 | |||
336 | cfelen = strntoul(tag->cfe_length, NULL, 10, IMAGE_LEN); |
||
337 | if (cfelen) { |
||
338 | fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n"); |
||
339 | exit(1); |
||
340 | } |
||
341 | |||
342 | if (quiet < 2) { |
||
343 | fprintf(stderr, "Verifying we actually have an imagetag.\n"); |
||
344 | } |
||
345 | |||
346 | headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd); |
||
347 | if (headercrc != *(uint32_t *)(&tag->header_crc)) { |
||
348 | fprintf(stderr, "Tag verify failed. This may not be a valid image.\n"); |
||
349 | exit(1); |
||
350 | } |
||
351 | |||
352 | if (quiet < 2) { |
||
353 | fprintf(stderr, "Checking current fixed status.\n"); |
||
354 | } |
||
355 | |||
356 | rootfslen = strntoul(&tag->root_length[0], NULL, 10, IMAGE_LEN); |
||
357 | if (rootfslen == 0) { |
||
358 | if (quiet < 2) |
||
359 | fprintf(stderr, "Header already fixed, exiting\n"); |
||
360 | close(fd); |
||
361 | return 0; |
||
362 | } |
||
363 | |||
364 | if (quiet < 2) { |
||
365 | fprintf(stderr, "Setting root length to 0.\n"); |
||
366 | } |
||
367 | |||
368 | sprintf(&tag->root_length[0], "%u", 0); |
||
369 | strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN); |
||
370 | |||
371 | if (quiet < 2) { |
||
372 | fprintf(stderr, "Recalculating CRCs.\n"); |
||
373 | } |
||
374 | |||
375 | imagestart = sizeof(tag); |
||
376 | memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t)); |
||
377 | memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t)); |
||
378 | rootfscrc = CRC_START; |
||
379 | memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t)); |
||
380 | headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc)); |
||
381 | memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t)); |
||
382 | |||
383 | if (quiet < 2) { |
||
384 | fprintf(stderr, "Erasing imagetag block\n"); |
||
385 | } |
||
386 | |||
387 | if (mtd_erase_block(fd, block_offset)) { |
||
388 | fprintf(stderr, "Can't erase block at 0x%x (%s)\n", block_offset, strerror(errno)); |
||
389 | exit(1); |
||
390 | } |
||
391 | |||
392 | if (quiet < 2) { |
||
393 | fprintf(stderr, "New image crc32: 0x%x, rewriting block\n", |
||
394 | *(uint32_t *)(&tag->image_crc)); |
||
395 | fprintf(stderr, "New header crc32: 0x%x, rewriting block\n", headercrc); |
||
396 | } |
||
397 | |||
398 | if (pwrite(fd, buf, erasesize, block_offset) != erasesize) { |
||
399 | fprintf(stderr, "Error writing block (%s)\n", strerror(errno)); |
||
400 | exit(1); |
||
401 | } |
||
402 | |||
403 | if (quiet < 2) |
||
404 | fprintf(stderr, "Done.\n"); |
||
405 | |||
406 | close (fd); |
||
407 | sync(); |
||
408 | return 0; |
||
409 | |||
410 | } |