summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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}