From fb69555edf2c9155285505eed5fd1e24571affd1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 14:01:11 +0200 Subject: [PATCH 1/4] llext: move 2 functions higher Move llext_manager_add_partition() and llext_manager_rm_partition() higher in the file for future use. No functional change. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 61 +++++++++++++++-------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 4ad3c55d55bc..1be78041b074 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -168,6 +168,38 @@ static int llext_manager_load_data_from_storage(const struct sys_mm_drv_region * return ret; } +#ifdef CONFIG_USERSPACE +static int llext_manager_add_partition(struct k_mem_domain *domain, + uintptr_t addr, size_t size, + k_mem_partition_attr_t attr) +{ + size_t pre_pad_size = addr & (PAGE_SZ - 1); + struct k_mem_partition part = { + .start = addr - pre_pad_size, + .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), + .attr = attr, + }; + + tr_dbg(&lib_manager_tr, "add %#zx @ %lx partition", part.size, part.start); + return k_mem_domain_add_partition(domain, &part); +} + +static int llext_manager_rm_partition(struct k_mem_domain *domain, + uintptr_t addr, size_t size, + k_mem_partition_attr_t attr) +{ + size_t pre_pad_size = addr & (PAGE_SZ - 1); + struct k_mem_partition part = { + .start = addr - pre_pad_size, + .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), + .attr = attr, + }; + + tr_dbg(&lib_manager_tr, "remove %#zx @ %lx partition", part.size, part.start); + return k_mem_domain_remove_partition(domain, &part); +} +#endif + static void llext_manager_unmap_detached_sections(const struct llext_loader *ldr, const struct llext *ext, enum llext_mem region, @@ -794,35 +826,6 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config } #ifdef CONFIG_USERSPACE -static int llext_manager_add_partition(struct k_mem_domain *domain, - uintptr_t addr, size_t size, - k_mem_partition_attr_t attr) -{ - size_t pre_pad_size = addr & (PAGE_SZ - 1); - struct k_mem_partition part = { - .start = addr - pre_pad_size, - .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), - .attr = attr, - }; - - tr_dbg(&lib_manager_tr, "add %#zx @ %lx partition", part.size, part.start); - return k_mem_domain_add_partition(domain, &part); -} - -static int llext_manager_rm_partition(struct k_mem_domain *domain, - uintptr_t addr, size_t size, - k_mem_partition_attr_t attr) -{ - size_t pre_pad_size = addr & (PAGE_SZ - 1); - struct k_mem_partition part = { - .start = addr - pre_pad_size, - .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), - .attr = attr, - }; - - tr_dbg(&lib_manager_tr, "remove %#zx @ %lx partition", part.size, part.start); - return k_mem_domain_remove_partition(domain, &part); -} static int llext_manager_add_mod_domain(struct lib_manager_module *mctx, struct k_mem_domain *domain) { From 2b7836484f72f2d485ce7d1df31d559846705072 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 14:48:45 +0200 Subject: [PATCH 2/4] llext: don't access DRAM when freeing With userspace LL enabled module freeing runs in syscall contex on behalf of the userspace IPC thread. That thread doesn't have access to DRAM. Therefore we cannot call lib_manager_get_module_manifest() in that case. Use SRAM module data by calling llext_manager_mod_find() instead. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib_manager.h | 1 + src/library_manager/lib_manager.c | 10 +++++++--- src/library_manager/llext_manager.c | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index fb277ac75f64..019695be69ef 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -123,6 +123,7 @@ struct lib_manager_module { struct lib_manager_mod_ctx { void *base_addr; /* library cold storage address (e.g. DRAM) */ unsigned int n_mod; + unsigned int load_type; struct lib_manager_module *mod; }; diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index 1b1dd5f2cc9e..a672f51133d2 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -423,15 +423,18 @@ static int lib_manager_free_module(const uint32_t component_id) tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id); + const struct lib_manager_mod_ctx *const ctx = lib_manager_get_mod_ctx(module_id); + + if (ctx->load_type == SOF_MAN_MOD_TYPE_LLEXT || + ctx->load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX) + return llext_manager_free_module(component_id); + mod = lib_manager_get_module_manifest(module_id); if (!mod) { tr_err(&lib_manager_tr, "failed to get module descriptor"); return -EINVAL; } - if (module_is_llext(mod)) - return llext_manager_free_module(component_id); - ret = lib_manager_unload_module(mod); if (ret < 0) return ret; @@ -500,6 +503,7 @@ static void lib_manager_update_sof_ctx(void *base_addr, uint32_t lib_id) } ctx->base_addr = base_addr; + ctx->load_type = SOF_MAN_MOD_TYPE_MODULE; _ext_lib->desc[lib_id] = ctx; /* TODO: maybe need to call dcache_writeback here? */ diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 1be78041b074..f3797f67a8d9 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -1170,6 +1170,7 @@ int llext_manager_add_library(uint32_t module_id) return ret; } } + ctx->load_type = SOF_MAN_MOD_TYPE_LLEXT; return 0; } From 12f50fe306d0de448c99ba02587edca136726316 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 15:09:09 +0200 Subject: [PATCH 3/4] llext: temporarily map ELF headers for userspace when freeing llext_manager_unload_module() is called in a syscall context on behalf of the userspace IPC thread, so it doesn't have direct access to LLEXT module DRAM data. Map section headers temporarily for the duration of the function. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index f3797f67a8d9..a163fdd062f2 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -382,6 +382,19 @@ static int llext_manager_unload_module(struct lib_manager_module *mctx) mctx->segment[LIB_MANAGER_BSS].size; int err = 0, ret; +#ifdef CONFIG_SOF_USERSPACE_LL + unsigned int sect_cnt = llext_section_count(ext); + size_t total = sect_cnt * sizeof(elf_shdr_t); + const elf_shdr_t *shdr; + + ret = llext_get_section_info(ldr, ext, 0, &shdr, NULL, NULL); + if (ret < 0) + return ret; + + /* Temporarily map ELF section headers */ + llext_manager_add_partition(zephyr_ll_mem_domain(), (uintptr_t)shdr, total, + K_MEM_PARTITION_P_RW_U_NA | XTENSA_MMU_CACHED_WB); +#endif llext_manager_unmap_detached_sections(ldr, ext, LLEXT_MEM_TEXT, va_base_text, text_size); ret = llext_manager_align_unmap(va_base_text, text_size); @@ -406,6 +419,10 @@ static int llext_manager_unload_module(struct lib_manager_module *mctx) if (ret < 0 && !err) err = ret; +#ifdef CONFIG_SOF_USERSPACE_LL + llext_manager_rm_partition(zephyr_ll_mem_domain(), (uintptr_t)shdr, total, + K_MEM_PARTITION_P_RW_U_NA | XTENSA_MMU_CACHED_WB); +#endif mctx->mapped = false; #ifdef CONFIG_SOF_USERSPACE_LL From 2068b0d347dfceaab1b72cc084688530deeb2e05 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 15:14:59 +0200 Subject: [PATCH 4/4] llext: avoid DRAM access in userspace when freeing llext_manager_free_module() cannot access DRAM when running with userspace LL enabled. Don't call lib_manager_get_library_manifest() to obtain the DRAM descriptor, needed to verify the entry index. The index is now verified by llext_manager_mod_find(). Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index a163fdd062f2..bcbfd290ceb0 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -1086,16 +1086,9 @@ int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *do int llext_manager_free_module(const uint32_t component_id) { const uint32_t module_id = IPC4_MOD_ID(component_id); - struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(module_id); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); - if (entry_index >= desc->header.num_module_entries) { - tr_err(&lib_manager_tr, "Invalid driver index %u exceeds %d", - entry_index, desc->header.num_module_entries - 1); - return -ENOENT; - } - if (!ctx->mod) { tr_err(&lib_manager_tr, "NULL module array: ID %#x ctx %p", component_id, ctx); return -ENOENT;