diff options
Diffstat (limited to 'utils/rknanoutils/rkboottool/rkboottool.c')
-rw-r--r-- | utils/rknanoutils/rkboottool/rkboottool.c | 295 |
1 files changed, 280 insertions, 15 deletions
diff --git a/utils/rknanoutils/rkboottool/rkboottool.c b/utils/rknanoutils/rkboottool/rkboottool.c index e41224065d..f1e0e97f69 100644 --- a/utils/rknanoutils/rkboottool/rkboottool.c +++ b/utils/rknanoutils/rkboottool/rkboottool.c | |||
@@ -3,9 +3,12 @@ | |||
3 | #include <stdbool.h> | 3 | #include <stdbool.h> |
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
5 | #include <string.h> | 5 | #include <string.h> |
6 | #include <getopt.h> | ||
6 | #include "misc.h" | 7 | #include "misc.h" |
7 | 8 | ||
8 | #define cprintf(col, ...) do {printf("%s", col); printf(__VA_ARGS__); }while(0) | 9 | #define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0) |
10 | |||
11 | bool g_debug = false; | ||
9 | 12 | ||
10 | typedef uint8_t packed_bcd_uint8_t; | 13 | typedef uint8_t packed_bcd_uint8_t; |
11 | typedef uint16_t packed_bcd_uint16_t; | 14 | typedef uint16_t packed_bcd_uint16_t; |
@@ -72,7 +75,7 @@ struct rknano_header_t | |||
72 | char magic[MAGIC_RKNANOFW_SIZE]; | 75 | char magic[MAGIC_RKNANOFW_SIZE]; |
73 | }; | 76 | }; |
74 | 77 | ||
75 | char *prefix = NULL; | 78 | char *g_out_prefix = NULL; |
76 | 79 | ||
77 | static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size) | 80 | static void encode_page(uint8_t *inpg, uint8_t *outpg, const int size) |
78 | { | 81 | { |
@@ -137,10 +140,10 @@ static uint16_t crc(uint8_t *buf, int size) | |||
137 | static void save_blob(const struct rknano_blob_t *b, void *buf, uint32_t size, | 140 | static void save_blob(const struct rknano_blob_t *b, void *buf, uint32_t size, |
138 | char *name, int suffix, bool descramble) | 141 | char *name, int suffix, bool descramble) |
139 | { | 142 | { |
140 | if(prefix == NULL || b->size == 0 || b->offset + b->size > size) | 143 | if(g_out_prefix == NULL || b->size == 0 || b->offset + b->size > size) |
141 | return; | 144 | return; |
142 | char *path = malloc(strlen(prefix) + strlen(name) + 32); | 145 | char *path = malloc(strlen(g_out_prefix) + strlen(name) + 32); |
143 | sprintf(path, "%s%s%d.bin", prefix, name, suffix); | 146 | sprintf(path, "%s%s%d.bin", g_out_prefix, name, suffix); |
144 | FILE *f = fopen(path, "wb"); | 147 | FILE *f = fopen(path, "wb"); |
145 | uint8_t *ptr = buf + b->offset; | 148 | uint8_t *ptr = buf + b->offset; |
146 | if(descramble) | 149 | if(descramble) |
@@ -164,16 +167,15 @@ static void print_blob_interval(const struct rknano_blob_t *b) | |||
164 | cprintf(YELLOW, "%#x -> %#x", b->offset, b->offset + b->size); | 167 | cprintf(YELLOW, "%#x -> %#x", b->offset, b->offset + b->size); |
165 | } | 168 | } |
166 | 169 | ||
167 | static int do_image(int argc, char **argv, uint8_t *buf, unsigned long size) | 170 | static int do_nanofw_image(uint8_t *buf, unsigned long size) |
168 | { | 171 | { |
169 | (void) argc; | ||
170 | (void) argv; | ||
171 | |||
172 | if(size < sizeof(struct rknano_header_t)) | 172 | if(size < sizeof(struct rknano_header_t)) |
173 | return 1; | 173 | return 1; |
174 | struct rknano_header_t *hdr = (void *)buf; | 174 | struct rknano_header_t *hdr = (void *)buf; |
175 | if(size < hdr->size) | 175 | if(size < hdr->size) |
176 | return 1; | 176 | return 1; |
177 | if(strncmp(hdr->magic, MAGIC_RKNANOFW, MAGIC_RKNANOFW_SIZE)) | ||
178 | return 1; | ||
177 | 179 | ||
178 | cprintf(BLUE, "Header\n"); | 180 | cprintf(BLUE, "Header\n"); |
179 | cprintf(GREEN, " Date: "); | 181 | cprintf(GREEN, " Date: "); |
@@ -249,18 +251,269 @@ static int do_image(int argc, char **argv, uint8_t *buf, unsigned long size) | |||
249 | return 0; | 251 | return 0; |
250 | } | 252 | } |
251 | 253 | ||
254 | struct rknano_stage_header_t | ||
255 | { | ||
256 | uint32_t addr; | ||
257 | } __attribute__((packed)); | ||
258 | |||
259 | struct rknano_stage_section_t | ||
260 | { | ||
261 | uint32_t a; | ||
262 | uint32_t code_pa; | ||
263 | uint32_t code_va; | ||
264 | uint32_t code_sz; | ||
265 | uint32_t data_pa; | ||
266 | uint32_t data_va; | ||
267 | uint32_t data_sz; | ||
268 | uint32_t bss_end_va; | ||
269 | } __attribute__((packed)); | ||
270 | |||
271 | static int do_nanostage_image(uint8_t *buf, unsigned long size) | ||
272 | { | ||
273 | if(size < sizeof(struct rknano_stage_section_t)) | ||
274 | return 1; | ||
275 | struct rknano_stage_header_t *hdr = (void *)buf; | ||
276 | |||
277 | cprintf(BLUE, "Header\n"); | ||
278 | cprintf(GREEN, " Base Address: "); | ||
279 | cprintf(YELLOW, "%#x\n", hdr->addr); | ||
280 | |||
281 | struct rknano_stage_section_t *sec = (void *)(hdr + 1); | ||
282 | void *end = buf + size; | ||
283 | |||
284 | int i = 0; | ||
285 | while((void *)sec < end && (sec->code_sz || sec->bss_end_va)) | ||
286 | { | ||
287 | cprintf(BLUE, "Section %d\n", i); | ||
288 | cprintf(GREEN, " Something: "); | ||
289 | cprintf(YELLOW, "%#x\n", sec->a); | ||
290 | cprintf(GREEN, " Code: "); | ||
291 | cprintf(YELLOW, "%#x", sec->code_pa); | ||
292 | cprintf(BLUE, " |--> "); | ||
293 | cprintf(YELLOW, "%#x", sec->code_va); | ||
294 | cprintf(RED, "-(code)-"); | ||
295 | cprintf(YELLOW, "%#x\n", sec->code_va + sec->code_sz); | ||
296 | |||
297 | cprintf(GREEN, " Data: "); | ||
298 | cprintf(YELLOW, "%#x", sec->data_pa); | ||
299 | cprintf(BLUE, " |--> "); | ||
300 | cprintf(YELLOW, "%#x", sec->data_va); | ||
301 | cprintf(RED, "-(data)-"); | ||
302 | cprintf(YELLOW, "%#x", sec->data_va + sec->data_sz); | ||
303 | cprintf(RED, "-(bss)-"); | ||
304 | cprintf(YELLOW, "%#x\n", sec->bss_end_va); | ||
305 | |||
306 | sec++; | ||
307 | i++; | ||
308 | } | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | #define MAGIC_BOOT "BOOT" | ||
314 | #define MAGIC_BOOT_SIZE 4 | ||
315 | |||
316 | struct rknano_boot_header_t | ||
317 | { | ||
318 | char magic[MAGIC_BOOT_SIZE]; | ||
319 | uint16_t field_4; | ||
320 | uint32_t field_6; | ||
321 | uint32_t field_A; | ||
322 | uint16_t field_E; | ||
323 | uint8_t field_10[5]; | ||
324 | uint32_t field_15; | ||
325 | uint8_t field_19; | ||
326 | uint32_t field_1A; | ||
327 | uint8_t field_1E[2]; | ||
328 | uint32_t field_20; | ||
329 | uint8_t field_24[2]; | ||
330 | uint32_t field_26; | ||
331 | uint8_t field_2A[10]; | ||
332 | uint32_t field_34; | ||
333 | } __attribute__((packed)); | ||
334 | |||
335 | static int do_boot_image(uint8_t *buf, unsigned long size) | ||
336 | { | ||
337 | if(sizeof(struct rknano_boot_header_t) != 0x38) | ||
338 | printf("aie"); | ||
339 | if(size < sizeof(struct rknano_boot_header_t)) | ||
340 | return 1; | ||
341 | struct rknano_boot_header_t *hdr = (void *)buf; | ||
342 | if(strncmp(hdr->magic, MAGIC_BOOT, MAGIC_BOOT_SIZE)) | ||
343 | return 1; | ||
344 | |||
345 | cprintf(BLUE, "Header\n"); | ||
346 | cprintf(GREEN, " Magic: "); | ||
347 | cprintf(YELLOW, "%." STR(MAGIC_BOOT_SIZE) "s ", hdr->magic); | ||
348 | if(strncmp(hdr->magic, MAGIC_BOOT, MAGIC_BOOT_SIZE) == 0) | ||
349 | cprintf(RED, "OK\n"); | ||
350 | else | ||
351 | cprintf(RED, "Mismatch\n"); | ||
352 | #define print(str, name) cprintf(GREEN, " "str": ");cprintf(YELLOW, "%#x\n", (unsigned)hdr->name) | ||
353 | #define print_arr(str, name, sz) \ | ||
354 | cprintf(GREEN, " "str":");for(int i = 0; i < sz; i++)cprintf(YELLOW, " %#x", (unsigned)hdr->name[i]);printf("\n") | ||
355 | |||
356 | print("field_4", field_4); | ||
357 | print("field_6", field_6); | ||
358 | print("field_A", field_A); | ||
359 | print("field_E", field_E); | ||
360 | print_arr("field_10", field_10, 5); | ||
361 | print("field_15", field_15); | ||
362 | print("field_19", field_19); | ||
363 | print("field_1A", field_1A); | ||
364 | print_arr("field_1E", field_1E, 2); | ||
365 | print("field_20", field_20); | ||
366 | print_arr("field_24", field_24, 2); | ||
367 | print("field_26", field_26); | ||
368 | print_arr("field_2A", field_2A, 10); | ||
369 | print("field_34", field_34); | ||
370 | cprintf(GREEN, "Value: "); | ||
371 | cprintf(YELLOW, "%#x\n", *(unsigned long *)((uint8_t *)hdr + hdr->field_34 - 10)); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | typedef struct rknano_blob_t rkfw_blob_t; | ||
377 | |||
378 | #define MAGIC_RKFW "RKFW" | ||
379 | #define MAGIC_RKFW_SIZE 4 | ||
380 | |||
381 | struct rkfw_header_t | ||
382 | { | ||
383 | char magic[MAGIC_RKFW_SIZE]; | ||
384 | uint16_t hdr_size; // UNSURE | ||
385 | uint32_t field_6; | ||
386 | uint32_t field_A; | ||
387 | uint16_t field_E; | ||
388 | uint8_t field_10[5]; | ||
389 | uint32_t field_15; | ||
390 | rkfw_blob_t loader; | ||
391 | rkfw_blob_t update; | ||
392 | uint8_t pad[60]; | ||
393 | uint8_t field_65; | ||
394 | } __attribute__((packed)); | ||
395 | |||
396 | static int do_rkfw_image(uint8_t *buf, unsigned long size) | ||
397 | { | ||
398 | if(sizeof(struct rkfw_header_t) != 0x66) | ||
399 | printf("aie"); | ||
400 | if(size < sizeof(struct rkfw_header_t)) | ||
401 | return 1; | ||
402 | struct rkfw_header_t *hdr = (void *)buf; | ||
403 | if(strncmp(hdr->magic, MAGIC_RKFW, MAGIC_RKFW_SIZE)) | ||
404 | return 1; | ||
405 | |||
406 | cprintf(BLUE, "Header\n"); | ||
407 | cprintf(GREEN, " Magic: "); | ||
408 | cprintf(YELLOW, "%." STR(MAGIC_RKFW_SIZE) "s ", hdr->magic); | ||
409 | if(strncmp(hdr->magic, MAGIC_RKFW, MAGIC_RKFW_SIZE) == 0) | ||
410 | cprintf(RED, "OK\n"); | ||
411 | else | ||
412 | cprintf(RED, "Mismatch\n"); | ||
413 | |||
414 | cprintf(GREEN, " Loader: "); | ||
415 | print_blob_interval(&hdr->loader); | ||
416 | cprintf(OFF, "\n"); | ||
417 | save_blob(&hdr->loader, buf, size, "loader", 0, false); | ||
418 | |||
419 | cprintf(GREEN, " Update: "); | ||
420 | print_blob_interval(&hdr->update); | ||
421 | cprintf(OFF, "\n"); | ||
422 | save_blob(&hdr->update, buf, size, "update", 0, false); | ||
423 | |||
424 | print("hdr_size", hdr_size); | ||
425 | print("field_6", field_6); | ||
426 | print("field_A", field_A); | ||
427 | print("field_E", field_E); | ||
428 | print_arr("field_10", field_10, 5); | ||
429 | print("field_15", field_15); | ||
430 | print_arr("pad", pad, 60); | ||
431 | print("field_65", field_65); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
252 | static void usage(void) | 436 | static void usage(void) |
253 | { | 437 | { |
254 | printf("Usage: rkboottool [options] rknanoboot.bin out_prefix\n"); | 438 | printf("Usage: rkboottool [options] rknanoboot.bin\n"); |
439 | printf("Options:\n"); | ||
440 | printf(" --rkfw\tUnpack a rkfw file\n"); | ||
441 | printf(" --rknanofw\tUnpack a regular RknanoFW file\n"); | ||
442 | printf(" --rkboot\tUnpack a BOOT file\n"); | ||
443 | printf(" --rknanostage\tUnpack a RknanoFW stage file\n"); | ||
444 | printf(" -o <prefix>\tSet output prefix\n"); | ||
445 | printf("The default is to try to guess the format.\n"); | ||
446 | printf("If several formats are specified, all are tried.\n"); | ||
255 | exit(1); | 447 | exit(1); |
256 | } | 448 | } |
257 | 449 | ||
258 | int main(int argc, char **argv) | 450 | int main(int argc, char **argv) |
259 | { | 451 | { |
260 | if(argc < 3) | 452 | bool try_nanofw = false; |
453 | bool try_rkfw = false; | ||
454 | bool try_boot = false; | ||
455 | bool try_nanostage = false; | ||
456 | |||
457 | while(1) | ||
458 | { | ||
459 | static struct option long_options[] = | ||
460 | { | ||
461 | {"help", no_argument, 0, '?'}, | ||
462 | {"debug", no_argument, 0, 'd'}, | ||
463 | {"rkfw", no_argument, 0, '9'}, | ||
464 | {"rknanofw", no_argument, 0, 'n'}, | ||
465 | {"rknanostage", no_argument, 0, 's'}, | ||
466 | {"rkboot", no_argument, 0, 'b'}, | ||
467 | {"no-color", no_argument, 0, 'c'}, | ||
468 | {0, 0, 0, 0} | ||
469 | }; | ||
470 | |||
471 | int c = getopt_long(argc, argv, "?d9nscbo:", long_options, NULL); | ||
472 | if(c == -1) | ||
473 | break; | ||
474 | switch(c) | ||
475 | { | ||
476 | case -1: | ||
477 | break; | ||
478 | case 'c': | ||
479 | enable_color(false); | ||
480 | break; | ||
481 | case 'b': | ||
482 | try_boot = true; | ||
483 | break; | ||
484 | case 'n': | ||
485 | try_nanofw = true; | ||
486 | break; | ||
487 | case 'd': | ||
488 | g_debug = true; | ||
489 | break; | ||
490 | case '?': | ||
491 | usage(); | ||
492 | break; | ||
493 | case 'o': | ||
494 | g_out_prefix = optarg; | ||
495 | break; | ||
496 | case '9': | ||
497 | try_rkfw = true; | ||
498 | break; | ||
499 | case 's': | ||
500 | try_nanostage = true; | ||
501 | break; | ||
502 | default: | ||
503 | abort(); | ||
504 | } | ||
505 | } | ||
506 | |||
507 | if(argc - optind != 1) | ||
508 | { | ||
261 | usage(); | 509 | usage(); |
262 | prefix = argv[argc - 1]; | 510 | return 1; |
263 | FILE *fin = fopen(argv[argc - 2], "r"); | 511 | } |
512 | |||
513 | if(!try_nanostage && !try_rkfw && !try_nanofw && !try_boot) | ||
514 | try_nanostage = try_rkfw = try_nanofw = try_boot = true; | ||
515 | |||
516 | FILE *fin = fopen(argv[optind], "r"); | ||
264 | if(fin == NULL) | 517 | if(fin == NULL) |
265 | { | 518 | { |
266 | perror("Cannot open boot file"); | 519 | perror("Cannot open boot file"); |
@@ -284,7 +537,19 @@ int main(int argc, char **argv) | |||
284 | } | 537 | } |
285 | 538 | ||
286 | fclose(fin); | 539 | fclose(fin); |
287 | 540 | ||
288 | return do_image(argc - 1, argv, buf, size); | 541 | if(try_nanofw && !do_nanofw_image(buf, size)) |
542 | goto Lsuccess; | ||
543 | if(try_rkfw && !do_rkfw_image(buf, size)) | ||
544 | goto Lsuccess; | ||
545 | if(try_boot && !do_boot_image(buf, size)) | ||
546 | goto Lsuccess; | ||
547 | if(try_nanostage && !do_nanostage_image(buf, size)) | ||
548 | goto Lsuccess; | ||
549 | cprintf(GREY, "No valid format found!\n"); | ||
550 | Lsuccess: | ||
551 | free(buf); | ||
552 | |||
553 | return 0; | ||
289 | } | 554 | } |
290 | 555 | ||