From e48b45c5f655f700116567c19c9c41ef0d7e8970 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 6 Apr 2023 13:13:48 +0000 Subject: [PATCH 1/9] app: zephyr still requires cmake version 3.20.0 Set min. cmake version required to what zephyr uses. Signed-off-by: Anas Nashif --- app/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index da9db799d387..ed6e53025fed 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -cmake_minimum_required(VERSION 3.21.0) +cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) project(sample_sof) From 35467d658fb80043abbc90c3766b201e80cbf414 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 4 Jun 2024 01:05:52 +0800 Subject: [PATCH 2/9] zephyr: change `z_arch_esf_t` to `struct arch_esf` `z_arch_esf_t` has been deprecated, use `struct arch_esf` instead. Signed-off-by: Yong Cong Sin --- zephyr/wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zephyr/wrapper.c b/zephyr/wrapper.c index 89c130c6a12d..190b5f8ba342 100644 --- a/zephyr/wrapper.c +++ b/zephyr/wrapper.c @@ -332,7 +332,7 @@ int poll_for_register_delay(uint32_t reg, uint32_t mask, volatile int *_sof_fatal_null = NULL; void k_sys_fatal_error_handler(unsigned int reason, - const z_arch_esf_t *esf) + const struct arch_esf *esf) { ARG_UNUSED(esf); From 1e4702f3080c68e6046b7b16eb030a3eba0ce231 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Mon, 4 Mar 2024 15:40:55 -0500 Subject: [PATCH 3/9] zephyr: arch_sched_ipi() -> arch_sched_broadcast_ipi() Renames arch_sched_ipi() to arch_sched_broadcast_ipi() to reflect recent changes from the IPI optimization work done in Zephyr. Signed-off-by: Peter Mitsis --- zephyr/lib/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zephyr/lib/cpu.c b/zephyr/lib/cpu.c index e65c85729c13..6055c8deeee6 100644 --- a/zephyr/lib/cpu.c +++ b/zephyr/lib/cpu.c @@ -156,7 +156,7 @@ void cpu_disable_core(int id) return; /* Broadcasting interrupts to other cores. */ - arch_sched_ipi(); + arch_sched_broadcast_ipi(); uint64_t timeout = k_cycle_get_64() + k_ms_to_cyc_ceil64(CONFIG_SECONDARY_CORE_DISABLING_TIMEOUT); From 23a5452ed24486a2a22a25d5f6ef426da1a32eed Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 28 May 2024 10:22:19 +0200 Subject: [PATCH 4/9] llext: (cosmetic) group headers Re-group headers more logically in eq_iir.c and mixin_mixout.c. Signed-off-by: Guennadi Liakhovetski --- src/audio/eq_iir/eq_iir.c | 3 +-- src/audio/mixin_mixout/mixin_mixout.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/audio/eq_iir/eq_iir.c b/src/audio/eq_iir/eq_iir.c index f60f38ffd4b5..6c298e4d59ff 100644 --- a/src/audio/eq_iir/eq_iir.c +++ b/src/audio/eq_iir/eq_iir.c @@ -262,9 +262,8 @@ SOF_MODULE_INIT(eq_iir, sys_comp_module_eq_iir_interface_init); /* modular: llext dynamic link */ #include -#include - #include +#include #define UUID_EQIIR 0xE6, 0xC0, 0x50, 0x51, 0xF9, 0x27, 0xC8, 0x4E, \ 0x83, 0x51, 0xC7, 0x05, 0xB6, 0x42, 0xD1, 0x2F diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index a7bd1c92fbc2..e89a5a15185b 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -969,9 +969,8 @@ SOF_MODULE_INIT(mixout, sys_comp_module_mixout_interface_init); /* modular: llext dynamic link */ #include -#include - #include +#include #define UUID_MIXIN 0xB2, 0x6E, 0x65, 0x39, 0x71, 0x3B, 0x49, 0x40, \ 0x8D, 0x3F, 0xF9, 0x2C, 0xD5, 0xC4, 0x3C, 0x09 From 4d1bd4d3beb4fde8e3945af890ca52d9fde0c10b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 28 May 2024 10:58:55 +0200 Subject: [PATCH 5/9] llext: update memory access flags when mapping When dynamically mapping memory, we need to update access flags according to the type of the mapping. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 42 ++++++++++++++++++----------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 23c35eb3d15d..bb98a041b079 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -51,6 +51,15 @@ extern struct tr_ctx lib_manager_tr; #define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE +static int llext_manager_update_flags(void __sparse_cache *vma, size_t size, uint32_t flags) +{ + size_t pre_pad_size = (uintptr_t)vma & (PAGE_SZ - 1); + void *aligned_vma = (__sparse_force uint8_t *)vma - pre_pad_size; + + return sys_mm_drv_update_region_flags(aligned_vma, + ALIGN_UP(pre_pad_size + size, PAGE_SZ), flags); +} + static int llext_manager_align_map(void __sparse_cache *vma, size_t size, uint32_t flags) { size_t pre_pad_size = (uintptr_t)vma & (PAGE_SZ - 1); @@ -71,15 +80,28 @@ static int llext_manager_align_unmap(void __sparse_cache *vma, size_t size) static int llext_manager_load_data_from_storage(void __sparse_cache *vma, void *s_addr, size_t size, uint32_t flags) { - int ret = llext_manager_align_map(vma, size, flags); + int ret = llext_manager_align_map(vma, size, SYS_MM_MEM_PERM_RW); if (ret < 0) { tr_err(&lib_manager_tr, "cannot map %u of %p", size, (__sparse_force void *)vma); return ret; } - /* TODO: Change attributes for memory to FLAGS */ - return memcpy_s((__sparse_force void *)vma, size, s_addr, size); + ret = memcpy_s((__sparse_force void *)vma, size, s_addr, size); + if (ret < 0) + return ret; + + /* + * We don't know what flags we're changing to, maybe the buffer will be + * executable or read-only. Need to write back caches now + */ + dcache_writeback_region(vma, size); + + ret = llext_manager_update_flags(vma, size, flags); + if (!ret && (flags & SYS_MM_MEM_PERM_EXEC)) + icache_invalidate_region(vma, size); + + return ret; } static int llext_manager_load_module(uint32_t module_id, const struct sof_man_module *mod) @@ -103,23 +125,11 @@ static int llext_manager_load_module(uint32_t module_id, const struct sof_man_mo if (ret < 0) return ret; - /* .text contains instructions and it also often contains local data */ - dcache_writeback_region(va_base_text, st_text_size); - icache_invalidate_region(va_base_text, st_text_size); - /* Copy RODATA */ ret = llext_manager_load_data_from_storage(va_base_rodata, src_rodata, st_rodata_size, SYS_MM_MEM_PERM_RW); if (ret < 0) - goto e_text; - - /* Some data can be accessed as uncached, in fact that's the default */ - dcache_writeback_region(va_base_rodata, st_rodata_size); - - return 0; - -e_text: - llext_manager_align_unmap(va_base_text, st_text_size); + llext_manager_align_unmap(va_base_text, st_text_size); return ret; } From 8a7bacba4bb5f89fecd02830ddd8096944ba602c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 28 May 2024 12:43:45 +0200 Subject: [PATCH 6/9] llext: use the first module for ELF information When an LLEXT module contains multiple Module Adapter instances, their manifests are stored in an array in the .module section. Those array entries contain per-instance information like module entry points, names, UUIDs, but ELF information is common for all instances. Store it in the first array entry to avoid confusion. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index bb98a041b079..a5871b9c912f 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -251,7 +251,7 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, const void *ipc_specific_config) { struct sof_man_fw_desc *desc; - struct sof_man_module *mod, *mod_array; + struct sof_man_module *mod_array; int ret; uint32_t module_id = IPC4_MOD_ID(ipc_config->id); uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); @@ -270,7 +270,6 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, } mod_array = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); - mod = mod_array + entry_index; /* LLEXT linking is only needed once for all the modules in the library */ ret = llext_manager_link(desc, mod_array, module_id, &proc->priv, (const void **)&buildinfo, @@ -291,11 +290,11 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, ctx->mod_manifest = mod_manifest; /* Map .text and the rest as .data */ - ret = llext_manager_load_module(module_id, mod); + ret = llext_manager_load_module(module_id, mod_array); if (ret < 0) return 0; - ret = llext_manager_allocate_module_bss(module_id, mod); + ret = llext_manager_allocate_module_bss(module_id, mod_array); if (ret < 0) { tr_err(&lib_manager_tr, "llext_manager_allocate_module(): module allocation failed: %d", From 90f58caad9b0a5ec2923c8bb7a43b51cb8f826da Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 28 May 2024 13:55:11 +0200 Subject: [PATCH 7/9] llext: split read-only and writable data properly We map memory pages for loaded modules dynamically and we're able to set memory flags for write access or for code execution. This commit takes advantage of the recently added section grouping and maps the three module parts separately: executable code, read-only data and writable data, including zero-initialised .bss. This also cleans up references, pointing into module storage in IMR instead of the mapped addresses. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib_manager.h | 16 +- src/library_manager/llext_manager.c | 221 +++++++++++++++------------- 2 files changed, 135 insertions(+), 102 deletions(-) diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index adf482f83f25..4429efdd938b 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -83,10 +83,24 @@ struct ipc_lib_msg { struct sof_man_module_manifest; +enum { + LIB_MANAGER_TEXT, + LIB_MANAGER_DATA, + LIB_MANAGER_RODATA, + LIB_MANAGER_BSS, + LIB_MANAGER_N_SEGMENTS, +}; + +struct lib_manager_segment_desc { + uintptr_t addr; + size_t size; + size_t file_offset; +}; + struct lib_manager_mod_ctx { void *base_addr; const struct sof_man_module_manifest *mod_manifest; - size_t segment_size[3]; + struct lib_manager_segment_desc segment[LIB_MANAGER_N_SEGMENTS]; }; struct ext_library { diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index a5871b9c912f..a5f4f4a0b4bc 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -108,28 +108,69 @@ static int llext_manager_load_module(uint32_t module_id, const struct sof_man_mo { struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); uint8_t *load_base = (uint8_t *)ctx->base_addr; + + /* Executable code (.text) */ void __sparse_cache *va_base_text = (void __sparse_cache *) - mod->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr; - void *src_txt = (void *)(load_base + mod->segment[SOF_MAN_SEGMENT_TEXT].file_offset); - size_t st_text_size = ctx->segment_size[SOF_MAN_SEGMENT_TEXT]; + ctx->segment[LIB_MANAGER_TEXT].addr; + void *src_txt = (void *)(load_base + ctx->segment[LIB_MANAGER_TEXT].file_offset); + size_t text_size = ctx->segment[LIB_MANAGER_TEXT].size; + + /* Read-only data (.rodata and others) */ void __sparse_cache *va_base_rodata = (void __sparse_cache *) - mod->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr; + ctx->segment[LIB_MANAGER_RODATA].addr; void *src_rodata = (void *)(load_base + - mod->segment[SOF_MAN_SEGMENT_RODATA].file_offset); - size_t st_rodata_size = ctx->segment_size[SOF_MAN_SEGMENT_RODATA]; + ctx->segment[LIB_MANAGER_RODATA].file_offset); + size_t rodata_size = ctx->segment[LIB_MANAGER_RODATA].size; + + /* Writable data (.data, .bss and others) */ + void __sparse_cache *va_base_data = (void __sparse_cache *) + ctx->segment[LIB_MANAGER_DATA].addr; + void *src_data = (void *)(load_base + + ctx->segment[LIB_MANAGER_DATA].file_offset); + size_t data_size = ctx->segment[LIB_MANAGER_DATA].size; + + /* .bss, should be within writable data above */ + void __sparse_cache *bss_addr = (void __sparse_cache *) + ctx->segment[LIB_MANAGER_BSS].addr; + size_t bss_size = ctx->segment[LIB_MANAGER_BSS].size; int ret; + /* Check, that .bss is within .data */ + if (bss_size && + ((uintptr_t)bss_addr + bss_size < (uintptr_t)va_base_data || + (uintptr_t)bss_addr >= (uintptr_t)va_base_data + data_size)) { + tr_err(&lib_manager_tr, ".bss %#x @ %p isn't within writable data %#x @ %p!", + bss_size, bss_addr, data_size, (void *)va_base_data); + return -EPROTO; + } + /* Copy Code */ - ret = llext_manager_load_data_from_storage(va_base_text, src_txt, st_text_size, - SYS_MM_MEM_PERM_RW | SYS_MM_MEM_PERM_EXEC); + ret = llext_manager_load_data_from_storage(va_base_text, src_txt, text_size, + SYS_MM_MEM_PERM_EXEC); if (ret < 0) return ret; - /* Copy RODATA */ + /* Copy read-only data */ ret = llext_manager_load_data_from_storage(va_base_rodata, src_rodata, - st_rodata_size, SYS_MM_MEM_PERM_RW); + rodata_size, 0); + if (ret < 0) + goto e_text; + + /* Copy writable data */ + ret = llext_manager_load_data_from_storage(va_base_data, src_data, + data_size, SYS_MM_MEM_PERM_RW); if (ret < 0) - llext_manager_align_unmap(va_base_text, st_text_size); + goto e_rodata; + + memset((__sparse_force void *)ctx->segment[LIB_MANAGER_BSS].addr, 0, + ctx->segment[LIB_MANAGER_BSS].size); + + return 0; + +e_rodata: + llext_manager_align_unmap(va_base_rodata, rodata_size); +e_text: + llext_manager_align_unmap(va_base_text, text_size); return ret; } @@ -137,53 +178,31 @@ static int llext_manager_load_module(uint32_t module_id, const struct sof_man_mo static int llext_manager_unload_module(uint32_t module_id, const struct sof_man_module *mod) { struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); + /* Executable code (.text) */ void __sparse_cache *va_base_text = (void __sparse_cache *) - mod->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr; - size_t st_text_size = ctx->segment_size[SOF_MAN_SEGMENT_TEXT]; + ctx->segment[LIB_MANAGER_TEXT].addr; + size_t text_size = ctx->segment[LIB_MANAGER_TEXT].size; + + /* Read-only data (.rodata, etc.) */ void __sparse_cache *va_base_rodata = (void __sparse_cache *) - mod->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr; - size_t st_rodata_size = ctx->segment_size[SOF_MAN_SEGMENT_RODATA]; + ctx->segment[LIB_MANAGER_RODATA].addr; + size_t rodata_size = ctx->segment[LIB_MANAGER_RODATA].size; + + /* Writable data (.data, .bss, etc.) */ + void __sparse_cache *va_base_data = (void __sparse_cache *) + ctx->segment[LIB_MANAGER_RODATA].addr; + size_t data_size = ctx->segment[LIB_MANAGER_RODATA].size; int ret; - ret = llext_manager_align_unmap(va_base_text, st_text_size); + ret = llext_manager_align_unmap(va_base_text, text_size); if (ret < 0) return ret; - return llext_manager_align_unmap(va_base_rodata, st_rodata_size); -} - -static void __sparse_cache *llext_manager_get_bss_address(uint32_t module_id, - const struct sof_man_module *mod) -{ - return (void __sparse_cache *)mod->segment[SOF_MAN_SEGMENT_BSS].v_base_addr; -} - -static int llext_manager_allocate_module_bss(uint32_t module_id, - const struct sof_man_module *mod) -{ - /* FIXME: just map .bss together with .data and simply memset(.bss, 0) */ - struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); - size_t bss_size = ctx->segment_size[SOF_MAN_SEGMENT_BSS]; - void __sparse_cache *va_base = llext_manager_get_bss_address(module_id, mod); - - /* Map bss memory and clear it. */ - if (llext_manager_align_map(va_base, bss_size, SYS_MM_MEM_PERM_RW) < 0) - return -ENOMEM; - - memset((__sparse_force void *)va_base, 0, bss_size); - - return 0; -} - -static int llext_manager_free_module_bss(uint32_t module_id, - const struct sof_man_module *mod) -{ - struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); - size_t bss_size = ctx->segment_size[SOF_MAN_SEGMENT_BSS]; - void __sparse_cache *va_base = llext_manager_get_bss_address(module_id, mod); + ret = llext_manager_align_unmap(va_base_data, data_size); + if (ret < 0) + return ret; - /* Unmap bss memory. */ - return llext_manager_align_unmap(va_base, bss_size); + return llext_manager_align_unmap(va_base_rodata, rodata_size); } static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_module *mod, @@ -191,47 +210,59 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul const struct sof_man_module_manifest **mod_manifest) { size_t mod_size = desc->header.preload_page_count * PAGE_SZ - FILE_TEXT_OFFSET_V1_8; - struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)desc - - SOF_MAN_ELF_TEXT_OFFSET + FILE_TEXT_OFFSET_V1_8, - mod_size); + uintptr_t imr_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; + struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)imr_base + FILE_TEXT_OFFSET_V1_8, + mod_size); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); /* Identify if this is the first time loading this module */ - struct llext_load_param ldr_parm = {!ctx->segment_size[SOF_MAN_SEGMENT_TEXT]}; + struct llext_load_param ldr_parm = { + .relocate_local = !ctx->segment[LIB_MANAGER_TEXT].size, + .pre_located = true, + }; int ret = llext_load(&ebl.loader, mod->name, &md->llext, &ldr_parm); if (ret) return ret; - mod->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr = ebl.loader.sects[LLEXT_MEM_TEXT].sh_addr; - mod->segment[SOF_MAN_SEGMENT_TEXT].file_offset = - (uintptr_t)md->llext->mem[LLEXT_MEM_TEXT] - - (uintptr_t)desc + SOF_MAN_ELF_TEXT_OFFSET; - ctx->segment_size[SOF_MAN_SEGMENT_TEXT] = ebl.loader.sects[LLEXT_MEM_TEXT].sh_size; + ctx->segment[LIB_MANAGER_TEXT].addr = ebl.loader.sects[LLEXT_MEM_TEXT].sh_addr; + ctx->segment[LIB_MANAGER_TEXT].file_offset = + (uintptr_t)md->llext->mem[LLEXT_MEM_TEXT] - imr_base; + ctx->segment[LIB_MANAGER_TEXT].size = ebl.loader.sects[LLEXT_MEM_TEXT].sh_size; - tr_dbg(&lib_manager_tr, ".text: start: %#x size %#x offset %#x", - mod->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr, - ctx->segment_size[SOF_MAN_SEGMENT_TEXT], - mod->segment[SOF_MAN_SEGMENT_TEXT].file_offset); + tr_dbg(&lib_manager_tr, ".text: start: %#lx size %#x offset %#x", + ctx->segment[LIB_MANAGER_TEXT].addr, + ctx->segment[LIB_MANAGER_TEXT].size, + ctx->segment[LIB_MANAGER_TEXT].file_offset); /* This contains all other sections, except .text, it might contain .bss too */ - mod->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr = + ctx->segment[LIB_MANAGER_RODATA].addr = ebl.loader.sects[LLEXT_MEM_RODATA].sh_addr; - mod->segment[SOF_MAN_SEGMENT_RODATA].file_offset = - (uintptr_t)md->llext->mem[LLEXT_MEM_RODATA] - - (uintptr_t)desc + SOF_MAN_ELF_TEXT_OFFSET; - ctx->segment_size[SOF_MAN_SEGMENT_RODATA] = ebl.loader.prog_data_size; + ctx->segment[LIB_MANAGER_RODATA].file_offset = + (uintptr_t)md->llext->mem[LLEXT_MEM_RODATA] - imr_base; + ctx->segment[LIB_MANAGER_RODATA].size = ebl.loader.sects[LLEXT_MEM_RODATA].sh_size; - tr_dbg(&lib_manager_tr, ".data: start: %#x size %#x offset %#x", - mod->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr, - ctx->segment_size[SOF_MAN_SEGMENT_RODATA], - mod->segment[SOF_MAN_SEGMENT_RODATA].file_offset); + tr_dbg(&lib_manager_tr, ".rodata: start: %#lx size %#x offset %#x", + ctx->segment[LIB_MANAGER_RODATA].addr, + ctx->segment[LIB_MANAGER_RODATA].size, + ctx->segment[LIB_MANAGER_RODATA].file_offset); - mod->segment[SOF_MAN_SEGMENT_BSS].v_base_addr = ebl.loader.sects[LLEXT_MEM_BSS].sh_addr; - ctx->segment_size[SOF_MAN_SEGMENT_BSS] = ebl.loader.sects[LLEXT_MEM_BSS].sh_size; + ctx->segment[LIB_MANAGER_DATA].addr = + ebl.loader.sects[LLEXT_MEM_DATA].sh_addr; + ctx->segment[LIB_MANAGER_DATA].file_offset = + (uintptr_t)md->llext->mem[LLEXT_MEM_DATA] - imr_base; + ctx->segment[LIB_MANAGER_DATA].size = ebl.loader.sects[LLEXT_MEM_DATA].sh_size; - tr_dbg(&lib_manager_tr, ".bss: start: %#x size %#x", - mod->segment[SOF_MAN_SEGMENT_BSS].v_base_addr, - ctx->segment_size[SOF_MAN_SEGMENT_BSS]); + tr_dbg(&lib_manager_tr, ".data: start: %#lx size %#x offset %#x", + ctx->segment[LIB_MANAGER_DATA].addr, + ctx->segment[LIB_MANAGER_DATA].size, + ctx->segment[LIB_MANAGER_DATA].file_offset); + + ctx->segment[LIB_MANAGER_BSS].addr = ebl.loader.sects[LLEXT_MEM_BSS].sh_addr; + ctx->segment[LIB_MANAGER_BSS].size = ebl.loader.sects[LLEXT_MEM_BSS].sh_size; + + tr_dbg(&lib_manager_tr, ".bss: start: %#lx size %#x", + ctx->segment[LIB_MANAGER_BSS].addr, + ctx->segment[LIB_MANAGER_BSS].size); ssize_t binfo_o = llext_find_section(&ebl.loader, ".mod_buildinfo"); @@ -243,7 +274,7 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul if (mod_o) *mod_manifest = llext_peek(&ebl.loader, mod_o); - return 0; + return binfo_o && mod_o ? 0 : -EPROTO; } uintptr_t llext_manager_allocate_module(struct processing_module *proc, @@ -286,21 +317,20 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, return -ENOEXEC; } - /* ctx->mod_manifest points to the array of module manifests */ - ctx->mod_manifest = mod_manifest; - - /* Map .text and the rest as .data */ + /* Map executable code and data */ ret = llext_manager_load_module(module_id, mod_array); if (ret < 0) return 0; - ret = llext_manager_allocate_module_bss(module_id, mod_array); - if (ret < 0) { - tr_err(&lib_manager_tr, - "llext_manager_allocate_module(): module allocation failed: %d", - ret); - return 0; - } + /* Manifest is in read-only data */ + uintptr_t imr_rodata = (uintptr_t)ctx->base_addr + + ctx->segment[LIB_MANAGER_RODATA].file_offset; + uintptr_t va_rodata_base = ctx->segment[LIB_MANAGER_RODATA].addr; + size_t offset = (uintptr_t)mod_manifest - imr_rodata; + + /* ctx->mod_manifest points to an array of module manifests */ + ctx->mod_manifest = (const struct sof_man_module_manifest *)(va_rodata_base + + offset); } return ctx->mod_manifest[entry_index].module.entry_point; @@ -312,21 +342,10 @@ int llext_manager_free_module(const uint32_t component_id) const uint32_t module_id = IPC4_MOD_ID(component_id); const unsigned int base_module_id = LIB_MANAGER_GET_LIB_ID(module_id) << LIB_MANAGER_LIB_ID_SHIFT; - int ret; tr_dbg(&lib_manager_tr, "llext_manager_free_module(): mod_id: %#x", component_id); mod = lib_manager_get_module_manifest(base_module_id); - ret = llext_manager_unload_module(base_module_id, mod); - if (ret < 0) - return ret; - - ret = llext_manager_free_module_bss(base_module_id, mod); - if (ret < 0) { - tr_err(&lib_manager_tr, - "llext_manager_free_module(): free module bss failed: %d", ret); - return ret; - } - return 0; + return llext_manager_unload_module(base_module_id, mod); } From 3f1716b0da7a48358bc265586b90b2252745c14c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Jun 2024 17:05:44 +0200 Subject: [PATCH 8/9] llext: add support for .bss directly adjacent to .data Zephyr places .bss into a separate section element, still if it's immediately adjacent to writable data we can merge and allocate them together. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index a5f4f4a0b4bc..416c76bbc682 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -137,11 +137,21 @@ static int llext_manager_load_module(uint32_t module_id, const struct sof_man_mo /* Check, that .bss is within .data */ if (bss_size && - ((uintptr_t)bss_addr + bss_size < (uintptr_t)va_base_data || + ((uintptr_t)bss_addr + bss_size <= (uintptr_t)va_base_data || (uintptr_t)bss_addr >= (uintptr_t)va_base_data + data_size)) { - tr_err(&lib_manager_tr, ".bss %#x @ %p isn't within writable data %#x @ %p!", - bss_size, bss_addr, data_size, (void *)va_base_data); - return -EPROTO; + if ((uintptr_t)bss_addr + bss_size == (uintptr_t)va_base_data && + !((uintptr_t)bss_addr & (PAGE_SZ - 1))) { + /* .bss directly in front of writable data and properly aligned, prepend */ + va_base_data = bss_addr; + data_size += bss_size; + } else if ((uintptr_t)bss_addr == (uintptr_t)va_base_data + data_size) { + /* .bss directly behind writable data, append */ + data_size += bss_size; + } else { + tr_err(&lib_manager_tr, ".bss %#x @ %p isn't within writable data %#x @ %p!", + bss_size, bss_addr, data_size, (void *)va_base_data); + return -EPROTO; + } } /* Copy Code */ @@ -162,8 +172,7 @@ static int llext_manager_load_module(uint32_t module_id, const struct sof_man_mo if (ret < 0) goto e_rodata; - memset((__sparse_force void *)ctx->segment[LIB_MANAGER_BSS].addr, 0, - ctx->segment[LIB_MANAGER_BSS].size); + memset((__sparse_force void *)bss_addr, 0, bss_size); return 0; From b577e7f9c3ed0cd102173cabc78326e5144cce89 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 8 Jul 2024 21:04:59 -0400 Subject: [PATCH 9/9] llext: manager: use k_ssize_t instead of ssize_t This change accompanies a similar Zephyr change where we create explicit k-types to avoid using POSIX types below the line in where the POSIX API sits in our stack, thus avoiding a dependency cycle. Additional types we should avoid using (as well as the header itself) are listed on the opengroup website (search for "sys/types.h"). Signed-off-by: Christopher Friedt --- src/library_manager/llext_manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 416c76bbc682..859ad84a79fb 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -273,12 +273,12 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul ctx->segment[LIB_MANAGER_BSS].addr, ctx->segment[LIB_MANAGER_BSS].size); - ssize_t binfo_o = llext_find_section(&ebl.loader, ".mod_buildinfo"); + k_ssize_t binfo_o = llext_find_section(&ebl.loader, ".mod_buildinfo"); if (binfo_o) *buildinfo = llext_peek(&ebl.loader, binfo_o); - ssize_t mod_o = llext_find_section(&ebl.loader, ".module"); + k_ssize_t mod_o = llext_find_section(&ebl.loader, ".module"); if (mod_o) *mod_manifest = llext_peek(&ebl.loader, mod_o);