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