[Sound-open-firmware] [PATCH] rimage: add support to build and sign runtime modules
Currently rimage only supports building ELF images with know TEXT, DATA and BSS addresses. This patch adds support to build runtime relocatable modules that can be loaded linked into the base SOF FW at runtime.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- rimage/elf.c | 72 +++++++++++++++++++++++++++++++++----- rimage/file_simple.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++- rimage/manifest.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++-- rimage/rimage.c | 9 +++-- rimage/rimage.h | 4 +++ 5 files changed, 266 insertions(+), 13 deletions(-)
diff --git a/rimage/elf.c b/rimage/elf.c index b1a1861b..6c7e3dae 100644 --- a/rimage/elf.c +++ b/rimage/elf.c @@ -283,6 +283,42 @@ static void elf_module_size(struct image *image, struct module *module, } }
+static void elf_module_size_reloc(struct image *image, struct module *module, + Elf32_Shdr *section, int index) +{ + switch (section->sh_type) { + case SHT_PROGBITS: + /* text or data */ + if (section->sh_flags & SHF_EXECINSTR) { + /* text */ + module->text_start = 0; + module->text_end += section->sh_size; + + fprintf(stdout, "\tTEXT\t"); + } else { + /* initialized data, also calc the writable sections */ + module->data_start = 0; + module->data_end += section->sh_size; + + fprintf(stdout, "\tDATA\t"); + } + break; + case SHT_NOBITS: + /* bss */ + if (index == module->bss_index) { + /* updated the .bss segment */ + module->bss_start = section->sh_addr; + module->bss_end = section->sh_addr + section->sh_size; + fprintf(stdout, "\tBSS\t"); + } else { + fprintf(stdout, "\tHEAP\t"); + } + break; + default: + break; + } +} + static void elf_module_limits(struct image *image, struct module *module) { Elf32_Shdr *section; @@ -302,22 +338,29 @@ static void elf_module_limits(struct image *image, struct module *module)
section = &module->section[i];
- /* only check valid sections */ - if (!(section->sh_flags & valid)) - continue; + /* module bss can sometimes be missed */ + if (i != module->bss_index) {
- if (section->sh_size == 0) - continue; + /* only check valid sections */ + if (!(section->sh_flags & valid)) + continue;
- if (elf_is_rom(image, section)) - continue; + if (section->sh_size == 0) + continue; + + if (elf_is_rom(image, section)) + continue; + }
fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t%d", i, section->sh_addr, section->sh_addr + section->sh_size, section->sh_size);
/* text or data section */ - elf_module_size(image, module, section, i); + if (image->reloc) + elf_module_size_reloc(image, module, section, i); + else + elf_module_size(image, module, section, i);
/* section name */ fprintf(stdout, "%s\n", module->strings + section->sh_name); @@ -388,6 +431,10 @@ int elf_validate_modules(struct image *image) uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); int i, j, ret;
+ /* relocatable modules have no physical addresses until runtime */ + if (image->reloc) + return 0; + /* for each module */ for (i = 0; i < image->num_modules; i++) { module = &image->module[i]; @@ -484,6 +531,15 @@ int elf_parse_module(struct image *image, int module_index, const char *name) } module->elf_file = name;
+ /* get file size */ + ret = fseek(module->fd, 0, SEEK_END); + if (ret < 0) + goto hdr_err; + module->file_size = ftell(module->fd); + ret = fseek(module->fd, 0, SEEK_SET); + if (ret < 0) + goto hdr_err; + /* read in elf header */ ret = elf_read_hdr(image, module); if (ret < 0) diff --git a/rimage/file_simple.c b/rimage/file_simple.c index dcf0d5b2..a9f22d04 100644 --- a/rimage/file_simple.c +++ b/rimage/file_simple.c @@ -204,6 +204,98 @@ static int simple_write_module(struct image *image, struct module *module) return 0; }
+static int write_block_reloc(struct image *image, struct module *module) +{ + struct snd_sof_blk_hdr block; + size_t count; + void *buffer; + int ret; + + block.size = module->file_size; + block.type = SOF_BLK_DATA; + block.offset = 0; + + /* write header */ + count = fwrite(&block, sizeof(block), 1, image->out_fd); + if (count != 1) + return -errno; + + /* alloc data data */ + buffer = calloc(1, module->file_size); + if (!buffer) + return -ENOMEM; + + /* read in section data */ + ret = fseek(module->fd, 0, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: can't seek to section %d\n", ret); + goto out; + } + count = fread(buffer, 1, module->file_size, module->fd); + if (count != module->file_size) { + fprintf(stderr, "error: can't read section %d\n", -errno); + ret = -errno; + goto out; + } + + /* write out section data */ + count = fwrite(buffer, 1, module->file_size, image->out_fd); + if (count != module->file_size) { + fprintf(stderr, "error: can't write section %d\n", -errno); + ret = -errno; + goto out; + } + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%8.8lx\t%s\n", block_idx++, + 0, module->file_size, ftell(image->out_fd), + block.type == SOF_BLK_TEXT ? "TEXT" : "DATA"); + +out: + free(buffer); + return ret; +} + +static int simple_write_module_reloc(struct image *image, struct module *module) +{ + struct snd_sof_mod_hdr hdr; + size_t count; + int i, err; + + hdr.num_blocks = 1; + hdr.size = module->text_size + module->data_size; + hdr.type = SOF_FW_BASE; // module + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) { + fprintf(stderr, "error: failed to write section header %d\n", + -errno); + return -errno; + } + + fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize"); + + fprintf(stdout, "\n\tTEXT\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->text_start, module->text_end, + module->text_end - module->text_start); + fprintf(stdout, "\tDATA\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->data_start, module->data_end, + module->data_end - module->data_start); + fprintf(stdout, "\tBSS\t0x%8.8x\t0x%8.8x\t0x%x\n\n ", + module->bss_start, module->bss_end, + module->bss_end - module->bss_start); + + fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\t\tType\n"); + + err = write_block_reloc(image, module); + if (err < 0) { + fprintf(stderr, "error: failed to write section #%d\n", i); + return err; + } + + fprintf(stdout, "\n"); + return 0; +} + /* used by others */ static int simple_write_firmware(struct image *image) { @@ -235,7 +327,10 @@ static int simple_write_firmware(struct image *image)
fprintf(stdout, "writing module %d %s\n", i, module->elf_file);
- ret = simple_write_module(image, module); + if (image->reloc) + ret = simple_write_module_reloc(image, module); + else + ret = simple_write_module(image, module); if (ret < 0) { fprintf(stderr, "error: failed to write module %d\n", i); diff --git a/rimage/manifest.c b/rimage/manifest.c index 87f80d7c..6bb4ad3f 100644 --- a/rimage/manifest.c +++ b/rimage/manifest.c @@ -403,7 +403,6 @@ static int man_module_create(struct image *image, struct module *module,
fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n");
- /* validate segments */ if (man_module_validate(man_module) < 0) return -EINVAL;
@@ -445,6 +444,96 @@ static int man_module_create(struct image *image, struct module *module, return 0; }
+static int man_module_create_reloc(struct image *image, struct module *module, + struct sof_man_module *man_module) +{ + /* create module and segments */ + int err; + unsigned int pages; + void *buffer = image->fw_image + module->foffset; + size_t count; + + image->image_end = 0; + + err = man_get_module_manifest(image, module, man_module); + if (err < 0) + return err; + + /* stack size ??? convert sizes to PAGES */ + man_module->instance_bss_size = 1; + + /* max number of instances of this module ?? */ + man_module->instance_max_count = 1; + + fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize"); + + fprintf(stdout, "\n\tTEXT\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->text_start, module->text_end, + module->text_end - module->text_start); + fprintf(stdout, "\tDATA\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->data_start, module->data_end, + module->data_end - module->data_start); + fprintf(stdout, "\tBSS\t0x%8.8x\t0x%8.8x\t0x%x\n\n ", + module->bss_start, module->bss_end, + module->bss_end - module->bss_start); + + /* main module */ + /* text section is first */ + man_module->segment[SOF_MAN_SEGMENT_TEXT].file_offset = + module->foffset; + man_module->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length = 0; + + /* data section */ + man_module->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_RODATA].file_offset = + module->foffset; + pages = module->data_file_size / MAN_PAGE_SIZE; + if (module->data_file_size % MAN_PAGE_SIZE) + pages += 1; + + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length = pages; + + /* bss is last */ + man_module->segment[SOF_MAN_SEGMENT_BSS].file_offset = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length = 0; + + fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n"); + + /* seek to beginning of file */ + err = fseek(module->fd, 0, SEEK_SET); + if (err < 0) { + fprintf(stderr, "error: can't seek to section %d\n", err); + return err; + } + + count = fread(buffer, 1, module->file_size, module->fd); + if (count != module->file_size) { + fprintf(stderr, "error: can't read section %d\n", -errno); + return -errno; + } + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%x\t%s\n", 0, + 0, module->file_size, 0, "DATA"); + + fprintf(stdout, "\n"); + image->image_end = module->foffset + module->file_size; + + /* round module end up to nearest page */ + if (image->image_end % MAN_PAGE_SIZE) { + image->image_end = (image->image_end / MAN_PAGE_SIZE) + 1; + image->image_end *= MAN_PAGE_SIZE; + } + + fprintf(stdout, " Total pages text %d data %d bss %d module file limit: 0x%x\n\n", + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length, + image->image_end); + return 0; +} + static int man_write_unsigned_mod(struct image *image) { int count; @@ -555,7 +644,11 @@ static int man_write_fw(struct image *image) module->foffset = image->image_end; }
- ret = man_module_create(image, module, man_module); + if (image->reloc) + ret = man_module_create_reloc(image, module, + man_module); + else + ret = man_module_create(image, module, man_module); if (ret < 0) goto err; } diff --git a/rimage/rimage.c b/rimage/rimage.c index 322820b0..cc0a6101 100644 --- a/rimage/rimage.c +++ b/rimage/rimage.c @@ -35,8 +35,10 @@ static const struct adsp *machine[] = {
static void usage(char *name) { - fprintf(stdout, "%s:\t -m machine -o outfile -k [key] ELF files\n", name); + fprintf(stdout, "%s:\t -m machine -o outfile -k [key] ELF files\n", + name); fprintf(stdout, "\t -v enable verbose output\n"); + fprintf(stdout, "\t -r enable relocatable ELF files\n"); exit(0); }
@@ -48,7 +50,7 @@ int main(int argc, char *argv[])
memset(&image, 0, sizeof(image));
- while ((opt = getopt(argc, argv, "ho:m:vba:sk:l:")) != -1) { + while ((opt = getopt(argc, argv, "ho:m:vba:sk:l:r")) != -1) { switch (opt) { case 'o': image.out_file = optarg; @@ -68,6 +70,9 @@ int main(int argc, char *argv[]) case 'k': image.key_name = optarg; break; + case 'r': + image.reloc = 1; + break; case 'h': usage(argv[0]); break; diff --git a/rimage/rimage.h b/rimage/rimage.h index 8b46766d..888e7e8e 100644 --- a/rimage/rimage.h +++ b/rimage/rimage.h @@ -78,6 +78,9 @@ struct module { int text_file_size; int text_fixup_size; int data_file_size; + + /* total file size */ + int file_size; };
/* @@ -92,6 +95,7 @@ struct image { const struct adsp *adsp; int abi; int verbose; + int reloc; /* ELF data is relocatable */ int num_modules; struct module module[MAX_MODULES]; uint32_t image_end;/* module end, equal to output image size */
participants (1)
-
Liam Girdwood