Skip to content

Commit

Permalink
llext_manager: convert to use new LLEXT inspection API
Browse files Browse the repository at this point in the history
This patch converts the llext_manager to use the new LLEXT inspection
API. The new API allows to get information about sections and regions
without the need to access the internal structures of the LLEXT loader,
decoupling SOF and LLEXT code and making it easier to maintain.

Signed-off-by: Luca Burelli <[email protected]>
  • Loading branch information
pillo79 committed Feb 10, 2025
1 parent 56a4b62 commit 590efbb
Showing 1 changed file with 55 additions and 37 deletions.
92 changes: 55 additions & 37 deletions src/library_manager/llext_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <zephyr/llext/buf_loader.h>
#include <zephyr/llext/loader.h>
#include <zephyr/llext/llext.h>
#include <zephyr/llext/inspect.h>

#include <rimage/sof/user/manifest.h>
#include <module/module/api_ver.h>
Expand Down Expand Up @@ -69,12 +70,15 @@ 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(const struct llext *ext,
static int llext_manager_load_data_from_storage(const struct llext_loader *ldr,
const struct llext *ext,
enum llext_mem region,
void __sparse_cache *vma,
const uint8_t *load_base,
size_t size, uint32_t flags)
{
unsigned int i;
void *region_addr;
size_t region_size;
int ret;

ret = llext_manager_align_map(vma, size, SYS_MM_MEM_PERM_RW);
Expand All @@ -83,22 +87,21 @@ static int llext_manager_load_data_from_storage(const struct llext *ext,
return ret;
}

size_t init_offset = 0;
llext_get_region_info(ldr, ext, region, NULL, &region_addr, &region_size);

/* 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;
for (i = 0; i < llext_section_count(ext); i++) {
const elf_shdr_t *shdr;
enum llext_mem s_region = LLEXT_MEM_COUNT;
size_t s_offset = 0;

if (!init_offset)
init_offset = shdr->sh_offset;
llext_get_section_info(ldr, ext, i, &shdr, &s_region, &s_offset);

/* found a section within the region */
size_t offset = shdr->sh_offset - init_offset;
if (s_region != region)
continue;

ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - offset,
load_base + offset, shdr->sh_size);
ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - s_offset,
(uint8_t *)region_addr + s_offset, shdr->sh_size);
if (ret < 0)
return ret;
}
Expand All @@ -119,6 +122,10 @@ static int llext_manager_load_data_from_storage(const struct llext *ext,
static int llext_manager_load_module(const struct llext *ext, const struct llext_buf_loader *ebl,
const struct lib_manager_module *mctx)
{
const elf_shdr_t *bss_hdr;

llext_get_region_info(&ebl->loader, ext, LLEXT_MEM_BSS, &bss_hdr, NULL, NULL);

/* Executable code (.text) */
void __sparse_cache *va_base_text = (void __sparse_cache *)
mctx->segment[LIB_MANAGER_TEXT].addr;
Expand All @@ -136,8 +143,8 @@ static int llext_manager_load_module(const struct llext *ext, const struct llext

/* .bss, should be within writable data above */
void __sparse_cache *bss_addr = (void __sparse_cache *)
ebl->loader.sects[LLEXT_MEM_BSS].sh_addr;
size_t bss_size = ebl->loader.sects[LLEXT_MEM_BSS].sh_size;
bss_hdr->sh_addr;
size_t bss_size = bss_hdr->sh_size;
int ret;

/* Check, that .bss is within .data */
Expand All @@ -150,7 +157,7 @@ static int llext_manager_load_module(const struct llext *ext, const struct llext
va_base_data = bss_addr;
data_size += bss_size;
} else if ((uintptr_t)bss_addr == (uintptr_t)va_base_data +
ALIGN_UP(data_size, ebl->loader.sects[LLEXT_MEM_BSS].sh_addralign)) {
ALIGN_UP(data_size, bss_hdr->sh_addralign)) {
/* .bss directly behind writable data, append */
data_size += bss_size;
} else {
Expand All @@ -162,20 +169,20 @@ static int llext_manager_load_module(const struct llext *ext, const struct llext
}

/* Copy Code */
ret = llext_manager_load_data_from_storage(ext, va_base_text, ext->mem[LLEXT_MEM_TEXT],
text_size, SYS_MM_MEM_PERM_EXEC);
ret = llext_manager_load_data_from_storage(&ebl->loader, ext, LLEXT_MEM_TEXT,
va_base_text, text_size, SYS_MM_MEM_PERM_EXEC);
if (ret < 0)
return ret;

/* Copy read-only data */
ret = llext_manager_load_data_from_storage(ext, va_base_rodata, ext->mem[LLEXT_MEM_RODATA],
rodata_size, 0);
ret = llext_manager_load_data_from_storage(&ebl->loader, ext, LLEXT_MEM_RODATA,
va_base_rodata, rodata_size, 0);
if (ret < 0)
goto e_text;

/* Copy writable data */
ret = llext_manager_load_data_from_storage(ext, va_base_data, ext->mem[LLEXT_MEM_DATA],
data_size, SYS_MM_MEM_PERM_RW);
ret = llext_manager_load_data_from_storage(&ebl->loader, ext, LLEXT_MEM_DATA,
va_base_data, data_size, SYS_MM_MEM_PERM_RW);
if (ret < 0)
goto e_rodata;

Expand Down Expand Up @@ -239,49 +246,60 @@ static int llext_manager_link(struct llext_buf_loader *ebl, const char *name,
.relocate_local = !mctx->segment[LIB_MANAGER_TEXT].size,
.pre_located = true,
.section_detached = llext_manager_section_detached,
.keep_section_info = true,
};
const elf_shdr_t *hdr;
int ret;

ret = llext_load(&ebl->loader, name, &md->llext, &ldr_parm);
if (ret)
return ret;

mctx->segment[LIB_MANAGER_TEXT].addr = ebl->loader.sects[LLEXT_MEM_TEXT].sh_addr;
mctx->segment[LIB_MANAGER_TEXT].size = ebl->loader.sects[LLEXT_MEM_TEXT].sh_size;
/* All code sections */
llext_get_region_info(&ebl->loader, md->llext, LLEXT_MEM_TEXT,
&hdr, NULL, NULL);
mctx->segment[LIB_MANAGER_TEXT].addr = hdr->sh_addr;
mctx->segment[LIB_MANAGER_TEXT].size = hdr->sh_size;

tr_dbg(&lib_manager_tr, ".text: start: %#lx size %#x",
mctx->segment[LIB_MANAGER_TEXT].addr,
mctx->segment[LIB_MANAGER_TEXT].size);

/* All read-only data sections */
mctx->segment[LIB_MANAGER_RODATA].addr =
ebl->loader.sects[LLEXT_MEM_RODATA].sh_addr;
mctx->segment[LIB_MANAGER_RODATA].size = ebl->loader.sects[LLEXT_MEM_RODATA].sh_size;
llext_get_region_info(&ebl->loader, md->llext, LLEXT_MEM_RODATA,
&hdr, NULL, NULL);
mctx->segment[LIB_MANAGER_RODATA].addr = hdr->sh_addr;
mctx->segment[LIB_MANAGER_RODATA].size = hdr->sh_size;

tr_dbg(&lib_manager_tr, ".rodata: start: %#lx size %#x",
mctx->segment[LIB_MANAGER_RODATA].addr,
mctx->segment[LIB_MANAGER_RODATA].size);

/* All writable data sections */
mctx->segment[LIB_MANAGER_DATA].addr =
ebl->loader.sects[LLEXT_MEM_DATA].sh_addr;
mctx->segment[LIB_MANAGER_DATA].size = ebl->loader.sects[LLEXT_MEM_DATA].sh_size;
llext_get_region_info(&ebl->loader, md->llext, LLEXT_MEM_DATA,
&hdr, NULL, NULL);
mctx->segment[LIB_MANAGER_DATA].addr = hdr->sh_addr;
mctx->segment[LIB_MANAGER_DATA].size = hdr->sh_size;

tr_dbg(&lib_manager_tr, ".data: start: %#lx size %#x",
mctx->segment[LIB_MANAGER_DATA].addr,
mctx->segment[LIB_MANAGER_DATA].size);

*buildinfo = NULL;
ssize_t binfo_o = llext_find_section(&ebl->loader, ".mod_buildinfo");

if (binfo_o >= 0)
*buildinfo = llext_peek(&ebl->loader, binfo_o);
ret = llext_section_shndx(&ebl->loader, md->llext, ".mod_buildinfo");
if (ret >= 0) {
llext_get_section_info(&ebl->loader, md->llext, ret, &hdr, NULL, NULL);
*buildinfo = llext_peek(&ebl->loader, hdr->sh_offset);
}

*mod_manifest = NULL;
ssize_t mod_o = llext_find_section(&ebl->loader, ".module");
ret = llext_section_shndx(&ebl->loader, md->llext, ".module");
if (ret >= 0) {
llext_get_section_info(&ebl->loader, md->llext, ret, &hdr, NULL, NULL);
*mod_manifest = llext_peek(&ebl->loader, hdr->sh_offset);
}

if (mod_o >= 0)
*mod_manifest = llext_peek(&ebl->loader, mod_o);
llext_free_inspection_data(&ebl->loader, md->llext);

return buildinfo && mod_manifest ? 0 : -EPROTO;
}
Expand Down

0 comments on commit 590efbb

Please sign in to comment.