OpenWrt – Blame information for rev 3
?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 }; |
||
3 | office | 104 | |
1 | office | 105 | char image_type; |
3 | office | 106 | int add_jffs2_eof; |
1 | office | 107 | |
108 | static void usage(int status) |
||
109 | { |
||
110 | fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname); |
||
111 | fprintf(stderr, |
||
112 | "\n" |
||
113 | "Options:\n" |
||
114 | " -i <file> inspect given firmware file <file>\n" |
||
115 | " -f set family member id (hexval prefixed with 0x)\n" |
||
116 | " -F <file> read image and convert it to FACTORY\n" |
||
117 | " -k <file> read kernel image from the file <file>\n" |
||
118 | " -r <file> read rootfs image from the file <file>\n" |
||
119 | " -o <file> write output to the file <file>\n" |
||
120 | " -s <size> set firmware partition size\n" |
||
121 | " -m <version> set rom id to <version> (12-bit string val: \"DLK*********\")\n" |
||
122 | " -h show this screen\n"); |
||
123 | |||
124 | exit(status); |
||
125 | } |
||
126 | |||
127 | void print_auh_header(struct auh_header *printed_header) |
||
128 | { |
||
129 | printf("\trom_id: %s\n" |
||
130 | "\tderange: 0x%04X\n" |
||
131 | "\timage_checksum: 0x%04X\n" |
||
132 | "\tspace1: 0x%08X\n" |
||
133 | "\tspace2: 0x%08X\n" |
||
134 | "\tspace3: 0x%04X\n" |
||
135 | "\tlpvs: 0x%02X\n" |
||
136 | "\tmbz: 0x%02X\n" |
||
137 | "\ttime_stamp: 0x%08X\n" |
||
138 | "\terase_start: 0x%08X\n" |
||
139 | "\terase_length: 0x%08X\n" |
||
140 | "\tdata_offset: 0x%08X\n" |
||
141 | "\tdata_length: 0x%08X\n" |
||
142 | "\tspace4: 0x%08X\n" |
||
143 | "\tspace5: 0x%08X\n" |
||
144 | "\tspace6: 0x%08X\n" |
||
145 | "\tspace7: 0x%08X\n" |
||
146 | "\theader_id: 0x%04X\n" |
||
147 | "\theader_version: 0x%02X\n" |
||
148 | "\tspace8: 0x%04X\n" |
||
149 | "\tsection_id: 0x%02X\n" |
||
150 | "\timage_info_type: 0x%02X\n" |
||
151 | "\timage_info_offset 0x%08X\n" |
||
152 | "\tfamily_member: 0x%04X\n" |
||
153 | "\theader_checksum: 0x%04X\n", |
||
154 | printed_header->rom_id, |
||
155 | printed_header->derange, |
||
156 | printed_header->image_checksum, |
||
157 | printed_header->space1, |
||
158 | printed_header->space2, |
||
159 | printed_header->space3, |
||
160 | printed_header->lpvs, |
||
161 | printed_header->mbz, |
||
162 | printed_header->time_stamp, |
||
163 | printed_header->erase_start, |
||
164 | printed_header->erase_length, |
||
165 | printed_header->data_offset, |
||
166 | printed_header->data_length, |
||
167 | printed_header->space4, |
||
168 | printed_header->space5, |
||
169 | printed_header->space6, |
||
170 | printed_header->space7, |
||
171 | printed_header->header_id, |
||
172 | printed_header->header_version, |
||
173 | printed_header->space8, |
||
174 | printed_header->section_id, |
||
175 | printed_header->image_info_type, |
||
176 | printed_header->image_info_offset, |
||
177 | printed_header->family_member, printed_header->header_checksum); |
||
178 | } |
||
179 | |||
180 | void print_stag_header(struct stag_header *printed_header) |
||
181 | { |
||
182 | printf("\tcmark: 0x%02X\n" |
||
183 | "\tid: 0x%02X\n" |
||
184 | "\tmagic: 0x%04X\n" |
||
185 | "\ttime_stamp: 0x%08X\n" |
||
186 | "\timage_length: 0x%04X\n" |
||
187 | "\timage_checksum: 0x%04X\n" |
||
188 | "\ttag_checksum: 0x%04X\n", |
||
189 | printed_header->cmark, |
||
190 | printed_header->id, |
||
191 | printed_header->magic, |
||
192 | printed_header->time_stamp, |
||
193 | printed_header->image_length, |
||
194 | printed_header->image_checksum, printed_header->tag_checksum); |
||
195 | } |
||
196 | |||
197 | void print_sch2_header(struct sch2_header *printed_header) |
||
198 | { |
||
199 | printf("\tmagic: 0x%04X\n" |
||
200 | "\tcp_type: 0x%02X\n" |
||
201 | "\tversion: 0x%02X\n" |
||
202 | "\tram_addr: 0x%08X\n" |
||
203 | "\timage_len: 0x%08X\n" |
||
204 | "\timage_crc32: 0x%08X\n" |
||
205 | "\tstart_addr: 0x%08X\n" |
||
206 | "\trootfs_addr: 0x%08X\n" |
||
207 | "\trootfs_len: 0x%08X\n" |
||
208 | "\trootfs_crc32: 0x%08X\n" |
||
209 | "\theader_crc32: 0x%08X\n" |
||
210 | "\theader_length: 0x%04X\n" |
||
211 | "\tcmd_line_length: 0x%04X\n", |
||
212 | printed_header->magic, |
||
213 | printed_header->cp_type, |
||
214 | printed_header->version, |
||
215 | printed_header->ram_addr, |
||
216 | printed_header->image_len, |
||
217 | printed_header->image_crc32, |
||
218 | printed_header->start_addr, |
||
219 | printed_header->rootfs_addr, |
||
220 | printed_header->rootfs_len, |
||
221 | printed_header->rootfs_crc32, |
||
222 | printed_header->header_crc32, |
||
223 | printed_header->header_length, printed_header->cmd_line_length); |
||
224 | } |
||
225 | |||
226 | static int find_auh_headers(char *buf) |
||
227 | { |
||
228 | char *tmp_buf = buf; |
||
229 | struct auh_header *tmp_header[MAX_HEADER_COUNTER]; |
||
230 | int header_counter = 0; |
||
231 | |||
232 | int ret = EXIT_FAILURE; |
||
233 | |||
234 | while (tmp_buf - buf <= inspect_info.file_size - AUH_SIZE) { |
||
235 | if (!memcmp(tmp_buf, AUH_MAGIC, 3)) { |
||
236 | if (((struct auh_header *)tmp_buf)->header_checksum == |
||
237 | (uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf, |
||
238 | AUH_SIZE - 2)) { |
||
239 | uint16_t checksum = 0; |
||
240 | printf("Find proper AUH header at: 0x%lX!\n", |
||
241 | tmp_buf - buf); |
||
242 | tmp_header[header_counter] = |
||
243 | (struct auh_header *)tmp_buf; |
||
244 | checksum = |
||
245 | jboot_checksum(0, (uint16_t *) ((char *) |
||
246 | tmp_header |
||
247 | [header_counter] |
||
248 | + AUH_SIZE), |
||
249 | tmp_header |
||
250 | [header_counter]->data_length); |
||
251 | if (tmp_header[header_counter]->image_checksum |
||
252 | == checksum) |
||
253 | printf("Image checksum ok.\n"); |
||
254 | else |
||
255 | ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", tmp_header[header_counter]->image_checksum, checksum); |
||
256 | header_counter++; |
||
257 | if (header_counter > MAX_HEADER_COUNTER) |
||
258 | break; |
||
259 | } |
||
260 | } |
||
261 | tmp_buf++; |
||
262 | } |
||
263 | |||
264 | if (header_counter == 0) |
||
265 | ERR("Can't find proper AUH header!\n"); |
||
266 | else if (header_counter > MAX_HEADER_COUNTER) |
||
267 | ERR("To many AUH headers!\n"); |
||
268 | else { |
||
269 | for (int i = 0; i < header_counter; i++) { |
||
270 | printf("AUH %d:\n", i); |
||
271 | print_auh_header(tmp_header[i]); |
||
272 | } |
||
273 | |||
274 | ret = EXIT_SUCCESS; |
||
275 | } |
||
276 | |||
277 | return ret; |
||
278 | } |
||
279 | |||
280 | static int check_stag_header(char *buf, struct stag_header *header) |
||
281 | { |
||
282 | |||
283 | int ret = EXIT_FAILURE; |
||
284 | |||
285 | uint8_t cmark_tmp = header->cmark; |
||
286 | header->cmark = header->id; |
||
287 | |||
288 | if (header->tag_checksum == |
||
289 | (uint16_t) ~jboot_checksum(0, (uint16_t *) header, |
||
290 | STAG_SIZE - 2)) { |
||
291 | uint16_t checksum = 0; |
||
292 | printf("Find proper STAG header at: 0x%lX!\n", |
||
293 | (char *)header - buf); |
||
294 | checksum = |
||
295 | jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE), |
||
296 | header->image_length); |
||
297 | if (header->image_checksum == checksum) { |
||
298 | printf("Image checksum ok.\n"); |
||
299 | header->cmark = cmark_tmp; |
||
300 | print_stag_header(header); |
||
301 | ret = EXIT_SUCCESS; |
||
302 | } else |
||
303 | ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_checksum, checksum); |
||
304 | } else |
||
305 | ERR("STAG header checksum incorrect!"); |
||
306 | |||
307 | header->cmark = cmark_tmp; |
||
308 | return ret; |
||
309 | } |
||
310 | |||
311 | static int check_sch2_header(char *buf, struct sch2_header *header) |
||
312 | { |
||
313 | |||
314 | int ret = EXIT_FAILURE; |
||
315 | |||
316 | uint32_t crc32_tmp = header->header_crc32; |
||
317 | header->header_crc32 = 0; |
||
318 | |||
319 | if (crc32_tmp == crc32(0, (uint8_t *) header, header->header_length)) { |
||
320 | uint32_t crc32_val; |
||
321 | printf("Find proper SCH2 header at: 0x%lX!\n", |
||
322 | (char *)header - buf); |
||
323 | |||
324 | crc32_val = |
||
325 | crc32(0, (uint8_t *) header + header->header_length, |
||
326 | header->image_len); |
||
327 | if (header->image_crc32 == crc32_val) { |
||
328 | printf("Kernel checksum ok.\n"); |
||
329 | |||
330 | header->header_crc32 = crc32_tmp; |
||
331 | print_sch2_header(header); |
||
332 | ret = EXIT_SUCCESS; |
||
333 | } else |
||
334 | ERR("Kernel checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_crc32, crc32_val); |
||
335 | |||
336 | } else |
||
337 | ERR("SCH2 header checksum incorrect!"); |
||
338 | |||
339 | header->header_crc32 = crc32_tmp; |
||
340 | return ret; |
||
341 | } |
||
342 | |||
343 | static int inspect_fw(void) |
||
344 | { |
||
345 | char *buf; |
||
346 | struct stag_header *stag_header_kernel; |
||
347 | struct sch2_header *sch2_header_kernel; |
||
348 | int ret = EXIT_FAILURE; |
||
349 | |||
350 | buf = malloc(inspect_info.file_size); |
||
351 | if (!buf) { |
||
352 | ERR("no memory for buffer!\n"); |
||
353 | goto out; |
||
354 | } |
||
355 | |||
356 | ret = read_to_buf(&inspect_info, buf); |
||
357 | if (ret) |
||
358 | goto out_free_buf; |
||
359 | |||
360 | ret = find_auh_headers(buf); |
||
361 | if (ret) |
||
362 | goto out_free_buf; |
||
363 | |||
364 | stag_header_kernel = (struct stag_header *)(buf + AUH_SIZE); |
||
365 | |||
366 | ret = check_stag_header(buf, stag_header_kernel); |
||
367 | if (ret) |
||
368 | goto out_free_buf; |
||
369 | |||
370 | sch2_header_kernel = (struct sch2_header *)(buf + AUH_SIZE + STAG_SIZE); |
||
371 | |||
372 | ret = check_sch2_header(buf, sch2_header_kernel); |
||
373 | if (ret) |
||
374 | goto out_free_buf; |
||
375 | |||
376 | out_free_buf: |
||
377 | free(buf); |
||
378 | out: |
||
379 | return ret; |
||
380 | } |
||
381 | |||
382 | static int check_options(void) |
||
383 | { |
||
384 | int ret; |
||
385 | |||
386 | if (inspect_info.file_name) { |
||
387 | ret = get_file_stat(&inspect_info); |
||
388 | if (ret) |
||
389 | return ret; |
||
390 | |||
391 | return 0; |
||
392 | } |
||
393 | |||
394 | return 0; |
||
395 | } |
||
396 | |||
397 | int fill_sch2(struct sch2_header *header, char *kernel_ptr, char *rootfs_ptr) |
||
398 | { |
||
399 | |||
400 | header->magic = SCH2_MAGIC; |
||
401 | header->cp_type = LZMA; |
||
402 | header->version = SCH2_VER; |
||
403 | header->ram_addr = RAM_LOAD_ADDR; |
||
404 | header->image_len = kernel_info.file_size; |
||
405 | header->image_crc32 = crc32(0, (uint8_t *) kernel_ptr, kernel_info.file_size); |
||
406 | header->start_addr = RAM_ENTRY_ADDR; |
||
407 | header->rootfs_addr = |
||
408 | JBOOT_SIZE + STAG_SIZE + SCH2_SIZE + kernel_info.file_size; |
||
409 | header->rootfs_len = rootfs_info.file_size; |
||
410 | header->rootfs_crc32 = crc32(0, (uint8_t *) rootfs_ptr, rootfs_info.file_size); |
||
411 | header->header_crc32 = 0; |
||
412 | header->header_length = SCH2_SIZE; |
||
413 | header->cmd_line_length = 0; |
||
414 | |||
415 | header->header_crc32 = crc32(0, (uint8_t *) header, header->header_length); |
||
416 | |||
417 | return EXIT_SUCCESS; |
||
418 | } |
||
419 | |||
420 | int fill_stag(struct stag_header *header, uint32_t length) |
||
421 | { |
||
422 | header->cmark = STAG_ID; |
||
423 | header->id = STAG_ID; |
||
424 | header->magic = STAG_MAGIC; |
||
425 | header->time_stamp = jboot_timestamp(); |
||
426 | header->image_length = length + SCH2_SIZE; |
||
427 | header->image_checksum = |
||
428 | jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE), |
||
429 | header->image_length); |
||
430 | header->tag_checksum = |
||
431 | ~jboot_checksum(0, (uint16_t *) header, STAG_SIZE - 2); |
||
432 | |||
433 | if (image_type == FACTORY) |
||
434 | header->cmark = STAG_CMARK_FACTORY; |
||
435 | |||
436 | return EXIT_SUCCESS; |
||
437 | }; |
||
438 | |||
439 | int fill_auh(struct auh_header *header, uint32_t length) |
||
440 | { |
||
441 | memcpy(header->rom_id, rom_id, 12); |
||
442 | header->derange = 0; |
||
443 | header->image_checksum = |
||
444 | jboot_checksum(0, (uint16_t *) ((char *)header + AUH_SIZE), length); |
||
445 | header->space1 = 0; |
||
446 | header->space2 = 0; |
||
447 | header->space3 = 0; |
||
448 | header->lpvs = AUH_LVPS; |
||
449 | header->mbz = 0; |
||
450 | header->time_stamp = jboot_timestamp(); |
||
451 | header->erase_start = JBOOT_SIZE; |
||
452 | header->erase_length = firmware_size; |
||
453 | header->data_offset = JBOOT_SIZE; |
||
454 | header->data_length = length; |
||
455 | header->space4 = 0; |
||
456 | header->space5 = 0; |
||
457 | header->space6 = 0; |
||
458 | header->space7 = 0; |
||
459 | header->header_id = AUH_HDR_ID; |
||
460 | header->header_version = AUH_HDR_VER; |
||
461 | header->space8 = 0; |
||
462 | header->section_id = AUH_SEC_ID; |
||
463 | header->image_info_type = AUH_INFO_TYPE; |
||
464 | header->image_info_offset = 0; |
||
465 | header->family_member = family_member; |
||
466 | header->header_checksum = |
||
467 | ~jboot_checksum(0, (uint16_t *) header, AUH_SIZE - 2); |
||
468 | |||
469 | return EXIT_SUCCESS; |
||
470 | } |
||
471 | |||
472 | int build_fw(void) |
||
473 | { |
||
474 | char *buf; |
||
475 | char *kernel_ptr; |
||
476 | char *rootfs_ptr; |
||
477 | int ret = EXIT_FAILURE; |
||
478 | int writelen; |
||
479 | |||
480 | struct stag_header *stag_header_kernel; |
||
481 | struct sch2_header *sch2_header_kernel; |
||
482 | |||
483 | if (!kernel_info.file_name | !rootfs_info.file_name) |
||
484 | goto out; |
||
485 | |||
486 | ret = get_file_stat(&kernel_info); |
||
487 | if (ret) |
||
488 | goto out; |
||
489 | ret = get_file_stat(&rootfs_info); |
||
490 | if (ret) |
||
491 | goto out; |
||
492 | |||
493 | buf = malloc(firmware_size); |
||
494 | if (!buf) { |
||
495 | ERR("no memory for buffer\n"); |
||
496 | goto out; |
||
497 | } |
||
498 | |||
499 | if (rootfs_info.file_size + kernel_info.file_size + ALL_HEADERS_SIZE > |
||
500 | firmware_size) { |
||
501 | ERR("data is bigger than firmware_size!\n"); |
||
502 | goto out; |
||
503 | } |
||
504 | |||
505 | memset(buf, 0xff, firmware_size); |
||
506 | |||
507 | stag_header_kernel = (struct stag_header *)buf; |
||
508 | |||
509 | sch2_header_kernel = |
||
510 | (struct sch2_header *)((char *)stag_header_kernel + STAG_SIZE); |
||
511 | kernel_ptr = (char *)sch2_header_kernel + SCH2_SIZE; |
||
512 | |||
513 | ret = read_to_buf(&kernel_info, kernel_ptr); |
||
514 | if (ret) |
||
515 | goto out_free_buf; |
||
516 | |||
517 | rootfs_ptr = kernel_ptr + kernel_info.file_size; |
||
518 | |||
519 | ret = read_to_buf(&rootfs_info, rootfs_ptr); |
||
520 | if (ret) |
||
521 | goto out_free_buf; |
||
522 | |||
523 | writelen = rootfs_ptr + rootfs_info.file_size - buf; |
||
524 | |||
525 | fill_sch2(sch2_header_kernel, kernel_ptr, rootfs_ptr); |
||
526 | fill_stag(stag_header_kernel, kernel_info.file_size); |
||
527 | |||
528 | ret = write_fw(ofname, buf, writelen); |
||
529 | if (ret) |
||
530 | goto out_free_buf; |
||
531 | |||
532 | ret = EXIT_SUCCESS; |
||
533 | |||
534 | out_free_buf: |
||
535 | free(buf); |
||
536 | out: |
||
537 | return ret; |
||
538 | } |
||
539 | |||
540 | int wrap_fw(void) |
||
541 | { |
||
542 | char *buf; |
||
543 | char *image_ptr; |
||
544 | int ret = EXIT_FAILURE; |
||
545 | int writelen; |
||
546 | |||
547 | struct auh_header *auh_header_kernel; |
||
548 | |||
549 | if (!image_info.file_name) |
||
550 | goto out; |
||
551 | |||
552 | ret = get_file_stat(&image_info); |
||
553 | if (ret) |
||
554 | goto out; |
||
555 | |||
556 | buf = malloc(firmware_size); |
||
557 | if (!buf) { |
||
558 | ERR("no memory for buffer\n"); |
||
559 | goto out; |
||
560 | } |
||
561 | |||
562 | if (image_info.file_size + AUH_SIZE > |
||
563 | firmware_size) { |
||
564 | ERR("data is bigger than firmware_size!\n"); |
||
565 | goto out; |
||
566 | } |
||
567 | if (!family_member) { |
||
568 | ERR("No family_member!\n"); |
||
569 | goto out; |
||
570 | } |
||
571 | if (!(rom_id[0])) { |
||
572 | ERR("No rom_id!\n"); |
||
573 | goto out; |
||
574 | } |
||
575 | memset(buf, 0xff, firmware_size); |
||
576 | |||
577 | image_ptr = (char *)(buf + AUH_SIZE); |
||
578 | |||
579 | ret = read_to_buf(&image_info, image_ptr); |
||
580 | if (ret) |
||
581 | goto out_free_buf; |
||
582 | |||
583 | writelen = image_ptr + image_info.file_size - buf; |
||
584 | |||
585 | auh_header_kernel = (struct auh_header *)buf; |
||
586 | fill_auh(auh_header_kernel, writelen - AUH_SIZE); |
||
587 | |||
588 | ret = write_fw(ofname, buf, writelen); |
||
589 | if (ret) |
||
590 | goto out_free_buf; |
||
591 | |||
592 | ret = EXIT_SUCCESS; |
||
593 | |||
594 | out_free_buf: |
||
595 | free(buf); |
||
596 | out: |
||
597 | return ret; |
||
598 | } |
||
599 | |||
600 | int main(int argc, char *argv[]) |
||
601 | { |
||
602 | int ret = EXIT_FAILURE; |
||
603 | |||
604 | progname = basename(argv[0]); |
||
605 | image_type = SYSUPGRADE; |
||
606 | family_member = 0; |
||
607 | firmware_size = 0; |
||
608 | |||
609 | while (1) { |
||
610 | int c; |
||
611 | |||
612 | c = getopt(argc, argv, "f:F:i:hk:m:o:r:s:"); |
||
613 | if (c == -1) |
||
614 | break; |
||
615 | |||
616 | switch (c) { |
||
617 | case 'f': |
||
618 | sscanf(optarg, "0x%hx", &family_member); |
||
619 | break; |
||
620 | case 'F': |
||
621 | image_info.file_name = optarg; |
||
622 | image_type = FACTORY; |
||
623 | break; |
||
624 | case 'i': |
||
625 | inspect_info.file_name = optarg; |
||
626 | break; |
||
627 | case 'k': |
||
628 | kernel_info.file_name = optarg; |
||
629 | break; |
||
630 | case 'm': |
||
631 | if (strlen(optarg) == 12) |
||
632 | memcpy(rom_id, optarg, 12); |
||
633 | break; |
||
634 | case 'r': |
||
635 | rootfs_info.file_name = optarg; |
||
636 | break; |
||
637 | case 'o': |
||
638 | ofname = optarg; |
||
639 | break; |
||
640 | case 's': |
||
641 | sscanf(optarg, "0x%x", &firmware_size); |
||
642 | break; |
||
643 | default: |
||
644 | usage(EXIT_FAILURE); |
||
645 | break; |
||
646 | } |
||
647 | } |
||
648 | |||
649 | ret = check_options(); |
||
650 | if (ret) |
||
651 | goto out; |
||
652 | |||
653 | if (!inspect_info.file_name) { |
||
654 | if (image_type == FACTORY) |
||
655 | ret = wrap_fw(); |
||
656 | else |
||
657 | ret = build_fw(); |
||
658 | } |
||
659 | else |
||
660 | ret = inspect_fw(); |
||
661 | |||
662 | out: |
||
663 | return ret; |
||
664 | |||
665 | } |