OpenWrt – Blame information for rev 2
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * mkdlinkfw |
||
3 | * |
||
4 | * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com> |
||
5 | * |
||
6 | * This tool is based on mktplinkfw. |
||
7 | * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> |
||
8 | * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn> |
||
9 | * |
||
10 | * This program is free software; you can redistribute it and/or modify it |
||
11 | * under the terms of the GNU General Public License as published by the Free |
||
12 | * Software Foundation; either version 2 of the License, or (at your option) |
||
13 | * any later version. |
||
14 | */ |
||
15 | |||
16 | #include <stdio.h> |
||
17 | #include <stdlib.h> |
||
18 | #include <stdint.h> |
||
19 | #include <string.h> |
||
20 | #include <unistd.h> /* for unlink() */ |
||
21 | #include <libgen.h> |
||
22 | #include <getopt.h> /* for getopt() */ |
||
23 | #include <stdarg.h> |
||
24 | #include <stdbool.h> |
||
25 | #include <endian.h> |
||
26 | #include <errno.h> |
||
27 | #include <sys/stat.h> |
||
28 | #include <zlib.h> /*for crc32 */ |
||
29 | |||
30 | #include "mkdlinkfw-lib.h" |
||
31 | |||
32 | /* ARM update header 2.0 |
||
33 | * used only in factory images to erase and flash selected area |
||
34 | */ |
||
35 | struct auh_header { |
||
36 | uint8_t rom_id[12]; /* 12-bit rom-id unique per router type */ |
||
37 | uint16_t derange; /* used for scramble header */ |
||
38 | uint16_t image_checksum; /* jboot_checksum of flashed data */ |
||
39 | |||
40 | uint32_t space1; /* zeros */ |
||
41 | uint32_t space2; /* zeros */ |
||
42 | uint16_t space3; /* zerosu */ |
||
43 | uint8_t lpvs; /* must be 0x01 */ |
||
44 | uint8_t mbz; /* bust be 0 */ |
||
45 | uint32_t time_stamp; /* timestamp calculated in jboot way */ |
||
46 | |||
47 | uint32_t erase_start; /* erase start address */ |
||
48 | uint32_t erase_length; /* erase length address */ |
||
49 | uint32_t data_offset; /* data start address */ |
||
50 | uint32_t data_length; /* data length address */ |
||
51 | |||
52 | uint32_t space4; /* zeros */ |
||
53 | uint32_t space5; /* zeros */ |
||
54 | uint32_t space6; /* zeros */ |
||
55 | uint32_t space7; /* zeros */ |
||
56 | |||
57 | uint16_t header_id; /* magic 0x4842 */ |
||
58 | uint16_t header_version; /* 0x02 for 2.0 */ |
||
59 | uint16_t space8; /* zeros */ |
||
60 | uint8_t section_id; /* section id */ |
||
61 | uint8_t image_info_type; /* (?) 0x04 in factory images */ |
||
62 | uint32_t image_info_offset; /* (?) zeros in factory images */ |
||
63 | uint16_t family_member; /* unique per router type */ |
||
64 | uint16_t header_checksum; /* negated jboot_checksum of header data */ |
||
65 | }; |
||
66 | |||
67 | struct stag_header { /* used only of sch2 wrapped kernel data */ |
||
68 | uint8_t cmark; /* in factory 0xFF ,in sysuograde must be the same as id */ |
||
69 | uint8_t id; /* 0x04 */ |
||
70 | uint16_t magic; /* magic 0x2B24 */ |
||
71 | uint32_t time_stamp; /* timestamp calculated in jboot way */ |
||
72 | uint32_t image_length; /* lentgh of kernel + sch2 header */ |
||
73 | uint16_t image_checksum; /* negated jboot_checksum of sch2 + kernel */ |
||
74 | uint16_t tag_checksum; /* negated jboot_checksum of stag header data */ |
||
75 | }; |
||
76 | |||
77 | struct sch2_header { /* used only in kernel partitions */ |
||
78 | uint16_t magic; /* magic 0x2124 */ |
||
79 | uint8_t cp_type; /* 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma */ |
||
80 | uint8_t version; /* 0x02 for sch2 */ |
||
81 | uint32_t ram_addr; /* ram entry address */ |
||
82 | uint32_t image_len; /* kernel image length */ |
||
83 | uint32_t image_crc32; /* kernel image crc */ |
||
84 | uint32_t start_addr; /* ram start address */ |
||
85 | uint32_t rootfs_addr; /* rootfs flash address */ |
||
86 | uint32_t rootfs_len; /* rootfls length */ |
||
87 | uint32_t rootfs_crc32; /* rootfs crc32 */ |
||
88 | uint32_t header_crc32; /* sch2 header crc32, durring calculation this area is replaced by zero */ |
||
89 | uint16_t header_length; /* sch2 header length: 0x28 */ |
||
90 | uint16_t cmd_line_length; /* cmd line length, known zeros */ |
||
91 | }; |
||
92 | |||
93 | /* globals */ |
||
94 | static struct file_info inspect_info; |
||
95 | struct file_info kernel_info; |
||
96 | struct file_info rootfs_info; |
||
97 | struct file_info image_info; |
||
98 | |||
99 | char *ofname; |
||
100 | char *progname; |
||
101 | uint32_t firmware_size; |
||
102 | uint16_t family_member; |
||
103 | char *rom_id[12] = { 0 }; |
||
104 | char image_type; |
||
105 | |||
106 | static void usage(int status) |
||
107 | { |
||
108 | fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname); |
||
109 | fprintf(stderr, |
||
110 | "\n" |
||
111 | "Options:\n" |
||
112 | " -i <file> inspect given firmware file <file>\n" |
||
113 | " -f set family member id (hexval prefixed with 0x)\n" |
||
114 | " -F <file> read image and convert it to FACTORY\n" |
||
115 | " -k <file> read kernel image from the file <file>\n" |
||
116 | " -r <file> read rootfs image from the file <file>\n" |
||
117 | " -o <file> write output to the file <file>\n" |
||
118 | " -s <size> set firmware partition size\n" |
||
119 | " -m <version> set rom id to <version> (12-bit string val: \"DLK*********\")\n" |
||
120 | " -h show this screen\n"); |
||
121 | |||
122 | exit(status); |
||
123 | } |
||
124 | |||
125 | void print_auh_header(struct auh_header *printed_header) |
||
126 | { |
||
127 | printf("\trom_id: %s\n" |
||
128 | "\tderange: 0x%04X\n" |
||
129 | "\timage_checksum: 0x%04X\n" |
||
130 | "\tspace1: 0x%08X\n" |
||
131 | "\tspace2: 0x%08X\n" |
||
132 | "\tspace3: 0x%04X\n" |
||
133 | "\tlpvs: 0x%02X\n" |
||
134 | "\tmbz: 0x%02X\n" |
||
135 | "\ttime_stamp: 0x%08X\n" |
||
136 | "\terase_start: 0x%08X\n" |
||
137 | "\terase_length: 0x%08X\n" |
||
138 | "\tdata_offset: 0x%08X\n" |
||
139 | "\tdata_length: 0x%08X\n" |
||
140 | "\tspace4: 0x%08X\n" |
||
141 | "\tspace5: 0x%08X\n" |
||
142 | "\tspace6: 0x%08X\n" |
||
143 | "\tspace7: 0x%08X\n" |
||
144 | "\theader_id: 0x%04X\n" |
||
145 | "\theader_version: 0x%02X\n" |
||
146 | "\tspace8: 0x%04X\n" |
||
147 | "\tsection_id: 0x%02X\n" |
||
148 | "\timage_info_type: 0x%02X\n" |
||
149 | "\timage_info_offset 0x%08X\n" |
||
150 | "\tfamily_member: 0x%04X\n" |
||
151 | "\theader_checksum: 0x%04X\n", |
||
152 | printed_header->rom_id, |
||
153 | printed_header->derange, |
||
154 | printed_header->image_checksum, |
||
155 | printed_header->space1, |
||
156 | printed_header->space2, |
||
157 | printed_header->space3, |
||
158 | printed_header->lpvs, |
||
159 | printed_header->mbz, |
||
160 | printed_header->time_stamp, |
||
161 | printed_header->erase_start, |
||
162 | printed_header->erase_length, |
||
163 | printed_header->data_offset, |
||
164 | printed_header->data_length, |
||
165 | printed_header->space4, |
||
166 | printed_header->space5, |
||
167 | printed_header->space6, |
||
168 | printed_header->space7, |
||
169 | printed_header->header_id, |
||
170 | printed_header->header_version, |
||
171 | printed_header->space8, |
||
172 | printed_header->section_id, |
||
173 | printed_header->image_info_type, |
||
174 | printed_header->image_info_offset, |
||
175 | printed_header->family_member, printed_header->header_checksum); |
||
176 | } |
||
177 | |||
178 | void print_stag_header(struct stag_header *printed_header) |
||
179 | { |
||
180 | printf("\tcmark: 0x%02X\n" |
||
181 | "\tid: 0x%02X\n" |
||
182 | "\tmagic: 0x%04X\n" |
||
183 | "\ttime_stamp: 0x%08X\n" |
||
184 | "\timage_length: 0x%04X\n" |
||
185 | "\timage_checksum: 0x%04X\n" |
||
186 | "\ttag_checksum: 0x%04X\n", |
||
187 | printed_header->cmark, |
||
188 | printed_header->id, |
||
189 | printed_header->magic, |
||
190 | printed_header->time_stamp, |
||
191 | printed_header->image_length, |
||
192 | printed_header->image_checksum, printed_header->tag_checksum); |
||
193 | } |
||
194 | |||
195 | void print_sch2_header(struct sch2_header *printed_header) |
||
196 | { |
||
197 | printf("\tmagic: 0x%04X\n" |
||
198 | "\tcp_type: 0x%02X\n" |
||
199 | "\tversion: 0x%02X\n" |
||
200 | "\tram_addr: 0x%08X\n" |
||
201 | "\timage_len: 0x%08X\n" |
||
202 | "\timage_crc32: 0x%08X\n" |
||
203 | "\tstart_addr: 0x%08X\n" |
||
204 | "\trootfs_addr: 0x%08X\n" |
||
205 | "\trootfs_len: 0x%08X\n" |
||
206 | "\trootfs_crc32: 0x%08X\n" |
||
207 | "\theader_crc32: 0x%08X\n" |
||
208 | "\theader_length: 0x%04X\n" |
||
209 | "\tcmd_line_length: 0x%04X\n", |
||
210 | printed_header->magic, |
||
211 | printed_header->cp_type, |
||
212 | printed_header->version, |
||
213 | printed_header->ram_addr, |
||
214 | printed_header->image_len, |
||
215 | printed_header->image_crc32, |
||
216 | printed_header->start_addr, |
||
217 | printed_header->rootfs_addr, |
||
218 | printed_header->rootfs_len, |
||
219 | printed_header->rootfs_crc32, |
||
220 | printed_header->header_crc32, |
||
221 | printed_header->header_length, printed_header->cmd_line_length); |
||
222 | } |
||
223 | |||
224 | static int find_auh_headers(char *buf) |
||
225 | { |
||
226 | char *tmp_buf = buf; |
||
227 | struct auh_header *tmp_header[MAX_HEADER_COUNTER]; |
||
228 | int header_counter = 0; |
||
229 | |||
230 | int ret = EXIT_FAILURE; |
||
231 | |||
232 | while (tmp_buf - buf <= inspect_info.file_size - AUH_SIZE) { |
||
233 | if (!memcmp(tmp_buf, AUH_MAGIC, 3)) { |
||
234 | if (((struct auh_header *)tmp_buf)->header_checksum == |
||
235 | (uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf, |
||
236 | AUH_SIZE - 2)) { |
||
237 | uint16_t checksum = 0; |
||
238 | printf("Find proper AUH header at: 0x%lX!\n", |
||
239 | tmp_buf - buf); |
||
240 | tmp_header[header_counter] = |
||
241 | (struct auh_header *)tmp_buf; |
||
242 | checksum = |
||
243 | jboot_checksum(0, (uint16_t *) ((char *) |
||
244 | tmp_header |
||
245 | [header_counter] |
||
246 | + AUH_SIZE), |
||
247 | tmp_header |
||
248 | [header_counter]->data_length); |
||
249 | if (tmp_header[header_counter]->image_checksum |
||
250 | == checksum) |
||
251 | printf("Image checksum ok.\n"); |
||
252 | else |
||
253 | ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", tmp_header[header_counter]->image_checksum, checksum); |
||
254 | header_counter++; |
||
255 | if (header_counter > MAX_HEADER_COUNTER) |
||
256 | break; |
||
257 | } |
||
258 | } |
||
259 | tmp_buf++; |
||
260 | } |
||
261 | |||
262 | if (header_counter == 0) |
||
263 | ERR("Can't find proper AUH header!\n"); |
||
264 | else if (header_counter > MAX_HEADER_COUNTER) |
||
265 | ERR("To many AUH headers!\n"); |
||
266 | else { |
||
267 | for (int i = 0; i < header_counter; i++) { |
||
268 | printf("AUH %d:\n", i); |
||
269 | print_auh_header(tmp_header[i]); |
||
270 | } |
||
271 | |||
272 | ret = EXIT_SUCCESS; |
||
273 | } |
||
274 | |||
275 | return ret; |
||
276 | } |
||
277 | |||
278 | static int check_stag_header(char *buf, struct stag_header *header) |
||
279 | { |
||
280 | |||
281 | int ret = EXIT_FAILURE; |
||
282 | |||
283 | uint8_t cmark_tmp = header->cmark; |
||
284 | header->cmark = header->id; |
||
285 | |||
286 | if (header->tag_checksum == |
||
287 | (uint16_t) ~jboot_checksum(0, (uint16_t *) header, |
||
288 | STAG_SIZE - 2)) { |
||
289 | uint16_t checksum = 0; |
||
290 | printf("Find proper STAG header at: 0x%lX!\n", |
||
291 | (char *)header - buf); |
||
292 | checksum = |
||
293 | jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE), |
||
294 | header->image_length); |
||
295 | if (header->image_checksum == checksum) { |
||
296 | printf("Image checksum ok.\n"); |
||
297 | header->cmark = cmark_tmp; |
||
298 | print_stag_header(header); |
||
299 | ret = EXIT_SUCCESS; |
||
300 | } else |
||
301 | ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_checksum, checksum); |
||
302 | } else |
||
303 | ERR("STAG header checksum incorrect!"); |
||
304 | |||
305 | header->cmark = cmark_tmp; |
||
306 | return ret; |
||
307 | } |
||
308 | |||
309 | static int check_sch2_header(char *buf, struct sch2_header *header) |
||
310 | { |
||
311 | |||
312 | int ret = EXIT_FAILURE; |
||
313 | |||
314 | uint32_t crc32_tmp = header->header_crc32; |
||
315 | header->header_crc32 = 0; |
||
316 | |||
317 | if (crc32_tmp == crc32(0, (uint8_t *) header, header->header_length)) { |
||
318 | uint32_t crc32_val; |
||
319 | printf("Find proper SCH2 header at: 0x%lX!\n", |
||
320 | (char *)header - buf); |
||
321 | |||
322 | crc32_val = |
||
323 | crc32(0, (uint8_t *) header + header->header_length, |
||
324 | header->image_len); |
||
325 | if (header->image_crc32 == crc32_val) { |
||
326 | printf("Kernel checksum ok.\n"); |
||
327 | |||
328 | header->header_crc32 = crc32_tmp; |
||
329 | print_sch2_header(header); |
||
330 | ret = EXIT_SUCCESS; |
||
331 | } else |
||
332 | ERR("Kernel checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_crc32, crc32_val); |
||
333 | |||
334 | } else |
||
335 | ERR("SCH2 header checksum incorrect!"); |
||
336 | |||
337 | header->header_crc32 = crc32_tmp; |
||
338 | return ret; |
||
339 | } |
||
340 | |||
341 | static int inspect_fw(void) |
||
342 | { |
||
343 | char *buf; |
||
344 | struct stag_header *stag_header_kernel; |
||
345 | struct sch2_header *sch2_header_kernel; |
||
346 | int ret = EXIT_FAILURE; |
||
347 | |||
348 | buf = malloc(inspect_info.file_size); |
||
349 | if (!buf) { |
||
350 | ERR("no memory for buffer!\n"); |
||
351 | goto out; |
||
352 | } |
||
353 | |||
354 | ret = read_to_buf(&inspect_info, buf); |
||
355 | if (ret) |
||
356 | goto out_free_buf; |
||
357 | |||
358 | ret = find_auh_headers(buf); |
||
359 | if (ret) |
||
360 | goto out_free_buf; |
||
361 | |||
362 | stag_header_kernel = (struct stag_header *)(buf + AUH_SIZE); |
||
363 | |||
364 | ret = check_stag_header(buf, stag_header_kernel); |
||
365 | if (ret) |
||
366 | goto out_free_buf; |
||
367 | |||
368 | sch2_header_kernel = (struct sch2_header *)(buf + AUH_SIZE + STAG_SIZE); |
||
369 | |||
370 | ret = check_sch2_header(buf, sch2_header_kernel); |
||
371 | if (ret) |
||
372 | goto out_free_buf; |
||
373 | |||
374 | out_free_buf: |
||
375 | free(buf); |
||
376 | out: |
||
377 | return ret; |
||
378 | } |
||
379 | |||
380 | static int check_options(void) |
||
381 | { |
||
382 | int ret; |
||
383 | |||
384 | if (inspect_info.file_name) { |
||
385 | ret = get_file_stat(&inspect_info); |
||
386 | if (ret) |
||
387 | return ret; |
||
388 | |||
389 | return 0; |
||
390 | } |
||
391 | |||
392 | return 0; |
||
393 | } |
||
394 | |||
395 | int fill_sch2(struct sch2_header *header, char *kernel_ptr, char *rootfs_ptr) |
||
396 | { |
||
397 | |||
398 | header->magic = SCH2_MAGIC; |
||
399 | header->cp_type = LZMA; |
||
400 | header->version = SCH2_VER; |
||
401 | header->ram_addr = RAM_LOAD_ADDR; |
||
402 | header->image_len = kernel_info.file_size; |
||
403 | header->image_crc32 = crc32(0, (uint8_t *) kernel_ptr, kernel_info.file_size); |
||
404 | header->start_addr = RAM_ENTRY_ADDR; |
||
405 | header->rootfs_addr = |
||
406 | JBOOT_SIZE + STAG_SIZE + SCH2_SIZE + kernel_info.file_size; |
||
407 | header->rootfs_len = rootfs_info.file_size; |
||
408 | header->rootfs_crc32 = crc32(0, (uint8_t *) rootfs_ptr, rootfs_info.file_size); |
||
409 | header->header_crc32 = 0; |
||
410 | header->header_length = SCH2_SIZE; |
||
411 | header->cmd_line_length = 0; |
||
412 | |||
413 | header->header_crc32 = crc32(0, (uint8_t *) header, header->header_length); |
||
414 | |||
415 | return EXIT_SUCCESS; |
||
416 | } |
||
417 | |||
418 | int fill_stag(struct stag_header *header, uint32_t length) |
||
419 | { |
||
420 | header->cmark = STAG_ID; |
||
421 | header->id = STAG_ID; |
||
422 | header->magic = STAG_MAGIC; |
||
423 | header->time_stamp = jboot_timestamp(); |
||
424 | header->image_length = length + SCH2_SIZE; |
||
425 | header->image_checksum = |
||
426 | jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE), |
||
427 | header->image_length); |
||
428 | header->tag_checksum = |
||
429 | ~jboot_checksum(0, (uint16_t *) header, STAG_SIZE - 2); |
||
430 | |||
431 | if (image_type == FACTORY) |
||
432 | header->cmark = STAG_CMARK_FACTORY; |
||
433 | |||
434 | return EXIT_SUCCESS; |
||
435 | }; |
||
436 | |||
437 | int fill_auh(struct auh_header *header, uint32_t length) |
||
438 | { |
||
439 | memcpy(header->rom_id, rom_id, 12); |
||
440 | header->derange = 0; |
||
441 | header->image_checksum = |
||
442 | jboot_checksum(0, (uint16_t *) ((char *)header + AUH_SIZE), length); |
||
443 | header->space1 = 0; |
||
444 | header->space2 = 0; |
||
445 | header->space3 = 0; |
||
446 | header->lpvs = AUH_LVPS; |
||
447 | header->mbz = 0; |
||
448 | header->time_stamp = jboot_timestamp(); |
||
449 | header->erase_start = JBOOT_SIZE; |
||
450 | header->erase_length = firmware_size; |
||
451 | header->data_offset = JBOOT_SIZE; |
||
452 | header->data_length = length; |
||
453 | header->space4 = 0; |
||
454 | header->space5 = 0; |
||
455 | header->space6 = 0; |
||
456 | header->space7 = 0; |
||
457 | header->header_id = AUH_HDR_ID; |
||
458 | header->header_version = AUH_HDR_VER; |
||
459 | header->space8 = 0; |
||
460 | header->section_id = AUH_SEC_ID; |
||
461 | header->image_info_type = AUH_INFO_TYPE; |
||
462 | header->image_info_offset = 0; |
||
463 | header->family_member = family_member; |
||
464 | header->header_checksum = |
||
465 | ~jboot_checksum(0, (uint16_t *) header, AUH_SIZE - 2); |
||
466 | |||
467 | return EXIT_SUCCESS; |
||
468 | } |
||
469 | |||
470 | int build_fw(void) |
||
471 | { |
||
472 | char *buf; |
||
473 | char *kernel_ptr; |
||
474 | char *rootfs_ptr; |
||
475 | int ret = EXIT_FAILURE; |
||
476 | int writelen; |
||
477 | |||
478 | struct stag_header *stag_header_kernel; |
||
479 | struct sch2_header *sch2_header_kernel; |
||
480 | |||
481 | if (!kernel_info.file_name | !rootfs_info.file_name) |
||
482 | goto out; |
||
483 | |||
484 | ret = get_file_stat(&kernel_info); |
||
485 | if (ret) |
||
486 | goto out; |
||
487 | ret = get_file_stat(&rootfs_info); |
||
488 | if (ret) |
||
489 | goto out; |
||
490 | |||
491 | buf = malloc(firmware_size); |
||
492 | if (!buf) { |
||
493 | ERR("no memory for buffer\n"); |
||
494 | goto out; |
||
495 | } |
||
496 | |||
497 | if (rootfs_info.file_size + kernel_info.file_size + ALL_HEADERS_SIZE > |
||
498 | firmware_size) { |
||
499 | ERR("data is bigger than firmware_size!\n"); |
||
500 | goto out; |
||
501 | } |
||
502 | |||
503 | memset(buf, 0xff, firmware_size); |
||
504 | |||
505 | stag_header_kernel = (struct stag_header *)buf; |
||
506 | |||
507 | sch2_header_kernel = |
||
508 | (struct sch2_header *)((char *)stag_header_kernel + STAG_SIZE); |
||
509 | kernel_ptr = (char *)sch2_header_kernel + SCH2_SIZE; |
||
510 | |||
511 | ret = read_to_buf(&kernel_info, kernel_ptr); |
||
512 | if (ret) |
||
513 | goto out_free_buf; |
||
514 | |||
515 | rootfs_ptr = kernel_ptr + kernel_info.file_size; |
||
516 | |||
517 | ret = read_to_buf(&rootfs_info, rootfs_ptr); |
||
518 | if (ret) |
||
519 | goto out_free_buf; |
||
520 | |||
521 | writelen = rootfs_ptr + rootfs_info.file_size - buf; |
||
522 | |||
523 | fill_sch2(sch2_header_kernel, kernel_ptr, rootfs_ptr); |
||
524 | fill_stag(stag_header_kernel, kernel_info.file_size); |
||
525 | |||
526 | ret = write_fw(ofname, buf, writelen); |
||
527 | if (ret) |
||
528 | goto out_free_buf; |
||
529 | |||
530 | ret = EXIT_SUCCESS; |
||
531 | |||
532 | out_free_buf: |
||
533 | free(buf); |
||
534 | out: |
||
535 | return ret; |
||
536 | } |
||
537 | |||
538 | int wrap_fw(void) |
||
539 | { |
||
540 | char *buf; |
||
541 | char *image_ptr; |
||
542 | int ret = EXIT_FAILURE; |
||
543 | int writelen; |
||
544 | |||
545 | struct auh_header *auh_header_kernel; |
||
546 | |||
547 | if (!image_info.file_name) |
||
548 | goto out; |
||
549 | |||
550 | ret = get_file_stat(&image_info); |
||
551 | if (ret) |
||
552 | goto out; |
||
553 | |||
554 | buf = malloc(firmware_size); |
||
555 | if (!buf) { |
||
556 | ERR("no memory for buffer\n"); |
||
557 | goto out; |
||
558 | } |
||
559 | |||
560 | if (image_info.file_size + AUH_SIZE > |
||
561 | firmware_size) { |
||
562 | ERR("data is bigger than firmware_size!\n"); |
||
563 | goto out; |
||
564 | } |
||
565 | if (!family_member) { |
||
566 | ERR("No family_member!\n"); |
||
567 | goto out; |
||
568 | } |
||
569 | if (!(rom_id[0])) { |
||
570 | ERR("No rom_id!\n"); |
||
571 | goto out; |
||
572 | } |
||
573 | memset(buf, 0xff, firmware_size); |
||
574 | |||
575 | image_ptr = (char *)(buf + AUH_SIZE); |
||
576 | |||
577 | ret = read_to_buf(&image_info, image_ptr); |
||
578 | if (ret) |
||
579 | goto out_free_buf; |
||
580 | |||
581 | writelen = image_ptr + image_info.file_size - buf; |
||
582 | |||
583 | auh_header_kernel = (struct auh_header *)buf; |
||
584 | fill_auh(auh_header_kernel, writelen - AUH_SIZE); |
||
585 | |||
586 | ret = write_fw(ofname, buf, writelen); |
||
587 | if (ret) |
||
588 | goto out_free_buf; |
||
589 | |||
590 | ret = EXIT_SUCCESS; |
||
591 | |||
592 | out_free_buf: |
||
593 | free(buf); |
||
594 | out: |
||
595 | return ret; |
||
596 | } |
||
597 | |||
598 | int main(int argc, char *argv[]) |
||
599 | { |
||
600 | int ret = EXIT_FAILURE; |
||
601 | |||
602 | progname = basename(argv[0]); |
||
603 | image_type = SYSUPGRADE; |
||
604 | family_member = 0; |
||
605 | firmware_size = 0; |
||
606 | |||
607 | while (1) { |
||
608 | int c; |
||
609 | |||
610 | c = getopt(argc, argv, "f:F:i:hk:m:o:r:s:"); |
||
611 | if (c == -1) |
||
612 | break; |
||
613 | |||
614 | switch (c) { |
||
615 | case 'f': |
||
616 | sscanf(optarg, "0x%hx", &family_member); |
||
617 | break; |
||
618 | case 'F': |
||
619 | image_info.file_name = optarg; |
||
620 | image_type = FACTORY; |
||
621 | break; |
||
622 | case 'i': |
||
623 | inspect_info.file_name = optarg; |
||
624 | break; |
||
625 | case 'k': |
||
626 | kernel_info.file_name = optarg; |
||
627 | break; |
||
628 | case 'm': |
||
629 | if (strlen(optarg) == 12) |
||
630 | memcpy(rom_id, optarg, 12); |
||
631 | break; |
||
632 | case 'r': |
||
633 | rootfs_info.file_name = optarg; |
||
634 | break; |
||
635 | case 'o': |
||
636 | ofname = optarg; |
||
637 | break; |
||
638 | case 's': |
||
639 | sscanf(optarg, "0x%x", &firmware_size); |
||
640 | break; |
||
641 | default: |
||
642 | usage(EXIT_FAILURE); |
||
643 | break; |
||
644 | } |
||
645 | } |
||
646 | |||
647 | ret = check_options(); |
||
648 | if (ret) |
||
649 | goto out; |
||
650 | |||
651 | if (!inspect_info.file_name) { |
||
652 | if (image_type == FACTORY) |
||
653 | ret = wrap_fw(); |
||
654 | else |
||
655 | ret = build_fw(); |
||
656 | } |
||
657 | else |
||
658 | ret = inspect_fw(); |
||
659 | |||
660 | out: |
||
661 | return ret; |
||
662 | |||
663 | } |