Skip to content

Commit 294f155

Browse files
committed
llext: keep minimal Zephyr context when unloading modules
Currently when module's last instance is destroyed, it's freed and its Zephyr context is destroyed too. At the same time the module is kept in DRAM in a linked and relocated state, which means, that next time when we have to use it, we need to tell Zephyr to instantiate it while skipping the linking step. Additionally this makes handling dependencies inconvenient: they are created during the linking step by Zephyr and therefore are lost when the module is released. Then, as described above, they're not recreated when the linking step is skipped during a subsequent load. To fix this problem this commit avoids destroying module's Zephyr context when freeing. This costs around 200 bytes but makes handling of dependencies possible. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
1 parent ffacce8 commit 294f155

File tree

2 files changed

+59
-14
lines changed

2 files changed

+59
-14
lines changed

src/include/sof/lib_manager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ struct lib_manager_module {
103103
* the library-global driver list */
104104
const struct sof_man_module_manifest *mod_manifest;
105105
struct llext *llext; /* Zephyr loadable extension context */
106+
bool mapped;
106107
struct lib_manager_segment_desc segment[LIB_MANAGER_N_SEGMENTS];
107108
};
108109

src/library_manager/llext_manager.c

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <zephyr/llext/buf_loader.h>
2929
#include <zephyr/llext/loader.h>
3030
#include <zephyr/llext/llext.h>
31+
#include <zephyr/logging/log_ctrl.h>
3132

3233
#include <rimage/sof/user/manifest.h>
3334
#include <module/module/api_ver.h>
@@ -116,7 +117,7 @@ static int llext_manager_load_data_from_storage(const struct llext *ext,
116117
return ret;
117118
}
118119

119-
static int llext_manager_load_module(const struct lib_manager_module *mctx)
120+
static int llext_manager_load_module(struct lib_manager_module *mctx)
120121
{
121122
/* Executable code (.text) */
122123
void __sparse_cache *va_base_text = (void __sparse_cache *)
@@ -183,6 +184,7 @@ static int llext_manager_load_module(const struct lib_manager_module *mctx)
183184
goto e_rodata;
184185

185186
memset((__sparse_force void *)bss_addr, 0, bss_size);
187+
mctx->mapped = true;
186188

187189
return 0;
188190

@@ -194,7 +196,7 @@ static int llext_manager_load_module(const struct lib_manager_module *mctx)
194196
return ret;
195197
}
196198

197-
static int llext_manager_unload_module(const struct lib_manager_module *mctx)
199+
static int llext_manager_unload_module(struct lib_manager_module *mctx)
198200
{
199201
/* Executable code (.text) */
200202
void __sparse_cache *va_base_text = (void __sparse_cache *)
@@ -224,6 +226,8 @@ static int llext_manager_unload_module(const struct lib_manager_module *mctx)
224226
if (ret < 0 && !err)
225227
err = ret;
226228

229+
mctx->mapped = false;
230+
227231
return err;
228232
}
229233

@@ -237,16 +241,35 @@ static int llext_manager_link(struct llext_buf_loader *ebl, const char *name,
237241
const struct sof_man_module_manifest **mod_manifest)
238242
{
239243
struct llext **llext = &mctx->llext;
240-
/* Identify if this is the first time loading this module */
241-
struct llext_load_param ldr_parm = {
242-
.relocate_local = !mctx->segment[LIB_MANAGER_TEXT].size,
243-
.pre_located = true,
244-
.section_detached = llext_manager_section_detached,
245-
};
246-
int ret = llext_load(&ebl->loader, name, llext, &ldr_parm);
247-
248-
if (ret)
249-
return ret;
244+
int ret;
245+
246+
if (*llext && !mctx->mapped) {
247+
/*
248+
* All module instances have been terminated, so we freed SRAM,
249+
* but we kept the full Zephyr LLEXT context. Now a new instance
250+
* is starting, so we just re-use all the configuration and only
251+
* re-allocate SRAM and copy the module into it
252+
*/
253+
*mod_manifest = mctx->mod_manifest;
254+
255+
return 0;
256+
}
257+
258+
if (!*llext || mctx->mapped) {
259+
/*
260+
* Either the very first time loading this module, or the module
261+
* is already mapped, we just call llext_load() to refcount it
262+
*/
263+
struct llext_load_param ldr_parm = {
264+
.relocate_local = !*llext,
265+
.pre_located = true,
266+
.section_detached = llext_manager_section_detached,
267+
};
268+
269+
ret = llext_load(&ebl->loader, name, llext, &ldr_parm);
270+
if (ret)
271+
return ret;
272+
}
250273

251274
mctx->segment[LIB_MANAGER_TEXT].addr = ebl->loader.sects[LLEXT_MEM_TEXT].sh_addr;
252275
mctx->segment[LIB_MANAGER_TEXT].size = ebl->loader.sects[LLEXT_MEM_TEXT].sh_size;
@@ -323,7 +346,7 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx,
323346
for (i = 0, n_mod = 0, offs = ~0; i < desc->header.num_module_entries; i++)
324347
if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != offs) {
325348
offs = mod_array[i].segment[LIB_MANAGER_TEXT].file_offset;
326-
ctx->mod[n_mod].segment[LIB_MANAGER_TEXT].size = 0;
349+
ctx->mod[n_mod].mapped = false;
327350
ctx->mod[n_mod].llext = NULL;
328351
ctx->mod[n_mod++].start_idx = i;
329352
}
@@ -474,7 +497,9 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config
474497
tr_err(&lib_manager_tr, "Unsupported module API version");
475498
return 0;
476499
}
500+
}
477501

502+
if (!mctx->mapped) {
478503
/* Map executable code and data */
479504
int ret = llext_manager_load_module(mctx);
480505

@@ -506,12 +531,31 @@ int llext_manager_free_module(const uint32_t component_id)
506531
unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index);
507532
struct lib_manager_module *mctx = ctx->mod + mod_idx;
508533

509-
if (llext_unload(&mctx->llext))
534+
/* Protected by IPC serialization */
535+
if (mctx->llext->use_count > 1) {
536+
/* llext_unload() will return a positive number */
537+
int ret = llext_unload(&mctx->llext);
538+
539+
if (ret <= 0) {
540+
tr_err(&lib_manager_tr,
541+
"mod_id: %#x: invalid return code from llext_unload(): %d",
542+
component_id, ret);
543+
return ret ? : -EPROTO;
544+
}
545+
510546
/* More users are active */
511547
return 0;
548+
}
512549

550+
/*
551+
* The last instance of the module has been destroyed and it can now be
552+
* unloaded from SRAM
553+
*/
513554
tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id);
514555

556+
/* Since the LLEXT context now is preserved, we have to flush logs ourselves */
557+
log_flush();
558+
515559
return llext_manager_unload_module(mctx);
516560
}
517561

0 commit comments

Comments
 (0)