diff options
-rw-r--r-- | rbutil/mkimxboot/mkimxboot.c | 471 | ||||
-rw-r--r-- | rbutil/mkimxboot/mkimxboot.h | 3 |
2 files changed, 252 insertions, 222 deletions
diff --git a/rbutil/mkimxboot/mkimxboot.c b/rbutil/mkimxboot/mkimxboot.c index d420afce5d..da1e49876d 100644 --- a/rbutil/mkimxboot/mkimxboot.c +++ b/rbutil/mkimxboot/mkimxboot.c | |||
@@ -28,6 +28,14 @@ | |||
28 | #include "dualboot.h" | 28 | #include "dualboot.h" |
29 | #include "md5.h" | 29 | #include "md5.h" |
30 | 30 | ||
31 | /* abstract structure to represent a Rockbox firmware. It can be a scrambled file | ||
32 | * or an ELF file or whatever. */ | ||
33 | struct rb_fw_t | ||
34 | { | ||
35 | void *boot; | ||
36 | size_t boot_sz; | ||
37 | }; | ||
38 | |||
31 | struct imx_fw_variant_desc_t | 39 | struct imx_fw_variant_desc_t |
32 | { | 40 | { |
33 | /* Offset within file */ | 41 | /* Offset within file */ |
@@ -160,7 +168,7 @@ static const struct imx_model_desc_t imx_models[] = | |||
160 | #define MAGIC_NORMAL 0xcafebabe | 168 | #define MAGIC_NORMAL 0xcafebabe |
161 | 169 | ||
162 | static enum imx_error_t patch_std_zero_host_play(int jump_before, int model, | 170 | static enum imx_error_t patch_std_zero_host_play(int jump_before, int model, |
163 | enum imx_output_type_t type, struct sb_file_t *sb_file, void *boot, size_t boot_sz) | 171 | enum imx_output_type_t type, struct sb_file_t *sb_file, struct rb_fw_t boot_fw) |
164 | { | 172 | { |
165 | /* We assume the file has three boot sections: ____, host, play and one | 173 | /* We assume the file has three boot sections: ____, host, play and one |
166 | * resource section rsrc. | 174 | * resource section rsrc. |
@@ -229,8 +237,8 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model, | |||
229 | rock_sec.insts = xmalloc(2 * sizeof(struct sb_inst_t)); | 237 | rock_sec.insts = xmalloc(2 * sizeof(struct sb_inst_t)); |
230 | memset(rock_sec.insts, 0, 2 * sizeof(struct sb_inst_t)); | 238 | memset(rock_sec.insts, 0, 2 * sizeof(struct sb_inst_t)); |
231 | rock_sec.insts[0].inst = SB_INST_LOAD; | 239 | rock_sec.insts[0].inst = SB_INST_LOAD; |
232 | rock_sec.insts[0].size = boot_sz; | 240 | rock_sec.insts[0].size = boot_fw.boot_sz; |
233 | rock_sec.insts[0].data = memdup(boot, boot_sz); | 241 | rock_sec.insts[0].data = memdup(boot_fw.boot, boot_fw.boot_sz); |
234 | rock_sec.insts[0].addr = imx_models[model].bootloader_addr; | 242 | rock_sec.insts[0].addr = imx_models[model].bootloader_addr; |
235 | rock_sec.insts[1].inst = SB_INST_JUMP; | 243 | rock_sec.insts[1].inst = SB_INST_JUMP; |
236 | rock_sec.insts[1].addr = imx_models[model].bootloader_addr; | 244 | rock_sec.insts[1].addr = imx_models[model].bootloader_addr; |
@@ -253,13 +261,13 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model, | |||
253 | sb_free_instruction(sec->insts[i]); | 261 | sb_free_instruction(sec->insts[i]); |
254 | memset(new_insts + jump_idx, 0, 2 * sizeof(struct sb_inst_t)); | 262 | memset(new_insts + jump_idx, 0, 2 * sizeof(struct sb_inst_t)); |
255 | new_insts[jump_idx + 0].inst = SB_INST_LOAD; | 263 | new_insts[jump_idx + 0].inst = SB_INST_LOAD; |
256 | new_insts[jump_idx + 0].size = boot_sz; | 264 | new_insts[jump_idx + 0].size = boot_fw.boot_sz; |
257 | new_insts[jump_idx + 0].data = memdup(boot, boot_sz); | 265 | new_insts[jump_idx + 0].data = memdup(boot_fw.boot, boot_fw.boot_sz); |
258 | new_insts[jump_idx + 0].addr = imx_models[model].bootloader_addr; | 266 | new_insts[jump_idx + 0].addr = imx_models[model].bootloader_addr; |
259 | new_insts[jump_idx + 1].inst = SB_INST_JUMP; | 267 | new_insts[jump_idx + 1].inst = SB_INST_JUMP; |
260 | new_insts[jump_idx + 1].addr = imx_models[model].bootloader_addr; | 268 | new_insts[jump_idx + 1].addr = imx_models[model].bootloader_addr; |
261 | new_insts[jump_idx + 1].argument = recovery ? MAGIC_RECOVERY : MAGIC_NORMAL; | 269 | new_insts[jump_idx + 1].argument = recovery ? MAGIC_RECOVERY : MAGIC_NORMAL; |
262 | 270 | ||
263 | free(sec->insts); | 271 | free(sec->insts); |
264 | sec->insts = new_insts; | 272 | sec->insts = new_insts; |
265 | sec->nr_insts = jump_idx + 2; | 273 | sec->nr_insts = jump_idx + 2; |
@@ -327,7 +335,7 @@ static enum imx_error_t parse_version(const char *s, struct sb_version_t *ver) | |||
327 | 335 | ||
328 | static enum imx_error_t patch_firmware(enum imx_model_t model, | 336 | static enum imx_error_t patch_firmware(enum imx_model_t model, |
329 | enum imx_firmware_variant_t variant, enum imx_output_type_t type, | 337 | enum imx_firmware_variant_t variant, enum imx_output_type_t type, |
330 | struct sb_file_t *sb_file, void *boot, size_t boot_sz, | 338 | struct sb_file_t *sb_file, struct rb_fw_t boot_fw, |
331 | const char *force_version) | 339 | const char *force_version) |
332 | { | 340 | { |
333 | if(force_version) | 341 | if(force_version) |
@@ -342,11 +350,11 @@ static enum imx_error_t patch_firmware(enum imx_model_t model, | |||
342 | case MODEL_FUZEPLUS: | 350 | case MODEL_FUZEPLUS: |
343 | /* The Fuze+ uses the standard ____, host, play sections, patch after third | 351 | /* The Fuze+ uses the standard ____, host, play sections, patch after third |
344 | * call in ____ section */ | 352 | * call in ____ section */ |
345 | return patch_std_zero_host_play(3, model, type, sb_file, boot, boot_sz); | 353 | return patch_std_zero_host_play(3, model, type, sb_file, boot_fw); |
346 | case MODEL_ZENXFI3: | 354 | case MODEL_ZENXFI3: |
347 | /* The ZEN X-Fi3 uses the standard ____, hSst, pSay sections, patch after third | 355 | /* The ZEN X-Fi3 uses the standard ____, hSst, pSay sections, patch after third |
348 | * call in ____ section. Although sections names use the S variant, they are standard. */ | 356 | * call in ____ section. Although sections names use the S variant, they are standard. */ |
349 | return patch_std_zero_host_play(3, model, type, sb_file, boot, boot_sz); | 357 | return patch_std_zero_host_play(3, model, type, sb_file, boot_fw); |
350 | case MODEL_ZENXFI2: | 358 | case MODEL_ZENXFI2: |
351 | /* The ZEN X-Fi2 has two types of firmware: recovery and normal. | 359 | /* The ZEN X-Fi2 has two types of firmware: recovery and normal. |
352 | * Normal uses the standard ___, host, play sections and recovery only ____ */ | 360 | * Normal uses the standard ___, host, play sections and recovery only ____ */ |
@@ -355,7 +363,7 @@ static enum imx_error_t patch_firmware(enum imx_model_t model, | |||
355 | case VARIANT_ZENXFI2_RECOVERY: | 363 | case VARIANT_ZENXFI2_RECOVERY: |
356 | case VARIANT_ZENXFI2_NAND: | 364 | case VARIANT_ZENXFI2_NAND: |
357 | case VARIANT_ZENXFI2_SD: | 365 | case VARIANT_ZENXFI2_SD: |
358 | return patch_std_zero_host_play(1, model, type, sb_file, boot, boot_sz); | 366 | return patch_std_zero_host_play(1, model, type, sb_file, boot_fw); |
359 | default: | 367 | default: |
360 | return IMX_DONT_KNOW_HOW_TO_PATCH; | 368 | return IMX_DONT_KNOW_HOW_TO_PATCH; |
361 | } | 369 | } |
@@ -413,165 +421,240 @@ void dump_imx_dev_info(const char *prefix) | |||
413 | } | 421 | } |
414 | } | 422 | } |
415 | 423 | ||
416 | enum imx_error_t mkimxboot(const char *infile, const char *bootfile, | 424 | /* find an entry into imx_sums which matches the MD5 sum of a file */ |
417 | const char *outfile, struct imx_option_t opt) | 425 | static enum imx_error_t find_model_by_md5sum(uint8_t file_md5sum[16], int *md5_idx) |
418 | { | 426 | { |
419 | /* Dump tables */ | 427 | int i = 0; |
420 | if(opt.fw_variant > VARIANT_COUNT) { | 428 | while(i < NR_IMX_SUMS) |
421 | return IMX_ERROR; | ||
422 | } | ||
423 | dump_imx_dev_info("[INFO] "); | ||
424 | /* compute MD5 sum of the file */ | ||
425 | uint8_t file_md5sum[16]; | ||
426 | do | ||
427 | { | 429 | { |
428 | FILE *f = fopen(infile, "rb"); | 430 | uint8_t md5[20]; |
429 | if(f == NULL) | 431 | if(strlen(imx_sums[i].md5sum) != 32) |
430 | { | 432 | { |
431 | printf("[ERR] Cannot open input file\n"); | 433 | printf("[INFO] Invalid MD5 sum in imx_sums\n"); |
432 | return IMX_OPEN_ERROR; | 434 | return IMX_ERROR; |
433 | } | 435 | } |
434 | fseek(f, 0, SEEK_END); | 436 | for(int j = 0; j < 16; j++) |
435 | size_t sz = ftell(f); | ||
436 | fseek(f, 0, SEEK_SET); | ||
437 | void *buf = xmalloc(sz); | ||
438 | if(fread(buf, sz, 1, f) != 1) | ||
439 | { | 437 | { |
440 | fclose(f); | 438 | byte a, b; |
441 | free(buf); | 439 | if(convxdigit(imx_sums[i].md5sum[2 * j], &a) || convxdigit(imx_sums[i].md5sum[2 * j + 1], &b)) |
442 | printf("[ERR] Cannot read file\n"); | 440 | { |
443 | return IMX_READ_ERROR; | 441 | printf("[ERR][INTERNAL] Bad checksum format: %s\n", imx_sums[i].md5sum); |
442 | return IMX_ERROR; | ||
443 | } | ||
444 | md5[j] = (a << 4) | b; | ||
444 | } | 445 | } |
446 | if(memcmp(file_md5sum, md5, 16) == 0) | ||
447 | break; | ||
448 | i++; | ||
449 | } | ||
450 | if(i == NR_IMX_SUMS) | ||
451 | { | ||
452 | printf("[ERR] MD5 sum doesn't match any known file\n"); | ||
453 | return IMX_NO_MATCH; | ||
454 | } | ||
455 | *md5_idx = i; | ||
456 | return IMX_SUCCESS; | ||
457 | } | ||
458 | |||
459 | /* read a file to a buffer */ | ||
460 | static enum imx_error_t read_file(const char *file, void **buffer, size_t *size) | ||
461 | { | ||
462 | FILE *f = fopen(file, "rb"); | ||
463 | if(f == NULL) | ||
464 | { | ||
465 | printf("[ERR] Cannot open file '%s' for reading: %m\n", file); | ||
466 | return IMX_OPEN_ERROR; | ||
467 | } | ||
468 | fseek(f, 0, SEEK_END); | ||
469 | *size = ftell(f); | ||
470 | fseek(f, 0, SEEK_SET); | ||
471 | *buffer = xmalloc(*size); | ||
472 | if(fread(*buffer, *size, 1, f) != 1) | ||
473 | { | ||
474 | free(*buffer); | ||
475 | fclose(f); | ||
476 | printf("[ERR] Cannot read file '%s': %m\n", file); | ||
477 | return IMX_READ_ERROR; | ||
478 | } | ||
479 | fclose(f); | ||
480 | return IMX_SUCCESS; | ||
481 | } | ||
482 | |||
483 | /* write a file from a buffer */ | ||
484 | static enum imx_error_t write_file(const char *file, void *buffer, size_t size) | ||
485 | { | ||
486 | FILE *f = fopen(file, "wb"); | ||
487 | if(f == NULL) | ||
488 | { | ||
489 | printf("[ERR] Cannot open file '%s' for writing: %m\n", file); | ||
490 | return IMX_OPEN_ERROR; | ||
491 | } | ||
492 | if(fwrite(buffer, size, 1, f) != 1) | ||
493 | { | ||
494 | fclose(f); | ||
495 | printf("[ERR] Cannot write file '%s': %m\n", file); | ||
496 | return IMX_WRITE_ERROR; | ||
497 | } | ||
498 | fclose(f); | ||
499 | return IMX_SUCCESS; | ||
500 | } | ||
501 | |||
502 | /* compute MD5 sum of a buffer */ | ||
503 | static enum imx_error_t compute_md5sum_buf(void *buf, size_t sz, uint8_t file_md5sum[16]) | ||
504 | { | ||
505 | md5_context ctx; | ||
506 | md5_starts(&ctx); | ||
507 | md5_update(&ctx, buf, sz); | ||
508 | md5_finish(&ctx, file_md5sum); | ||
509 | return IMX_SUCCESS; | ||
510 | } | ||
511 | |||
512 | /* compute MD5 of a file */ | ||
513 | static enum imx_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16]) | ||
514 | { | ||
515 | FILE *f = fopen(file, "rb"); | ||
516 | if(f == NULL) | ||
517 | { | ||
518 | printf("[ERR] Cannot open input file\n"); | ||
519 | return IMX_OPEN_ERROR; | ||
520 | } | ||
521 | fseek(f, 0, SEEK_END); | ||
522 | size_t sz = ftell(f); | ||
523 | fseek(f, 0, SEEK_SET); | ||
524 | void *buf = xmalloc(sz); | ||
525 | if(fread(buf, sz, 1, f) != 1) | ||
526 | { | ||
445 | fclose(f); | 527 | fclose(f); |
446 | md5_context ctx; | ||
447 | md5_starts(&ctx); | ||
448 | md5_update(&ctx, buf, sz); | ||
449 | md5_finish(&ctx, file_md5sum); | ||
450 | free(buf); | 528 | free(buf); |
451 | }while(0); | 529 | printf("[ERR] Cannot read file\n"); |
530 | return IMX_READ_ERROR; | ||
531 | } | ||
532 | fclose(f); | ||
533 | compute_md5sum_buf(buf, sz, file_md5sum); | ||
534 | free(buf); | ||
535 | return IMX_SUCCESS; | ||
536 | } | ||
537 | |||
538 | static enum imx_error_t load_sb_file(const char *file, int md5_idx, | ||
539 | struct imx_option_t opt, struct sb_file_t **sb_file) | ||
540 | { | ||
541 | if(imx_sums[md5_idx].fw_variants[opt.fw_variant].size == 0) | ||
542 | { | ||
543 | printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[opt.fw_variant]); | ||
544 | return IMX_VARIANT_MISMATCH; | ||
545 | } | ||
546 | enum imx_model_t model = imx_sums[md5_idx].model; | ||
547 | enum sb_error_t err; | ||
548 | g_debug = opt.debug; | ||
549 | clear_keys(); | ||
550 | add_keys(imx_models[model].keys, imx_models[model].nr_keys); | ||
551 | *sb_file = sb_read_file_ex(file, imx_sums[md5_idx].fw_variants[opt.fw_variant].offset, | ||
552 | imx_sums[md5_idx].fw_variants[opt.fw_variant].size, false, NULL, &imx_printf, &err); | ||
553 | if(*sb_file == NULL) | ||
554 | { | ||
555 | clear_keys(); | ||
556 | return IMX_FIRST_SB_ERROR + err; | ||
557 | } | ||
558 | return IMX_SUCCESS; | ||
559 | } | ||
560 | |||
561 | /* Load a rockbox firwmare from a buffer. Data is copied. */ | ||
562 | static enum imx_error_t rb_fw_load_buf(struct rb_fw_t *fw, uint8_t *buf, size_t sz, | ||
563 | enum imx_model_t model) | ||
564 | { | ||
565 | if(sz < 8) | ||
566 | { | ||
567 | printf("[ERR] Bootloader file is too small to be valid\n"); | ||
568 | return IMX_BOOT_INVALID; | ||
569 | } | ||
570 | /* check model name */ | ||
571 | uint8_t *name = buf + 4; | ||
572 | if(memcmp(name, imx_models[model].rb_model_name, 4) != 0) | ||
573 | { | ||
574 | printf("[ERR] Bootloader model doesn't match found model for input file\n"); | ||
575 | return IMX_BOOT_MISMATCH; | ||
576 | } | ||
577 | /* check checksum */ | ||
578 | uint32_t sum = imx_models[model].rb_model_num; | ||
579 | for(int i = 8; i < sz; i++) | ||
580 | sum += buf[i]; | ||
581 | if(sum != get_uint32be(buf)) | ||
582 | { | ||
583 | printf("[ERR] Bootloader checksum mismatch\n"); | ||
584 | return IMX_BOOT_CHECKSUM_ERROR; | ||
585 | } | ||
586 | fw->boot = memdup(buf + 8, sz - 8); | ||
587 | fw->boot_sz = sz - 8; | ||
588 | return IMX_SUCCESS; | ||
589 | } | ||
590 | |||
591 | /* load a rockbox firmware from a file. */ | ||
592 | static enum imx_error_t rb_fw_load(struct rb_fw_t *fw, const char *file, | ||
593 | enum imx_model_t model) | ||
594 | { | ||
595 | void *buf; | ||
596 | size_t sz; | ||
597 | int ret = read_file(file, &buf, &sz); | ||
598 | if(ret == IMX_SUCCESS) | ||
599 | { | ||
600 | ret = rb_fw_load_buf(fw, buf, sz, model); | ||
601 | free(buf); | ||
602 | } | ||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | /* free rockbox firmware */ | ||
607 | static void rb_fw_free(struct rb_fw_t *fw) | ||
608 | { | ||
609 | free(fw->boot); | ||
610 | fw->boot = NULL; | ||
611 | fw->boot_sz = 0; | ||
612 | } | ||
613 | |||
614 | enum imx_error_t mkimxboot(const char *infile, const char *bootfile, | ||
615 | const char *outfile, struct imx_option_t opt) | ||
616 | { | ||
617 | /* sanity check */ | ||
618 | if(opt.fw_variant > VARIANT_COUNT) | ||
619 | return IMX_ERROR; | ||
620 | /* Dump tables */ | ||
621 | dump_imx_dev_info("[INFO] "); | ||
622 | /* compute MD5 sum of the file */ | ||
623 | uint8_t file_md5sum[16]; | ||
624 | enum imx_error_t ret = compute_md5sum(infile, file_md5sum); | ||
625 | if(ret != IMX_SUCCESS) | ||
626 | return ret; | ||
452 | printf("[INFO] MD5 sum of the file: "); | 627 | printf("[INFO] MD5 sum of the file: "); |
453 | print_hex(file_md5sum, 16, true); | 628 | print_hex(file_md5sum, 16, true); |
454 | /* find model */ | 629 | /* find model */ |
455 | enum imx_model_t model; | ||
456 | int md5_idx; | 630 | int md5_idx; |
457 | do | 631 | ret = find_model_by_md5sum(file_md5sum, &md5_idx); |
458 | { | 632 | if(ret != IMX_SUCCESS) |
459 | int i = 0; | 633 | return ret; |
460 | while(i < NR_IMX_SUMS) | 634 | enum imx_model_t model = imx_sums[md5_idx].model; |
461 | { | ||
462 | uint8_t md5[20]; | ||
463 | if(strlen(imx_sums[i].md5sum) != 32) | ||
464 | { | ||
465 | printf("[INFO] Invalid MD5 sum in imx_sums\n"); | ||
466 | return IMX_ERROR; | ||
467 | } | ||
468 | for(int j = 0; j < 16; j++) | ||
469 | { | ||
470 | byte a, b; | ||
471 | if(convxdigit(imx_sums[i].md5sum[2 * j], &a) || convxdigit(imx_sums[i].md5sum[2 * j + 1], &b)) | ||
472 | { | ||
473 | printf("[ERR][INTERNAL] Bad checksum format: %s\n", imx_sums[i].md5sum); | ||
474 | return IMX_ERROR; | ||
475 | } | ||
476 | md5[j] = (a << 4) | b; | ||
477 | } | ||
478 | if(memcmp(file_md5sum, md5, 16) == 0) | ||
479 | break; | ||
480 | i++; | ||
481 | } | ||
482 | if(i == NR_IMX_SUMS) | ||
483 | { | ||
484 | printf("[ERR] MD5 sum doesn't match any known file\n"); | ||
485 | return IMX_NO_MATCH; | ||
486 | } | ||
487 | model = imx_sums[i].model; | ||
488 | md5_idx = i; | ||
489 | }while(0); | ||
490 | printf("[INFO] File is for model %d (%s, version %s)\n", model, | 635 | printf("[INFO] File is for model %d (%s, version %s)\n", model, |
491 | imx_models[model].model_name, imx_sums[md5_idx].version); | 636 | imx_models[model].model_name, imx_sums[md5_idx].version); |
492 | /* load rockbox file */ | 637 | /* load rockbox file */ |
493 | uint8_t *boot; | 638 | struct rb_fw_t boot_fw; |
494 | size_t boot_size; | 639 | ret = rb_fw_load(&boot_fw, bootfile, model); |
495 | do | 640 | if(ret != IMX_SUCCESS) |
496 | { | 641 | return ret; |
497 | FILE *f = fopen(bootfile, "rb"); | ||
498 | if(f == NULL) | ||
499 | { | ||
500 | printf("[ERR] Cannot open boot file\n"); | ||
501 | return IMX_OPEN_ERROR; | ||
502 | } | ||
503 | fseek(f, 0, SEEK_END); | ||
504 | boot_size = ftell(f); | ||
505 | fseek(f, 0, SEEK_SET); | ||
506 | boot = xmalloc(boot_size); | ||
507 | if(fread(boot, boot_size, 1, f) != 1) | ||
508 | { | ||
509 | free(boot); | ||
510 | fclose(f); | ||
511 | printf("[ERR] Cannot read boot file\n"); | ||
512 | return IMX_READ_ERROR; | ||
513 | } | ||
514 | fclose(f); | ||
515 | }while(0); | ||
516 | /* Check boot file */ | ||
517 | do | ||
518 | { | ||
519 | if(boot_size < 8) | ||
520 | { | ||
521 | printf("[ERR] Bootloader file is too small to be valid\n"); | ||
522 | free(boot); | ||
523 | return IMX_BOOT_INVALID; | ||
524 | } | ||
525 | /* check model name */ | ||
526 | uint8_t *name = boot + 4; | ||
527 | if(memcmp(name, imx_models[model].rb_model_name, 4) != 0) | ||
528 | { | ||
529 | printf("[ERR] Bootloader model doesn't match found model for input file\n"); | ||
530 | free(boot); | ||
531 | return IMX_BOOT_MISMATCH; | ||
532 | } | ||
533 | /* check checksum */ | ||
534 | uint32_t sum = imx_models[model].rb_model_num; | ||
535 | for(int i = 8; i < boot_size; i++) | ||
536 | sum += boot[i]; | ||
537 | if(sum != get_uint32be(boot)) | ||
538 | { | ||
539 | printf("[ERR] Bootloader checksum mismatch\n"); | ||
540 | free(boot); | ||
541 | return IMX_BOOT_CHECKSUM_ERROR; | ||
542 | } | ||
543 | }while(0); | ||
544 | /* load OF file */ | 642 | /* load OF file */ |
545 | struct sb_file_t *sb_file; | 643 | struct sb_file_t *sb_file; |
546 | do | 644 | ret = load_sb_file(infile, md5_idx, opt, &sb_file); |
645 | if(ret != IMX_SUCCESS) | ||
547 | { | 646 | { |
548 | if(imx_sums[md5_idx].fw_variants[opt.fw_variant].size == 0) | 647 | rb_fw_free(&boot_fw); |
549 | { | 648 | return ret; |
550 | printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[opt.fw_variant]); | 649 | } |
551 | free(boot); | ||
552 | return IMX_VARIANT_MISMATCH; | ||
553 | } | ||
554 | enum sb_error_t err; | ||
555 | g_debug = opt.debug; | ||
556 | clear_keys(); | ||
557 | add_keys(imx_models[model].keys, imx_models[model].nr_keys); | ||
558 | sb_file = sb_read_file_ex(infile, imx_sums[md5_idx].fw_variants[opt.fw_variant].offset, | ||
559 | imx_sums[md5_idx].fw_variants[opt.fw_variant].size, false, NULL, &imx_printf, &err); | ||
560 | if(sb_file == NULL) | ||
561 | { | ||
562 | clear_keys(); | ||
563 | free(boot); | ||
564 | return IMX_FIRST_SB_ERROR + err; | ||
565 | } | ||
566 | }while(0); | ||
567 | /* produce file */ | 650 | /* produce file */ |
568 | enum imx_error_t ret = patch_firmware(model, opt.fw_variant, opt.output, | 651 | ret = patch_firmware(model, opt.fw_variant, opt.output, |
569 | sb_file, boot + 8, boot_size - 8, opt.force_version); | 652 | sb_file, boot_fw, opt.force_version); |
570 | if(ret == IMX_SUCCESS) | 653 | if(ret == IMX_SUCCESS) |
571 | ret = sb_write_file(sb_file, outfile); | 654 | ret = sb_write_file(sb_file, outfile); |
572 | 655 | ||
573 | clear_keys(); | 656 | clear_keys(); |
574 | free(boot); | 657 | rb_fw_free(&boot_fw); |
575 | sb_free(sb_file); | 658 | sb_free(sb_file); |
576 | return ret; | 659 | return ret; |
577 | } | 660 | } |
@@ -579,78 +662,38 @@ enum imx_error_t mkimxboot(const char *infile, const char *bootfile, | |||
579 | enum imx_error_t extract_firmware(const char *infile, | 662 | enum imx_error_t extract_firmware(const char *infile, |
580 | enum imx_firmware_variant_t fw_variant, const char *outfile) | 663 | enum imx_firmware_variant_t fw_variant, const char *outfile) |
581 | { | 664 | { |
582 | /* Dump tables */ | 665 | /* sanity check */ |
583 | if(fw_variant > VARIANT_COUNT) { | 666 | if(fw_variant > VARIANT_COUNT) |
584 | return IMX_ERROR; | 667 | return IMX_ERROR; |
585 | } | 668 | /* dump tables */ |
586 | dump_imx_dev_info("[INFO] "); | 669 | dump_imx_dev_info("[INFO] "); |
587 | /* compute MD5 sum of the file */ | 670 | /* compute MD5 sum of the file */ |
671 | void *buf; | ||
672 | size_t sz; | ||
588 | uint8_t file_md5sum[16]; | 673 | uint8_t file_md5sum[16]; |
589 | FILE *f = fopen(infile, "rb"); | 674 | int ret = read_file(infile, &buf, &sz); |
590 | if(f == NULL) | 675 | if(ret != IMX_SUCCESS) |
591 | { | 676 | return ret; |
592 | printf("[ERR] Cannot open input file\n"); | 677 | ret = compute_md5sum_buf(buf, sz, file_md5sum); |
593 | return IMX_OPEN_ERROR; | 678 | if(ret != IMX_SUCCESS) |
594 | } | ||
595 | fseek(f, 0, SEEK_END); | ||
596 | size_t sz = ftell(f); | ||
597 | fseek(f, 0, SEEK_SET); | ||
598 | void *buf = xmalloc(sz); | ||
599 | if(fread(buf, sz, 1, f) != 1) | ||
600 | { | 679 | { |
601 | fclose(f); | ||
602 | free(buf); | 680 | free(buf); |
603 | printf("[ERR] Cannot read file\n"); | 681 | return ret; |
604 | return IMX_READ_ERROR; | ||
605 | } | 682 | } |
606 | md5_context ctx; | ||
607 | md5_starts(&ctx); | ||
608 | md5_update(&ctx, buf, sz); | ||
609 | md5_finish(&ctx, file_md5sum); | ||
610 | fclose(f); | ||
611 | |||
612 | printf("[INFO] MD5 sum of the file: "); | 683 | printf("[INFO] MD5 sum of the file: "); |
613 | print_hex(file_md5sum, 16, true); | 684 | print_hex(file_md5sum, 16, true); |
614 | /* find model */ | 685 | /* find model */ |
615 | enum imx_model_t model; | ||
616 | int md5_idx; | 686 | int md5_idx; |
617 | do | 687 | ret = find_model_by_md5sum(file_md5sum, &md5_idx); |
688 | if(ret != IMX_SUCCESS) | ||
618 | { | 689 | { |
619 | int i = 0; | 690 | free(buf); |
620 | while(i < NR_IMX_SUMS) | 691 | return ret; |
621 | { | 692 | } |
622 | uint8_t md5[20]; | 693 | enum imx_model_t model = imx_sums[md5_idx].model; |
623 | if(strlen(imx_sums[i].md5sum) != 32) | ||
624 | { | ||
625 | printf("[INFO] Invalid MD5 sum in imx_sums\n"); | ||
626 | return IMX_ERROR; | ||
627 | } | ||
628 | for(int j = 0; j < 16; j++) | ||
629 | { | ||
630 | byte a, b; | ||
631 | if(convxdigit(imx_sums[i].md5sum[2 * j], &a) || convxdigit(imx_sums[i].md5sum[2 * j + 1], &b)) | ||
632 | { | ||
633 | printf("[ERR][INTERNAL] Bad checksum format: %s\n", imx_sums[i].md5sum); | ||
634 | free(buf); | ||
635 | return IMX_ERROR; | ||
636 | } | ||
637 | md5[j] = (a << 4) | b; | ||
638 | } | ||
639 | if(memcmp(file_md5sum, md5, 16) == 0) | ||
640 | break; | ||
641 | i++; | ||
642 | } | ||
643 | if(i == NR_IMX_SUMS) | ||
644 | { | ||
645 | printf("[ERR] MD5 sum doesn't match any known file\n"); | ||
646 | return IMX_NO_MATCH; | ||
647 | } | ||
648 | model = imx_sums[i].model; | ||
649 | md5_idx = i; | ||
650 | }while(0); | ||
651 | printf("[INFO] File is for model %d (%s, version %s)\n", model, | 694 | printf("[INFO] File is for model %d (%s, version %s)\n", model, |
652 | imx_models[model].model_name, imx_sums[md5_idx].version); | 695 | imx_models[model].model_name, imx_sums[md5_idx].version); |
653 | 696 | /* extract firmware */ | |
654 | if(imx_sums[md5_idx].fw_variants[fw_variant].size == 0) | 697 | if(imx_sums[md5_idx].fw_variants[fw_variant].size == 0) |
655 | { | 698 | { |
656 | printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[fw_variant]); | 699 | printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[fw_variant]); |
@@ -658,23 +701,9 @@ enum imx_error_t extract_firmware(const char *infile, | |||
658 | return IMX_VARIANT_MISMATCH; | 701 | return IMX_VARIANT_MISMATCH; |
659 | } | 702 | } |
660 | 703 | ||
661 | f = fopen(outfile, "wb"); | 704 | ret = write_file(outfile, |
662 | if(f == NULL) | 705 | buf + imx_sums[md5_idx].fw_variants[fw_variant].offset, |
663 | { | 706 | imx_sums[md5_idx].fw_variants[fw_variant].size); |
664 | printf("[ERR] Cannot open input file\n"); | ||
665 | free(buf); | ||
666 | return IMX_OPEN_ERROR; | ||
667 | } | ||
668 | enum imx_error_t ret = IMX_SUCCESS; | ||
669 | |||
670 | if(fwrite(buf + imx_sums[md5_idx].fw_variants[fw_variant].offset, | ||
671 | imx_sums[md5_idx].fw_variants[fw_variant].size, 1, f) != 1) | ||
672 | { | ||
673 | printf("[ERR] Cannot write file\n"); | ||
674 | ret = IMX_ERROR; | ||
675 | } | ||
676 | fclose(f); | ||
677 | free(buf); | 707 | free(buf); |
678 | |||
679 | return ret; | 708 | return ret; |
680 | } | 709 | } |
diff --git a/rbutil/mkimxboot/mkimxboot.h b/rbutil/mkimxboot/mkimxboot.h index 748742f523..de564dc5d4 100644 --- a/rbutil/mkimxboot/mkimxboot.h +++ b/rbutil/mkimxboot/mkimxboot.h | |||
@@ -41,7 +41,8 @@ enum imx_error_t | |||
41 | IMX_BOOT_CHECKSUM_ERROR = -7, | 41 | IMX_BOOT_CHECKSUM_ERROR = -7, |
42 | IMX_DONT_KNOW_HOW_TO_PATCH = -8, | 42 | IMX_DONT_KNOW_HOW_TO_PATCH = -8, |
43 | IMX_VARIANT_MISMATCH = -9, | 43 | IMX_VARIANT_MISMATCH = -9, |
44 | IMX_FIRST_SB_ERROR = -10, | 44 | IMX_WRITE_ERROR = -10, |
45 | IMX_FIRST_SB_ERROR = -11, | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | enum imx_output_type_t | 48 | enum imx_output_type_t |