summaryrefslogtreecommitdiffstats
path: root/rbutil/mkimxboot
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-06-15 22:13:08 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-06-15 22:27:34 +0200
commit58e27b9fa1e9ea058eb5161f140e0909c4821c92 (patch)
treed4f105c3fc42f78805ab8e86ad3455c4ae313136 /rbutil/mkimxboot
parent6483e23f07f52bd3f90373896b585c0afa38036a (diff)
downloadrockbox-58e27b9fa1e9ea058eb5161f140e0909c4821c92.tar.gz
rockbox-58e27b9fa1e9ea058eb5161f140e0909c4821c92.tar.bz2
rockbox-58e27b9fa1e9ea058eb5161f140e0909c4821c92.zip
mkimxboot: refactor code, no functional change
The mkimxboot was becoming messy with juge functions and redundant code. Factor reading/writing/loading code into smaller functions. Introduce the concept of rockbox firmware to simplify support of other formats than scramble. Change-Id: I3a61295ca5abca1a0eee8c9e8709c6b8dfa256a6
Diffstat (limited to 'rbutil/mkimxboot')
-rw-r--r--rbutil/mkimxboot/mkimxboot.c471
-rw-r--r--rbutil/mkimxboot/mkimxboot.h3
2 files changed, 252 insertions, 222 deletions
diff --git a/rbutil/mkimxboot/mkimxboot.c b/rbutil/mkimxboot/mkimxboot.c
index d420afce5d..da1e49876d 100644
--- a/rbutil/mkimxboot/mkimxboot.c
+++ b/rbutil/mkimxboot/mkimxboot.c
@@ -28,6 +28,14 @@
#include "dualboot.h"
#include "md5.h"
+/* abstract structure to represent a Rockbox firmware. It can be a scrambled file
+ * or an ELF file or whatever. */
+struct rb_fw_t
+{
+ void *boot;
+ size_t boot_sz;
+};
+
struct imx_fw_variant_desc_t
{
/* Offset within file */
@@ -160,7 +168,7 @@ static const struct imx_model_desc_t imx_models[] =
#define MAGIC_NORMAL 0xcafebabe
static enum imx_error_t patch_std_zero_host_play(int jump_before, int model,
- enum imx_output_type_t type, struct sb_file_t *sb_file, void *boot, size_t boot_sz)
+ enum imx_output_type_t type, struct sb_file_t *sb_file, struct rb_fw_t boot_fw)
{
/* We assume the file has three boot sections: ____, host, play and one
* resource section rsrc.
@@ -229,8 +237,8 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model,
rock_sec.insts = xmalloc(2 * sizeof(struct sb_inst_t));
memset(rock_sec.insts, 0, 2 * sizeof(struct sb_inst_t));
rock_sec.insts[0].inst = SB_INST_LOAD;
- rock_sec.insts[0].size = boot_sz;
- rock_sec.insts[0].data = memdup(boot, boot_sz);
+ rock_sec.insts[0].size = boot_fw.boot_sz;
+ rock_sec.insts[0].data = memdup(boot_fw.boot, boot_fw.boot_sz);
rock_sec.insts[0].addr = imx_models[model].bootloader_addr;
rock_sec.insts[1].inst = SB_INST_JUMP;
rock_sec.insts[1].addr = imx_models[model].bootloader_addr;
@@ -253,13 +261,13 @@ static enum imx_error_t patch_std_zero_host_play(int jump_before, int model,
sb_free_instruction(sec->insts[i]);
memset(new_insts + jump_idx, 0, 2 * sizeof(struct sb_inst_t));
new_insts[jump_idx + 0].inst = SB_INST_LOAD;
- new_insts[jump_idx + 0].size = boot_sz;
- new_insts[jump_idx + 0].data = memdup(boot, boot_sz);
+ new_insts[jump_idx + 0].size = boot_fw.boot_sz;
+ new_insts[jump_idx + 0].data = memdup(boot_fw.boot, boot_fw.boot_sz);
new_insts[jump_idx + 0].addr = imx_models[model].bootloader_addr;
new_insts[jump_idx + 1].inst = SB_INST_JUMP;
new_insts[jump_idx + 1].addr = imx_models[model].bootloader_addr;
new_insts[jump_idx + 1].argument = recovery ? MAGIC_RECOVERY : MAGIC_NORMAL;
-
+
free(sec->insts);
sec->insts = new_insts;
sec->nr_insts = jump_idx + 2;
@@ -327,7 +335,7 @@ static enum imx_error_t parse_version(const char *s, struct sb_version_t *ver)
static enum imx_error_t patch_firmware(enum imx_model_t model,
enum imx_firmware_variant_t variant, enum imx_output_type_t type,
- struct sb_file_t *sb_file, void *boot, size_t boot_sz,
+ struct sb_file_t *sb_file, struct rb_fw_t boot_fw,
const char *force_version)
{
if(force_version)
@@ -342,11 +350,11 @@ static enum imx_error_t patch_firmware(enum imx_model_t model,
case MODEL_FUZEPLUS:
/* The Fuze+ uses the standard ____, host, play sections, patch after third
* call in ____ section */
- return patch_std_zero_host_play(3, model, type, sb_file, boot, boot_sz);
+ return patch_std_zero_host_play(3, model, type, sb_file, boot_fw);
case MODEL_ZENXFI3:
/* The ZEN X-Fi3 uses the standard ____, hSst, pSay sections, patch after third
* call in ____ section. Although sections names use the S variant, they are standard. */
- return patch_std_zero_host_play(3, model, type, sb_file, boot, boot_sz);
+ return patch_std_zero_host_play(3, model, type, sb_file, boot_fw);
case MODEL_ZENXFI2:
/* The ZEN X-Fi2 has two types of firmware: recovery and normal.
* Normal uses the standard ___, host, play sections and recovery only ____ */
@@ -355,7 +363,7 @@ static enum imx_error_t patch_firmware(enum imx_model_t model,
case VARIANT_ZENXFI2_RECOVERY:
case VARIANT_ZENXFI2_NAND:
case VARIANT_ZENXFI2_SD:
- return patch_std_zero_host_play(1, model, type, sb_file, boot, boot_sz);
+ return patch_std_zero_host_play(1, model, type, sb_file, boot_fw);
default:
return IMX_DONT_KNOW_HOW_TO_PATCH;
}
@@ -413,165 +421,240 @@ void dump_imx_dev_info(const char *prefix)
}
}
-enum imx_error_t mkimxboot(const char *infile, const char *bootfile,
- const char *outfile, struct imx_option_t opt)
+/* find an entry into imx_sums which matches the MD5 sum of a file */
+static enum imx_error_t find_model_by_md5sum(uint8_t file_md5sum[16], int *md5_idx)
{
- /* Dump tables */
- if(opt.fw_variant > VARIANT_COUNT) {
- return IMX_ERROR;
- }
- dump_imx_dev_info("[INFO] ");
- /* compute MD5 sum of the file */
- uint8_t file_md5sum[16];
- do
+ int i = 0;
+ while(i < NR_IMX_SUMS)
{
- FILE *f = fopen(infile, "rb");
- if(f == NULL)
+ uint8_t md5[20];
+ if(strlen(imx_sums[i].md5sum) != 32)
{
- printf("[ERR] Cannot open input file\n");
- return IMX_OPEN_ERROR;
+ printf("[INFO] Invalid MD5 sum in imx_sums\n");
+ return IMX_ERROR;
}
- fseek(f, 0, SEEK_END);
- size_t sz = ftell(f);
- fseek(f, 0, SEEK_SET);
- void *buf = xmalloc(sz);
- if(fread(buf, sz, 1, f) != 1)
+ for(int j = 0; j < 16; j++)
{
- fclose(f);
- free(buf);
- printf("[ERR] Cannot read file\n");
- return IMX_READ_ERROR;
+ byte a, b;
+ if(convxdigit(imx_sums[i].md5sum[2 * j], &a) || convxdigit(imx_sums[i].md5sum[2 * j + 1], &b))
+ {
+ printf("[ERR][INTERNAL] Bad checksum format: %s\n", imx_sums[i].md5sum);
+ return IMX_ERROR;
+ }
+ md5[j] = (a << 4) | b;
}
+ if(memcmp(file_md5sum, md5, 16) == 0)
+ break;
+ i++;
+ }
+ if(i == NR_IMX_SUMS)
+ {
+ printf("[ERR] MD5 sum doesn't match any known file\n");
+ return IMX_NO_MATCH;
+ }
+ *md5_idx = i;
+ return IMX_SUCCESS;
+}
+
+/* read a file to a buffer */
+static enum imx_error_t read_file(const char *file, void **buffer, size_t *size)
+{
+ FILE *f = fopen(file, "rb");
+ if(f == NULL)
+ {
+ printf("[ERR] Cannot open file '%s' for reading: %m\n", file);
+ return IMX_OPEN_ERROR;
+ }
+ fseek(f, 0, SEEK_END);
+ *size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ *buffer = xmalloc(*size);
+ if(fread(*buffer, *size, 1, f) != 1)
+ {
+ free(*buffer);
+ fclose(f);
+ printf("[ERR] Cannot read file '%s': %m\n", file);
+ return IMX_READ_ERROR;
+ }
+ fclose(f);
+ return IMX_SUCCESS;
+}
+
+/* write a file from a buffer */
+static enum imx_error_t write_file(const char *file, void *buffer, size_t size)
+{
+ FILE *f = fopen(file, "wb");
+ if(f == NULL)
+ {
+ printf("[ERR] Cannot open file '%s' for writing: %m\n", file);
+ return IMX_OPEN_ERROR;
+ }
+ if(fwrite(buffer, size, 1, f) != 1)
+ {
+ fclose(f);
+ printf("[ERR] Cannot write file '%s': %m\n", file);
+ return IMX_WRITE_ERROR;
+ }
+ fclose(f);
+ return IMX_SUCCESS;
+}
+
+/* compute MD5 sum of a buffer */
+static enum imx_error_t compute_md5sum_buf(void *buf, size_t sz, uint8_t file_md5sum[16])
+{
+ md5_context ctx;
+ md5_starts(&ctx);
+ md5_update(&ctx, buf, sz);
+ md5_finish(&ctx, file_md5sum);
+ return IMX_SUCCESS;
+}
+
+/* compute MD5 of a file */
+static enum imx_error_t compute_md5sum(const char *file, uint8_t file_md5sum[16])
+{
+ FILE *f = fopen(file, "rb");
+ if(f == NULL)
+ {
+ printf("[ERR] Cannot open input file\n");
+ return IMX_OPEN_ERROR;
+ }
+ fseek(f, 0, SEEK_END);
+ size_t sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ void *buf = xmalloc(sz);
+ if(fread(buf, sz, 1, f) != 1)
+ {
fclose(f);
- md5_context ctx;
- md5_starts(&ctx);
- md5_update(&ctx, buf, sz);
- md5_finish(&ctx, file_md5sum);
free(buf);
- }while(0);
+ printf("[ERR] Cannot read file\n");
+ return IMX_READ_ERROR;
+ }
+ fclose(f);
+ compute_md5sum_buf(buf, sz, file_md5sum);
+ free(buf);
+ return IMX_SUCCESS;
+}
+
+static enum imx_error_t load_sb_file(const char *file, int md5_idx,
+ struct imx_option_t opt, struct sb_file_t **sb_file)
+{
+ if(imx_sums[md5_idx].fw_variants[opt.fw_variant].size == 0)
+ {
+ printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[opt.fw_variant]);
+ return IMX_VARIANT_MISMATCH;
+ }
+ enum imx_model_t model = imx_sums[md5_idx].model;
+ enum sb_error_t err;
+ g_debug = opt.debug;
+ clear_keys();
+ add_keys(imx_models[model].keys, imx_models[model].nr_keys);
+ *sb_file = sb_read_file_ex(file, imx_sums[md5_idx].fw_variants[opt.fw_variant].offset,
+ imx_sums[md5_idx].fw_variants[opt.fw_variant].size, false, NULL, &imx_printf, &err);
+ if(*sb_file == NULL)
+ {
+ clear_keys();
+ return IMX_FIRST_SB_ERROR + err;
+ }
+ return IMX_SUCCESS;
+}
+
+/* Load a rockbox firwmare from a buffer. Data is copied. */
+static enum imx_error_t rb_fw_load_buf(struct rb_fw_t *fw, uint8_t *buf, size_t sz,
+ enum imx_model_t model)
+{
+ if(sz < 8)
+ {
+ printf("[ERR] Bootloader file is too small to be valid\n");
+ return IMX_BOOT_INVALID;
+ }
+ /* check model name */
+ uint8_t *name = buf + 4;
+ if(memcmp(name, imx_models[model].rb_model_name, 4) != 0)
+ {
+ printf("[ERR] Bootloader model doesn't match found model for input file\n");
+ return IMX_BOOT_MISMATCH;
+ }
+ /* check checksum */
+ uint32_t sum = imx_models[model].rb_model_num;
+ for(int i = 8; i < sz; i++)
+ sum += buf[i];
+ if(sum != get_uint32be(buf))
+ {
+ printf("[ERR] Bootloader checksum mismatch\n");
+ return IMX_BOOT_CHECKSUM_ERROR;
+ }
+ fw->boot = memdup(buf + 8, sz - 8);
+ fw->boot_sz = sz - 8;
+ return IMX_SUCCESS;
+}
+
+/* load a rockbox firmware from a file. */
+static enum imx_error_t rb_fw_load(struct rb_fw_t *fw, const char *file,
+ enum imx_model_t model)
+{
+ void *buf;
+ size_t sz;
+ int ret = read_file(file, &buf, &sz);
+ if(ret == IMX_SUCCESS)
+ {
+ ret = rb_fw_load_buf(fw, buf, sz, model);
+ free(buf);
+ }
+ return ret;
+}
+
+/* free rockbox firmware */
+static void rb_fw_free(struct rb_fw_t *fw)
+{
+ free(fw->boot);
+ fw->boot = NULL;
+ fw->boot_sz = 0;
+}
+
+enum imx_error_t mkimxboot(const char *infile, const char *bootfile,
+ const char *outfile, struct imx_option_t opt)
+{
+ /* sanity check */
+ if(opt.fw_variant > VARIANT_COUNT)
+ return IMX_ERROR;
+ /* Dump tables */
+ dump_imx_dev_info("[INFO] ");
+ /* compute MD5 sum of the file */
+ uint8_t file_md5sum[16];
+ enum imx_error_t ret = compute_md5sum(infile, file_md5sum);
+ if(ret != IMX_SUCCESS)
+ return ret;
printf("[INFO] MD5 sum of the file: ");
print_hex(file_md5sum, 16, true);
/* find model */
- enum imx_model_t model;
int md5_idx;
- do
- {
- int i = 0;
- while(i < NR_IMX_SUMS)
- {
- uint8_t md5[20];
- if(strlen(imx_sums[i].md5sum) != 32)
- {
- printf("[INFO] Invalid MD5 sum in imx_sums\n");
- return IMX_ERROR;
- }
- for(int j = 0; j < 16; j++)
- {
- byte a, b;
- if(convxdigit(imx_sums[i].md5sum[2 * j], &a) || convxdigit(imx_sums[i].md5sum[2 * j + 1], &b))
- {
- printf("[ERR][INTERNAL] Bad checksum format: %s\n", imx_sums[i].md5sum);
- return IMX_ERROR;
- }
- md5[j] = (a << 4) | b;
- }
- if(memcmp(file_md5sum, md5, 16) == 0)
- break;
- i++;
- }
- if(i == NR_IMX_SUMS)
- {
- printf("[ERR] MD5 sum doesn't match any known file\n");
- return IMX_NO_MATCH;
- }
- model = imx_sums[i].model;
- md5_idx = i;
- }while(0);
+ ret = find_model_by_md5sum(file_md5sum, &md5_idx);
+ if(ret != IMX_SUCCESS)
+ return ret;
+ enum imx_model_t model = imx_sums[md5_idx].model;
printf("[INFO] File is for model %d (%s, version %s)\n", model,
imx_models[model].model_name, imx_sums[md5_idx].version);
/* load rockbox file */
- uint8_t *boot;
- size_t boot_size;
- do
- {
- FILE *f = fopen(bootfile, "rb");
- if(f == NULL)
- {
- printf("[ERR] Cannot open boot file\n");
- return IMX_OPEN_ERROR;
- }
- fseek(f, 0, SEEK_END);
- boot_size = ftell(f);
- fseek(f, 0, SEEK_SET);
- boot = xmalloc(boot_size);
- if(fread(boot, boot_size, 1, f) != 1)
- {
- free(boot);
- fclose(f);
- printf("[ERR] Cannot read boot file\n");
- return IMX_READ_ERROR;
- }
- fclose(f);
- }while(0);
- /* Check boot file */
- do
- {
- if(boot_size < 8)
- {
- printf("[ERR] Bootloader file is too small to be valid\n");
- free(boot);
- return IMX_BOOT_INVALID;
- }
- /* check model name */
- uint8_t *name = boot + 4;
- if(memcmp(name, imx_models[model].rb_model_name, 4) != 0)
- {
- printf("[ERR] Bootloader model doesn't match found model for input file\n");
- free(boot);
- return IMX_BOOT_MISMATCH;
- }
- /* check checksum */
- uint32_t sum = imx_models[model].rb_model_num;
- for(int i = 8; i < boot_size; i++)
- sum += boot[i];
- if(sum != get_uint32be(boot))
- {
- printf("[ERR] Bootloader checksum mismatch\n");
- free(boot);
- return IMX_BOOT_CHECKSUM_ERROR;
- }
- }while(0);
+ struct rb_fw_t boot_fw;
+ ret = rb_fw_load(&boot_fw, bootfile, model);
+ if(ret != IMX_SUCCESS)
+ return ret;
/* load OF file */
struct sb_file_t *sb_file;
- do
+ ret = load_sb_file(infile, md5_idx, opt, &sb_file);
+ if(ret != IMX_SUCCESS)
{
- if(imx_sums[md5_idx].fw_variants[opt.fw_variant].size == 0)
- {
- printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[opt.fw_variant]);
- free(boot);
- return IMX_VARIANT_MISMATCH;
- }
- enum sb_error_t err;
- g_debug = opt.debug;
- clear_keys();
- add_keys(imx_models[model].keys, imx_models[model].nr_keys);
- sb_file = sb_read_file_ex(infile, imx_sums[md5_idx].fw_variants[opt.fw_variant].offset,
- imx_sums[md5_idx].fw_variants[opt.fw_variant].size, false, NULL, &imx_printf, &err);
- if(sb_file == NULL)
- {
- clear_keys();
- free(boot);
- return IMX_FIRST_SB_ERROR + err;
- }
- }while(0);
+ rb_fw_free(&boot_fw);
+ return ret;
+ }
/* produce file */
- enum imx_error_t ret = patch_firmware(model, opt.fw_variant, opt.output,
- sb_file, boot + 8, boot_size - 8, opt.force_version);
+ ret = patch_firmware(model, opt.fw_variant, opt.output,
+ sb_file, boot_fw, opt.force_version);
if(ret == IMX_SUCCESS)
ret = sb_write_file(sb_file, outfile);
clear_keys();
- free(boot);
+ rb_fw_free(&boot_fw);
sb_free(sb_file);
return ret;
}
@@ -579,78 +662,38 @@ enum imx_error_t mkimxboot(const char *infile, const char *bootfile,
enum imx_error_t extract_firmware(const char *infile,
enum imx_firmware_variant_t fw_variant, const char *outfile)
{
- /* Dump tables */
- if(fw_variant > VARIANT_COUNT) {
+ /* sanity check */
+ if(fw_variant > VARIANT_COUNT)
return IMX_ERROR;
- }
+ /* dump tables */
dump_imx_dev_info("[INFO] ");
/* compute MD5 sum of the file */
+ void *buf;
+ size_t sz;
uint8_t file_md5sum[16];
- FILE *f = fopen(infile, "rb");
- if(f == NULL)
- {
- printf("[ERR] Cannot open input file\n");
- return IMX_OPEN_ERROR;
- }
- fseek(f, 0, SEEK_END);
- size_t sz = ftell(f);
- fseek(f, 0, SEEK_SET);
- void *buf = xmalloc(sz);
- if(fread(buf, sz, 1, f) != 1)
+ int ret = read_file(infile, &buf, &sz);
+ if(ret != IMX_SUCCESS)
+ return ret;
+ ret = compute_md5sum_buf(buf, sz, file_md5sum);
+ if(ret != IMX_SUCCESS)
{
- fclose(f);
free(buf);
- printf("[ERR] Cannot read file\n");
- return IMX_READ_ERROR;
+ return ret;
}
- md5_context ctx;
- md5_starts(&ctx);
- md5_update(&ctx, buf, sz);
- md5_finish(&ctx, file_md5sum);
- fclose(f);
-
printf("[INFO] MD5 sum of the file: ");
print_hex(file_md5sum, 16, true);
/* find model */
- enum imx_model_t model;
int md5_idx;
- do
+ ret = find_model_by_md5sum(file_md5sum, &md5_idx);
+ if(ret != IMX_SUCCESS)
{
- int i = 0;
- while(i < NR_IMX_SUMS)
- {
- uint8_t md5[20];
- if(strlen(imx_sums[i].md5sum) != 32)
- {
- printf("[INFO] Invalid MD5 sum in imx_sums\n");
- return IMX_ERROR;
- }
- for(int j = 0; j < 16; j++)
- {
- byte a, b;
- if(convxdigit(imx_sums[i].md5sum[2 * j], &a) || convxdigit(imx_sums[i].md5sum[2 * j + 1], &b))
- {
- printf("[ERR][INTERNAL] Bad checksum format: %s\n", imx_sums[i].md5sum);
- free(buf);
- return IMX_ERROR;
- }
- md5[j] = (a << 4) | b;
- }
- if(memcmp(file_md5sum, md5, 16) == 0)
- break;
- i++;
- }
- if(i == NR_IMX_SUMS)
- {
- printf("[ERR] MD5 sum doesn't match any known file\n");
- return IMX_NO_MATCH;
- }
- model = imx_sums[i].model;
- md5_idx = i;
- }while(0);
+ free(buf);
+ return ret;
+ }
+ enum imx_model_t model = imx_sums[md5_idx].model;
printf("[INFO] File is for model %d (%s, version %s)\n", model,
imx_models[model].model_name, imx_sums[md5_idx].version);
-
+ /* extract firmware */
if(imx_sums[md5_idx].fw_variants[fw_variant].size == 0)
{
printf("[ERR] Input file does not contain variant '%s'\n", imx_fw_variant[fw_variant]);
@@ -658,23 +701,9 @@ enum imx_error_t extract_firmware(const char *infile,
return IMX_VARIANT_MISMATCH;
}
- f = fopen(outfile, "wb");
- if(f == NULL)
- {
- printf("[ERR] Cannot open input file\n");
- free(buf);
- return IMX_OPEN_ERROR;
- }
- enum imx_error_t ret = IMX_SUCCESS;
-
- if(fwrite(buf + imx_sums[md5_idx].fw_variants[fw_variant].offset,
- imx_sums[md5_idx].fw_variants[fw_variant].size, 1, f) != 1)
- {
- printf("[ERR] Cannot write file\n");
- ret = IMX_ERROR;
- }
- fclose(f);
+ ret = write_file(outfile,
+ buf + imx_sums[md5_idx].fw_variants[fw_variant].offset,
+ imx_sums[md5_idx].fw_variants[fw_variant].size);
free(buf);
-
return ret;
}
diff --git a/rbutil/mkimxboot/mkimxboot.h b/rbutil/mkimxboot/mkimxboot.h
index 748742f523..de564dc5d4 100644
--- a/rbutil/mkimxboot/mkimxboot.h
+++ b/rbutil/mkimxboot/mkimxboot.h
@@ -41,7 +41,8 @@ enum imx_error_t
IMX_BOOT_CHECKSUM_ERROR = -7,
IMX_DONT_KNOW_HOW_TO_PATCH = -8,
IMX_VARIANT_MISMATCH = -9,
- IMX_FIRST_SB_ERROR = -10,
+ IMX_WRITE_ERROR = -10,
+ IMX_FIRST_SB_ERROR = -11,
};
enum imx_output_type_t