Skip to content

Commit

Permalink
llext: add auxiliary library dependency support
Browse files Browse the repository at this point in the history
LLEXT modules can depend on other LLEXT auxiliary libraries. Zephyr
LLEXT core takes core to link them. This commit implements their
loading into and unloading from SRAM when the first dependent is
added or the last one is removed respectively.

Signed-off-by: Guennadi Liakhovetski <[email protected]>
  • Loading branch information
lyakh committed Sep 2, 2024
1 parent b8c5357 commit 7381cd1
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 14 deletions.
3 changes: 3 additions & 0 deletions src/include/sof/llext_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 10 additions & 1 deletion src/library_manager/lib_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
118 changes: 105 additions & 13 deletions src/library_manager/llext_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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;

Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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)
Expand Down

0 comments on commit 7381cd1

Please sign in to comment.