diff --git a/src/include/sof/llext_manager.h b/src/include/sof/llext_manager.h index 0022551159c5..cb6777142960 100644 --- a/src/include/sof/llext_manager.h +++ b/src/include/sof/llext_manager.h @@ -27,11 +27,14 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config int llext_manager_free_module(const uint32_t component_id); +int llext_manager_add_library(const struct sof_man_module *mod, uint32_t module_id); + bool comp_is_llext(struct comp_dev *comp); #else #define module_is_llext(mod) false #define llext_manager_allocate_module(ipc_config, ipc_specific_config) 0 #define llext_manager_free_module(component_id) 0 +#define llext_manager_add_library(mod, module_id) 0 #define llext_unload(ext) 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 a68077a44a72..c878b36e091b 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -1050,12 +1050,21 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type) rfree((__sparse_force void *)man_tmp_buffer); cleanup: - core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); 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) + /* Auxiliary LLEXT libraries need to be linked upon loading */ + ret = llext_manager_add_library(mod, module_id); + + core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); + 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 a8a68461e910..d7bf466aa10a 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -104,7 +104,7 @@ static int llext_manager_load_data_from_storage(void __sparse_cache *vma, void * return ret; } -static int llext_manager_load_module(uint32_t module_id, const struct sof_man_module *mod) +static int llext_manager_load_module(uint32_t module_id) { struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); uint8_t *load_base = (uint8_t *)ctx->base_addr; @@ -185,9 +185,8 @@ static int llext_manager_load_module(uint32_t module_id, const struct sof_man_mo return ret; } -static int llext_manager_unload_module(uint32_t module_id, const struct sof_man_module *mod) +static int llext_manager_unload_module(struct lib_manager_mod_ctx *ctx) { - 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; @@ -219,8 +218,9 @@ static int llext_manager_unload_module(uint32_t module_id, const struct sof_man_ return err; } -static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_module *mod, - uint32_t module_id, struct llext **llext, const void **buildinfo, +static int llext_manager_link(const struct sof_man_fw_desc *desc, const struct sof_man_module *mod, + uint32_t module_id, struct llext **llext, + const struct sof_module_api_build_info **buildinfo, const struct sof_man_module_manifest **mod_manifest) { size_t mod_size = desc->header.preload_page_count * PAGE_SZ - FILE_TEXT_OFFSET_V1_8; @@ -291,10 +291,34 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul return binfo_o >= 0 && mod_o >= 0 ? 0 : -EPROTO; } +static int llext_lib_find(const struct llext *llext, struct lib_manager_mod_ctx **dep_ctx) +{ + struct ext_library *_ext_lib = ext_lib_get(); + unsigned int i; + + if (!llext) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(_ext_lib->desc); i++) + if (_ext_lib->desc[i] && _ext_lib->desc[i]->llext == llext) { + *dep_ctx = _ext_lib->desc[i]; + return i; + } + + return -ENOENT; +} + +static void llext_depend_unlink(struct lib_manager_mod_ctx *dep_ctx[], int n) +{ + for (; n >= 0; n--) + if (dep_ctx[n]->llext->use_count == 1) + llext_manager_unload_module(dep_ctx[n]); +} + uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config, const void *ipc_specific_config) { - struct sof_man_fw_desc *desc; + const struct sof_man_fw_desc *desc; struct sof_man_module *mod_array; int ret; uint32_t module_id = IPC4_MOD_ID(ipc_config->id); @@ -311,11 +335,16 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config return 0; } - mod_array = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); + mod_array = (struct sof_man_module *)((const char *)desc + SOF_MAN_MODULE_OFFSET(0)); - /* LLEXT linking is only needed once for all the modules in the library */ + /* + * LLEXT linking is only needed once for all the modules in the library. + * This calls llext_load(), which also takes references to any + * dependencies, sets up sections and retrieves buildinfo and + * mod_manifest + */ ret = llext_manager_link(desc, mod_array, module_id, &ctx->llext, - (const void **)&buildinfo, &mod_manifest); + &buildinfo, &mod_manifest); if (ret < 0) return 0; @@ -327,8 +356,49 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config return -ENOEXEC; } + int i; + + /* Check if any dependencies need to be mapped */ + for (i = 0; i < ARRAY_SIZE(ctx->llext->dependency); i++) { + /* Dependencies are filled from the beginning of the array upwards */ + if (!ctx->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 (ctx->llext->dependency[i]->use_count > 2) + continue; + + /* First user of this dependency, load it into SRAM */ + struct lib_manager_mod_ctx *dep_ctx[LLEXT_MAX_DEPENDENCIES]; + int dep_id = llext_lib_find(ctx->llext->dependency[i], &dep_ctx[i]); + + if (dep_id < 0) { + tr_err(&lib_manager_tr, + "Unmet dependency: cannot find dependency %u", i); + continue; + } + + tr_info(&lib_manager_tr, "%s depending on %s base %p, %u users", + ctx->llext->name, + ctx->llext->dependency[i]->name, + dep_ctx[i]->base_addr, + ctx->llext->dependency[i]->use_count); + + ret = llext_manager_load_module(dep_id << LIB_MANAGER_LIB_ID_SHIFT); + if (ret < 0) { + llext_depend_unlink(dep_ctx, i - 1); + return 0; + } + } + /* Map executable code and data */ - ret = llext_manager_load_module(module_id, mod_array); + ret = llext_manager_load_module(module_id); if (ret < 0) return 0; @@ -348,7 +418,6 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config int llext_manager_free_module(const uint32_t component_id) { - const struct sof_man_module *mod; const uint32_t module_id = IPC4_MOD_ID(component_id); const unsigned int base_module_id = LIB_MANAGER_GET_LIB_ID(module_id) << LIB_MANAGER_LIB_ID_SHIFT; @@ -361,13 +430,36 @@ int llext_manager_free_module(const uint32_t component_id) return -ENOENT; } + struct lib_manager_mod_ctx *dep_ctx[LLEXT_MAX_DEPENDENCIES] = {}; + int i; + + for (i = 0; i < ARRAY_SIZE(ctx->llext->dependency); i++) + if (llext_lib_find(ctx->llext->dependency[i], &dep_ctx[i]) < 0) + break; + if (llext_unload(&ctx->llext)) /* More users are active */ return 0; - mod = lib_manager_get_module_manifest(base_module_id); + /* Last user cleaning up, put dependencies */ + if (i > 0) + llext_depend_unlink(dep_ctx, i - 1); + + return llext_manager_unload_module(ctx); +} + +/* An auxiliary library has been loaded, need to read in its exported symbols */ +int llext_manager_add_library(const struct sof_man_module *mod, uint32_t module_id) +{ + if (mod->type.load_type != SOF_MAN_MOD_TYPE_LLEXT_AUX) + return 0; + + 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); + const struct sof_module_api_build_info *buildinfo; + const struct sof_man_module_manifest *mod_manifest; - return llext_manager_unload_module(base_module_id, mod); + return llext_manager_link(desc, mod, module_id, &ctx->llext, &buildinfo, &mod_manifest); } bool comp_is_llext(struct comp_dev *comp)