From 81f97f67e2638623abe3ba4094bffea563832355 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Thu, 22 Aug 2013 00:58:19 +0200 Subject: sbtools: now generate a db file along with with elf/rsrc files Now always generate a "make.db" file which aims at being the exact representation of the file, ie running sbtoelf and elftosb using the generated command file should produce the exact same file (except for the random paddings). We still miss the support for some option parsing to achieve that though. Change-Id: Ib7d6b241f7855fd35225df8ab8e0711f69d9ee5a --- utils/imxtools/sbtools/Makefile | 2 +- utils/imxtools/sbtools/dbparser.c | 226 ++++++++++++++++++++++++++++++++++++++ utils/imxtools/sbtools/dbparser.h | 17 +++ utils/imxtools/sbtools/sb.c | 23 +++- utils/imxtools/sbtools/sb.h | 3 + utils/imxtools/sbtools/sbtoelf.c | 53 +++++++-- 6 files changed, 315 insertions(+), 9 deletions(-) (limited to 'utils/imxtools') diff --git a/utils/imxtools/sbtools/Makefile b/utils/imxtools/sbtools/Makefile index eab5b8d27b..13b0a1280f 100644 --- a/utils/imxtools/sbtools/Makefile +++ b/utils/imxtools/sbtools/Makefile @@ -10,7 +10,7 @@ all: $(BINS) %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o xorcrypt.o elf.o misc.o sb.o sb1.o +sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o xorcrypt.o dbparser.o elf.o misc.o sb.o sb1.o $(LD) -o $@ $^ $(LDFLAGS) elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o diff --git a/utils/imxtools/sbtools/dbparser.c b/utils/imxtools/sbtools/dbparser.c index 37f812d585..414b771617 100644 --- a/utils/imxtools/sbtools/dbparser.c +++ b/utils/imxtools/sbtools/dbparser.c @@ -316,6 +316,84 @@ static void log_lexem(struct lexem_t *lexem) } #endif +struct cmd_option_t *db_add_opt(struct cmd_option_t **opt, const char *identifier, bool is_str) +{ + while(*opt) + opt = &(*opt)->next; + *opt = xmalloc(sizeof(struct cmd_option_t)); + memset(*opt, 0, sizeof(struct cmd_option_t)); + (*opt)->name = strdup(identifier); + (*opt)->is_string = is_str; + return *opt; +} + +void db_add_str_opt(struct cmd_option_t **opt, const char *name, const char *value) +{ + db_add_opt(opt, name, true)->str = strdup(value); +} + +void db_add_int_opt(struct cmd_option_t **opt, const char *name, uint32_t value) +{ + db_add_opt(opt, name, false)->val = value; +} + +static struct cmd_source_t *db_add_src(struct cmd_source_t **src, const char *identifier, bool is_extern) +{ + while(*src) + src = &(*src)->next; + *src = xmalloc(sizeof(struct cmd_source_t)); + memset(*src, 0, sizeof(struct cmd_source_t)); + (*src)->identifier = strdup(identifier); + (*src)->is_extern = is_extern; + return *src; +} + +void db_add_source(struct cmd_file_t *cmd_file, const char *identifier, const char *filename) +{ + db_add_src(&cmd_file->source_list, identifier, false)->filename = strdup(filename); +} + +void db_add_extern_source(struct cmd_file_t *cmd_file, const char *identifier, int extern_nr) +{ + db_add_src(&cmd_file->source_list, identifier, false)->extern_nr = extern_nr; +} + +static struct cmd_inst_t *db_add_inst(struct cmd_inst_t **list, enum cmd_inst_type_t type, + uint32_t argument) +{ + while(*list) + list = &(*list)->next; + *list = xmalloc(sizeof(struct cmd_inst_t)); + memset(*list, 0, sizeof(struct cmd_inst_t)); + (*list)->type = type; + (*list)->argument = argument; + return *list; +} + +void db_add_inst_id(struct cmd_section_t *cmd_section, enum cmd_inst_type_t type, + const char *identifier, uint32_t argument) +{ + db_add_inst(&cmd_section->inst_list, type, argument)->identifier = strdup(identifier); +} + +void db_add_inst_addr(struct cmd_section_t *cmd_section, enum cmd_inst_type_t type, + uint32_t addr, uint32_t argument) +{ + db_add_inst(&cmd_section->inst_list, type, argument)->addr = addr; +} + +struct cmd_section_t *db_add_section(struct cmd_file_t *cmd_file, uint32_t identifier, bool data) +{ + struct cmd_section_t **prev = &cmd_file->section_list; + while(*prev) + prev = &(*prev)->next; + *prev = xmalloc(sizeof(struct cmd_section_t)); + memset(*prev, 0, sizeof(struct cmd_section_t)); + (*prev)->identifier = identifier; + (*prev)->is_data = data; + return *prev; +} + struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id) { struct cmd_source_t *src = cmd_file->source_list; @@ -381,6 +459,26 @@ bool db_parse_sb_version(struct sb_version_t *ver, char *str) ver->revision != INVALID_SB_SUBVERSION; } +static bool db_generate_sb_subversion(uint16_t subver, char *str) +{ + str[0] = '0' + ((subver >> 8) & 0xf); + str[1] = '0' + ((subver >> 4) & 0xf); + str[2] = '0' + (subver & 0xf); + return true; +} + +bool db_generate_sb_version(struct sb_version_t *ver, char *str, int size) +{ + if(size < 12) + return false; + str[3] = '.'; + str[7] = '.'; + str[11] = 0; + return db_generate_sb_subversion(ver->major, str) && + db_generate_sb_subversion(ver->minor, str + 4) && + db_generate_sb_subversion(ver->revision, str + 8); +} + #undef parse_error #define parse_error(lexem, ...) \ do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \ @@ -815,6 +913,134 @@ void db_free_option_list(struct cmd_option_t *opt_list) } } +static bool db_generate_options(FILE *f, const char *secname, struct cmd_option_t *list) +{ + fprintf(f, "%s\n", secname); + fprintf(f, "{\n"); + while(list) + { + fprintf(f, " %s = ", list->name); + if(list->is_string) + fprintf(f, "\"%s\";\n", list->str); // FIXME handle escape + else + fprintf(f, "0x%x;\n", list->val); + list = list->next; + } + fprintf(f, "}\n"); + return true; +} + +static bool db_generate_section_options(FILE *f, struct cmd_option_t *list) +{ + bool first = true; + while(list) + { + fprintf(f, "%c %s = ", first ? ';' : ',', list->name); + if(list->is_string) + fprintf(f, "\"%s\"", list->str); // FIXME handle escape + else + fprintf(f, "0x%x", list->val); + first = false; + list = list->next; + } + return true; +} + +static bool db_generate_sources(FILE *f, struct cmd_source_t *list) +{ + fprintf(f, "sources\n"), + fprintf(f, "{\n"); + while(list) + { + fprintf(f, " %s = ", list->identifier); + if(list->is_extern) + fprintf(f, "extern(%d);\n", list->extern_nr); + else + fprintf(f, "\"%s\";\n", list->filename); // FIXME handle escape + list = list->next; + } + fprintf(f, "}\n"); + return true; +} + +static bool db_generate_section(FILE *f, struct cmd_section_t *section) +{ + fprintf(f, "section(%#x", section->identifier); + db_generate_section_options(f, section->opt_list); + if(section->is_data) + { + fprintf(f, ") <= %s;\n", section->source_id); + return true; + } + fprintf(f, ")\n{\n"); + struct cmd_inst_t *inst = section->inst_list; + while(inst) + { + fprintf(f, " "); + switch(inst->type) + { + case CMD_LOAD: + fprintf(f, "load %s;\n", inst->identifier); + break; + case CMD_LOAD_AT: + fprintf(f, "load %s > %#x;\n", inst->identifier, inst->addr); + break; + case CMD_CALL: + fprintf(f, "call %s(%#x);\n", inst->identifier, inst->argument); + break; + case CMD_CALL_AT: + fprintf(f, "call %#x(%#x);\n", inst->addr, inst->argument); + break; + case CMD_JUMP: + fprintf(f, "jump %s(%#x);\n", inst->identifier, inst->argument); + break; + case CMD_JUMP_AT: + fprintf(f, "jump %#x(%#x);\n", inst->addr, inst->argument); + break; + case CMD_MODE: + fprintf(f, "mode %#x;\n", inst->argument); + break; + default: + bug("die"); + } + inst = inst->next; + } + fprintf(f, "}\n"); + return true; +} + +static bool db_generate_sections(FILE *f, struct cmd_section_t *section) +{ + while(section) + if(!db_generate_section(f, section)) + return false; + else + section = section->next; + return true; +} + +bool db_generate_file(struct cmd_file_t *file, const char *filename, void *user, db_color_printf printf) +{ + FILE *f = fopen(filename, "w"); + if(f == NULL) + return printf(user, true, GREY, "Cannot open '%s' for writing: %m\n", filename), false; + if(!db_generate_options(f, "constants", file->constant_list)) + goto Lerr; + if(!db_generate_options(f, "options", file->opt_list)) + goto Lerr; + if(!db_generate_sources(f, file->source_list)) + goto Lerr; + if(!db_generate_sections(f, file->section_list)) + goto Lerr; + + fclose(f); + return true; + + Lerr: + fclose(f); + return false; +} + void db_free(struct cmd_file_t *file) { db_free_option_list(file->opt_list); diff --git a/utils/imxtools/sbtools/dbparser.h b/utils/imxtools/sbtools/dbparser.h index 4a36861583..b99eae9a2b 100644 --- a/utils/imxtools/sbtools/dbparser.h +++ b/utils/imxtools/sbtools/dbparser.h @@ -107,12 +107,29 @@ struct cmd_file_t struct cmd_section_t *section_list; }; +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_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); +/* NOTE: db_add_{str_opt,int_opt,source,extern_source} add at the beginning of the list */ +void db_add_str_opt(struct cmd_option_t **opt, const char *name, const char *str); +void db_add_int_opt(struct cmd_option_t **opt, const char *name, uint32_t value); +void db_add_source(struct cmd_file_t *cmd_file, const char *identifier, const char *filename); +void db_add_inst_id(struct cmd_section_t *cmd_section, enum cmd_inst_type_t type, + const char *identifier, uint32_t argument); +void db_add_inst_addr(struct cmd_section_t *cmd_section, enum cmd_inst_type_t type, + uint32_t addr, uint32_t argument); +struct cmd_section_t *db_add_section(struct cmd_file_t *cmd_file, uint32_t identifier, bool data); +void db_add_extern_source(struct cmd_file_t *cmd_file, const char *identifier, int extern_nr); +bool db_generate_file(struct cmd_file_t *file, const char *filename, void *user, db_color_printf printf); void db_free_option_list(struct cmd_option_t *opt_list); void db_free(struct cmd_file_t *file); +/* standard implementation: user is unused*/ +void db_std_printf(void *user, bool error, color_t c, const char *fmt, ...); + #endif /* __DBPARSER__ */ diff --git a/utils/imxtools/sbtools/sb.c b/utils/imxtools/sbtools/sb.c index a642af5945..d7d3734a91 100644 --- a/utils/imxtools/sbtools/sb.c +++ b/utils/imxtools/sbtools/sb.c @@ -237,7 +237,10 @@ 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); - sb_hdr->timestamp = generate_timestamp(); + if(sb->override_timestamp) + sb_hdr->timestamp = sb->timestamp; + else + sb_hdr->timestamp = generate_timestamp(); sb_hdr->product_ver = sb->product_ver; fix_version(&sb_hdr->product_ver); sb_hdr->component_ver = sb->component_ver; @@ -789,6 +792,7 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, bool raw_mode, voi struct tm *time = gmtime(&seconds); printf(GREEN, " Creation date/time = "); printf(YELLOW, "%s", asctime(time)); + sb_file->timestamp = sb_header->timestamp; struct sb_version_t product_ver = sb_header->product_ver; fix_version(&product_ver); @@ -1186,6 +1190,23 @@ void sb_dump(struct sb_file_t *file, void *u, generic_printf_t cprintf) char name[5]; sb_fill_section_name(name, file->first_boot_sec_id); printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name); + printf(TREE, "+-"); + printf(HEADER, "Timestamp: "); + printf(TEXT, "%#llx", file->timestamp); + { + uint64_t micros = file->timestamp; + time_t seconds = (micros / (uint64_t)1000000L); + struct tm tm_base; + memset(&tm_base, 0, sizeof(tm_base)); + /* 2000/1/1 0:00:00 */ + tm_base.tm_mday = 1; + tm_base.tm_year = 100; + seconds += mktime(&tm_base); + struct tm *time = gmtime(&seconds); + char *str = asctime(time); + str[strlen(str) - 1] = 0; + printf(TEXT2, " (%s)\n", str); + } if(file->override_real_key) { diff --git a/utils/imxtools/sbtools/sb.h b/utils/imxtools/sbtools/sb.h index 4f725da750..aa382fca82 100644 --- a/utils/imxtools/sbtools/sb.h +++ b/utils/imxtools/sbtools/sb.h @@ -204,6 +204,9 @@ 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 */ int nr_sections; uint16_t drive_tag; diff --git a/utils/imxtools/sbtools/sbtoelf.c b/utils/imxtools/sbtools/sbtoelf.c index 640a2418c1..ed27a53f16 100644 --- a/utils/imxtools/sbtools/sbtoelf.c +++ b/utils/imxtools/sbtools/sbtoelf.c @@ -43,6 +43,7 @@ #include "sb.h" #include "sb1.h" #include "misc.h" +#include "dbparser.h" /* all blocks are sized as a multiple of 0x1ff */ #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) @@ -61,12 +62,21 @@ static char *g_out_prefix; static bool g_elf_simplify = true; -static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id) +static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id, + struct cmd_file_t *cmd_file, struct cmd_section_t *section, bool is_call, uint32_t arg) { char name[5]; + char fileid[16]; char *filename = xmalloc(strlen(g_out_prefix) + 32); sb_fill_section_name(name, id); + sb_fill_section_name(fileid, id); + sprintf(fileid + strlen(fileid), "%d", count); sprintf(filename, "%s%s.%d.elf", g_out_prefix, name, count); + db_add_source(cmd_file, fileid, filename + strlen(g_out_prefix)); + db_add_inst_id(section, CMD_LOAD, fileid, 0); + if(elf_get_start_addr(elf, NULL)) + db_add_inst_id(section, is_call ? CMD_CALL : CMD_JUMP, fileid, arg); + if(g_debug) printf("Write boot section %s to %s\n", name, filename); @@ -81,14 +91,21 @@ static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id fclose(fd); } -static void extract_sb_section(struct sb_section_t *sec) +static void extract_sb_section(struct sb_section_t *sec, struct cmd_file_t *cmd_file) { + 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); + if(sec->is_data) { char sec_name[5]; char *filename = xmalloc(strlen(g_out_prefix) + 32); sb_fill_section_name(sec_name, sec->identifier); sprintf(filename, "%s%s.bin", g_out_prefix, sec_name); + db_add_source(cmd_file, sec_name, filename + strlen(g_out_prefix)); + db_sec->source_id = strdup(sec_name); + FILE *fd = fopen(filename, "wb"); if(fd == NULL) bugp("Cannot open %s for writing\n", filename); @@ -116,7 +133,7 @@ static void extract_sb_section(struct sb_section_t *sec) switch(inst->inst) { case SB_INST_LOAD: - sprintf(secname, ".text%d", text_idx++); + sprintf(secname, ".text%d", text_idx); elf_add_load_section(&elf, inst->addr, inst->size, inst->data, secname); break; case SB_INST_FILL: @@ -126,7 +143,8 @@ static void extract_sb_section(struct sb_section_t *sec) case SB_INST_CALL: case SB_INST_JUMP: elf_set_start_addr(&elf, inst->addr); - extract_elf_section(&elf, elf_count++, sec->identifier); + extract_elf_section(&elf, elf_count++, sec->identifier, cmd_file, db_sec, + inst->inst == SB_INST_CALL, inst->argument); elf_release(&elf); elf_init(&elf); bss_idx = text_idx = 0; @@ -138,20 +156,40 @@ static void extract_sb_section(struct sb_section_t *sec) } if(!elf_is_empty(&elf)) - extract_elf_section(&elf, elf_count, sec->identifier); + extract_elf_section(&elf, elf_count, sec->identifier, cmd_file, db_sec, false, 0); elf_release(&elf); } static void extract_sb_file(struct sb_file_t *file) { + char buffer[64]; + struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); + memset(cmd_file, 0, sizeof(struct cmd_file_t)); + db_generate_sb_version(&file->product_ver, buffer, sizeof(buffer)); + db_add_str_opt(&cmd_file->opt_list, "productVersion", buffer); + db_generate_sb_version(&file->component_ver, buffer, sizeof(buffer)); + db_add_str_opt(&cmd_file->opt_list, "componentVersion", buffer); + db_add_int_opt(&cmd_file->opt_list, "driveTag", file->drive_tag); + db_add_int_opt(&cmd_file->opt_list, "flags", file->flags); + db_add_int_opt(&cmd_file->opt_list, "timestampLow", file->timestamp & 0xffffffff); + db_add_int_opt(&cmd_file->opt_list, "timestampHigh", file->timestamp >> 32); + db_add_int_opt(&cmd_file->opt_list, "sbMinorVersion", file->minor_version); + for(int i = 0; i < file->nr_sections; i++) - extract_sb_section(&file->sections[i]); + extract_sb_section(&file->sections[i], cmd_file); + + char *filename = xmalloc(strlen(g_out_prefix) + 32); + sprintf(filename, "%smake.db", g_out_prefix); + if(g_debug) + printf("Write command file to %s\n", filename); + db_generate_file(cmd_file, filename, NULL, generic_std_printf); + db_free(cmd_file); } static void extract_elf(struct elf_params_t *elf, int count) { char *filename = xmalloc(strlen(g_out_prefix) + 32); - sprintf(filename, "%s.%d.elf", g_out_prefix, count); + sprintf(filename, "%s%d.elf", g_out_prefix, count); if(g_debug) printf("Write boot content to %s\n", filename); @@ -375,6 +413,7 @@ 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