summaryrefslogtreecommitdiff
path: root/rbutil/mkimxboot/mkimxboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/mkimxboot/mkimxboot.c')
-rw-r--r--rbutil/mkimxboot/mkimxboot.c330
1 files changed, 183 insertions, 147 deletions
diff --git a/rbutil/mkimxboot/mkimxboot.c b/rbutil/mkimxboot/mkimxboot.c
index 909dad8641..1d1ec54e10 100644
--- a/rbutil/mkimxboot/mkimxboot.c
+++ b/rbutil/mkimxboot/mkimxboot.c
@@ -38,6 +38,8 @@ struct rb_fw_t
38 int entry_idx; 38 int entry_idx;
39}; 39};
40 40
41/* A firmware upgrade can contains several variants like recovery image, or
42 * images for different models */
41struct imx_fw_variant_desc_t 43struct imx_fw_variant_desc_t
42{ 44{
43 /* Offset within file */ 45 /* Offset within file */
@@ -46,6 +48,7 @@ struct imx_fw_variant_desc_t
46 size_t size; 48 size_t size;
47}; 49};
48 50
51/* Map a MD5 sum of the whole file to a model and describe the variants in it */
49struct imx_md5sum_t 52struct imx_md5sum_t
50{ 53{
51 /* Device model */ 54 /* Device model */
@@ -58,6 +61,7 @@ struct imx_md5sum_t
58 struct imx_fw_variant_desc_t fw_variants[VARIANT_COUNT]; 61 struct imx_fw_variant_desc_t fw_variants[VARIANT_COUNT];
59}; 62};
60 63
64/* Describe how to produce a bootloader image for a specific model */
61struct imx_model_desc_t 65struct imx_model_desc_t
62{ 66{
63 /* Descriptive name of this model */ 67 /* Descriptive name of this model */
@@ -72,16 +76,15 @@ struct imx_model_desc_t
72 /* Model number used to initialise the checksum in the Rockbox header in 76 /* Model number used to initialise the checksum in the Rockbox header in
73 ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */ 77 ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */
74 const int rb_model_num; 78 const int rb_model_num;
75 /* Number of keys needed to decrypt/encrypt */ 79 /* Array of NULL-terminated keys */
76 int nr_keys; 80 struct crypto_key_t **keys;
77 /* Array of keys */
78 struct crypto_key_t *keys;
79 /* Dualboot load address */ 81 /* Dualboot load address */
80 uint32_t dualboot_addr; 82 uint32_t dualboot_addr;
81 /* Bootloader load address */ 83 /* Bootloader load address */
82 uint32_t bootloader_addr; 84 uint32_t bootloader_addr;
83}; 85};
84 86
87/* Friendly names for variants */
85static const char *imx_fw_variant[] = 88static const char *imx_fw_variant[] =
86{ 89{
87 [VARIANT_DEFAULT] = "default", 90 [VARIANT_DEFAULT] = "default",
@@ -92,6 +95,7 @@ static const char *imx_fw_variant[] =
92 [VARIANT_ZENSTYLE_RECOVERY] = "ZEN Style 100/300 Recovery", 95 [VARIANT_ZENSTYLE_RECOVERY] = "ZEN Style 100/300 Recovery",
93}; 96};
94 97
98/* List of known MD5 sums for firmware upgrades */
95static const struct imx_md5sum_t imx_sums[] = 99static const struct imx_md5sum_t imx_sums[] =
96{ 100{
97 /** Fuze+ */ 101 /** Fuze+ */
@@ -196,22 +200,24 @@ static struct crypto_key_t zero_key =
196 .u.key = {0} 200 .u.key = {0}
197}; 201};
198 202
203static struct crypto_key_t *list_zero_key[] = { &zero_key, NULL };
204static struct crypto_key_t *list_all_keys[] = { &zero_key, NULL };
205
199static const struct imx_model_desc_t imx_models[] = 206static const struct imx_model_desc_t imx_models[] =
200{ 207{
201 [MODEL_FUZEPLUS] = {"Fuze+", dualboot_fuzeplus, sizeof(dualboot_fuzeplus), "fuz+", 72, 208 [MODEL_FUZEPLUS] = {"Fuze+", dualboot_fuzeplus, sizeof(dualboot_fuzeplus),
202 1, &zero_key, 0, 0x40000000 }, 209 "fuz+", 72, list_zero_key, 0, 0x40000000 },
203 [MODEL_ZENXFI2] = {"Zen X-Fi2", dualboot_zenxfi2, sizeof(dualboot_zenxfi2), "zxf2", 82, 210 [MODEL_ZENXFI2] = {"Zen X-Fi2", dualboot_zenxfi2, sizeof(dualboot_zenxfi2),
204 1, &zero_key, 0, 0x40000000 }, 211 "zxf2", 82, list_zero_key, 0, 0x40000000 },
205 [MODEL_ZENXFI3] = {"Zen X-Fi3", dualboot_zenxfi3, sizeof(dualboot_zenxfi3), "zxf3", 83, 212 [MODEL_ZENXFI3] = {"Zen X-Fi3", dualboot_zenxfi3, sizeof(dualboot_zenxfi3),
206 1, &zero_key, 0, 0x40000000 }, 213 "zxf3", 83, list_zero_key, 0, 0x40000000 },
207 [MODEL_ZENXFISTYLE] = {"Zen X-Fi Style", dualboot_zenxfistyle, sizeof(dualboot_zenxfistyle), "zxfs", 94, 214 [MODEL_ZENXFISTYLE] = {"Zen X-Fi Style", dualboot_zenxfistyle, sizeof(dualboot_zenxfistyle),
208 1, &zero_key, 0, 0x40000000 }, 215 "zxfs", 94, list_zero_key, 0, 0x40000000 },
209 [MODEL_ZENSTYLE] = {"Zen Style 100/300", NULL, 0, "", -1, 216 [MODEL_ZENSTYLE] = {"Zen Style 100/300", NULL, 0, "", -1, list_zero_key, 0, 0x40000000 },
210 1, &zero_key, 0, 0x40000000 }, 217 [MODEL_NWZE370] = {"NWZ-E370", dualboot_nwze370, sizeof(dualboot_nwze370),
211 [MODEL_NWZE370] = {"NWZ-E370", dualboot_nwze370, sizeof(dualboot_nwze370), "e370", 88, 218 "e370", 88, list_zero_key, 0, 0x40000000 },
212 1, &zero_key, 0, 0x40000000 }, 219 [MODEL_NWZE360] = {"NWZ-E360", dualboot_nwze360, sizeof(dualboot_nwze360),
213 [MODEL_NWZE360] = {"NWZ-E360", dualboot_nwze360, sizeof(dualboot_nwze360), "e360", 89, 220 "e360", 89, list_zero_key, 0, 0x40000000 },
214 1, &zero_key, 0, 0x40000000 },
215}; 221};
216 222
217#define NR_IMX_SUMS (sizeof(imx_sums) / sizeof(imx_sums[0])) 223#define NR_IMX_SUMS (sizeof(imx_sums) / sizeof(imx_sums[0]))
@@ -222,6 +228,12 @@ static const struct imx_model_desc_t imx_models[] =
222#define MAGIC_NORMAL 0xcafebabe 228#define MAGIC_NORMAL 0xcafebabe
223#define MAGIC_CHARGE 0x67726863 /* 'chrg' */ 229#define MAGIC_CHARGE 0x67726863 /* 'chrg' */
224 230
231static void add_key_list(struct crypto_key_t **list)
232{
233 while(*list != NULL)
234 add_keys(*list++, 1);
235}
236
225static int rb_fw_get_sb_inst_count(struct rb_fw_t *fw) 237static int rb_fw_get_sb_inst_count(struct rb_fw_t *fw)
226{ 238{
227 return fw->nr_insts; 239 return fw->nr_insts;
@@ -240,8 +252,8 @@ static void rb_fw_fill_sb(struct rb_fw_t *fw, struct sb_inst_t *inst,
240 inst[fw->entry_idx].argument = entry_arg; 252 inst[fw->entry_idx].argument = entry_arg;
241} 253}
242 254
243static enum imx_error_t patch_std_zero_host_play(int jump_before, int model, 255static enum imx_error_t patch_std_zero_host_play(int jump_before,
244 enum imx_output_type_t type, struct sb_file_t *sb_file, struct rb_fw_t boot_fw) 256 struct imx_option_t opt, struct sb_file_t *sb_file, struct rb_fw_t boot_fw)
245{ 257{
246 /* We assume the file has three boot sections: ____, host, play and one 258 /* We assume the file has three boot sections: ____, host, play and one
247 * resource section rsrc. 259 * resource section rsrc.
@@ -277,7 +289,7 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model,
277 return IMX_DONT_KNOW_HOW_TO_PATCH; 289 return IMX_DONT_KNOW_HOW_TO_PATCH;
278 } 290 }
279 291
280 if(type == IMX_DUALBOOT) 292 if(opt.output == IMX_DUALBOOT)
281 { 293 {
282 /* create a new instruction array with a hole for two instructions */ 294 /* create a new instruction array with a hole for two instructions */
283 struct sb_inst_t *new_insts = xmalloc(sizeof(struct sb_inst_t) * (sec->nr_insts + 2)); 295 struct sb_inst_t *new_insts = xmalloc(sizeof(struct sb_inst_t) * (sec->nr_insts + 2));
@@ -288,15 +300,16 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model,
288 struct sb_inst_t *load = &new_insts[jump_idx]; 300 struct sb_inst_t *load = &new_insts[jump_idx];
289 memset(load, 0, sizeof(struct sb_inst_t)); 301 memset(load, 0, sizeof(struct sb_inst_t));
290 load->inst = SB_INST_LOAD; 302 load->inst = SB_INST_LOAD;
291 load->size = imx_models[model].dualboot_size; 303 load->size = imx_models[opt.model].dualboot_size;
292 load->addr = imx_models[model].dualboot_addr; 304 load->addr = imx_models[opt.model].dualboot_addr;
293 /* duplicate memory because it will be free'd */ 305 /* duplicate memory because it will be free'd */
294 load->data = memdup(imx_models[model].dualboot, imx_models[model].dualboot_size); 306 load->data = memdup(imx_models[opt.model].dualboot,
307 imx_models[opt.model].dualboot_size);
295 /* second instruction is a call */ 308 /* second instruction is a call */
296 struct sb_inst_t *call = &new_insts[jump_idx + 1]; 309 struct sb_inst_t *call = &new_insts[jump_idx + 1];
297 memset(call, 0, sizeof(struct sb_inst_t)); 310 memset(call, 0, sizeof(struct sb_inst_t));
298 call->inst = SB_INST_CALL; 311 call->inst = SB_INST_CALL;
299 call->addr = imx_models[model].dualboot_addr; 312 call->addr = imx_models[opt.model].dualboot_addr;
300 call->argument = MAGIC_ROCK; 313 call->argument = MAGIC_ROCK;
301 /* free old instruction array */ 314 /* free old instruction array */
302 free(sec->insts); 315 free(sec->insts);
@@ -320,9 +333,9 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model,
320 333
321 return IMX_SUCCESS; 334 return IMX_SUCCESS;
322 } 335 }
323 else if(type == IMX_SINGLEBOOT || type == IMX_RECOVERY) 336 else if(opt.output == IMX_SINGLEBOOT || opt.output == IMX_RECOVERY)
324 { 337 {
325 bool recovery = type == IMX_RECOVERY; 338 bool recovery = (opt.output == IMX_RECOVERY);
326 /* remove everything after the call and add instructions for firmware */ 339 /* remove everything after the call and add instructions for firmware */
327 struct sb_inst_t *new_insts = xmalloc(sizeof(struct sb_inst_t) * (jump_idx + nr_boot_inst)); 340 struct sb_inst_t *new_insts = xmalloc(sizeof(struct sb_inst_t) * (jump_idx + nr_boot_inst));
328 memcpy(new_insts, sec->insts, sizeof(struct sb_inst_t) * jump_idx); 341 memcpy(new_insts, sec->insts, sizeof(struct sb_inst_t) * jump_idx);
@@ -344,7 +357,7 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model,
344 357
345 return IMX_SUCCESS; 358 return IMX_SUCCESS;
346 } 359 }
347 else if(type == IMX_CHARGE) 360 else if(opt.output == IMX_CHARGE)
348 { 361 {
349 /* throw away everything except the dualboot stub with a special argument */ 362 /* throw away everything except the dualboot stub with a special argument */
350 struct sb_inst_t *new_insts = xmalloc(sizeof(struct sb_inst_t) * 2); 363 struct sb_inst_t *new_insts = xmalloc(sizeof(struct sb_inst_t) * 2);
@@ -352,15 +365,16 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model,
352 struct sb_inst_t *load = &new_insts[0]; 365 struct sb_inst_t *load = &new_insts[0];
353 memset(load, 0, sizeof(struct sb_inst_t)); 366 memset(load, 0, sizeof(struct sb_inst_t));
354 load->inst = SB_INST_LOAD; 367 load->inst = SB_INST_LOAD;
355 load->size = imx_models[model].dualboot_size; 368 load->size = imx_models[opt.model].dualboot_size;
356 load->addr = imx_models[model].dualboot_addr; 369 load->addr = imx_models[opt.model].dualboot_addr;
357 /* duplicate memory because it will be free'd */ 370 /* duplicate memory because it will be free'd */
358 load->data = memdup(imx_models[model].dualboot, imx_models[model].dualboot_size); 371 load->data = memdup(imx_models[opt.model].dualboot,
372 imx_models[opt.model].dualboot_size);
359 /* second instruction is a call */ 373 /* second instruction is a call */
360 struct sb_inst_t *call = &new_insts[1]; 374 struct sb_inst_t *call = &new_insts[1];
361 memset(call, 0, sizeof(struct sb_inst_t)); 375 memset(call, 0, sizeof(struct sb_inst_t));
362 call->inst = SB_INST_CALL; 376 call->inst = SB_INST_CALL;
363 call->addr = imx_models[model].dualboot_addr; 377 call->addr = imx_models[opt.model].dualboot_addr;
364 call->argument = MAGIC_CHARGE; 378 call->argument = MAGIC_CHARGE;
365 /* free old instruction array */ 379 /* free old instruction array */
366 free(sec->insts); 380 free(sec->insts);
@@ -428,42 +442,42 @@ static enum imx_error_t parse_version(const char *s, struct sb_version_t *ver)
428 return IMX_SUCCESS; 442 return IMX_SUCCESS;
429} 443}
430 444
431static enum imx_error_t patch_firmware(enum imx_model_t model, 445static enum imx_error_t patch_firmware(struct imx_option_t opt,
432 enum imx_firmware_variant_t variant, enum imx_output_type_t type, 446 struct sb_file_t *sb_file, struct rb_fw_t boot_fw)
433 struct sb_file_t *sb_file, struct rb_fw_t boot_fw,
434 const char *force_version)
435{ 447{
436 if(force_version) 448 if(opt.force_version)
437 { 449 {
438 enum imx_error_t err = parse_version(force_version, &sb_file->product_ver); 450 enum imx_error_t err = parse_version(opt.force_version, &sb_file->product_ver);
439 if(err != IMX_SUCCESS) return err; 451 if(err != IMX_SUCCESS)
440 err = parse_version(force_version, &sb_file->component_ver); 452 return err;
441 if(err != IMX_SUCCESS) return err; 453 err = parse_version(opt.force_version, &sb_file->component_ver);
454 if(err != IMX_SUCCESS)
455 return err;
442 } 456 }
443 switch(model) 457 switch(opt.model)
444 { 458 {
445 case MODEL_FUZEPLUS: 459 case MODEL_FUZEPLUS:
446 /* The Fuze+ uses the standard ____, host, play sections, patch after third 460 /* The Fuze+ uses the standard ____, host, play sections, patch after third
447 * call in ____ section */ 461 * call in ____ section */
448 return patch_std_zero_host_play(3, model, type, sb_file, boot_fw); 462 return patch_std_zero_host_play(3, opt, sb_file, boot_fw);
449 case MODEL_ZENXFI3: 463 case MODEL_ZENXFI3:
450 /* The ZEN X-Fi3 uses the standard ____, hSst, pSay sections, patch after third 464 /* The ZEN X-Fi3 uses the standard ____, hSst, pSay sections, patch after third
451 * call in ____ section. Although sections names use the S variant, they are standard. */ 465 * call in ____ section. Although sections names use the S variant, they are standard. */
452 return patch_std_zero_host_play(3, model, type, sb_file, boot_fw); 466 return patch_std_zero_host_play(3, opt, sb_file, boot_fw);
453 case MODEL_NWZE360: 467 case MODEL_NWZE360:
454 case MODEL_NWZE370: 468 case MODEL_NWZE370:
455 /* The NWZ-E360/E370 uses the standard ____, host, play sections, patch after first 469 /* The NWZ-E360/E370 uses the standard ____, host, play sections, patch after first
456 * call in ____ section. */ 470 * call in ____ section. */
457 return patch_std_zero_host_play(1, model, type, sb_file, boot_fw); 471 return patch_std_zero_host_play(1, opt, sb_file, boot_fw);
458 case MODEL_ZENXFI2: 472 case MODEL_ZENXFI2:
459 /* The ZEN X-Fi2 has two types of firmware: recovery and normal. 473 /* The ZEN X-Fi2 has two types of firmware: recovery and normal.
460 * Normal uses the standard ___, host, play sections and recovery only ____ */ 474 * Normal uses the standard ___, host, play sections and recovery only ____ */
461 switch(variant) 475 switch(opt.fw_variant)
462 { 476 {
463 case VARIANT_ZENXFI2_RECOVERY: 477 case VARIANT_ZENXFI2_RECOVERY:
464 case VARIANT_ZENXFI2_NAND: 478 case VARIANT_ZENXFI2_NAND:
465 case VARIANT_ZENXFI2_SD: 479 case VARIANT_ZENXFI2_SD:
466 return patch_std_zero_host_play(1, model, type, sb_file, boot_fw); 480 return patch_std_zero_host_play(1, opt, sb_file, boot_fw);
467 default: 481 default:
468 return IMX_DONT_KNOW_HOW_TO_PATCH; 482 return IMX_DONT_KNOW_HOW_TO_PATCH;
469 } 483 }
@@ -471,12 +485,19 @@ static enum imx_error_t patch_firmware(enum imx_model_t model,
471 case MODEL_ZENXFISTYLE: 485 case MODEL_ZENXFISTYLE:
472 /* The ZEN X-Fi Style uses the standard ____, host, play sections, patch after first 486 /* The ZEN X-Fi Style uses the standard ____, host, play sections, patch after first
473 * call in ____ section. */ 487 * call in ____ section. */
474 return patch_std_zero_host_play(1, model, type, sb_file, boot_fw); 488 return patch_std_zero_host_play(1, opt, sb_file, boot_fw);
475 default: 489 default:
476 return IMX_DONT_KNOW_HOW_TO_PATCH; 490 return IMX_DONT_KNOW_HOW_TO_PATCH;
477 } 491 }
478} 492}
479 493
494static enum imx_error_t unpatch_firmware(struct imx_option_t opt,
495 struct sb_file_t *sb_file)
496{
497 printf("[ERR] Unimplemented\n");
498 return IMX_ERROR;
499}
500
480static uint32_t get_uint32be(unsigned char *p) 501static uint32_t get_uint32be(unsigned char *p)
481{ 502{
482 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 503 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
@@ -680,16 +701,10 @@ enum imx_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16])
680} 701}
681 702
682/* compute soft MD5 of a file */ 703/* compute soft MD5 of a file */
683enum imx_error_t compute_soft_md5sum(const char *file, enum imx_model_t model, 704enum imx_error_t compute_soft_md5sum(const char *file, uint8_t soft_md5sum[16])
684 uint8_t soft_md5sum[16])
685{ 705{
686 if(model == MODEL_UNKNOWN)
687 {
688 printf("[ERR] Cannot compute soft MD5 without knowing the model\n");
689 return IMX_ERROR;
690 }
691 clear_keys(); 706 clear_keys();
692 add_keys(imx_models[model].keys, imx_models[model].nr_keys); 707 add_key_list(list_all_keys);
693 /* read file */ 708 /* read file */
694 enum sb_error_t err; 709 enum sb_error_t err;
695 struct sb_file_t *sb = sb_read_file(file, false, NULL, generic_std_printf, &err); 710 struct sb_file_t *sb = sb_read_file(file, false, NULL, generic_std_printf, &err);
@@ -705,29 +720,6 @@ enum imx_error_t compute_soft_md5sum(const char *file, enum imx_model_t model,
705 return err; 720 return err;
706} 721}
707 722
708static enum imx_error_t load_sb_file(const char *file, int md5_idx,
709 struct imx_option_t opt, struct sb_file_t **sb_file)
710{
711 if(imx_sums[md5_idx].fw_variants[opt.fw_variant].size == 0)
712 {
713 printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[opt.fw_variant]);
714 return IMX_VARIANT_MISMATCH;
715 }
716 enum imx_model_t model = imx_sums[md5_idx].model;
717 enum sb_error_t err;
718 g_debug = opt.debug;
719 clear_keys();
720 add_keys(imx_models[model].keys, imx_models[model].nr_keys);
721 *sb_file = sb_read_file_ex(file, imx_sums[md5_idx].fw_variants[opt.fw_variant].offset,
722 imx_sums[md5_idx].fw_variants[opt.fw_variant].size, false, NULL, generic_std_printf, &err);
723 if(*sb_file == NULL)
724 {
725 clear_keys();
726 return IMX_FIRST_SB_ERROR + err;
727 }
728 return IMX_SUCCESS;
729}
730
731/* Load a rockbox firwmare from a buffer. Data is copied. Assume firmware is 723/* Load a rockbox firwmare from a buffer. Data is copied. Assume firmware is
732 * using our scramble format. */ 724 * using our scramble format. */
733static enum imx_error_t rb_fw_load_buf_scramble(struct rb_fw_t *fw, uint8_t *buf, 725static enum imx_error_t rb_fw_load_buf_scramble(struct rb_fw_t *fw, uint8_t *buf,
@@ -873,101 +865,145 @@ static void rb_fw_free(struct rb_fw_t *fw)
873 memset(fw, 0, sizeof(struct rb_fw_t)); 865 memset(fw, 0, sizeof(struct rb_fw_t));
874} 866}
875 867
876enum imx_error_t mkimxboot(const char *infile, const char *bootfile, 868static bool contains_rockbox_bootloader(struct sb_file_t *sb_file)
877 const char *outfile, struct imx_option_t opt)
878{ 869{
879 /* sanity check */ 870 for(int i = 0; i < sb_file->nr_sections; i++)
880 if(opt.fw_variant > VARIANT_COUNT) 871 if(sb_file->sections[i].identifier == MAGIC_ROCK)
881 return IMX_ERROR; 872 return true;
882 /* Dump tables */ 873 return false;
883 dump_imx_dev_info("[INFO] "); 874}
884 /* compute MD5 sum of the file */ 875
885 uint8_t file_md5sum[16]; 876/* modify sb_file to produce requested boot image */
886 enum imx_error_t ret = compute_md5sum(infile, file_md5sum); 877static enum imx_error_t make_boot(struct sb_file_t *sb_file, const char *bootfile,
887 if(ret != IMX_SUCCESS) 878 struct imx_option_t opt)
888 return ret; 879{
889 printf("[INFO] MD5 sum of the file: "); 880 /* things went smoothly, we have a SB image but it may not be suitable as an
890 for(int i = 0; i < 16; i++) 881 * input image: if it contains a rockbox bootloader, we need to remove it */
891 printf("%02x", file_md5sum[i]); 882 if(contains_rockbox_bootloader(sb_file))
892 printf("\n"); 883 {
893 /* find model */ 884 printf("[INFO] SB file contains a Rockbox bootloader, trying to remove it...\n");
894 int md5_idx; 885 enum imx_error_t ret = unpatch_firmware(opt, sb_file);
895 ret = find_model_by_md5sum(file_md5sum, &md5_idx); 886 if(ret != IMX_SUCCESS)
896 if(ret != IMX_SUCCESS) 887 return ret;
897 return ret; 888 }
898 enum imx_model_t model = imx_sums[md5_idx].model;
899 printf("[INFO] File is for model %d (%s, version %s)\n", model,
900 imx_models[model].model_name, imx_sums[md5_idx].version);
901 /* load rockbox file */ 889 /* load rockbox file */
902 struct rb_fw_t boot_fw; 890 struct rb_fw_t boot_fw;
903 ret = rb_fw_load(&boot_fw, bootfile, model); 891 enum imx_error_t ret = rb_fw_load(&boot_fw, bootfile, opt.model);
904 if(ret != IMX_SUCCESS)
905 return ret;
906 /* load OF file */
907 struct sb_file_t *sb_file;
908 ret = load_sb_file(infile, md5_idx, opt, &sb_file);
909 if(ret != IMX_SUCCESS) 892 if(ret != IMX_SUCCESS)
910 {
911 rb_fw_free(&boot_fw);
912 return ret; 893 return ret;
913 }
914 /* produce file */ 894 /* produce file */
915 ret = patch_firmware(model, opt.fw_variant, opt.output, 895 ret = patch_firmware(opt, sb_file, boot_fw);
916 sb_file, boot_fw, opt.force_version);
917 if(ret == IMX_SUCCESS)
918 ret = sb_write_file(sb_file, outfile, NULL, generic_std_printf);
919
920 clear_keys();
921 rb_fw_free(&boot_fw); 896 rb_fw_free(&boot_fw);
922 sb_free(sb_file); 897 return IMX_SUCCESS;
923 return ret;
924} 898}
925 899
926enum imx_error_t extract_firmware(const char *infile, 900enum imx_error_t mkimxboot(const char *infile, const char *bootfile,
927 enum imx_firmware_variant_t fw_variant, const char *outfile) 901 const char *outfile, struct imx_option_t opt)
928{ 902{
929 /* sanity check */ 903 /* sanity check */
930 if(fw_variant > VARIANT_COUNT) 904 if(opt.fw_variant >= VARIANT_COUNT || opt.model >= MODEL_COUNT)
931 return IMX_ERROR; 905 return IMX_ERROR;
932 /* dump tables */ 906 /* dump tables */
933 dump_imx_dev_info("[INFO] "); 907 dump_imx_dev_info("[INFO] ");
934 /* compute MD5 sum of the file */ 908 /* load file */
935 void *buf; 909 void *buf;
936 size_t sz; 910 size_t offset = 0, size = 0;
937 uint8_t file_md5sum[16]; 911 enum imx_error_t ret = read_file(infile, &buf, &size);
938 int ret = read_file(infile, &buf, &sz);
939 if(ret != IMX_SUCCESS) 912 if(ret != IMX_SUCCESS)
940 return ret; 913 return ret;
941 ret = compute_md5sum_buf(buf, sz, file_md5sum); 914 /* compute MD5 sum of the file */
942 if(ret != IMX_SUCCESS) 915 uint8_t file_md5sum[16];
943 { 916 compute_md5sum_buf(buf, size, file_md5sum);
944 free(buf);
945 return ret;
946 }
947 printf("[INFO] MD5 sum of the file: "); 917 printf("[INFO] MD5 sum of the file: ");
948 print_hex(NULL, misc_std_printf, file_md5sum, 16, true); 918 for(int i = 0; i < 16; i++)
919 printf("%02x", file_md5sum[i]);
920 printf("\n");
949 /* find model */ 921 /* find model */
950 int md5_idx; 922 int md5_idx;
951 ret = find_model_by_md5sum(file_md5sum, &md5_idx); 923 ret = find_model_by_md5sum(file_md5sum, &md5_idx);
952 if(ret != IMX_SUCCESS) 924 /* is this a known firmware upgrade ? */
925 if(ret == IMX_SUCCESS)
953 { 926 {
927 enum imx_model_t model = imx_sums[md5_idx].model;
928 printf("[INFO] File is for model %d (%s, version %s)\n", model,
929 imx_models[model].model_name, imx_sums[md5_idx].version);
930 /* check the model is the expected one */
931 if(opt.model == MODEL_UNKNOWN)
932 opt.model = model;
933 else if(opt.model != model)
934 {
935 printf("[ERR] Model mismatch, was expecting model %d (%s)\n",
936 opt.model, imx_models[opt.model].model_name);
937 free(buf);
938 return IMX_MODEL_MISMATCH;
939 }
940 /* use database values */
941 offset = imx_sums[md5_idx].fw_variants[opt.fw_variant].offset;
942 size = imx_sums[md5_idx].fw_variants[opt.fw_variant].size;
943 if(size == 0)
944 {
945 printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[opt.fw_variant]);
946 free(buf);
947 return IMX_VARIANT_MISMATCH;
948 }
949 /* special case: if we need to produce the OF, just bypass read/write of
950 * the SB file and output this chunk of the file. This is faster and it
951 * also avoids modifying the OF by reconstructing it */
952 if(opt.output == IMX_ORIG_FW)
953 {
954 printf("[INFO] Extracting original firmware...\n");
955 ret = write_file(outfile, buf + offset, size);
956 free(buf);
957 return ret;
958 }
959 }
960 else
961 {
962 printf("[INFO] File doesn't have a known MD5 sum, assuming it's a SB image...\n");
963 /* image didn't match, so we expect the file to be a raw SB image, either
964 * produced by mkimxboot when uninstalling bootloader or after installing RB,
965 * so load all known keys and go on */
966
967 /* To be more user friendly, give a nice error message if we detect
968 * the file is not a SB file */
969 if(guess_sb_version(infile) == SB_VERSION_UNK)
970 {
971 printf("[ERR] Your firmware doesn't look like a SB file\n");
972 printf("[ERR] This is probably a firmware upgrade\n");
973 printf("[ERR] Unfortunately, this tool doesn't know about it yet\n");
974 printf("[ERR] Please report to the developers to add it\n");
975 free(buf);
976 return IMX_ERROR;
977 }
978 }
979 /* to proceed further, we need to know the model */
980 if(opt.model == MODEL_UNKNOWN)
981 {
982 printf("[ERR] Cannot do processing of soft image without knowing the model\n");
954 free(buf); 983 free(buf);
955 return ret; 984 return IMX_MODEL_MISMATCH;
956 } 985 }
957 enum imx_model_t model = imx_sums[md5_idx].model; 986 /* load image */
958 printf("[INFO] File is for model %d (%s, version %s)\n", model, 987 g_debug = opt.debug;
959 imx_models[model].model_name, imx_sums[md5_idx].version); 988 clear_keys();
960 /* extract firmware */ 989 add_key_list(imx_models[opt.model].keys);
961 if(imx_sums[md5_idx].fw_variants[fw_variant].size == 0) 990 enum sb_error_t err;
991 struct sb_file_t *sb_file = sb_read_memory(buf + offset, size, false, NULL, generic_std_printf, &err);
992 if(sb_file == NULL)
962 { 993 {
963 printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[fw_variant]); 994 printf("[ERR] Cannot open firmware as SB file: %d\n", err);
964 free(buf); 995 free(buf);
965 return IMX_VARIANT_MISMATCH; 996 return IMX_FIRST_SB_ERROR + err;
966 } 997 }
967 998 /* modify image */
968 ret = write_file(outfile, 999 ret = make_boot(sb_file, bootfile, opt);
969 buf + imx_sums[md5_idx].fw_variants[fw_variant].offset, 1000 if(ret == IMX_SUCCESS)
970 imx_sums[md5_idx].fw_variants[fw_variant].size); 1001 {
1002 /* write image */
1003 ret = sb_write_file(sb_file, outfile, NULL, generic_std_printf);
1004 }
1005 /* cleanup */
1006 sb_free(sb_file);
971 free(buf); 1007 free(buf);
972 return ret; 1008 return ret;
973} 1009}