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); FILE *fd = fopen(filename, "wb"); free(filename); if(fd == NULL) return; if(g_elf_simplify) elf_simplify(elf); elf_write_file(elf, elf_std_write, generic_std_printf, fd); fclose(fd); }
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); if(g_debug) printf("Applying command file...\n"); /* count sections */ struct cmd_section_t *csec = cmd_file->section_list; while(csec) { sb->nr_sections++; csec = csec->next; } sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t)); memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t)); /* flatten sections */ csec = cmd_file->section_list; for(int i = 0; i < sb->nr_sections; i++, csec = csec->next) { struct sb_section_t *sec = &sb->sections[i]; sec->identifier = csec->identifier; /* options */ 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; } /* 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 = BLOCK_SIZE; }while(0); if(csec->is_data) { sec->is_data = true; sec->nr_insts = 1; sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); load_bin_by_id(cmd_file, csec->source_id); struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin; sec->insts[0].inst = SB_INST_DATA; sec->insts[0].size = bin->size; sec->insts[0].data = memdup(bin->data, bin->size); } else { sec->is_data = false; /* count instructions and loads things */ struct cmd_inst_t *cinst = csec->inst_list; while(cinst) { if(cinst->type == CMD_LOAD) { load_elf_by_id(cmd_file, cinst->identifier); struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; sec->nr_insts += elf_get_nr_sections(elf); } else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) { load_elf_by_id(cmd_file, cinst->identifier); struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; if(!elf_get_start_addr(elf, NULL)) bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); sec->nr_insts++; } else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT) { sec->nr_insts++; } else if(cinst->type == CMD_LOAD_AT) { load_bin_by_id(cmd_file, cinst->identifier); sec->nr_insts++; } else if(cinst->type == CMD_MODE) { sec->nr_insts++; } else bug("die\n"); cinst = cinst->next; } sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); /* flatten */ int idx = 0; cinst = csec->inst_list; while(cinst) { if(cinst->type == CMD_LOAD) { struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; struct elf_section_t *esec = elf->first_section; while(esec) { if(esec->type == EST_LOAD) { sec->insts[idx].inst = SB_INST_LOAD; sec->insts[idx].addr = esec->addr; sec->insts[idx].size = esec->size; sec->insts[idx++].data = memdup(esec->section, esec->size); } else if(esec->type == EST_FILL) { sec->insts[idx].inst = SB_INST_FILL; sec->insts[idx].addr = esec->addr; sec->insts[idx].size = esec->size; sec->insts[idx++].pattern = esec->pattern; } esec = esec->next; } } else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) { struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; sec->insts[idx].argument = cinst->argument; sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; sec->insts[idx++].addr = elf->start_addr; } else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT) { sec->insts[idx].argument = cinst->argument; sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL; sec->insts[idx++].addr = cinst->addr; } else if(cinst->type == CMD_LOAD_AT) { struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin; sec->insts[idx].inst = SB_INST_LOAD; sec->insts[idx].addr = cinst->addr; sec->insts[idx].data = memdup(bin->data, bin->size); sec->insts[idx++].size = bin->size; } else if(cinst->type == CMD_MODE) { sec->insts[idx].inst = SB_INST_MODE; sec->insts[idx++].addr = cinst->argument; } else bug("die\n"); cinst = cinst->next; } } } return sb; }
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)); 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"); /* count sections */ struct cmd_section_t *csec = cmd_file->section_list; while(csec) { sb->nr_sections++; csec = csec->next; } sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t)); memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t)); /* flatten sections */ csec = cmd_file->section_list; for(int i = 0; i < sb->nr_sections; i++, csec = csec->next) { struct sb_section_t *sec = &sb->sections[i]; sec->identifier = csec->identifier; /* options */ do { /* cleartext */ sec->is_cleartext = get_int_opt(csec->opt_list, "cleartext", false); /* alignment */ 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) { sec->is_data = true; sec->nr_insts = 1; sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); load_bin_by_id(cmd_file, csec->source_id); struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin; sec->insts[0].inst = SB_INST_DATA; sec->insts[0].size = bin->size; sec->insts[0].data = memdup(bin->data, bin->size); } else { sec->is_data = false; /* count instructions and loads things */ struct cmd_inst_t *cinst = csec->inst_list; while(cinst) { if(cinst->type == CMD_LOAD) { load_elf_by_id(cmd_file, cinst->identifier); struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; sec->nr_insts += elf_get_nr_sections(elf); } else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) { load_elf_by_id(cmd_file, cinst->identifier); struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; if(!elf_get_start_addr(elf, NULL)) bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); sec->nr_insts++; } else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT) { sec->nr_insts++; } else if(cinst->type == CMD_LOAD_AT) { load_bin_by_id(cmd_file, cinst->identifier); sec->nr_insts++; } else if(cinst->type == CMD_MODE) { sec->nr_insts++; } else bug("die\n"); cinst = cinst->next; } sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); /* flatten */ int idx = 0; cinst = csec->inst_list; while(cinst) { if(cinst->type == CMD_LOAD) { struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; struct elf_section_t *esec = elf->first_section; while(esec) { if(esec->type == EST_LOAD) { sec->insts[idx].inst = SB_INST_LOAD; sec->insts[idx].addr = esec->addr; sec->insts[idx].size = esec->size; sec->insts[idx++].data = memdup(esec->section, esec->size); } else if(esec->type == EST_FILL) { sec->insts[idx].inst = SB_INST_FILL; sec->insts[idx].addr = esec->addr; sec->insts[idx].size = esec->size; sec->insts[idx++].pattern = esec->pattern; } esec = esec->next; } } else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) { struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; sec->insts[idx].argument = cinst->argument; sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; sec->insts[idx++].addr = elf->start_addr; } else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT) { sec->insts[idx].argument = cinst->argument; sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL; sec->insts[idx++].addr = cinst->addr; } else if(cinst->type == CMD_LOAD_AT) { struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin; sec->insts[idx].inst = SB_INST_LOAD; sec->insts[idx].addr = cinst->addr; sec->insts[idx].data = memdup(bin->data, bin->size); sec->insts[idx++].size = bin->size; } else if(cinst->type == CMD_MODE) { sec->insts[idx].inst = SB_INST_MODE; sec->insts[idx++].addr = cinst->argument; } else bug("die\n"); cinst = cinst->next; } } } return sb; }