From 260399ee8c44970aaa1cc9fd27db20df96604c5d Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Thu, 22 Aug 2013 14:39:46 +0200 Subject: sbtools: more work on sbtoelf and elftosb, support more attributes Now handle timestamp, sb minor version, component/product versions, section flags. Change-Id: I35313efe60c28f04ea3732b36e5e01be3213cf9e --- utils/imxtools/sbtools/dbparser.c | 56 +++++++++----------------- utils/imxtools/sbtools/dbparser.h | 2 +- utils/imxtools/sbtools/elftosb.c | 82 +++++++++++++++++++++++---------------- utils/imxtools/sbtools/sb.c | 42 +++++++++++++++----- utils/imxtools/sbtools/sb.h | 9 +++-- utils/imxtools/sbtools/sbtoelf.c | 2 +- 6 files changed, 107 insertions(+), 86 deletions(-) (limited to 'utils/imxtools') diff --git a/utils/imxtools/sbtools/dbparser.c b/utils/imxtools/sbtools/dbparser.c index 6cba91f34b..54939db6d2 100644 --- a/utils/imxtools/sbtools/dbparser.c +++ b/utils/imxtools/sbtools/dbparser.c @@ -419,44 +419,29 @@ struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char * #define INVALID_SB_SUBVERSION 0xffff -static uint16_t parse_sb_subversion(char *str) +static const char *parse_sb_subversion(const char *str, uint16_t *v) { - int len = strlen(str); - uint16_t n = 0; - if(len == 0 || len > 4) - return INVALID_SB_SUBVERSION; - for(int i = 0; i < len; i++) - { - if(!isdigit(str[i])) - return INVALID_SB_SUBVERSION; - n = n << 4 | (str[i] - '0'); - } - return n; + int len = 0; + *v = 0; + while(isdigit(str[len]) && len < 3) + *v = (*v) << 4 | (str[len++] - '0'); + if(len == 0) + *v = INVALID_SB_SUBVERSION; + return str + len; } -bool db_parse_sb_version(struct sb_version_t *ver, char *str) +bool db_parse_sb_version(struct sb_version_t *ver, const char *str) { - int len = strlen(str); - int cnt = 0; - int pos[2]; - - for(int i = 0; i < len; i++) - { - if(str[i] != '.') - continue; - if(cnt == 2) - return false; - pos[cnt++] = i + 1; - str[i] = 0; - } - if(cnt != 2) + str = parse_sb_subversion(str, &ver->major); + if(ver->major == INVALID_SB_SUBVERSION || *str != '.') + return false; + str = parse_sb_subversion(str + 1, &ver->minor); + if(ver->minor == INVALID_SB_SUBVERSION || *str != '.') return false; - ver->major = parse_sb_subversion(str); - ver->minor = parse_sb_subversion(str + pos[0]); - ver->revision = parse_sb_subversion(str + pos[1]); - return ver->major != INVALID_SB_SUBVERSION && - ver->minor != INVALID_SB_SUBVERSION && - ver->revision != INVALID_SB_SUBVERSION; + str = parse_sb_subversion(str + 1, &ver->revision); + if(ver->revision == INVALID_SB_SUBVERSION || *str != 0) + return false; + return true; } static bool db_generate_sb_subversion(uint16_t subver, char *str) @@ -831,11 +816,6 @@ struct cmd_file_t *db_parse_file(const char *file) return cmd_file; } -void db_generate_default_sb_version(struct sb_version_t *ver) -{ - ver->major = ver->minor = ver->revision = 0x999; -} - void db_free_option_list(struct cmd_option_t *opt_list) { while(opt_list) diff --git a/utils/imxtools/sbtools/dbparser.h b/utils/imxtools/sbtools/dbparser.h index b99eae9a2b..c55d560df4 100644 --- a/utils/imxtools/sbtools/dbparser.h +++ b/utils/imxtools/sbtools/dbparser.h @@ -111,7 +111,7 @@ typedef void (*db_color_printf)(void *u, bool err, color_t c, const char *f, ... struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id); struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name); -bool db_parse_sb_version(struct sb_version_t *ver, char *str); +bool db_parse_sb_version(struct sb_version_t *ver, const char *str); bool db_generate_sb_version(struct sb_version_t *ver, char *str, int size); void db_generate_default_sb_version(struct sb_version_t *ver); struct cmd_file_t *db_parse_file(const char *file); diff --git a/utils/imxtools/sbtools/elftosb.c b/utils/imxtools/sbtools/elftosb.c index c904e42f79..b65b65d402 100644 --- a/utils/imxtools/sbtools/elftosb.c +++ b/utils/imxtools/sbtools/elftosb.c @@ -118,13 +118,51 @@ static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id) src->loaded = true; } +static const char *get_str_opt(struct cmd_option_t *opt_list, const char *id, const char *dflt) +{ + struct cmd_option_t *opt = db_find_option_by_id(opt_list, id); + if(!opt) + return dflt; + if(!opt->is_string) + bug("'%s' option must be a string\n", id); + return opt->str; +} + +static uint32_t get_int_opt(struct cmd_option_t *opt_list, const char *id, uint32_t dflt) +{ + struct cmd_option_t *opt = db_find_option_by_id(opt_list, id); + if(!opt) + return dflt; + if(opt->is_string) + bug("'%s' option must be an integer\n", id); + return opt->val; +} + static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) { struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); memset(sb, 0, sizeof(struct sb_file_t)); - - db_generate_default_sb_version(&sb->product_ver); - db_generate_default_sb_version(&sb->component_ver); + sb_build_default_image(sb); + + if(db_find_option_by_id(cmd_file->opt_list, "componentVersion") && + !db_parse_sb_version(&sb->component_ver, get_str_opt(cmd_file->opt_list, "componentVersion", ""))) + bug("Invalid 'componentVersion' format\n"); + if(db_find_option_by_id(cmd_file->opt_list, "productVersion") && + !db_parse_sb_version(&sb->product_ver, get_str_opt(cmd_file->opt_list, "productVersion", ""))) + bug("Invalid 'productVersion' format\n"); + if(db_find_option_by_id(cmd_file->opt_list, "sbMinorVersion")) + sb->minor_version = get_int_opt(cmd_file->opt_list, "sbMinorVersion", 0); + if(db_find_option_by_id(cmd_file->opt_list, "flags")) + sb->flags = get_int_opt(cmd_file->opt_list, "flags", 0); + if(db_find_option_by_id(cmd_file->opt_list, "driveTag")) + sb->drive_tag = get_int_opt(cmd_file->opt_list, "driveTag", 0); + if(db_find_option_by_id(cmd_file->opt_list, "timestampLow")) + { + if(!db_find_option_by_id(cmd_file->opt_list, "timestampHigh")) + bug("Option 'timestampLow' and 'timestampHigh' must both specified\n"); + sb->timestamp = (uint64_t)get_int_opt(cmd_file->opt_list, "timestampHigh", 0) << 32 | + get_int_opt(cmd_file->opt_list, "timestampLow", 0); + } if(g_debug) printf("Applying command file...\n"); @@ -149,32 +187,16 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) do { /* cleartext */ - struct cmd_option_t *opt = db_find_option_by_id(csec->opt_list, "cleartext"); - if(opt != NULL) - { - if(opt->is_string) - bug("Cleartext section attribute must be an integer\n"); - if(opt->val != 0 && opt->val != 1) - bug("Cleartext section attribute must be 0 or 1\n"); - sec->is_cleartext = opt->val; - } + sec->is_cleartext = get_int_opt(csec->opt_list, "cleartext", false); /* alignment */ - opt = db_find_option_by_id(csec->opt_list, "alignment"); - if(opt != NULL) - { - if(opt->is_string) - bug("Cleartext section attribute must be an integer\n"); - // n is a power of 2 iff n & (n - 1) = 0 - // alignement cannot be lower than block size - if((opt->val & (opt->val - 1)) != 0) - bug("Cleartext section attribute must be a power of two\n"); - if(opt->val < BLOCK_SIZE) - sec->alignment = BLOCK_SIZE; - else - sec->alignment = opt->val; - } - else + sec->alignment = get_int_opt(csec->opt_list, "alignment", BLOCK_SIZE); + // alignement cannot be lower than block size + if((sec->alignment & (sec->alignment - 1)) != 0) + bug("Alignment section attribute must be a power of two\n"); + if(sec->alignment < BLOCK_SIZE) sec->alignment = BLOCK_SIZE; + /* other flags */ + sec->other_flags = get_int_opt(csec->opt_list, "sectionFlags", 0) & ~SECTION_STD_MASK; }while(0); if(csec->is_data) @@ -424,12 +446,6 @@ int main(int argc, char **argv) memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16); } - /* fill with default parameters since there is no command file support for them */ - sb_file->drive_tag = 0; - sb_file->first_boot_sec_id = sb_file->sections[0].identifier; - sb_file->flags = 0; - sb_file->minor_version = 1; - sb_write_file(sb_file, output_filename, 0, generic_std_printf); sb_free(sb_file); clear_keys(); diff --git a/utils/imxtools/sbtools/sb.c b/utils/imxtools/sbtools/sb.c index d7d3734a91..bea0438cca 100644 --- a/utils/imxtools/sbtools/sb.c +++ b/utils/imxtools/sbtools/sb.c @@ -186,7 +186,7 @@ static void compute_sb_offsets(struct sb_file_t *sb, void *u, generic_printf_t c #undef printf } -static uint64_t generate_timestamp() +uint64_t sb_generate_timestamp(void) { struct tm tm_base; memset(&tm_base, 0, sizeof(tm_base)); @@ -218,11 +218,11 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) sb_hdr->signature[2] = 'M'; sb_hdr->signature[3] = 'P'; sb_hdr->major_ver = IMAGE_MAJOR_VERSION; - sb_hdr->minor_ver = IMAGE_MINOR_VERSION; - sb_hdr->flags = 0; + sb_hdr->minor_ver = sb->minor_version; + sb_hdr->flags = sb->flags; sb_hdr->image_size = sb->image_size; sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; - sb_hdr->first_boot_sec_id = sb->first_boot_sec_id; + sb_hdr->first_boot_sec_id = sb->sections[0].identifier; sb_hdr->nr_keys = g_nr_keys; sb_hdr->nr_sections = sb->nr_sections; sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; @@ -237,10 +237,7 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) if(sb->minor_version >= 1) memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4); - if(sb->override_timestamp) - sb_hdr->timestamp = sb->timestamp; - else - sb_hdr->timestamp = generate_timestamp(); + sb_hdr->timestamp = sb->timestamp; sb_hdr->product_ver = sb->product_ver; fix_version(&sb_hdr->product_ver); sb_hdr->component_ver = sb->component_ver; @@ -261,7 +258,8 @@ static void produce_sb_section_header(struct sb_section_t *sec, sec_hdr->offset = sec->file_offset; sec_hdr->size = sec->sec_size; sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE) - | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); + | (sec->is_cleartext ? SECTION_CLEARTEXT : 0) + | sec->other_flags; } static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) @@ -281,7 +279,8 @@ static void produce_section_tag_cmd(struct sb_section_t *sec, tag->identifier = sec->identifier; tag->len = sec->sec_size; tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE) - | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); + | (sec->is_cleartext ? SECTION_CLEARTEXT : 0) + | sec->other_flags; tag->hdr.checksum = instruction_checksum(&tag->hdr); } @@ -333,6 +332,11 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void * memset(cbc_macs[i], 0, 16); fill_gaps(sb); + if(sb->nr_sections == 0 || sb->sections[0].is_data) + { + cprintf(u, true, GREY, "First section of the image is not bootable, I cannot handle that.\n"); + return SB_ERROR; + } compute_sb_offsets(sb, u, cprintf); generate_random_data(real_key.u.key, 16); @@ -983,6 +987,7 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, bool raw_mode, voi sec, size, " ", u, cprintf, err); if(s) { + s->other_flags = sec_hdr->flags & ~SECTION_STD_MASK; s->is_cleartext = !encrypted; s->alignment = guess_alignment(pos); memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t)); @@ -1073,6 +1078,7 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, bool raw_mode, voi sec, size, " ", u, cprintf, err); if(s) { + s->other_flags = tag->flags & ~SECTION_STD_MASK; s->is_cleartext = !encrypted; s->alignment = guess_alignment(pos); sb_file->sections = augment_array(sb_file->sections, @@ -1138,6 +1144,19 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, bool raw_mode, voi #undef print_hex } +void sb_generate_default_version(struct sb_version_t *ver) +{ + ver->major = ver->minor = ver->revision = 0x999; +} + +void sb_build_default_image(struct sb_file_t *sb) +{ + sb->minor_version = IMAGE_MINOR_VERSION; + sb->timestamp = sb_generate_timestamp(); + sb_generate_default_version(&sb->product_ver); + sb_generate_default_version(&sb->component_ver); +} + void sb_free_instruction(struct sb_inst_t inst) { free(inst.padding); @@ -1246,6 +1265,9 @@ void sb_dump(struct sb_file_t *file, void *u, generic_printf_t cprintf) printf(HEADER, "Alignment: "); printf(TEXT, "%d (bytes)\n", sec->alignment); printf(TREE, "| +-"); + printf(HEADER, "Other Flags: "); + printf(TEXT, "%#x\n", sec->other_flags); + printf(TREE, "| +-"); printf(HEADER, "Instructions\n"); for(int j = 0; j < sec->nr_insts; j++) { diff --git a/utils/imxtools/sbtools/sb.h b/utils/imxtools/sbtools/sb.h index aa382fca82..67d0d8c423 100644 --- a/utils/imxtools/sbtools/sb.h +++ b/utils/imxtools/sbtools/sb.h @@ -81,6 +81,7 @@ struct sb_key_dictionary_entry_t #define SECTION_BOOTABLE (1 << 0) #define SECTION_CLEARTEXT (1 << 1) +#define SECTION_STD_MASK (3 << 0) #define SB_INST_NOP 0x0 #define SB_INST_TAG 0x1 @@ -187,6 +188,7 @@ struct sb_section_t uint32_t identifier; bool is_data; bool is_cleartext; + uint32_t other_flags; uint32_t alignment; // data sections are handled as one or more SB_INST_DATA virtual instruction int nr_insts; @@ -204,15 +206,13 @@ struct sb_file_t /* override crypto IV, use with caution ! Use NULL to generate it */ bool override_crypto_iv; uint8_t crypto_iv[16]; - /* override timestamp */ - bool override_timestamp; uint64_t timestamp; /* In microseconds since 2000/1/1 00:00:00 */ + uint8_t minor_version; int nr_sections; uint16_t drive_tag; uint32_t first_boot_sec_id; uint16_t flags; - uint8_t minor_version; struct sb_section_t *sections; struct sb_version_t product_ver; struct sb_version_t component_ver; @@ -244,6 +244,9 @@ struct sb_file_t *sb_read_file_ex(const char *filename, size_t offset, size_t si struct sb_file_t *sb_read_memory(void *buffer, size_t size, bool raw_mode, void *u, generic_printf_t printf, enum sb_error_t *err); +uint64_t sb_generate_timestamp(void); +void sb_generate_default_version(struct sb_version_t *ver); +void sb_build_default_image(struct sb_file_t *file); void sb_fill_section_name(char name[5], uint32_t identifier); void sb_dump(struct sb_file_t *file, void *u, generic_printf_t printf); void sb_free_instruction(struct sb_inst_t inst); diff --git a/utils/imxtools/sbtools/sbtoelf.c b/utils/imxtools/sbtools/sbtoelf.c index ed27a53f16..04bde051ad 100644 --- a/utils/imxtools/sbtools/sbtoelf.c +++ b/utils/imxtools/sbtools/sbtoelf.c @@ -96,6 +96,7 @@ static void extract_sb_section(struct sb_section_t *sec, struct cmd_file_t *cmd_ struct cmd_section_t *db_sec = db_add_section(cmd_file, sec->identifier, sec->is_data); db_add_int_opt(&db_sec->opt_list, "alignment", sec->alignment); db_add_int_opt(&db_sec->opt_list, "cleartext", sec->is_cleartext); + db_add_int_opt(&db_sec->opt_list, "sectionFlags", sec->other_flags); if(sec->is_data) { @@ -413,7 +414,6 @@ int main(int argc, char **argv) * garbage */ file->override_real_key = false; file->override_crypto_iv = false; - file->override_timestamp = true; sb_write_file(file, loopback, 0, generic_std_printf); } sb_free(file); -- cgit