Skip to content

Commit 7381cd1

Browse files
committed
llext: add auxiliary library dependency support
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]>
1 parent b8c5357 commit 7381cd1

File tree

3 files changed

+118
-14
lines changed

3 files changed

+118
-14
lines changed

src/include/sof/llext_manager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config
2727

2828
int llext_manager_free_module(const uint32_t component_id);
2929

30+
int llext_manager_add_library(const struct sof_man_module *mod, uint32_t module_id);
31+
3032
bool comp_is_llext(struct comp_dev *comp);
3133
#else
3234
#define module_is_llext(mod) false
3335
#define llext_manager_allocate_module(ipc_config, ipc_specific_config) 0
3436
#define llext_manager_free_module(component_id) 0
37+
#define llext_manager_add_library(mod, module_id) 0
3538
#define llext_unload(ext) 0
3639
#define comp_is_llext(comp) false
3740
#endif

src/library_manager/lib_manager.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1050,12 +1050,21 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type)
10501050
rfree((__sparse_force void *)man_tmp_buffer);
10511051

10521052
cleanup:
1053-
core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000));
10541053
rfree((void *)dma_ext->dma_addr);
10551054
lib_manager_dma_deinit(dma_ext, dma_id);
10561055
rfree(dma_ext);
10571056
_ext_lib->runtime_data = NULL;
10581057

1058+
uint32_t module_id = lib_id << LIB_MANAGER_LIB_ID_SHIFT;
1059+
1060+
const struct sof_man_module *mod = lib_manager_get_module_manifest(module_id);
1061+
1062+
if (module_is_llext(mod) && !ret)
1063+
/* Auxiliary LLEXT libraries need to be linked upon loading */
1064+
ret = llext_manager_add_library(mod, module_id);
1065+
1066+
core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000));
1067+
10591068
if (!ret)
10601069
tr_info(&ipc_tr, "loaded library id: %u", lib_id);
10611070

src/library_manager/llext_manager.c

Lines changed: 105 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static int llext_manager_load_data_from_storage(void __sparse_cache *vma, void *
104104
return ret;
105105
}
106106

107-
static int llext_manager_load_module(uint32_t module_id, const struct sof_man_module *mod)
107+
static int llext_manager_load_module(uint32_t module_id)
108108
{
109109
struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id);
110110
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
185185
return ret;
186186
}
187187

188-
static int llext_manager_unload_module(uint32_t module_id, const struct sof_man_module *mod)
188+
static int llext_manager_unload_module(struct lib_manager_mod_ctx *ctx)
189189
{
190-
struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id);
191190
/* Executable code (.text) */
192191
void __sparse_cache *va_base_text = (void __sparse_cache *)
193192
ctx->segment[LIB_MANAGER_TEXT].addr;
@@ -219,8 +218,9 @@ static int llext_manager_unload_module(uint32_t module_id, const struct sof_man_
219218
return err;
220219
}
221220

222-
static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_module *mod,
223-
uint32_t module_id, struct llext **llext, const void **buildinfo,
221+
static int llext_manager_link(const struct sof_man_fw_desc *desc, const struct sof_man_module *mod,
222+
uint32_t module_id, struct llext **llext,
223+
const struct sof_module_api_build_info **buildinfo,
224224
const struct sof_man_module_manifest **mod_manifest)
225225
{
226226
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
291291
return binfo_o >= 0 && mod_o >= 0 ? 0 : -EPROTO;
292292
}
293293

294+
static int llext_lib_find(const struct llext *llext, struct lib_manager_mod_ctx **dep_ctx)
295+
{
296+
struct ext_library *_ext_lib = ext_lib_get();
297+
unsigned int i;
298+
299+
if (!llext)
300+
return -EINVAL;
301+
302+
for (i = 0; i < ARRAY_SIZE(_ext_lib->desc); i++)
303+
if (_ext_lib->desc[i] && _ext_lib->desc[i]->llext == llext) {
304+
*dep_ctx = _ext_lib->desc[i];
305+
return i;
306+
}
307+
308+
return -ENOENT;
309+
}
310+
311+
static void llext_depend_unlink(struct lib_manager_mod_ctx *dep_ctx[], int n)
312+
{
313+
for (; n >= 0; n--)
314+
if (dep_ctx[n]->llext->use_count == 1)
315+
llext_manager_unload_module(dep_ctx[n]);
316+
}
317+
294318
uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config,
295319
const void *ipc_specific_config)
296320
{
297-
struct sof_man_fw_desc *desc;
321+
const struct sof_man_fw_desc *desc;
298322
struct sof_man_module *mod_array;
299323
int ret;
300324
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
311335
return 0;
312336
}
313337

314-
mod_array = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0));
338+
mod_array = (struct sof_man_module *)((const char *)desc + SOF_MAN_MODULE_OFFSET(0));
315339

316-
/* LLEXT linking is only needed once for all the modules in the library */
340+
/*
341+
* LLEXT linking is only needed once for all the modules in the library.
342+
* This calls llext_load(), which also takes references to any
343+
* dependencies, sets up sections and retrieves buildinfo and
344+
* mod_manifest
345+
*/
317346
ret = llext_manager_link(desc, mod_array, module_id, &ctx->llext,
318-
(const void **)&buildinfo, &mod_manifest);
347+
&buildinfo, &mod_manifest);
319348
if (ret < 0)
320349
return 0;
321350

@@ -327,8 +356,49 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config
327356
return -ENOEXEC;
328357
}
329358

359+
int i;
360+
361+
/* Check if any dependencies need to be mapped */
362+
for (i = 0; i < ARRAY_SIZE(ctx->llext->dependency); i++) {
363+
/* Dependencies are filled from the beginning of the array upwards */
364+
if (!ctx->llext->dependency[i])
365+
break;
366+
367+
/*
368+
* Protected by the IPC serialization, but maybe we should protect the
369+
* use-count explicitly too. Currently the use-count is first incremented
370+
* when an auxiliary library is loaded, it was then additionally incremented
371+
* when the current dependent module was mapped. If it's higher than two,
372+
* then some other modules also depend on it and have already mapped it.
373+
*/
374+
if (ctx->llext->dependency[i]->use_count > 2)
375+
continue;
376+
377+
/* First user of this dependency, load it into SRAM */
378+
struct lib_manager_mod_ctx *dep_ctx[LLEXT_MAX_DEPENDENCIES];
379+
int dep_id = llext_lib_find(ctx->llext->dependency[i], &dep_ctx[i]);
380+
381+
if (dep_id < 0) {
382+
tr_err(&lib_manager_tr,
383+
"Unmet dependency: cannot find dependency %u", i);
384+
continue;
385+
}
386+
387+
tr_info(&lib_manager_tr, "%s depending on %s base %p, %u users",
388+
ctx->llext->name,
389+
ctx->llext->dependency[i]->name,
390+
dep_ctx[i]->base_addr,
391+
ctx->llext->dependency[i]->use_count);
392+
393+
ret = llext_manager_load_module(dep_id << LIB_MANAGER_LIB_ID_SHIFT);
394+
if (ret < 0) {
395+
llext_depend_unlink(dep_ctx, i - 1);
396+
return 0;
397+
}
398+
}
399+
330400
/* Map executable code and data */
331-
ret = llext_manager_load_module(module_id, mod_array);
401+
ret = llext_manager_load_module(module_id);
332402
if (ret < 0)
333403
return 0;
334404

@@ -348,7 +418,6 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config
348418

349419
int llext_manager_free_module(const uint32_t component_id)
350420
{
351-
const struct sof_man_module *mod;
352421
const uint32_t module_id = IPC4_MOD_ID(component_id);
353422
const unsigned int base_module_id = LIB_MANAGER_GET_LIB_ID(module_id) <<
354423
LIB_MANAGER_LIB_ID_SHIFT;
@@ -361,13 +430,36 @@ int llext_manager_free_module(const uint32_t component_id)
361430
return -ENOENT;
362431
}
363432

433+
struct lib_manager_mod_ctx *dep_ctx[LLEXT_MAX_DEPENDENCIES] = {};
434+
int i;
435+
436+
for (i = 0; i < ARRAY_SIZE(ctx->llext->dependency); i++)
437+
if (llext_lib_find(ctx->llext->dependency[i], &dep_ctx[i]) < 0)
438+
break;
439+
364440
if (llext_unload(&ctx->llext))
365441
/* More users are active */
366442
return 0;
367443

368-
mod = lib_manager_get_module_manifest(base_module_id);
444+
/* Last user cleaning up, put dependencies */
445+
if (i > 0)
446+
llext_depend_unlink(dep_ctx, i - 1);
447+
448+
return llext_manager_unload_module(ctx);
449+
}
450+
451+
/* An auxiliary library has been loaded, need to read in its exported symbols */
452+
int llext_manager_add_library(const struct sof_man_module *mod, uint32_t module_id)
453+
{
454+
if (mod->type.load_type != SOF_MAN_MOD_TYPE_LLEXT_AUX)
455+
return 0;
456+
457+
struct lib_manager_mod_ctx *const ctx = lib_manager_get_mod_ctx(module_id);
458+
const struct sof_man_fw_desc *desc = lib_manager_get_library_manifest(module_id);
459+
const struct sof_module_api_build_info *buildinfo;
460+
const struct sof_man_module_manifest *mod_manifest;
369461

370-
return llext_manager_unload_module(base_module_id, mod);
462+
return llext_manager_link(desc, mod, module_id, &ctx->llext, &buildinfo, &mod_manifest);
371463
}
372464

373465
bool comp_is_llext(struct comp_dev *comp)

0 commit comments

Comments
 (0)