diff options
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 | } |