diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2017-01-01 21:31:47 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2017-01-02 21:43:10 +0100 |
commit | ff946f1f69c325a948e3e73ac21c3880a0ea94d2 (patch) | |
tree | 2b3f4c8679f0eadbdd16015245b954258b66f7d5 /rbutil/mkimxboot/mkimxboot.c | |
parent | 782d9c0d80f1edc29955dbe7e7f42770f730b597 (diff) | |
download | rockbox-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.c | 330 |
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 */ | ||
41 | struct imx_fw_variant_desc_t | 43 | struct 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 */ | ||
49 | struct imx_md5sum_t | 52 | struct 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 */ | ||
61 | struct imx_model_desc_t | 65 | struct 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 */ | ||
85 | static const char *imx_fw_variant[] = | 88 | static 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 */ | ||
95 | static const struct imx_md5sum_t imx_sums[] = | 99 | static 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 | ||
203 | static struct crypto_key_t *list_zero_key[] = { &zero_key, NULL }; | ||
204 | static struct crypto_key_t *list_all_keys[] = { &zero_key, NULL }; | ||
205 | |||
199 | static const struct imx_model_desc_t imx_models[] = | 206 | static 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 | ||
231 | static void add_key_list(struct crypto_key_t **list) | ||
232 | { | ||
233 | while(*list != NULL) | ||
234 | add_keys(*list++, 1); | ||
235 | } | ||
236 | |||
225 | static int rb_fw_get_sb_inst_count(struct rb_fw_t *fw) | 237 | static 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 | ||
243 | static enum imx_error_t patch_std_zero_host_play(int jump_before, int model, | 255 | static 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 | ||
431 | static enum imx_error_t patch_firmware(enum imx_model_t model, | 445 | static 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 | ||
494 | static 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 | |||
480 | static uint32_t get_uint32be(unsigned char *p) | 501 | static 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 */ |
683 | enum imx_error_t compute_soft_md5sum(const char *file, enum imx_model_t model, | 704 | enum 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 | ||
708 | static 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. */ |
733 | static enum imx_error_t rb_fw_load_buf_scramble(struct rb_fw_t *fw, uint8_t *buf, | 725 | static 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 | ||
876 | enum imx_error_t mkimxboot(const char *infile, const char *bootfile, | 868 | static 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); | 877 | static 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 | ||
926 | enum imx_error_t extract_firmware(const char *infile, | 900 | enum 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 | } |