summaryrefslogtreecommitdiff
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
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
-rw-r--r--rbutil/mkimxboot/main.c30
-rw-r--r--rbutil/mkimxboot/mkimxboot.c330
-rw-r--r--rbutil/mkimxboot/mkimxboot.h29
3 files changed, 211 insertions, 178 deletions
diff --git a/rbutil/mkimxboot/main.c b/rbutil/mkimxboot/main.c
index 611715f7c1..90f2f20a5f 100644
--- a/rbutil/mkimxboot/main.c
+++ b/rbutil/mkimxboot/main.c
@@ -72,10 +72,9 @@ static void usage(void)
72 printf(" -i <file> Set input file\n"); 72 printf(" -i <file> Set input file\n");
73 printf(" -b <file> Set boot file\n"); 73 printf(" -b <file> Set boot file\n");
74 printf(" -d/--debug Enable debug output\n"); 74 printf(" -d/--debug Enable debug output\n");
75 printf(" -t <type> Set type (dualboot, singleboot, recovery, charge)\n"); 75 printf(" -t <type> Set type (dualboot, singleboot, recovery, origfw, charge)\n");
76 printf(" -v <v> Set variant\n"); 76 printf(" -v <v> Set variant\n");
77 printf(" -x Dump device informations\n"); 77 printf(" -x Dump device informations\n");
78 printf(" -w Extract the original firmware\n");
79 printf(" -p <ver> Force product and component version\n"); 78 printf(" -p <ver> Force product and component version\n");
80 printf(" -5 <type> Compute <type> MD5 sum of the input file\n"); 79 printf(" -5 <type> Compute <type> MD5 sum of the input file\n");
81 printf(" -m <model> Specify model (useful for soft MD5 sum)\n"); 80 printf(" -m <model> Specify model (useful for soft MD5 sum)\n");
@@ -108,14 +107,14 @@ static void usage(void)
108 exit(1); 107 exit(1);
109} 108}
110 109
111static int print_md5(const char *file, enum imx_model_t model, const char *type) 110static int print_md5(const char *file, const char *type)
112{ 111{
113 uint8_t md5sum[16]; 112 uint8_t md5sum[16];
114 enum imx_error_t err; 113 enum imx_error_t err;
115 if(strcmp(type, "full") == 0) 114 if(strcmp(type, "full") == 0)
116 err = compute_md5sum(file, md5sum); 115 err = compute_md5sum(file, md5sum);
117 else if(strcmp(type, "soft") == 0) 116 else if(strcmp(type, "soft") == 0)
118 err = compute_soft_md5sum(file, model, md5sum); 117 err = compute_soft_md5sum(file, md5sum);
119 else 118 else
120 { 119 {
121 printf("Invalid md5sum type '%s'\n", type); 120 printf("Invalid md5sum type '%s'\n", type);
@@ -142,7 +141,6 @@ int main(int argc, char *argv[])
142 enum imx_output_type_t type = IMX_DUALBOOT; 141 enum imx_output_type_t type = IMX_DUALBOOT;
143 enum imx_model_t model = MODEL_UNKNOWN; 142 enum imx_model_t model = MODEL_UNKNOWN;
144 bool debug = false; 143 bool debug = false;
145 bool extract_of = false;
146 const char *md5type = NULL; 144 const char *md5type = NULL;
147 const char *force_version = NULL; 145 const char *force_version = NULL;
148 146
@@ -153,7 +151,7 @@ int main(int argc, char *argv[])
153 { 151 {
154 static struct option long_options[] = 152 static struct option long_options[] =
155 { 153 {
156 {"help", no_argument, 0, '?'}, 154 {"help", no_argument, 0, 'h'},
157 {"in-file", no_argument, 0, 'i'}, 155 {"in-file", no_argument, 0, 'i'},
158 {"out-file", required_argument, 0, 'o'}, 156 {"out-file", required_argument, 0, 'o'},
159 {"boot-file", required_argument, 0, 'b'}, 157 {"boot-file", required_argument, 0, 'b'},
@@ -166,7 +164,7 @@ int main(int argc, char *argv[])
166 {0, 0, 0, 0} 164 {0, 0, 0, 0}
167 }; 165 };
168 166
169 int c = getopt_long(argc, argv, "?di:o:b:t:v:xwp:m:5:", long_options, NULL); 167 int c = getopt_long(argc, argv, "hdi:o:b:t:v:xp:m:5:", long_options, NULL);
170 if(c == -1) 168 if(c == -1)
171 break; 169 break;
172 switch(c) 170 switch(c)
@@ -174,7 +172,7 @@ int main(int argc, char *argv[])
174 case 'd': 172 case 'd':
175 debug = true; 173 debug = true;
176 break; 174 break;
177 case '?': 175 case 'h':
178 usage(); 176 usage();
179 break; 177 break;
180 case 'o': 178 case 'o':
@@ -195,6 +193,8 @@ int main(int argc, char *argv[])
195 type = IMX_RECOVERY; 193 type = IMX_RECOVERY;
196 else if(strcmp(optarg, "charge") == 0) 194 else if(strcmp(optarg, "charge") == 0)
197 type = IMX_CHARGE; 195 type = IMX_CHARGE;
196 else if(strcmp(optarg, "origfw") == 0)
197 type = IMX_ORIG_FW;
198 else 198 else
199 { 199 {
200 printf("Invalid boot type '%s'\n", optarg); 200 printf("Invalid boot type '%s'\n", optarg);
@@ -223,9 +223,6 @@ int main(int argc, char *argv[])
223 for(int i = 0; i < sizeof(imx_variants) / sizeof(imx_variants[0]); i++) 223 for(int i = 0; i < sizeof(imx_variants) / sizeof(imx_variants[0]); i++)
224 printf(" %s -> variant=%d\n", imx_variants[i].name, imx_variants[i].variant); 224 printf(" %s -> variant=%d\n", imx_variants[i].name, imx_variants[i].variant);
225 break; 225 break;
226 case 'w':
227 extract_of = true;
228 break;
229 case 'p': 226 case 'p':
230 force_version = optarg; 227 force_version = optarg;
231 break; 228 break;
@@ -266,24 +263,19 @@ int main(int argc, char *argv[])
266 printf("You must specify an output file\n"); 263 printf("You must specify an output file\n");
267 return 1; 264 return 1;
268 } 265 }
269 if(!bootfile && !extract_of) 266
267 if(!bootfile && type != IMX_ORIG_FW)
270 { 268 {
271 printf("You must specify an boot file\n"); 269 printf("You must specify an boot file\n");
272 return 1; 270 return 1;
273 } 271 }
272
274 if(optind != argc) 273 if(optind != argc)
275 { 274 {
276 printf("Extra arguments on command line\n"); 275 printf("Extra arguments on command line\n");
277 return 1; 276 return 1;
278 } 277 }
279 278
280 if(extract_of)
281 {
282 enum imx_error_t err = extract_firmware(infile, variant, outfile);
283 printf("Result: %d\n", err);
284 return 0;
285 }
286
287 struct imx_option_t opt; 279 struct imx_option_t opt;
288 memset(&opt, 0, sizeof(opt)); 280 memset(&opt, 0, sizeof(opt));
289 opt.debug = debug; 281 opt.debug = debug;
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}
diff --git a/rbutil/mkimxboot/mkimxboot.h b/rbutil/mkimxboot/mkimxboot.h
index 3157bd7daa..59f28a98a0 100644
--- a/rbutil/mkimxboot/mkimxboot.h
+++ b/rbutil/mkimxboot/mkimxboot.h
@@ -29,6 +29,7 @@
29#ifdef __cplusplus 29#ifdef __cplusplus
30extern "C" { 30extern "C" {
31#endif 31#endif
32
32enum imx_error_t 33enum imx_error_t
33{ 34{
34 IMX_SUCCESS = 0, 35 IMX_SUCCESS = 0,
@@ -43,30 +44,31 @@ enum imx_error_t
43 IMX_VARIANT_MISMATCH = -9, 44 IMX_VARIANT_MISMATCH = -9,
44 IMX_WRITE_ERROR = -10, 45 IMX_WRITE_ERROR = -10,
45 IMX_FIRST_SB_ERROR = -11, 46 IMX_FIRST_SB_ERROR = -11,
47 IMX_MODEL_MISMATCH = -12,
46}; 48};
47 49
48enum imx_output_type_t 50enum imx_output_type_t
49{ 51{
50 IMX_DUALBOOT = 0, 52 IMX_DUALBOOT = 0,
51 IMX_RECOVERY = 1, 53 IMX_RECOVERY,
52 IMX_SINGLEBOOT = 2, 54 IMX_SINGLEBOOT,
53 IMX_CHARGE = 3, 55 IMX_CHARGE,
56 IMX_ORIG_FW,
54}; 57};
55 58
56/* Supported models */ 59/* Supported models */
57enum imx_model_t 60enum imx_model_t
58{ 61{
59 MODEL_UNKNOWN = -1, 62 MODEL_UNKNOWN = 0,
60 MODEL_FUZEPLUS = 0, 63 MODEL_FUZEPLUS,
61 MODEL_ZENXFI2, 64 MODEL_ZENXFI2,
62 MODEL_ZENXFI3, 65 MODEL_ZENXFI3,
63 MODEL_ZENXFISTYLE, 66 MODEL_ZENXFISTYLE,
64 MODEL_ZENSTYLE, /* Style 100 and Style 300 */ 67 MODEL_ZENSTYLE, /* Style 100 and Style 300 */
65 MODEL_NWZE370, 68 MODEL_NWZE370,
66 MODEL_NWZE360, 69 MODEL_NWZE360,
67 /* new models go here */ 70 /* Last */
68 71 MODEL_COUNT
69 NUM_MODELS
70}; 72};
71 73
72/* Supported firmware variants */ 74/* Supported firmware variants */
@@ -88,19 +90,22 @@ enum imx_firmware_variant_t
88struct imx_option_t 90struct imx_option_t
89{ 91{
90 bool debug; 92 bool debug;
93 enum imx_model_t model;
91 enum imx_output_type_t output; 94 enum imx_output_type_t output;
92 enum imx_firmware_variant_t fw_variant; 95 enum imx_firmware_variant_t fw_variant;
93 const char *force_version; // set to NULL to ignore 96 const char *force_version; // set to NULL to ignore
94}; 97};
95 98
99/* Print internal information to stdout about device database */
96void dump_imx_dev_info(const char *prefix); 100void dump_imx_dev_info(const char *prefix);
101/* Build a SB image from an input firmware and a bootloader, input firmware
102 * can either be a firmware update or another SB file produced by this tool */
97enum imx_error_t mkimxboot(const char *infile, const char *bootfile, 103enum imx_error_t mkimxboot(const char *infile, const char *bootfile,
98 const char *outfile, struct imx_option_t opt); 104 const char *outfile, struct imx_option_t opt);
99enum imx_error_t extract_firmware(const char *infile, 105/* Compute MD5 sum of an entire file */
100 enum imx_firmware_variant_t fw_variant, const char *outfile);
101enum imx_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16]); 106enum imx_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16]);
102enum imx_error_t compute_soft_md5sum(const char *file, enum imx_model_t model, 107/* Compute "soft" MD5 sum of a SB file */
103 uint8_t soft_md5sum[16]); 108enum imx_error_t compute_soft_md5sum(const char *file, uint8_t soft_md5sum[16]);
104 109
105#ifdef __cplusplus 110#ifdef __cplusplus
106} 111}