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);