Skip to content

Commit 4e7e74e

Browse files
committed
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 <guennadi.liakhovetski@linux.intel.com>
1 parent b344522 commit 4e7e74e

File tree

1 file changed

+101
-22
lines changed

1 file changed

+101
-22
lines changed

src/library_manager/llext_manager.c

Lines changed: 101 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,6 @@
3737
#include <stddef.h>
3838
#include <stdint.h>
3939

40-
/*
41-
* FIXME: this definition is copied from tools/rimage/src/include/rimage/manifest.h
42-
* which we cannot easily include here, because it also pulls in
43-
* tools/rimage/src/include/rimage/elf.h which then conflicts with
44-
* zephyr/include/zephyr/llext/elf.h
45-
*/
46-
#define FILE_TEXT_OFFSET_V1_8 0x8000
47-
4840
LOG_MODULE_DECLARE(lib_manager, CONFIG_SOF_LOG_LEVEL);
4941

5042
extern struct tr_ctx lib_manager_tr;
@@ -295,21 +287,48 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx,
295287
const struct sof_man_fw_desc *desc,
296288
const struct sof_man_module *mod_array)
297289
{
290+
unsigned int i, n_mod;
291+
size_t offs;
292+
293+
/* count modules */
294+
for (i = 0, n_mod = 0, offs = ~0; i < desc->header.num_module_entries; i++)
295+
if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != offs) {
296+
offs = mod_array[i].segment[LIB_MANAGER_TEXT].file_offset;
297+
n_mod++;
298+
}
299+
298300
/*
299301
* Loadable modules are loaded to DRAM once and never unloaded from it.
300302
* Context, related to them, is never freed
301303
*/
302304
ctx->mod = rmalloc(SOF_MEM_ZONE_RUNTIME_SHARED, SOF_MEM_FLAG_COHERENT,
303-
SOF_MEM_CAPS_RAM, sizeof(ctx->mod[0]));
305+
SOF_MEM_CAPS_RAM, n_mod * sizeof(ctx->mod[0]));
304306
if (!ctx->mod)
305307
return -ENOMEM;
306308

307-
ctx->n_mod = 1;
308-
ctx->mod[0].start_idx = 0;
309+
ctx->n_mod = n_mod;
310+
311+
for (i = 0, n_mod = 0, offs = ~0; i < desc->header.num_module_entries; i++)
312+
if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != offs) {
313+
offs = mod_array[i].segment[LIB_MANAGER_TEXT].file_offset;
314+
ctx->mod[n_mod].segment[LIB_MANAGER_TEXT].size = 0;
315+
ctx->mod[n_mod++].start_idx = i;
316+
}
309317

310318
return 0;
311319
}
312320

321+
static unsigned int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx, unsigned int idx)
322+
{
323+
unsigned int i;
324+
325+
for (i = 0; i < ctx->n_mod; i++)
326+
if (ctx->mod[i].start_idx > idx)
327+
break;
328+
329+
return i - 1;
330+
}
331+
313332
uintptr_t llext_manager_allocate_module(struct processing_module *proc,
314333
const struct comp_ipc_config *ipc_config,
315334
const void *ipc_specific_config)
@@ -325,25 +344,70 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc,
325344

326345
struct sof_man_module *mod_array = (struct sof_man_module *)((char *)desc +
327346
SOF_MAN_MODULE_OFFSET(0));
328-
size_t mod_size = desc->header.preload_page_count * PAGE_SZ - FILE_TEXT_OFFSET_V1_8;
329-
uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET;
330-
struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_base + FILE_TEXT_OFFSET_V1_8,
331-
mod_size);
332347
uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id);
348+
size_t mod_offset = mod_array[entry_index].segment[LIB_MANAGER_TEXT].file_offset;
333349
const struct sof_man_module_manifest *mod_manifest;
334350
const struct sof_module_api_build_info *buildinfo;
335351
struct module_data *md = &proc->priv;
352+
size_t mod_size;
353+
int i, inst_idx;
336354
int ret;
337355

338356
tr_dbg(&lib_manager_tr, "mod_id: %#x", ipc_config->id);
339357

340358
if (!ctx->mod)
341359
llext_manager_mod_init(ctx, desc, mod_array);
342360

343-
struct lib_manager_module *mctx = ctx->mod;
361+
if (entry_index >= desc->header.num_module_entries) {
362+
tr_err(&lib_manager_tr, "Invalid driver index %u exceeds %d",
363+
entry_index, desc->header.num_module_entries - 1);
364+
return 0;
365+
}
344366

345-
/* LLEXT linking is only needed once for all the modules in the library */
346-
ret = llext_manager_link(&ebl, mod_array[0].name, module_id, md,
367+
unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index);
368+
struct lib_manager_module *mctx = ctx->mod + mod_idx;
369+
370+
/*
371+
* We don't know the number of ELF files that this library is built of.
372+
* We know the number of module drivers, but each of those ELF files can
373+
* also contain multiple such drivers. Each driver brings two copies of
374+
* its manifest with it: one in the ".module" ELF section and one in an
375+
* array of manifests at the beginning of the library. This latter array
376+
* is created from a TOML configuration file. The order is preserved -
377+
* this is guaranteed by rimage.
378+
* All module drivers within a single ELF file have equal .file_offset,
379+
* this makes it possible to find borders between them.
380+
* We know the global index of the requested driver in that array, but
381+
* we need to find the matching manifest in ".module" because only it
382+
* contains the entry point. For safety we calculate the ELF driver
383+
* index and then also check the driver name.
384+
* We also need the driver size. For this we search the manifest array
385+
* for the next ELF file, then the difference between offsets gives us
386+
* the driver size.
387+
*/
388+
for (i = entry_index - 1; i >= 0; i--)
389+
if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != mod_offset)
390+
break;
391+
392+
/* Driver index within a single module */
393+
inst_idx = entry_index - i - 1;
394+
395+
/* Find the next module or stop at the end */
396+
for (i = entry_index + 1; i < desc->header.num_module_entries; i++)
397+
if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != mod_offset)
398+
break;
399+
400+
if (i == desc->header.num_module_entries)
401+
mod_size = desc->header.preload_page_count * PAGE_SZ - mod_offset;
402+
else
403+
mod_size = ALIGN_UP(mod_array[i].segment[LIB_MANAGER_TEXT].file_offset - mod_offset,
404+
PAGE_SZ);
405+
406+
uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET;
407+
struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_base + mod_offset, mod_size);
408+
409+
/* LLEXT linking is only needed once for all the drivers in each module */
410+
ret = llext_manager_link(&ebl, mod_array[entry_index - inst_idx].name, mctx, md,
347411
(const void **)&buildinfo, &mod_manifest);
348412
if (ret < 0) {
349413
tr_err(&lib_manager_tr, "linking failed: %d", ret);
@@ -367,16 +431,31 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc,
367431
mctx->mod_manifest = mod_manifest;
368432
}
369433

370-
return mctx->mod_manifest[entry_index].module.entry_point;
434+
if (strncmp(mod_array[entry_index].name, mctx->mod_manifest[inst_idx].module.name,
435+
sizeof(mod_array[0].name))) {
436+
tr_err(&lib_manager_tr, "Name mismatch %s vs. %s",
437+
mod_array[entry_index].name, mctx->mod_manifest[inst_idx].module.name);
438+
return 0;
439+
}
440+
441+
return mctx->mod_manifest[inst_idx].module.entry_point;
371442
}
372443

373444
int llext_manager_free_module(const uint32_t component_id)
374445
{
375446
const uint32_t module_id = IPC4_MOD_ID(component_id);
447+
struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(module_id);
376448
struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id);
377-
const unsigned int base_module_id = LIB_MANAGER_GET_LIB_ID(module_id) <<
378-
LIB_MANAGER_LIB_ID_SHIFT;
379-
struct lib_manager_module *mctx = ctx->mod;
449+
uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id);
450+
451+
if (entry_index >= desc->header.num_module_entries) {
452+
tr_err(&lib_manager_tr, "Invalid driver index %u exceeds %d",
453+
entry_index, desc->header.num_module_entries - 1);
454+
return -ENOENT;
455+
}
456+
457+
unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index);
458+
struct lib_manager_module *mctx = ctx->mod + mod_idx;
380459

381460
tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id);
382461

0 commit comments

Comments
 (0)