From 099754c16acc61911496e9388a21b00f90ef820b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Nov 2024 16:37:45 +0100 Subject: [PATCH 1/4] LLEXT: (cosmetic) replace IMR with DRAM IMR is architecture-specific, use a generic DRAM term. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index f64461ede909..6c3f3b272daa 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -224,8 +224,8 @@ 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; - 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, + uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; + struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_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 */ @@ -240,7 +240,7 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul 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; + (uintptr_t)md->llext->mem[LLEXT_MEM_TEXT] - dram_base; ctx->segment[LIB_MANAGER_TEXT].size = ebl.loader.sects[LLEXT_MEM_TEXT].sh_size; tr_dbg(&lib_manager_tr, ".text: start: %#lx size %#x offset %#x", @@ -252,7 +252,7 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul ctx->segment[LIB_MANAGER_RODATA].addr = ebl.loader.sects[LLEXT_MEM_RODATA].sh_addr; ctx->segment[LIB_MANAGER_RODATA].file_offset = - (uintptr_t)md->llext->mem[LLEXT_MEM_RODATA] - imr_base; + (uintptr_t)md->llext->mem[LLEXT_MEM_RODATA] - dram_base; ctx->segment[LIB_MANAGER_RODATA].size = ebl.loader.sects[LLEXT_MEM_RODATA].sh_size; tr_dbg(&lib_manager_tr, ".rodata: start: %#lx size %#x offset %#x", @@ -263,7 +263,7 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul 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; + (uintptr_t)md->llext->mem[LLEXT_MEM_DATA] - dram_base; ctx->segment[LIB_MANAGER_DATA].size = ebl.loader.sects[LLEXT_MEM_DATA].sh_size; tr_dbg(&lib_manager_tr, ".data: start: %#lx size %#x offset %#x", @@ -337,10 +337,10 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, return 0; /* Manifest is in read-only data */ - uintptr_t imr_rodata = (uintptr_t)ctx->base_addr + + uintptr_t dram_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; + size_t offset = (uintptr_t)mod_manifest - dram_rodata; /* ctx->mod_manifest points to an array of module manifests */ ctx->mod_manifest = sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) From c32a520b1dd84907f862efa9a6d102eab2db9276 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 7 Nov 2024 17:03:28 +0200 Subject: [PATCH 2/4] LLEXT: align .bss for verification When verifying whether .bss is correctly following .data take its alignment into account. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 59 ++++++++++++++++------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 6c3f3b272daa..fb8e74e5a9fe 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -104,7 +104,8 @@ static int llext_manager_load_data_from_storage(void __sparse_cache *vma, void * return ret; } -static int llext_manager_load_module(uint32_t module_id, const struct sof_man_module *mod) +static int llext_manager_load_module(const struct llext_buf_loader *ebl, + uint32_t module_id, const struct sof_man_module *mod) { struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); uint8_t *load_base = (uint8_t *)ctx->base_addr; @@ -144,7 +145,8 @@ static int llext_manager_load_module(uint32_t module_id, const struct sof_man_mo /* .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) { + } else if ((uintptr_t)bss_addr == (uintptr_t)va_base_data + + ALIGN_UP(data_size, ebl->loader.sects[LLEXT_MEM_BSS].sh_addralign)) { /* .bss directly behind writable data, append */ data_size += bss_size; } else { @@ -219,29 +221,27 @@ static int llext_manager_unload_module(uint32_t module_id, const struct sof_man_ return err; } -static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_module *mod, - uint32_t module_id, struct module_data *md, const void **buildinfo, +static int llext_manager_link(struct llext_buf_loader *ebl, struct sof_man_fw_desc *desc, + struct sof_man_module *mod, uint32_t module_id, struct module_data *md, + const void **buildinfo, const struct sof_man_module_manifest **mod_manifest) { - size_t mod_size = desc->header.preload_page_count * PAGE_SZ - FILE_TEXT_OFFSET_V1_8; uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; - struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_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 = { .relocate_local = !ctx->segment[LIB_MANAGER_TEXT].size, .pre_located = true, }; - int ret = llext_load(&ebl.loader, mod->name, &md->llext, &ldr_parm); + int ret = llext_load(&ebl->loader, mod->name, &md->llext, &ldr_parm); if (ret) return ret; - ctx->segment[LIB_MANAGER_TEXT].addr = ebl.loader.sects[LLEXT_MEM_TEXT].sh_addr; + 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] - dram_base; - ctx->segment[LIB_MANAGER_TEXT].size = ebl.loader.sects[LLEXT_MEM_TEXT].sh_size; + ctx->segment[LIB_MANAGER_TEXT].size = ebl->loader.sects[LLEXT_MEM_TEXT].sh_size; tr_dbg(&lib_manager_tr, ".text: start: %#lx size %#x offset %#x", ctx->segment[LIB_MANAGER_TEXT].addr, @@ -250,10 +250,10 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul /* This contains all other sections, except .text, it might contain .bss too */ ctx->segment[LIB_MANAGER_RODATA].addr = - ebl.loader.sects[LLEXT_MEM_RODATA].sh_addr; + ebl->loader.sects[LLEXT_MEM_RODATA].sh_addr; ctx->segment[LIB_MANAGER_RODATA].file_offset = (uintptr_t)md->llext->mem[LLEXT_MEM_RODATA] - dram_base; - ctx->segment[LIB_MANAGER_RODATA].size = ebl.loader.sects[LLEXT_MEM_RODATA].sh_size; + ctx->segment[LIB_MANAGER_RODATA].size = ebl->loader.sects[LLEXT_MEM_RODATA].sh_size; tr_dbg(&lib_manager_tr, ".rodata: start: %#lx size %#x offset %#x", ctx->segment[LIB_MANAGER_RODATA].addr, @@ -261,32 +261,32 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul ctx->segment[LIB_MANAGER_RODATA].file_offset); ctx->segment[LIB_MANAGER_DATA].addr = - ebl.loader.sects[LLEXT_MEM_DATA].sh_addr; + ebl->loader.sects[LLEXT_MEM_DATA].sh_addr; ctx->segment[LIB_MANAGER_DATA].file_offset = (uintptr_t)md->llext->mem[LLEXT_MEM_DATA] - dram_base; - ctx->segment[LIB_MANAGER_DATA].size = ebl.loader.sects[LLEXT_MEM_DATA].sh_size; + ctx->segment[LIB_MANAGER_DATA].size = ebl->loader.sects[LLEXT_MEM_DATA].sh_size; 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; + 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"); + ssize_t binfo_o = llext_find_section(&ebl->loader, ".mod_buildinfo"); if (binfo_o >= 0) - *buildinfo = llext_peek(&ebl.loader, binfo_o); + *buildinfo = llext_peek(&ebl->loader, binfo_o); - ssize_t mod_o = llext_find_section(&ebl.loader, ".module"); + ssize_t mod_o = llext_find_section(&ebl->loader, ".module"); if (mod_o >= 0) - *mod_manifest = llext_peek(&ebl.loader, mod_o); + *mod_manifest = llext_peek(&ebl->loader, mod_o); return binfo_o >= 0 && mod_o >= 0 ? 0 : -EPROTO; } @@ -295,19 +295,22 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, const struct comp_ipc_config *ipc_config, const void *ipc_specific_config) { - struct sof_man_fw_desc *desc; + uint32_t module_id = IPC4_MOD_ID(ipc_config->id); + struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(module_id); 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); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); const struct sof_module_api_build_info *buildinfo; const struct sof_man_module_manifest *mod_manifest; + size_t mod_size = desc->header.preload_page_count * PAGE_SZ - FILE_TEXT_OFFSET_V1_8; + uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; + struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_base + FILE_TEXT_OFFSET_V1_8, + mod_size); tr_dbg(&lib_manager_tr, "llext_manager_allocate_module(): mod_id: %#x", ipc_config->id); - desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(module_id); if (!ctx || !desc) { tr_err(&lib_manager_tr, "llext_manager_allocate_module(): failed to get module descriptor"); @@ -317,10 +320,12 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, mod_array = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); /* 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, - &mod_manifest); - if (ret < 0) + ret = llext_manager_link(&ebl, desc, mod_array, module_id, &proc->priv, + (const void **)&buildinfo, &mod_manifest); + if (ret < 0) { + tr_err(&lib_manager_tr, "linking failed: %d", ret); return 0; + } if (!ret) { /* First instance: check that the module is native */ @@ -332,7 +337,7 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, } /* Map executable code and data */ - ret = llext_manager_load_module(module_id, mod_array); + ret = llext_manager_load_module(&ebl, module_id, mod_array); if (ret < 0) return 0; From 8f6ddb45cf701426e2dd7bd7f3e65bf4fa39addb Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Nov 2024 10:58:35 +0200 Subject: [PATCH 3/4] LLEXT: copy individual sections Section alignment might differ in the ELF image and at module target address. To obey that we need to copy sections individually from regions / segments. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 50 +++++++++++++++++++---------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index fb8e74e5a9fe..144634339b8d 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -77,19 +77,36 @@ static int llext_manager_align_unmap(void __sparse_cache *vma, size_t size) return sys_mm_drv_unmap_region(aligned_vma, ALIGN_UP(pre_pad_size + size, PAGE_SZ)); } -static int llext_manager_load_data_from_storage(void __sparse_cache *vma, void *s_addr, +static int llext_manager_load_data_from_storage(const struct llext *ext, + void __sparse_cache *vma, + const uint8_t *load_base, + size_t region_offset, size_t size, uint32_t flags) { + const uint8_t *s_addr = load_base + region_offset; + unsigned int i; int ret = llext_manager_align_map(vma, size, SYS_MM_MEM_PERM_RW); + const elf_shdr_t *shdr; if (ret < 0) { tr_err(&lib_manager_tr, "cannot map %u of %p", size, (__sparse_force void *)vma); return ret; } - ret = memcpy_s((__sparse_force void *)vma, size, s_addr, size); - if (ret < 0) - return ret; + /* Need to copy sections within regions individually, offsets may differ */ + for (i = 0, shdr = llext_section_headers(ext); i < llext_section_count(ext); i++, shdr++) { + if ((uintptr_t)shdr->sh_addr < (uintptr_t)vma || + (uintptr_t)shdr->sh_addr >= (uintptr_t)vma + size) + continue; + + size_t offset = shdr->sh_offset + FILE_TEXT_OFFSET_V1_8 - region_offset; + + /* found a section within the region */ + ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - offset, + s_addr + offset, shdr->sh_size); + if (ret < 0) + return ret; + } /* * We don't know what flags we're changing to, maybe the buffer will be @@ -104,30 +121,25 @@ static int llext_manager_load_data_from_storage(void __sparse_cache *vma, void * return ret; } -static int llext_manager_load_module(const struct llext_buf_loader *ebl, +static int llext_manager_load_module(const struct llext *ext, const struct llext_buf_loader *ebl, uint32_t module_id, const struct sof_man_module *mod) { struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); - uint8_t *load_base = (uint8_t *)ctx->base_addr; + const uint8_t *load_base = (const uint8_t *)ctx->base_addr; /* Executable code (.text) */ void __sparse_cache *va_base_text = (void __sparse_cache *) 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 *) ctx->segment[LIB_MANAGER_RODATA].addr; - void *src_rodata = (void *)(load_base + - 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 */ @@ -158,19 +170,22 @@ static int llext_manager_load_module(const struct llext_buf_loader *ebl, } /* Copy Code */ - ret = llext_manager_load_data_from_storage(va_base_text, src_txt, text_size, - SYS_MM_MEM_PERM_EXEC); + ret = llext_manager_load_data_from_storage(ext, va_base_text, load_base, + ctx->segment[LIB_MANAGER_TEXT].file_offset, + text_size, SYS_MM_MEM_PERM_EXEC); if (ret < 0) return ret; /* Copy read-only data */ - ret = llext_manager_load_data_from_storage(va_base_rodata, src_rodata, + ret = llext_manager_load_data_from_storage(ext, va_base_rodata, load_base, + ctx->segment[LIB_MANAGER_RODATA].file_offset, rodata_size, 0); if (ret < 0) goto e_text; /* Copy writable data */ - ret = llext_manager_load_data_from_storage(va_base_data, src_data, + ret = llext_manager_load_data_from_storage(ext, va_base_data, load_base, + ctx->segment[LIB_MANAGER_DATA].file_offset, data_size, SYS_MM_MEM_PERM_RW); if (ret < 0) goto e_rodata; @@ -307,6 +322,7 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, uintptr_t dram_base = (uintptr_t)desc - SOF_MAN_ELF_TEXT_OFFSET; struct llext_buf_loader ebl = LLEXT_BUF_LOADER((uint8_t *)dram_base + FILE_TEXT_OFFSET_V1_8, mod_size); + struct module_data *md = &proc->priv; tr_dbg(&lib_manager_tr, "llext_manager_allocate_module(): mod_id: %#x", ipc_config->id); @@ -320,7 +336,7 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, mod_array = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); /* LLEXT linking is only needed once for all the modules in the library */ - ret = llext_manager_link(&ebl, desc, mod_array, module_id, &proc->priv, + ret = llext_manager_link(&ebl, desc, mod_array, module_id, md, (const void **)&buildinfo, &mod_manifest); if (ret < 0) { tr_err(&lib_manager_tr, "linking failed: %d", ret); @@ -337,7 +353,7 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc, } /* Map executable code and data */ - ret = llext_manager_load_module(&ebl, module_id, mod_array); + ret = llext_manager_load_module(md->llext, &ebl, module_id, mod_array); if (ret < 0) return 0; From cc26dd93237aae1bfe40d3b8d4f7af6a07fbe0e4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 18 Nov 2024 12:29:06 +0100 Subject: [PATCH 4/4] west.yml: update zephyr to include LLEXT fixes Update to include Zephyr fixes for unaligned section placement in object files. Signed-off-by: Guennadi Liakhovetski --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 4e971d900d74..abe21291c4da 100644 --- a/west.yml +++ b/west.yml @@ -43,7 +43,7 @@ manifest: - name: zephyr repo-path: zephyr - revision: 7e8ee254797917ff3d89c628f821cf10260c4034 + revision: cbb6199e679c50c75d3ed090852b4993e8b06a8a remote: zephyrproject # Import some projects listed in zephyr/west.yml@revision