summaryrefslogtreecommitdiff
path: root/rbutil/mkimxboot/mkimxboot.c
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-01-01 21:31:47 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2017-01-02 21:43:10 +0100
commitff946f1f69c325a948e3e73ac21c3880a0ea94d2 (patch)
tree2b3f4c8679f0eadbdd16015245b954258b66f7d5 /rbutil/mkimxboot/mkimxboot.c
parent782d9c0d80f1edc29955dbe7e7f42770f730b597 (diff)
downloadrockbox-ff946f1f69c325a948e3e73ac21c3880a0ea94d2.tar.gz
rockbox-ff946f1f69c325a948e3e73ac21c3880a0ea94d2.zip
imxtools: completely rework patching logic to prepare unpatching
The old code was working but a mess to maintain. The new code is cleaner and always simpler handling of all the different options. Extraction of the OF is no longer a standalone function but just one particular output type. This commit prepares the ground for firmware "unpatching" (aka OF extraction from patched OF). The patching code itself did not change so this commit should still produce the exact same images as before. Change-Id: I3840793d4b78b8435e38c08f558840925085ead1
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}