From 95c4be7c2e3b26832cacd8c11cfc1c9d18ee9f9b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 25 Nov 2024 16:56:50 +0200 Subject: [PATCH 1/7] rimage: split a function Split man_get_module_manifest() into two functions in preparation for multi-part relocatable module library support. Signed-off-by: Guennadi Liakhovetski --- tools/rimage/src/manifest.c | 56 +++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c index 52b328e85ca7..6f9283c85747 100644 --- a/tools/rimage/src/manifest.c +++ b/tools/rimage/src/manifest.c @@ -195,29 +195,11 @@ static int man_copy_elf_sections(struct image *image, struct manifest_module *mo return 0; } -static int man_get_module_manifest(struct image *image, struct manifest_module *module, - struct sof_man_module *man_module) +static void man_get_section_manifest(struct image *image, + const struct sof_man_module_manifest *sof_mod, + struct sof_man_module *man_module) { - struct elf_section section; struct sof_man_segment_desc *segment; - const struct sof_man_module_manifest *sof_mod; - int ret; - - fprintf(stdout, "Module Write: %s\n", module->file.elf.filename); - - /* load in module manifest data */ - ret = elf_section_read_by_name(&module->file.elf, ".module", §ion); - if (ret) { - fprintf(stderr, "error: can't read module manifest from '.module' section.\n"); - return ret; - } - - if (sizeof(*sof_mod) > section.header.data.size) { - fprintf(stderr, "error: Invalid module manifest in '.module' section.\n"); - ret = -ENODATA; - goto error; - } - sof_mod = section.data; /* configure man_module with sofmod data */ memcpy(man_module->struct_id, "$AME", 4); @@ -230,9 +212,6 @@ static int man_get_module_manifest(struct image *image, struct manifest_module * man_module->type.domain_ll = sof_mod->module.type.domain_ll; man_module->type.load_type = sof_mod->module.type.load_type; - /* read out text_fixup_size from memory mapping */ - module->text_fixup_size = sof_mod->text_size; - /* text segment */ segment = &man_module->segment[SOF_MAN_SEGMENT_TEXT]; segment->flags.r.contents = 1; @@ -257,6 +236,35 @@ static int man_get_module_manifest(struct image *image, struct manifest_module * segment->flags.r.type = SOF_MAN_SEGMENT_BSS; fprintf(stdout, " Entry point 0x%8.8x\n", man_module->entry_point); +} + +static int man_get_module_manifest(struct image *image, struct manifest_module *module, + struct sof_man_module *man_module) +{ + struct elf_section section; + const struct sof_man_module_manifest *sof_mod; + int ret; + + fprintf(stdout, "Module Write: %s\n", module->file.elf.filename); + + /* load in module manifest data */ + ret = elf_section_read_by_name(&module->file.elf, ".module", §ion); + if (ret) { + fprintf(stderr, "error: can't read module manifest from '.module' section.\n"); + return ret; + } + + if (sizeof(*sof_mod) > section.header.data.size) { + fprintf(stderr, "error: Invalid module manifest in '.module' section.\n"); + ret = -ENODATA; + goto error; + } + + sof_mod = section.data; + man_get_section_manifest(image, sof_mod, man_module); + + /* read out text_fixup_size from memory mapping */ + module->text_fixup_size = sof_mod->text_size; error: elf_section_free(§ion); From 2d2c5bf838c82b507f8a87eb1d5eb5ff385f6419 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 25 Nov 2024 17:22:33 +0200 Subject: [PATCH 2/7] rimage: split man_module_create_reloc() The second preparatory step for multi-part relocatable module libraries. Signed-off-by: Guennadi Liakhovetski --- tools/rimage/src/manifest.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c index 6f9283c85747..629950c773c7 100644 --- a/tools/rimage/src/manifest.c +++ b/tools/rimage/src/manifest.c @@ -457,23 +457,12 @@ static int man_module_create(struct image *image, struct manifest_module *module return 0; } -static int man_module_create_reloc(struct image *image, struct manifest_module *module, - struct sof_man_module *man_module) +static void man_module_fill_reloc(const struct manifest_module *module, + struct sof_man_module *man_module) { - /* create module and segments */ - int err; - - 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; - module_print_zones(&module->file); - /* main module */ /* text section is first */ man_module->segment[SOF_MAN_SEGMENT_TEXT].file_offset = @@ -491,6 +480,23 @@ static int man_module_create_reloc(struct image *image, struct manifest_module * 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; +} + +static int man_module_create_reloc(struct image *image, struct manifest_module *module, + struct sof_man_module *man_module) +{ + /* create module and segments */ + int err; + + image->image_end = 0; + + err = man_get_module_manifest(image, module, man_module); + if (err < 0) + return err; + + module_print_zones(&module->file); + + man_module_fill_reloc(module, man_module); fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n"); From d3cd367e3977c9fe5c4186496dcf949e7a7a6b7b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 25 Nov 2024 18:23:09 +0200 Subject: [PATCH 3/7] rimage: add support for multi-part llext libraries Rimage generates an image from multiple input modules. However, in case of building libraries from multiple relocatable ELF files it doesn't currently construct manifest correctly. It mixes up manifest provided in TOML with manifest structures in ".module" sections of modules. Clean this up to only use manifests from ELF and append configuration from TOML. Signed-off-by: Guennadi Liakhovetski --- tools/rimage/src/manifest.c | 106 +++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 32 deletions(-) diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c index 629950c773c7..84fada5a8859 100644 --- a/tools/rimage/src/manifest.c +++ b/tools/rimage/src/manifest.c @@ -207,6 +207,7 @@ static void man_get_section_manifest(struct image *image, memcpy(man_module->name, sof_mod->module.name, SOF_MAN_MOD_NAME_LEN); memcpy(man_module->uuid, sof_mod->module.uuid, 16); man_module->affinity_mask = sof_mod->module.affinity_mask; + man_module->instance_max_count = sof_mod->module.instance_max_count; man_module->type.auto_start = sof_mod->module.type.auto_start; man_module->type.domain_dp = sof_mod->module.type.domain_dp; man_module->type.domain_ll = sof_mod->module.type.domain_ll; @@ -483,20 +484,61 @@ static void man_module_fill_reloc(const struct manifest_module *module, } static int man_module_create_reloc(struct image *image, struct manifest_module *module, - struct sof_man_module *man_module) + struct sof_man_module **man_module) { /* create module and segments */ + const struct sof_man_module_manifest *sof_mod; + struct elf_section section; int err; - image->image_end = 0; - - err = man_get_module_manifest(image, module, man_module); - if (err < 0) + /* load in module manifest data */ + err = elf_section_read_by_name(&module->file.elf, ".module", §ion); + if (err) { + fprintf(stderr, "error: can't read module manifest from '.module' section.\n"); return err; + } + + unsigned int n_mod = section.header.data.size / sizeof(*sof_mod); + + if (!n_mod || n_mod * sizeof(*sof_mod) != section.header.data.size) { + fprintf(stderr, "error: Invalid module manifests in '.module' section.\n"); + return -ENOEXEC; + } + + unsigned int i; + + for (i = 0, sof_mod = section.data; i < n_mod; i++, sof_mod++) { + char name[SOF_MAN_MOD_NAME_LEN + 1]; + unsigned int j; + + strncpy(name, (char *)sof_mod->module.name, SOF_MAN_MOD_NAME_LEN); + + for (j = 0; j < image->adsp->modules->mod_man_count; j++) { + if (!strncmp(name, (char *)image->adsp->modules->mod_man[j].name, + SOF_MAN_MOD_NAME_LEN)) { + /* Found a TOML manifest, matching ELF */ + if (i) + (*man_module)++; + man_get_section_manifest(image, sof_mod, *man_module); + man_module_fill_reloc(module, *man_module); + break; + } + } + + if (j == image->adsp->modules->mod_man_count) { + fprintf(stderr, "error: cannot find %s in manifest.\n", name); + return -ENOEXEC; + } + } + + elf_section_free(§ion); module_print_zones(&module->file); - man_module_fill_reloc(module, man_module); + image->image_end = module->foffset + module->file.elf.file_size; + + /* round module end up to nearest page */ + image->image_end = ALIGN_UP(image->image_end, MAN_PAGE_SIZE); fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n"); @@ -510,15 +552,11 @@ static int man_module_create_reloc(struct image *image, struct manifest_module * 0, module->file.elf.file_size, 0, "DATA"); fprintf(stdout, "\n"); - image->image_end = module->foffset + module->file.elf.file_size; - - /* round module end up to nearest page */ - image->image_end = ALIGN_UP(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, + (*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; } @@ -595,16 +633,11 @@ static int man_create_modules(struct image *image, struct sof_man_fw_desc *desc, offset = 1; } - for (; i < image->num_modules; i++) { - man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(i - offset); - - /* Some platforms dont have modules configuration in toml file */ - if (image->adsp->modules) { - /* Use manifest created using toml files as template */ - assert(i < image->adsp->modules->mod_man_count); - memcpy(man_module, &image->adsp->modules->mod_man[i], sizeof(*man_module)); - } + image->image_end = 0; + for (man_module = (struct sof_man_module *)((uint8_t *)desc + SOF_MAN_MODULE_OFFSET(i - offset)); + i < image->num_modules; + i++, man_module++) { module = &image->module[i]; if (i == 0) @@ -612,11 +645,17 @@ static int man_create_modules(struct image *image, struct sof_man_fw_desc *desc, else module->foffset = image->image_end; - if (image->reloc) - err = man_module_create_reloc(image, module, - man_module); - else + if (image->reloc) { + err = man_module_create_reloc(image, module, &man_module); + } else { + /* Some platforms dont have modules configuration in toml file */ + if (image->adsp->modules) { + assert(i < image->adsp->modules->mod_man_count); + memcpy(man_module, &image->adsp->modules->mod_man[i], sizeof(*man_module)); + } + err = man_module_create(image, module, man_module); + } if (err < 0) return err; @@ -636,12 +675,15 @@ static void man_create_modules_in_config(struct image *image, struct sof_man_fw_ if (!modules) return; - /* skip modules passed as parameters. Their manifests have already been copied by the - * man_create_modules function. */ - for (i = image->num_modules; i < modules->mod_man_count; i++) { - man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(i); - memcpy(man_module, &modules->mod_man[i], sizeof(*man_module)); - } + if (!image->loadable_module) + /* skip modules passed as parameters. Their manifests have + * already been copied by the man_create_modules function. */ + for (i = image->num_modules; i < modules->mod_man_count; i++) { + man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(i); + memcpy(man_module, &modules->mod_man[i], sizeof(*man_module)); + } + else + i = modules->mod_man_count; /* We need to copy the configurations for all modules. */ cfg_start = (void *)desc + SOF_MAN_MODULE_OFFSET(i); From 3bd6ba4a595bbb11e298392b9bab84283b18758f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Nov 2024 14:50:21 +0200 Subject: [PATCH 4/7] llext: add per-module contexts Run-time loadable SOF libraries can contain multiple modules. To prepare to support them add a module context type. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib_manager.h | 10 ++- src/library_manager/llext_manager.c | 98 ++++++++++++++++++----------- 2 files changed, 68 insertions(+), 40 deletions(-) diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index eb7bc21856d2..ba1f8eadbfb0 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -95,12 +95,18 @@ struct lib_manager_segment_desc { size_t size; }; -struct lib_manager_mod_ctx { - void *base_addr; +struct lib_manager_module { + unsigned int start_idx; const struct sof_man_module_manifest *mod_manifest; struct lib_manager_segment_desc segment[LIB_MANAGER_N_SEGMENTS]; }; +struct lib_manager_mod_ctx { + void *base_addr; + unsigned int n_mod; + struct lib_manager_module *mod; +}; + struct ext_library { struct k_spinlock lock; /* last locking CPU record */ struct lib_manager_mod_ctx *desc[LIB_MANAGER_MAX_LIBS]; diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 1644fb36a369..2aa43f17b9fe 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -125,24 +125,22 @@ static int llext_manager_load_data_from_storage(const struct llext *ext, } static int llext_manager_load_module(const struct llext *ext, const struct llext_buf_loader *ebl, - uint32_t module_id) + const struct lib_manager_module *mctx) { - struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); - /* Executable code (.text) */ void __sparse_cache *va_base_text = (void __sparse_cache *) - ctx->segment[LIB_MANAGER_TEXT].addr; - size_t text_size = ctx->segment[LIB_MANAGER_TEXT].size; + mctx->segment[LIB_MANAGER_TEXT].addr; + size_t text_size = mctx->segment[LIB_MANAGER_TEXT].size; /* Read-only data (.rodata and others) */ void __sparse_cache *va_base_rodata = (void __sparse_cache *) - ctx->segment[LIB_MANAGER_RODATA].addr; - size_t rodata_size = ctx->segment[LIB_MANAGER_RODATA].size; + mctx->segment[LIB_MANAGER_RODATA].addr; + size_t rodata_size = mctx->segment[LIB_MANAGER_RODATA].size; /* Writable data (.data, .bss and others) */ void __sparse_cache *va_base_data = (void __sparse_cache *) - ctx->segment[LIB_MANAGER_DATA].addr; - size_t data_size = ctx->segment[LIB_MANAGER_DATA].size; + mctx->segment[LIB_MANAGER_DATA].addr; + size_t data_size = mctx->segment[LIB_MANAGER_DATA].size; /* .bss, should be within writable data above */ void __sparse_cache *bss_addr = (void __sparse_cache *) @@ -201,23 +199,22 @@ static int llext_manager_load_module(const struct llext *ext, const struct llext return ret; } -static int llext_manager_unload_module(uint32_t module_id) +static int llext_manager_unload_module(const struct lib_manager_module *mctx) { - struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); /* Executable code (.text) */ void __sparse_cache *va_base_text = (void __sparse_cache *) - ctx->segment[LIB_MANAGER_TEXT].addr; - size_t text_size = ctx->segment[LIB_MANAGER_TEXT].size; + mctx->segment[LIB_MANAGER_TEXT].addr; + size_t text_size = mctx->segment[LIB_MANAGER_TEXT].size; /* Read-only data (.rodata, etc.) */ void __sparse_cache *va_base_rodata = (void __sparse_cache *) - ctx->segment[LIB_MANAGER_RODATA].addr; - size_t rodata_size = ctx->segment[LIB_MANAGER_RODATA].size; + mctx->segment[LIB_MANAGER_RODATA].addr; + size_t rodata_size = mctx->segment[LIB_MANAGER_RODATA].size; /* Writable data (.data, .bss, etc.) */ void __sparse_cache *va_base_data = (void __sparse_cache *) - ctx->segment[LIB_MANAGER_DATA].addr; - size_t data_size = ctx->segment[LIB_MANAGER_DATA].size; + mctx->segment[LIB_MANAGER_DATA].addr; + size_t data_size = mctx->segment[LIB_MANAGER_DATA].size; int err = 0, ret; ret = llext_manager_align_unmap(va_base_text, text_size); @@ -240,15 +237,14 @@ static bool llext_manager_section_detached(const elf_shdr_t *shdr) return shdr->sh_addr < SOF_MODULE_DRAM_LINK_END; } -static int llext_manager_link(struct llext_buf_loader *ebl, - const char *name, uint32_t module_id, struct module_data *md, +static int llext_manager_link(struct llext_buf_loader *ebl, const char *name, + struct lib_manager_module *mctx, struct module_data *md, const void **buildinfo, const struct sof_man_module_manifest **mod_manifest) { - struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); /* Identify if this is the first time loading this module */ struct llext_load_param ldr_parm = { - .relocate_local = !ctx->segment[LIB_MANAGER_TEXT].size, + .relocate_local = !mctx->segment[LIB_MANAGER_TEXT].size, .pre_located = true, .section_detached = llext_manager_section_detached, }; @@ -257,30 +253,30 @@ static int llext_manager_link(struct llext_buf_loader *ebl, if (ret) return ret; - ctx->segment[LIB_MANAGER_TEXT].addr = ebl->loader.sects[LLEXT_MEM_TEXT].sh_addr; - ctx->segment[LIB_MANAGER_TEXT].size = ebl->loader.sects[LLEXT_MEM_TEXT].sh_size; + mctx->segment[LIB_MANAGER_TEXT].addr = ebl->loader.sects[LLEXT_MEM_TEXT].sh_addr; + mctx->segment[LIB_MANAGER_TEXT].size = ebl->loader.sects[LLEXT_MEM_TEXT].sh_size; tr_dbg(&lib_manager_tr, ".text: start: %#lx size %#x", - ctx->segment[LIB_MANAGER_TEXT].addr, - ctx->segment[LIB_MANAGER_TEXT].size); + mctx->segment[LIB_MANAGER_TEXT].addr, + mctx->segment[LIB_MANAGER_TEXT].size); /* All read-only data sections */ - ctx->segment[LIB_MANAGER_RODATA].addr = + mctx->segment[LIB_MANAGER_RODATA].addr = ebl->loader.sects[LLEXT_MEM_RODATA].sh_addr; - ctx->segment[LIB_MANAGER_RODATA].size = ebl->loader.sects[LLEXT_MEM_RODATA].sh_size; + mctx->segment[LIB_MANAGER_RODATA].size = ebl->loader.sects[LLEXT_MEM_RODATA].sh_size; tr_dbg(&lib_manager_tr, ".rodata: start: %#lx size %#x", - ctx->segment[LIB_MANAGER_RODATA].addr, - ctx->segment[LIB_MANAGER_RODATA].size); + mctx->segment[LIB_MANAGER_RODATA].addr, + mctx->segment[LIB_MANAGER_RODATA].size); /* All writable data sections */ - ctx->segment[LIB_MANAGER_DATA].addr = + mctx->segment[LIB_MANAGER_DATA].addr = ebl->loader.sects[LLEXT_MEM_DATA].sh_addr; - ctx->segment[LIB_MANAGER_DATA].size = ebl->loader.sects[LLEXT_MEM_DATA].sh_size; + mctx->segment[LIB_MANAGER_DATA].size = ebl->loader.sects[LLEXT_MEM_DATA].sh_size; tr_dbg(&lib_manager_tr, ".data: start: %#lx size %#x", - ctx->segment[LIB_MANAGER_DATA].addr, - ctx->segment[LIB_MANAGER_DATA].size); + mctx->segment[LIB_MANAGER_DATA].addr, + mctx->segment[LIB_MANAGER_DATA].size); ssize_t binfo_o = llext_find_section(&ebl->loader, ".mod_buildinfo"); @@ -295,6 +291,25 @@ static int llext_manager_link(struct llext_buf_loader *ebl, return binfo_o >= 0 && mod_o >= 0 ? 0 : -EPROTO; } +static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, + const struct sof_man_fw_desc *desc, + const struct sof_man_module *mod_array) +{ + /* + * Loadable modules are loaded to DRAM once and never unloaded from it. + * Context, related to them, is never freed + */ + ctx->mod = rmalloc(SOF_MEM_ZONE_RUNTIME_SHARED, SOF_MEM_FLAG_COHERENT, + SOF_MEM_CAPS_RAM, sizeof(ctx->mod[0])); + if (!ctx->mod) + return -ENOMEM; + + ctx->n_mod = 1; + ctx->mod[0].start_idx = 0; + + return 0; +} + uintptr_t llext_manager_allocate_module(struct processing_module *proc, const struct comp_ipc_config *ipc_config, const void *ipc_specific_config) @@ -322,6 +337,11 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, mod_array = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); + if (!ctx->mod) + llext_manager_mod_init(ctx, desc, mod_array); + + struct lib_manager_module *mctx = ctx->mod; + /* LLEXT linking is only needed once for all the modules in the library */ ret = llext_manager_link(&ebl, mod_array[0].name, module_id, md, (const void **)&buildinfo, &mod_manifest); @@ -339,26 +359,28 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, } /* Map executable code and data */ - ret = llext_manager_load_module(md->llext, &ebl, module_id); + ret = llext_manager_load_module(md->llext, &ebl, mctx); if (ret < 0) return 0; - /* ctx->mod_manifest points to a const array of module manifests */ - ctx->mod_manifest = mod_manifest; + /* mctx->mod_manifest points to a const array of module manifests */ + mctx->mod_manifest = mod_manifest; } - return ctx->mod_manifest[entry_index].module.entry_point; + return mctx->mod_manifest[entry_index].module.entry_point; } int llext_manager_free_module(const uint32_t component_id) { const uint32_t module_id = IPC4_MOD_ID(component_id); + struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); const unsigned int base_module_id = LIB_MANAGER_GET_LIB_ID(module_id) << LIB_MANAGER_LIB_ID_SHIFT; + struct lib_manager_module *mctx = ctx->mod; tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id); - return llext_manager_unload_module(base_module_id); + return llext_manager_unload_module(mctx); } bool comp_is_llext(struct comp_dev *comp) From 50f82a9c038a5b2bd8ca0139501d30665eabe294 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Nov 2024 17:38:41 +0200 Subject: [PATCH 5/7] llext: fix potential NULL dereference NULL checking should be done before dereferencing, not after. Also rearrange varoable definition in llext_manager_allocate_module() to make it more logical. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 2aa43f17b9fe..65c9d0f9c6a8 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -316,27 +316,27 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, { uint32_t module_id = IPC4_MOD_ID(ipc_config->id); struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(module_id); - struct sof_man_module *mod_array; - int ret; - uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); - const struct sof_module_api_build_info *buildinfo; - const struct sof_man_module_manifest *mod_manifest; + + if (!ctx || !desc) { + tr_err(&lib_manager_tr, "failed to get module descriptor"); + return 0; + } + + struct sof_man_module *mod_array = (struct sof_man_module *)((char *)desc + + SOF_MAN_MODULE_OFFSET(0)); size_t mod_size = desc->header.preload_page_count * PAGE_SZ - FILE_TEXT_OFFSET_V1_8; uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_base + FILE_TEXT_OFFSET_V1_8, mod_size); + uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); + const struct sof_man_module_manifest *mod_manifest; + const struct sof_module_api_build_info *buildinfo; struct module_data *md = &proc->priv; + int ret; tr_dbg(&lib_manager_tr, "mod_id: %#x", ipc_config->id); - if (!ctx || !desc) { - tr_err(&lib_manager_tr, "failed to get module descriptor"); - return 0; - } - - mod_array = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); - if (!ctx->mod) llext_manager_mod_init(ctx, desc, mod_array); From 3853ab168008c434acb64906ff7f0b9f572d61c8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 26 Nov 2024 18:05:22 +0200 Subject: [PATCH 6/7] llext: support libraries with multiple modules Loadable libraries can contain multiple modules, where each module can contain multiple manifest entries, e.g. when providing multiple Module Adapter drivers. This commit adds support for such libraries, built by specifying all the modules on rimage command line. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 123 +++++++++++++++++++++++----- tools/rimage/src/manifest.c | 9 +- 2 files changed, 108 insertions(+), 24 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 65c9d0f9c6a8..0aaa0797419f 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -37,14 +37,6 @@ #include #include -/* - * FIXME: this definition is copied from tools/rimage/src/include/rimage/manifest.h - * which we cannot easily include here, because it also pulls in - * tools/rimage/src/include/rimage/elf.h which then conflicts with - * zephyr/include/zephyr/llext/elf.h - */ -#define FILE_TEXT_OFFSET_V1_8 0x8000 - LOG_MODULE_DECLARE(lib_manager, CONFIG_SOF_LOG_LEVEL); extern struct tr_ctx lib_manager_tr; @@ -295,21 +287,48 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, const struct sof_man_fw_desc *desc, const struct sof_man_module *mod_array) { + unsigned int i, n_mod; + size_t offs; + + /* count modules */ + for (i = 0, n_mod = 0, offs = ~0; i < desc->header.num_module_entries; i++) + if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != offs) { + offs = mod_array[i].segment[LIB_MANAGER_TEXT].file_offset; + n_mod++; + } + /* * Loadable modules are loaded to DRAM once and never unloaded from it. * Context, related to them, is never freed */ ctx->mod = rmalloc(SOF_MEM_ZONE_RUNTIME_SHARED, SOF_MEM_FLAG_COHERENT, - SOF_MEM_CAPS_RAM, sizeof(ctx->mod[0])); + SOF_MEM_CAPS_RAM, n_mod * sizeof(ctx->mod[0])); if (!ctx->mod) return -ENOMEM; - ctx->n_mod = 1; - ctx->mod[0].start_idx = 0; + ctx->n_mod = n_mod; + + for (i = 0, n_mod = 0, offs = ~0; i < desc->header.num_module_entries; i++) + if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != offs) { + offs = mod_array[i].segment[LIB_MANAGER_TEXT].file_offset; + ctx->mod[n_mod].segment[LIB_MANAGER_TEXT].size = 0; + ctx->mod[n_mod++].start_idx = i; + } return 0; } +static unsigned int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx, unsigned int idx) +{ + unsigned int i; + + for (i = 0; i < ctx->n_mod; i++) + if (ctx->mod[i].start_idx > idx) + break; + + return i - 1; +} + uintptr_t llext_manager_allocate_module(struct processing_module *proc, const struct comp_ipc_config *ipc_config, const void *ipc_specific_config) @@ -325,14 +344,13 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, struct sof_man_module *mod_array = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); - size_t mod_size = desc->header.preload_page_count * PAGE_SZ - FILE_TEXT_OFFSET_V1_8; - uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; - struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_base + FILE_TEXT_OFFSET_V1_8, - mod_size); uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); + size_t mod_offset = mod_array[entry_index].segment[LIB_MANAGER_TEXT].file_offset; const struct sof_man_module_manifest *mod_manifest; const struct sof_module_api_build_info *buildinfo; struct module_data *md = &proc->priv; + size_t mod_size; + int i, inst_idx; int ret; tr_dbg(&lib_manager_tr, "mod_id: %#x", ipc_config->id); @@ -340,10 +358,56 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, if (!ctx->mod) llext_manager_mod_init(ctx, desc, mod_array); - struct lib_manager_module *mctx = ctx->mod; + if (entry_index >= desc->header.num_module_entries) { + tr_err(&lib_manager_tr, "Invalid driver index %u exceeds %d", + entry_index, desc->header.num_module_entries - 1); + return 0; + } - /* LLEXT linking is only needed once for all the modules in the library */ - ret = llext_manager_link(&ebl, mod_array[0].name, module_id, md, + unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); + struct lib_manager_module *mctx = ctx->mod + mod_idx; + + /* + * We don't know the number of ELF files that this library is built of. + * We know the number of module drivers, but each of those ELF files can + * also contain multiple such drivers. Each driver brings two copies of + * its manifest with it: one in the ".module" ELF section and one in an + * array of manifests at the beginning of the library. This latter array + * is created from a TOML configuration file. The order is preserved - + * this is guaranteed by rimage. + * All module drivers within a single ELF file have equal .file_offset, + * this makes it possible to find borders between them. + * We know the global index of the requested driver in that array, but + * we need to find the matching manifest in ".module" because only it + * contains the entry point. For safety we calculate the ELF driver + * index and then also check the driver name. + * We also need the driver size. For this we search the manifest array + * for the next ELF file, then the difference between offsets gives us + * the driver size. + */ + for (i = entry_index - 1; i >= 0; i--) + if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != mod_offset) + break; + + /* Driver index within a single module */ + inst_idx = entry_index - i - 1; + + /* Find the next module or stop at the end */ + for (i = entry_index + 1; i < desc->header.num_module_entries; i++) + if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != mod_offset) + break; + + if (i == desc->header.num_module_entries) + mod_size = desc->header.preload_page_count * PAGE_SZ - mod_offset; + else + mod_size = ALIGN_UP(mod_array[i].segment[LIB_MANAGER_TEXT].file_offset - mod_offset, + PAGE_SZ); + + uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; + struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_base + mod_offset, mod_size); + + /* LLEXT linking is only needed once for all the drivers in each module */ + ret = llext_manager_link(&ebl, mod_array[entry_index - inst_idx].name, mctx, md, (const void **)&buildinfo, &mod_manifest); if (ret < 0) { tr_err(&lib_manager_tr, "linking failed: %d", ret); @@ -367,16 +431,31 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, mctx->mod_manifest = mod_manifest; } - return mctx->mod_manifest[entry_index].module.entry_point; + if (strncmp(mod_array[entry_index].name, mctx->mod_manifest[inst_idx].module.name, + sizeof(mod_array[0].name))) { + tr_err(&lib_manager_tr, "Name mismatch %s vs. %s", + mod_array[entry_index].name, mctx->mod_manifest[inst_idx].module.name); + return 0; + } + + return mctx->mod_manifest[inst_idx].module.entry_point; } int llext_manager_free_module(const uint32_t component_id) { const uint32_t module_id = IPC4_MOD_ID(component_id); + struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(module_id); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); - const unsigned int base_module_id = LIB_MANAGER_GET_LIB_ID(module_id) << - LIB_MANAGER_LIB_ID_SHIFT; - struct lib_manager_module *mctx = ctx->mod; + uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); + + if (entry_index >= desc->header.num_module_entries) { + tr_err(&lib_manager_tr, "Invalid driver index %u exceeds %d", + entry_index, desc->header.num_module_entries - 1); + return -ENOENT; + } + + unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); + struct lib_manager_module *mctx = ctx->mod + mod_idx; tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id); diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c index 84fada5a8859..88d37df73c67 100644 --- a/tools/rimage/src/manifest.c +++ b/tools/rimage/src/manifest.c @@ -519,6 +519,9 @@ static int man_module_create_reloc(struct image *image, struct manifest_module * /* Found a TOML manifest, matching ELF */ if (i) (*man_module)++; + /* Use manifest created using toml files as template */ + **man_module = image->adsp->modules->mod_man[j]; + /* Use .manifest to update individual fields */ man_get_section_manifest(image, sof_mod, *man_module); man_module_fill_reloc(module, *man_module); break; @@ -648,10 +651,12 @@ static int man_create_modules(struct image *image, struct sof_man_fw_desc *desc, if (image->reloc) { err = man_module_create_reloc(image, module, &man_module); } else { - /* Some platforms dont have modules configuration in toml file */ + /* Some platforms don't have modules configuration in toml file */ if (image->adsp->modules) { + /* Use manifest created using toml files as template */ assert(i < image->adsp->modules->mod_man_count); - memcpy(man_module, &image->adsp->modules->mod_man[i], sizeof(*man_module)); + memcpy(man_module, &image->adsp->modules->mod_man[i], + sizeof(*man_module)); } err = man_module_create(image, module, man_module); From 1e3f9abc160b79a3454a8785c23599d589408261 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 27 Nov 2024 17:47:54 +0100 Subject: [PATCH 7/7] mux: remove DEMUX entry from LLEXT build mux.toml doesn't have a demux entry in it, therefore we cannot have one in .module either, remove it until fixed. Also fix a copy-paste error in the same code block. Signed-off-by: Guennadi Liakhovetski --- src/audio/mux/mux.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/audio/mux/mux.c b/src/audio/mux/mux.c index bd2ae7d5c7d1..8d65b2b2698d 100644 --- a/src/audio/mux/mux.c +++ b/src/audio/mux/mux.c @@ -475,7 +475,7 @@ static const struct module_interface demux_interface = { DECLARE_MODULE_ADAPTER(demux_interface, demux_uuid, demux_tr); SOF_MODULE_INIT(demux, sys_comp_module_demux_interface_init); -#if CONFIG_COMP_VOLUME_MODULE +#if CONFIG_COMP_MUX_MODULE /* modular: llext dynamic link */ #include @@ -486,13 +486,21 @@ SOF_MODULE_INIT(demux, sys_comp_module_demux_interface_init); 0xE2, 0xA2, 0xF4, 0x2E, 0x30, 0x69 SOF_LLEXT_MOD_ENTRY(mux, &mux_interface); -#define UUID_DEMUX 0x68, 0x68, 0xB2, 0xC4, 0x30, 0x14, 0x0E, 0x47, 0x89, 0xA0, \ - 0x15, 0xD1, 0xC7, 0x7F, 0x85, 0x1A -SOF_LLEXT_MOD_ENTRY(demux, &demux_interface); +/* + * The demux entry is removed because mtl.toml doesn't have an entry + * for it. Once that is fixed, the manifest line below can be + * re-activated: + * #define UUID_DEMUX 0x68, 0x68, 0xB2, 0xC4, 0x30, 0x14, 0x0E, 0x47, 0x89, 0xA0, \ + * 0x15, 0xD1, 0xC7, 0x7F, 0x85, 0x1A + * SOF_LLEXT_MOD_ENTRY(demux, &demux_interface); + */ static const struct sof_man_module_manifest mod_manifest[] __section(".module") __used = { SOF_LLEXT_MODULE_MANIFEST("MUX", mux_llext_entry, 1, UUID_MUX, 15), - SOF_LLEXT_MODULE_MANIFEST("DEMUX", demux_llext_entry, 1, UUID_DEMUX, 15), + /* + * See comment above for a demux deactivation reason + * SOF_LLEXT_MODULE_MANIFEST("DEMUX", demux_llext_entry, 1, UUID_DEMUX, 15), + */ }; SOF_LLEXT_BUILDINFO;