1
0
Fork 0
forked from len0rd/rockbox

sbtools: more work on sbtoelf and elftosb, support more attributes

Now handle timestamp, sb minor version, component/product versions,
section flags.

Change-Id: I35313efe60c28f04ea3732b36e5e01be3213cf9e
This commit is contained in:
Amaury Pouly 2013-08-22 14:39:46 +02:00
parent a122b52d66
commit 260399ee8c
6 changed files with 106 additions and 85 deletions

View file

@ -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;
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->minor);
if(ver->minor == INVALID_SB_SUBVERSION || *str != '.')
return false;
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)

View file

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

View file

@ -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));
sb_build_default_image(sb);
db_generate_default_sb_version(&sb->product_ver);
db_generate_default_sb_version(&sb->component_ver);
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();

View file

@ -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++)
{

View file

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

View file

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