diff --git a/src/audio/module_adapter/module/modules.c b/src/audio/module_adapter/module/modules.c index 690f111fb0bc..68050089f037 100644 --- a/src/audio/module_adapter/module/modules.c +++ b/src/audio/module_adapter/module/modules.c @@ -62,7 +62,7 @@ static int modules_init(struct processing_module *mod) void *adapter; int ret; - uintptr_t module_entry_point = lib_manager_allocate_module(mod, config, src_cfg); + uintptr_t module_entry_point = lib_manager_allocate_module(config, src_cfg); if (module_entry_point == 0) { comp_err(dev, "modules_init(), lib_manager_allocate_module() failed!"); diff --git a/src/include/module/module/base.h b/src/include/module/module/base.h index d3f912957791..83b165f176f2 100644 --- a/src/include/module/module/base.h +++ b/src/include/module/module/base.h @@ -37,8 +37,6 @@ struct module_config { #endif }; -struct llext; - /* * A structure containing a module's private data, intended for its exclusive use. * @@ -60,7 +58,6 @@ struct module_data { void *runtime_params; struct module_memory memory; /**< memory allocated by module */ struct module_processing_data mpd; /**< shared data comp <-> module */ - struct llext *llext; /**< Zephyr loadable extension context */ #endif /* SOF_MODULE_PRIVATE */ }; diff --git a/src/include/module/module/llext.h b/src/include/module/module/llext.h index 05b8f0ffb5f5..2daab49a4ede 100644 --- a/src/include/module/module/llext.h +++ b/src/include/module/module/llext.h @@ -10,7 +10,7 @@ { \ .module = { \ .name = manifest_name, \ - .uuid = {mod_uuid}, \ + .uuid = {mod_uuid}, \ .entry_point = (uint32_t)(entry), \ .instance_max_count = instances, \ .type = { \ @@ -21,6 +21,18 @@ } \ } +#define SOF_LLEXT_AUX_MANIFEST(manifest_name, entry, mod_uuid) \ +{ \ + .module = { \ + .name = manifest_name, \ + .uuid = {mod_uuid}, \ + .entry_point = (uint32_t)(entry), \ + .type = { \ + .load_type = SOF_MAN_MOD_TYPE_LLEXT_AUX, \ + }, \ + } \ +} + #define SOF_LLEXT_MOD_ENTRY(name, interface) \ static const struct module_interface *name##_llext_entry(void *mod_cfg, \ void *parent_ppl, void **mod_ptr) \ diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index ba1f8eadbfb0..43d7366dbfb4 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -87,6 +87,7 @@ enum { LIB_MANAGER_TEXT, LIB_MANAGER_DATA, LIB_MANAGER_RODATA, + LIB_MANAGER_BSS, LIB_MANAGER_N_SEGMENTS, }; @@ -95,14 +96,20 @@ struct lib_manager_segment_desc { size_t size; }; +struct llext; + struct lib_manager_module { - unsigned int start_idx; + unsigned int start_idx; /* Index of the first driver from this module in + * the library-global driver list */ const struct sof_man_module_manifest *mod_manifest; + struct llext *llext; /* Zephyr loadable extension context */ struct lib_manager_segment_desc segment[LIB_MANAGER_N_SEGMENTS]; + unsigned int n_depend; + const char **depend; }; struct lib_manager_mod_ctx { - void *base_addr; + void *base_addr; /* library storage address (DRAM) */ unsigned int n_mod; struct lib_manager_module *mod; }; @@ -188,8 +195,7 @@ struct processing_module; * Function is responsible to allocate module in available free memory and assigning proper address. * (WIP) These feature will contain module validation and proper memory management. */ -uintptr_t lib_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, +uintptr_t lib_manager_allocate_module(const struct comp_ipc_config *ipc_config, const void *ipc_specific_config); /* diff --git a/src/include/sof/llext_manager.h b/src/include/sof/llext_manager.h index c963ef4adfd6..7394e62725cf 100644 --- a/src/include/sof/llext_manager.h +++ b/src/include/sof/llext_manager.h @@ -18,21 +18,23 @@ struct comp_ipc_config; static inline bool module_is_llext(const struct sof_man_module *mod) { - return mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT; + return mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT || + mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX; } -uintptr_t llext_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, +uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config, const void *ipc_specific_config); int llext_manager_free_module(const uint32_t component_id); +int llext_manager_add_library(uint32_t module_id); + bool comp_is_llext(struct comp_dev *comp); #else #define module_is_llext(mod) false -#define llext_manager_allocate_module(proc, ipc_config, ipc_specific_config) 0 +#define llext_manager_allocate_module(ipc_config, ipc_specific_config) 0 #define llext_manager_free_module(component_id) 0 -#define llext_unload(ext) 0 +#define llext_manager_add_library(module_id) 0 #define comp_is_llext(comp) false #endif diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index ae824d512dc5..f8b6e3443bb1 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -338,8 +338,7 @@ static int lib_manager_free_module_instance(uint32_t module_id, uint32_t instanc return sys_mm_drv_unmap_region((__sparse_force void *)va_base, bss_size); } -uintptr_t lib_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, +uintptr_t lib_manager_allocate_module(const struct comp_ipc_config *ipc_config, const void *ipc_specific_config) { const struct sof_man_module *mod; @@ -356,7 +355,7 @@ uintptr_t lib_manager_allocate_module(struct processing_module *proc, } if (module_is_llext(mod)) - return llext_manager_allocate_module(proc, ipc_config, ipc_specific_config); + return llext_manager_allocate_module(ipc_config, ipc_specific_config); ret = lib_manager_load_module(module_id, mod); if (ret < 0) @@ -419,8 +418,7 @@ int lib_manager_free_module(const uint32_t component_id) #define PAGE_SZ 4096 /* equals to MAN_PAGE_SIZE used by rimage */ -uintptr_t lib_manager_allocate_module(struct processing_module *proc, - const struct comp_ipc_config *ipc_config, +uintptr_t lib_manager_allocate_module(const struct comp_ipc_config *ipc_config, const void *ipc_specific_config, const void **buildinfo) { tr_err(&lib_manager_tr, "Dynamic module allocation is not supported"); @@ -510,12 +508,10 @@ static struct comp_dev *lib_manager_module_create(const struct comp_driver *drv, * Variable used by llext_manager to temporary store llext handle before creation * a instance of processing_module. */ - struct processing_module tmp_proc; struct comp_dev *dev; /* At this point module resources are allocated and it is moved to L2 memory. */ - tmp_proc.priv.llext = NULL; - const uint32_t module_entry_point = lib_manager_allocate_module(&tmp_proc, config, + const uint32_t module_entry_point = lib_manager_allocate_module(config, args->data); if (!module_entry_point) { @@ -540,20 +536,15 @@ static struct comp_dev *lib_manager_module_create(const struct comp_driver *drv, } dev = module_adapter_new(drv, config, spec); - if (dev) { - struct processing_module *mod = comp_mod(dev); - - mod->priv.llext = tmp_proc.priv.llext; - } else { + if (!dev) lib_manager_free_module(module_id); - } + return dev; } static void lib_manager_module_free(struct comp_dev *dev) { struct processing_module *mod = comp_mod(dev); - struct llext *llext = mod->priv.llext; const struct comp_ipc_config *const config = &mod->dev->ipc_config; const uint32_t module_id = config->id; int ret; @@ -561,12 +552,10 @@ static void lib_manager_module_free(struct comp_dev *dev) /* This call invalidates dev, mod and config pointers! */ module_adapter_free(dev); - if (!llext || !llext_unload(&llext)) { - /* Free module resources allocated in L2 memory. */ - ret = lib_manager_free_module(module_id); - if (ret < 0) - comp_err(dev, "lib_manager_free_module() failed!"); - } + /* Free module resources allocated in L2 memory. */ + ret = lib_manager_free_module(module_id); + if (ret < 0) + comp_err(dev, "lib_manager_free_module() failed!"); } static void lib_manager_prepare_module_adapter(struct comp_driver *drv, const struct sof_uuid *uuid) @@ -1044,14 +1033,22 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type) rfree((__sparse_force void *)man_tmp_buffer); cleanup: -#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL - core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); -#endif rfree((void *)dma_ext->dma_addr); lib_manager_dma_deinit(dma_ext, dma_id); rfree(dma_ext); _ext_lib->runtime_data = NULL; + uint32_t module_id = lib_id << LIB_MANAGER_LIB_ID_SHIFT; + const struct sof_man_module *mod = lib_manager_get_module_manifest(module_id); + + if (module_is_llext(mod) && !ret) + /* LLEXT libraries need to be initialized upon loading */ + ret = llext_manager_add_library(lib_id); + +#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL + core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); +#endif + if (!ret) tr_info(&ipc_tr, "loaded library id: %u", lib_id); diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 0aaa0797419f..9dbab67ff488 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -116,8 +116,7 @@ static int llext_manager_load_data_from_storage(const struct llext *ext, return ret; } -static int llext_manager_load_module(const struct llext *ext, const struct llext_buf_loader *ebl, - const struct lib_manager_module *mctx) +static int llext_manager_load_module(const struct llext *ext, const struct lib_manager_module *mctx) { /* Executable code (.text) */ void __sparse_cache *va_base_text = (void __sparse_cache *) @@ -136,21 +135,23 @@ static int llext_manager_load_module(const struct llext *ext, const struct llext /* .bss, should be within writable data above */ void __sparse_cache *bss_addr = (void __sparse_cache *) - ebl->loader.sects[LLEXT_MEM_BSS].sh_addr; - size_t bss_size = ebl->loader.sects[LLEXT_MEM_BSS].sh_size; + mctx->segment[LIB_MANAGER_BSS].addr; + size_t bss_size = mctx->segment[LIB_MANAGER_BSS].size; int ret; /* Check, that .bss is within .data */ if (bss_size && ((uintptr_t)bss_addr + bss_size <= (uintptr_t)va_base_data || (uintptr_t)bss_addr >= (uintptr_t)va_base_data + data_size)) { + size_t bss_align = MIN(PAGE_SZ, BIT(__builtin_ctz((uintptr_t)bss_addr))); + if ((uintptr_t)bss_addr + bss_size == (uintptr_t)va_base_data && !((uintptr_t)bss_addr & (PAGE_SZ - 1))) { /* .bss directly in front of writable data and properly aligned, prepend */ va_base_data = bss_addr; data_size += bss_size; } else if ((uintptr_t)bss_addr == (uintptr_t)va_base_data + - ALIGN_UP(data_size, ebl->loader.sects[LLEXT_MEM_BSS].sh_addralign)) { + ALIGN_UP(data_size, bss_align)) { /* .bss directly behind writable data, append */ data_size += bss_size; } else { @@ -229,22 +230,64 @@ static bool llext_manager_section_detached(const elf_shdr_t *shdr) return shdr->sh_addr < SOF_MODULE_DRAM_LINK_END; } +static int llext_manager_add_dependency(struct llext_loader *loader, + struct lib_manager_module *mctx) +{ + if (mctx->n_depend) + return 0; + + unsigned int n_dep; + + for (n_dep = 0; n_dep < LLEXT_MAX_DEPENDENCIES && loader->dependency[n_dep][0]; n_dep++) + ; + + if (!n_dep) + return 0; + + void *dep = rmalloc(SOF_MEM_ZONE_RUNTIME_SHARED, SOF_MEM_FLAG_COHERENT, + SOF_MEM_CAPS_RAM, n_dep * LLEXT_MAX_NAME_LENGTH); + + if (!dep) + return -ENOMEM; + + memcpy(dep, loader->dependency, n_dep * LLEXT_MAX_NAME_LENGTH); + + mctx->depend = dep; + mctx->n_depend = n_dep; + + return 0; +} + +static void llext_manager_restore_dependency(struct llext_loader *loader, + struct lib_manager_module *mctx) +{ + if (mctx->n_depend) + memcpy(loader->dependency, mctx->depend, mctx->n_depend * LLEXT_MAX_NAME_LENGTH); +} + 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, + struct lib_manager_module *mctx, const void **buildinfo, const struct sof_man_module_manifest **mod_manifest) { + struct llext **llext = &mctx->llext; /* Identify if this is the first time loading this module */ struct llext_load_param ldr_parm = { .relocate_local = !mctx->segment[LIB_MANAGER_TEXT].size, .pre_located = true, .section_detached = llext_manager_section_detached, }; - int ret = llext_load(&ebl->loader, name, &md->llext, &ldr_parm); + + llext_manager_restore_dependency(&ebl->loader, mctx); + + int ret = llext_load(&ebl->loader, name, llext, &ldr_parm); if (ret) return ret; + ret = llext_manager_add_dependency(&ebl->loader, mctx); + if (ret < 0) + return ret; + 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; @@ -270,6 +313,13 @@ static int llext_manager_link(struct llext_buf_loader *ebl, const char *name, mctx->segment[LIB_MANAGER_DATA].addr, mctx->segment[LIB_MANAGER_DATA].size); + mctx->segment[LIB_MANAGER_BSS].addr = ebl->loader.sects[LLEXT_MEM_BSS].sh_addr; + mctx->segment[LIB_MANAGER_BSS].size = ebl->loader.sects[LLEXT_MEM_BSS].sh_size; + + tr_dbg(&lib_manager_tr, ".bss: start: %#lx size %#x", + mctx->segment[LIB_MANAGER_BSS].addr, + mctx->segment[LIB_MANAGER_BSS].size); + ssize_t binfo_o = llext_find_section(&ebl->loader, ".mod_buildinfo"); if (binfo_o >= 0) @@ -283,10 +333,12 @@ static int llext_manager_link(struct llext_buf_loader *ebl, const char *name, return binfo_o >= 0 && mod_o >= 0 ? 0 : -EPROTO; } +/* Count "module files" in the library, allocate and initialize memory for their descriptors */ 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) + const struct sof_man_fw_desc *desc) { + struct sof_man_module *mod_array = (struct sof_man_module *)((uint8_t *)desc + + SOF_MAN_MODULE_OFFSET(0)); unsigned int i, n_mod; size_t offs; @@ -311,6 +363,7 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, 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].n_depend = 0; ctx->mod[n_mod].segment[LIB_MANAGER_TEXT].size = 0; ctx->mod[n_mod++].start_idx = i; } @@ -318,6 +371,7 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, return 0; } +/* Find a module context, containing the driver with the supplied index */ static unsigned int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx, unsigned int idx) { unsigned int i; @@ -329,43 +383,57 @@ static unsigned int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx 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) +static int llext_lib_find(const struct llext *llext, struct lib_manager_module **dep_ctx) { - 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 lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); + struct ext_library *_ext_lib = ext_lib_get(); + unsigned int i, j; - if (!ctx || !desc) { - tr_err(&lib_manager_tr, "failed to get module descriptor"); - return 0; + if (!llext) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(_ext_lib->desc); i++) { + if (!_ext_lib->desc[i]) + continue; + + for (j = 0; j < _ext_lib->desc[i]->n_mod; j++) + if (_ext_lib->desc[i]->mod[j].llext == llext) { + *dep_ctx = _ext_lib->desc[i]->mod + j; + return i; + } } - struct sof_man_module *mod_array = (struct sof_man_module *)((char *)desc + + return -ENOENT; +} + +static void llext_depend_unlink(struct lib_manager_module *dep_ctx[], int n) +{ + for (; n >= 0; n--) + if (dep_ctx[n] && dep_ctx[n]->llext->use_count == 1) + llext_manager_unload_module(dep_ctx[n]); +} + +static int llext_manager_link_single(uint32_t module_id, const struct sof_man_fw_desc *desc, + struct lib_manager_mod_ctx *ctx, const void **buildinfo, + const struct sof_man_module_manifest **mod_manifest) +{ + struct sof_man_module *mod_array = (struct sof_man_module *)((uint8_t *)desc + SOF_MAN_MODULE_OFFSET(0)); 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); - - if (!ctx->mod) - llext_manager_mod_init(ctx, desc, mod_array); + tr_dbg(&lib_manager_tr, "mod_id: %u", 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 0; + return -EINVAL; } - unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); - struct lib_manager_module *mctx = ctx->mod + mod_idx; + unsigned int mod_ctx_idx = llext_manager_mod_find(ctx, entry_index); + struct lib_manager_module *mctx = ctx->mod + mod_ctx_idx; + size_t mod_size; + int i, inst_idx; /* * We don't know the number of ELF files that this library is built of. @@ -381,9 +449,9 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, * 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. + * We also need a module size. For this we search the manifest array for + * the next ELF file, then the difference between offsets gives us the + * module size. */ for (i = entry_index - 1; i >= 0; i--) if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != mod_offset) @@ -406,15 +474,67 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, 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); + /* + * LLEXT linking is only needed once for all the "drivers" in the + * module. This calls llext_load(), which also takes references to any + * dependencies, sets up sections and retrieves buildinfo and + * mod_manifest + */ + ret = llext_manager_link(&ebl, mod_array[entry_index - inst_idx].name, mctx, + buildinfo, mod_manifest); if (ret < 0) { tr_err(&lib_manager_tr, "linking failed: %d", ret); + return ret; + } + + /* if ret > 0, then the "driver" is already loaded */ + if (!ret) + /* mctx->mod_manifest points to a const array of module manifests */ + mctx->mod_manifest = *mod_manifest; + + /* Return the manifest, related to the specific instance */ + *mod_manifest = mctx->mod_manifest + inst_idx; + + if (strncmp(mod_array[entry_index].name, (*mod_manifest)->module.name, + sizeof(mod_array[0].name))) { + tr_err(&lib_manager_tr, "Name mismatch %s vs. %s", + mod_array[entry_index].name, (*mod_manifest)->module.name); + return -ENOEXEC; + } + + return mod_ctx_idx; +} + +uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config, + const void *ipc_specific_config) +{ + uint32_t module_id = IPC4_MOD_ID(ipc_config->id); + /* Library manifest */ + struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *) + lib_manager_get_library_manifest(module_id); + /* Library context */ + struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); + + if (!ctx || !desc) { + tr_err(&lib_manager_tr, "failed to get module descriptor"); return 0; } - if (!ret) { + /* Array of all "module drivers" (manifests) in the library */ + const struct sof_man_module_manifest *mod_manifest; + const struct sof_module_api_build_info *buildinfo = NULL; + int ret, i; + + /* "module file" index in the ctx->mod array */ + int mod_ctx_idx = llext_manager_link_single(module_id, desc, ctx, + (const void **)&buildinfo, &mod_manifest); + + if (mod_ctx_idx < 0) + return 0; + + struct lib_manager_module *mctx = ctx->mod + mod_ctx_idx; + + if (buildinfo) { /* First instance: check that the module is native */ if (buildinfo->format != SOF_MODULE_API_BUILD_INFO_FORMAT || buildinfo->api_version_number.full != SOF_MODULE_API_CURRENT_VERSION) { @@ -422,23 +542,49 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, return 0; } + /* + * Check if any dependencies need to be mapped - collect + * pointers to library contexts + */ + struct lib_manager_module *dep_ctx[LLEXT_MAX_DEPENDENCIES] = {}; + + for (i = 0; i < ARRAY_SIZE(mctx->llext->dependency); i++) { + /* Dependencies are filled from the beginning of the array upwards */ + if (!mctx->llext->dependency[i]) + break; + + /* + * Protected by the IPC serialization, but maybe we should protect the + * use-count explicitly too. Currently the use-count is first incremented + * when an auxiliary library is loaded, it was then additionally incremented + * when the current dependent module was mapped. If it's higher than two, + * then some other modules also depend on it and have already mapped it. + */ + if (mctx->llext->dependency[i]->use_count > 2) + continue; + + /* First user of this dependency, load it into SRAM */ + ret = llext_lib_find(mctx->llext->dependency[i], &dep_ctx[i]); + if (ret < 0) { + tr_err(&lib_manager_tr, + "Unmet dependency: cannot find dependency %u", i); + continue; + } + + ret = llext_manager_load_module(dep_ctx[i]->llext, dep_ctx[i]); + if (ret < 0) { + llext_depend_unlink(dep_ctx, i - 1); + return 0; + } + } + /* Map executable code and data */ - ret = llext_manager_load_module(md->llext, &ebl, mctx); + ret = llext_manager_load_module(mctx->llext, mctx); if (ret < 0) return 0; - - /* mctx->mod_manifest points to a const array of module manifests */ - mctx->mod_manifest = mod_manifest; } - 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; + return mod_manifest->module.entry_point; } int llext_manager_free_module(const uint32_t component_id) @@ -454,14 +600,69 @@ int llext_manager_free_module(const uint32_t component_id) return -ENOENT; } + if (!ctx->mod) { + tr_err(&lib_manager_tr, "NULL module array: ID %#x ctx %p", component_id, ctx); + return -ENOENT; + } + unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); struct lib_manager_module *mctx = ctx->mod + mod_idx; + struct lib_manager_module *dep_ctx[LLEXT_MAX_DEPENDENCIES] = {}; + int dep_cnt; + + for (dep_cnt = 0; dep_cnt < ARRAY_SIZE(mctx->llext->dependency); dep_cnt++) + if (llext_lib_find(mctx->llext->dependency[dep_cnt], &dep_ctx[dep_cnt]) < 0) + break; + + if (llext_unload(&mctx->llext)) + /* More users are active */ + return 0; + tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id); + /* Last user cleaning up, put dependencies */ + if (dep_cnt > 0) + llext_depend_unlink(dep_ctx, dep_cnt - 1); + return llext_manager_unload_module(mctx); } +/* A library has been loaded, need to initialize its context */ +int llext_manager_add_library(uint32_t lib_id) +{ + uint32_t module_id = lib_id << LIB_MANAGER_LIB_ID_SHIFT; + struct lib_manager_mod_ctx *const ctx = lib_manager_get_mod_ctx(module_id); + const struct sof_man_fw_desc *desc = lib_manager_get_library_manifest(module_id); + unsigned int i; + + if (ctx->mod) { + tr_err(&lib_manager_tr, "lib_id: %u: repeated load!", lib_id); + return -EBUSY; + } + + int ret = llext_manager_mod_init(ctx, desc); + + if (ret < 0) + return ret; + + for (i = 0; i < ctx->n_mod; i++) { + const struct sof_man_module *mod = lib_manager_get_module_manifest(module_id + i); + + if (mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX) { + const struct sof_man_module_manifest *mod_manifest; + const struct sof_module_api_build_info *buildinfo; + int ret = llext_manager_link_single(module_id + i, desc, ctx, + (const void **)&buildinfo, &mod_manifest); + + if (ret < 0) + return ret; + } + } + + return 0; +} + bool comp_is_llext(struct comp_dev *comp) { const uint32_t module_id = IPC4_MOD_ID(comp->ipc_config.id); diff --git a/src/math/Kconfig b/src/math/Kconfig index ccd7520f20a7..b97f87bfe781 100644 --- a/src/math/Kconfig +++ b/src/math/Kconfig @@ -170,7 +170,7 @@ choice "FILTER_SIMD_LEVEL_SELECT" endchoice config MATH_FIR - bool "FIR filter library" + tristate "FIR filter library" default n help This option builds FIR (Finite Impulse Response) filter library. It diff --git a/src/math/fir.toml b/src/math/fir.toml new file mode 100644 index 000000000000..a81268637761 --- /dev/null +++ b/src/math/fir.toml @@ -0,0 +1,6 @@ + [[module.entry]] + name = "FIR" + uuid = "93446E12-1864-4E04-AFE0-3B1D778FFB79" + load_type = "3" + + index = __COUNTER__ diff --git a/src/math/fir_common.c b/src/math/fir_common.c new file mode 100644 index 000000000000..beca09dc5590 --- /dev/null +++ b/src/math/fir_common.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. + +/* modular: llext dynamic link */ + +#include +#include +#include +#include + +#include + +/* 93446e12-1864-4e04-afe0-3b1d778ffb79 */ +#define UUID_FIR 0x12, 0x6e, 0x44, 0x93, 0x64, 0x18, 0x04, 0x4e, \ + 0xaf, 0xe0, 0x3b, 0x1d, 0x77, 0x8f, 0xfb, 0x79 + +static const struct sof_man_module_manifest mod_manifest __section(".module") __used = + SOF_LLEXT_AUX_MANIFEST("FIR", NULL, UUID_FIR); + +SOF_LLEXT_BUILDINFO; diff --git a/src/math/fir_generic.c b/src/math/fir_generic.c index 24fbdc665988..802242d4dbec 100644 --- a/src/math/fir_generic.c +++ b/src/math/fir_generic.c @@ -118,6 +118,7 @@ int32_t fir_32x16(struct fir_state_32x16 *fir, int32_t x) /* Q2.46 -> Q2.31, saturate to Q1.31 */ return sat_int32(y >> shift); } +EXPORT_SYMBOL(fir_32x16); void fir_32x16_2x(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, int32_t *y0, int32_t *y1) { @@ -184,5 +185,6 @@ void fir_32x16_2x(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, int32_t * *y0 = sat_int32(a0 >> shift); *y1 = sat_int32(a1 >> shift); } +EXPORT_SYMBOL(fir_32x16_2x); #endif diff --git a/src/math/fir_hifi2ep.c b/src/math/fir_hifi2ep.c index 7f3a2d42a829..2172e3e98d53 100644 --- a/src/math/fir_hifi2ep.c +++ b/src/math/fir_hifi2ep.c @@ -156,6 +156,7 @@ void fir_32x16_hifiep(struct fir_state_32x16 *fir, int32_t x, int32_t *y, int ls a = AE_SRAAQ56(AE_SLLASQ56S(a, lshift), rshift); AE_SQ32F_I(AE_ROUNDSQ32SYM(a), (ae_q32s *)y, 0); } +EXPORT_SYMBOL(fir_32x16_hifiep); /* HiFi EP has the follow number of reqisters that should not be exceeded * 4x 56 bit registers in register file Q @@ -249,5 +250,6 @@ void fir_32x16_2x_hifiep(struct fir_state_32x16 *fir, int32_t x0, int32_t x1, AE_SQ32F_I(AE_ROUNDSQ32SYM(b), (ae_q32s *)y1, 0); AE_SQ32F_I(AE_ROUNDSQ32SYM(a), (ae_q32s *)y0, 0); } +EXPORT_SYMBOL(fir_32x16_2x_hifiep); #endif diff --git a/src/math/fir_hifi3.c b/src/math/fir_hifi3.c index e71fc47fc900..a485bf235f79 100644 --- a/src/math/fir_hifi3.c +++ b/src/math/fir_hifi3.c @@ -162,6 +162,7 @@ void fir_32x16_hifi3(struct fir_state_32x16 *fir, ae_int32 x, ae_int32 *y, a = AE_SLAA64S(a, shift); AE_S32_L_I(AE_ROUND32F48SSYM(a), (ae_int32 *)y, 0); } +EXPORT_SYMBOL(fir_32x16_hifi3); /* HiFi EP has the follow number of reqisters that should not be exceeded * 4x 56 bit registers in register file Q diff --git a/src/math/fir_llext/CMakeLists.txt b/src/math/fir_llext/CMakeLists.txt new file mode 100644 index 000000000000..9b8d2531bea3 --- /dev/null +++ b/src/math/fir_llext/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +sof_llext_build("fir" + SOURCES ../fir_common.c + ../fir_generic.c + ../fir_hifi2ep.c + ../fir_hifi3.c + LIB openmodules +) diff --git a/src/math/fir_llext/llext.toml.h b/src/math/fir_llext/llext.toml.h new file mode 100644 index 000000000000..fa2eab98627b --- /dev/null +++ b/src/math/fir_llext/llext.toml.h @@ -0,0 +1,5 @@ +#include +#include "../fir.toml" + +[module] +count = __COUNTER__ diff --git a/tools/rimage/src/include/rimage/sof/user/manifest.h b/tools/rimage/src/include/rimage/sof/user/manifest.h index 829b1b134810..29beb7eda62b 100644 --- a/tools/rimage/src/include/rimage/sof/user/manifest.h +++ b/tools/rimage/src/include/rimage/sof/user/manifest.h @@ -26,6 +26,7 @@ #define SOF_MAN_MOD_TYPE_BUILTIN 0 #define SOF_MAN_MOD_TYPE_MODULE 1 #define SOF_MAN_MOD_TYPE_LLEXT 2 /* Zephyr LLEXT-style dynamically linked */ +#define SOF_MAN_MOD_TYPE_LLEXT_AUX 3 /* Zephyr LLEXT-style dynamically linked auxiliary */ /* module init config */ #define SOF_MAN_MOD_INIT_CONFIG_BASE_CFG 0 /* Base config only */ diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c index d7a1fbe58e4e..0b55c04363a5 100644 --- a/tools/rimage/src/manifest.c +++ b/tools/rimage/src/manifest.c @@ -536,18 +536,20 @@ static int man_module_create_reloc(struct image *image, struct manifest_module * unsigned int i; for (i = 0, sof_mod = section.data; i < n_mod; i++, sof_mod++) { - int j = man_module_find_cfg(modules, &sof_mod->module); - - if (j < 0) { - elf_section_free(§ion); - return j; - } - - /* Found a TOML manifest, matching ELF */ if (i) (*man_module)++; - /* Use manifest created using toml files as template */ - **man_module = modules->mod_man[j]; + + if (sof_mod->module.type.load_type != SOF_MAN_MOD_TYPE_LLEXT_AUX) { + int j = man_module_find_cfg(modules, &sof_mod->module); + + if (j < 0) { + elf_section_free(§ion); + return j; + } + + /* Found a TOML manifest, matching ELF: use as a template */ + **man_module = 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); @@ -723,6 +725,9 @@ static int man_create_modules_in_config(struct image *image, struct sof_man_fw_d SOF_MAN_MODULE_OFFSET(0)); i < modules->output_mod_cfg_count; i++, man_module++) { + if (man_module->type.load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX) + continue; + int j = man_module_find_cfg(modules, man_module); if (j < 0) diff --git a/west.yml b/west.yml index 6fd718c542ea..086873f76d66 100644 --- a/west.yml +++ b/west.yml @@ -43,7 +43,7 @@ manifest: - name: zephyr repo-path: zephyr - revision: 42701fdb27298d20b4040cea5cde375b72c27cfc + revision: pull/84389/head remote: zephyrproject # Import some projects listed in zephyr/west.yml@revision diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 68eb85834942..508d998195be 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -671,11 +671,17 @@ elseif(CONFIG_COMP_IIR) ) endif() -zephyr_library_sources_ifdef(CONFIG_MATH_FIR - ${SOF_MATH_PATH}/fir_generic.c - ${SOF_MATH_PATH}/fir_hifi2ep.c - ${SOF_MATH_PATH}/fir_hifi3.c -) +if(CONFIG_MATH_FIR STREQUAL "m") + add_subdirectory(${SOF_MATH_PATH}/fir_llext + ${PROJECT_BINARY_DIR}/fir_llext) + add_dependencies(app fir) +elseif(CONFIG_MATH_FIR) + zephyr_library_sources( + ${SOF_MATH_PATH}/fir_generic.c + ${SOF_MATH_PATH}/fir_hifi2ep.c + ${SOF_MATH_PATH}/fir_hifi3.c + ) +endif() zephyr_library_sources_ifdef(CONFIG_MATH_IIR_DF1 ${SOF_MATH_PATH}/iir_df1_generic.c