Skip to content

Commit 67ebb10

Browse files
pillo79lgirdwood
authored andcommitted
llext_manager: convert to use new LLEXT inspection API
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. NOTE: Once loaded the first time, the extensions are never unloaded, so the inspection data is also never freed. If this behavior needs to be modified to allow extensions to be fully removed from memory, the inspection data in the loader must be freed as well by calling the llext_free_inspection_data() function before the final llext_unload(). Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
1 parent 5a4a38c commit 67ebb10

File tree

1 file changed

+73
-42
lines changed

1 file changed

+73
-42
lines changed

src/library_manager/llext_manager.c

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <zephyr/llext/loader.h>
3030
#include <zephyr/llext/llext.h>
3131
#include <zephyr/logging/log_ctrl.h>
32+
#include <zephyr/llext/inspect.h>
3233

3334
#include <rimage/sof/user/manifest.h>
3435
#include <module/module/api_ver.h>
@@ -70,40 +71,49 @@ static int llext_manager_align_unmap(void __sparse_cache *vma, size_t size)
7071
return sys_mm_drv_unmap_region(aligned_vma, ALIGN_UP(pre_pad_size + size, PAGE_SZ));
7172
}
7273

73-
static int llext_manager_load_data_from_storage(const struct llext *ext,
74+
/*
75+
* Map the memory range covered by 'vma' and 'size' as writable, copy all
76+
* sections that belong to the specified 'region' and are contained in the
77+
* memory range, then remap the same area according to the 'flags' parameter.
78+
*/
79+
static int llext_manager_load_data_from_storage(const struct llext_loader *ldr,
80+
const struct llext *ext,
81+
enum llext_mem region,
7482
void __sparse_cache *vma,
75-
const uint8_t *load_base,
7683
size_t size, uint32_t flags)
7784
{
7885
unsigned int i;
86+
const void *region_addr;
7987
int ret = llext_manager_align_map(vma, size, SYS_MM_MEM_PERM_RW);
80-
const elf_shdr_t *shdr;
8188

8289
if (ret < 0) {
8390
tr_err(&lib_manager_tr, "cannot map %u of %p", size, (__sparse_force void *)vma);
8491
return ret;
8592
}
8693

87-
size_t init_offset = 0;
94+
llext_get_region_info(ldr, ext, region, NULL, &region_addr, NULL);
8895

8996
/* Need to copy sections within regions individually, offsets may differ */
90-
for (i = 0, shdr = llext_section_headers(ext); i < llext_section_count(ext); i++, shdr++) {
97+
for (i = 0; i < llext_section_count(ext); i++) {
98+
const elf_shdr_t *shdr;
99+
enum llext_mem s_region = LLEXT_MEM_COUNT;
100+
size_t s_offset = 0;
101+
102+
llext_get_section_info(ldr, ext, i, &shdr, &s_region, &s_offset);
103+
104+
/* skip sections not in the requested region */
105+
if (s_region != region)
106+
continue;
107+
108+
/* skip detached sections (will be outside requested VMA area) */
91109
if ((uintptr_t)shdr->sh_addr < (uintptr_t)vma ||
92110
(uintptr_t)shdr->sh_addr >= (uintptr_t)vma + size)
93111
continue;
94112

95-
if (!init_offset)
96-
init_offset = shdr->sh_offset;
97-
98-
/* found a section within the region */
99-
size_t offset = shdr->sh_offset - init_offset;
100-
101-
if (shdr->sh_type != SHT_NOBITS) {
102-
ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - offset,
103-
load_base + offset, shdr->sh_size);
104-
if (ret < 0)
105-
return ret;
106-
}
113+
ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - s_offset,
114+
(const uint8_t *)region_addr + s_offset, shdr->sh_size);
115+
if (ret < 0)
116+
return ret;
107117
}
108118

109119
/*
@@ -165,23 +175,29 @@ static int llext_manager_load_module(struct lib_manager_module *mctx)
165175
}
166176
}
167177

178+
const struct llext_loader *ldr = &mctx->ebl->loader;
168179
const struct llext *ext = mctx->llext;
169180

170181
/* Copy Code */
171-
ret = llext_manager_load_data_from_storage(ext, va_base_text, ext->mem[LLEXT_MEM_TEXT],
172-
text_size, SYS_MM_MEM_PERM_EXEC);
182+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_TEXT,
183+
va_base_text, text_size, SYS_MM_MEM_PERM_EXEC);
173184
if (ret < 0)
174185
return ret;
175186

176187
/* Copy read-only data */
177-
ret = llext_manager_load_data_from_storage(ext, va_base_rodata, ext->mem[LLEXT_MEM_RODATA],
178-
rodata_size, 0);
188+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_RODATA,
189+
va_base_rodata, rodata_size, 0);
179190
if (ret < 0)
180191
goto e_text;
181192

182193
/* Copy writable data */
183-
ret = llext_manager_load_data_from_storage(ext, va_base_data, ext->mem[LLEXT_MEM_DATA],
184-
data_size, SYS_MM_MEM_PERM_RW);
194+
/*
195+
* NOTE: va_base_data and data_size refer to an address range that
196+
* spans over the BSS area as well, so the mapping will cover
197+
* both, but only LLEXT_MEM_DATA sections will be copied.
198+
*/
199+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_DATA,
200+
va_base_data, data_size, SYS_MM_MEM_PERM_RW);
185201
if (ret < 0)
186202
goto e_rodata;
187203

@@ -244,6 +260,7 @@ static int llext_manager_link(const char *name,
244260
{
245261
struct llext **llext = &mctx->llext;
246262
struct llext_loader *ldr = &mctx->ebl->loader;
263+
const elf_shdr_t *hdr;
247264
int ret;
248265

249266
if (*llext && !mctx->mapped) {
@@ -267,56 +284,63 @@ static int llext_manager_link(const char *name,
267284
.relocate_local = !*llext,
268285
.pre_located = true,
269286
.section_detached = llext_manager_section_detached,
287+
.keep_section_info = true,
270288
};
271289

272290
ret = llext_load(ldr, name, llext, &ldr_parm);
273291
if (ret)
274292
return ret;
275293
}
276294

277-
mctx->segment[LIB_MANAGER_TEXT].addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr;
278-
mctx->segment[LIB_MANAGER_TEXT].size = ldr->sects[LLEXT_MEM_TEXT].sh_size;
295+
/* All code sections */
296+
llext_get_region_info(ldr, *llext, LLEXT_MEM_TEXT, &hdr, NULL, NULL);
297+
mctx->segment[LIB_MANAGER_TEXT].addr = hdr->sh_addr;
298+
mctx->segment[LIB_MANAGER_TEXT].size = hdr->sh_size;
279299

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

284304
/* All read-only data sections */
285-
mctx->segment[LIB_MANAGER_RODATA].addr =
286-
ldr->sects[LLEXT_MEM_RODATA].sh_addr;
287-
mctx->segment[LIB_MANAGER_RODATA].size = ldr->sects[LLEXT_MEM_RODATA].sh_size;
305+
llext_get_region_info(ldr, *llext, LLEXT_MEM_RODATA, &hdr, NULL, NULL);
306+
mctx->segment[LIB_MANAGER_RODATA].addr = hdr->sh_addr;
307+
mctx->segment[LIB_MANAGER_RODATA].size = hdr->sh_size;
288308

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

293313
/* All writable data sections */
294-
mctx->segment[LIB_MANAGER_DATA].addr =
295-
ldr->sects[LLEXT_MEM_DATA].sh_addr;
296-
mctx->segment[LIB_MANAGER_DATA].size = ldr->sects[LLEXT_MEM_DATA].sh_size;
314+
llext_get_region_info(ldr, *llext, LLEXT_MEM_DATA, &hdr, NULL, NULL);
315+
mctx->segment[LIB_MANAGER_DATA].addr = hdr->sh_addr;
316+
mctx->segment[LIB_MANAGER_DATA].size = hdr->sh_size;
297317

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

302-
mctx->segment[LIB_MANAGER_BSS].addr = ldr->sects[LLEXT_MEM_BSS].sh_addr;
303-
mctx->segment[LIB_MANAGER_BSS].size = ldr->sects[LLEXT_MEM_BSS].sh_size;
322+
/* Writable uninitialized data section */
323+
llext_get_region_info(ldr, *llext, LLEXT_MEM_BSS, &hdr, NULL, NULL);
324+
mctx->segment[LIB_MANAGER_BSS].addr = hdr->sh_addr;
325+
mctx->segment[LIB_MANAGER_BSS].size = hdr->sh_size;
304326

305327
tr_dbg(&lib_manager_tr, ".bss: start: %#lx size %#x",
306328
mctx->segment[LIB_MANAGER_BSS].addr,
307329
mctx->segment[LIB_MANAGER_BSS].size);
308330

309331
*buildinfo = NULL;
310-
ssize_t binfo_o = llext_find_section(ldr, ".mod_buildinfo");
311-
312-
if (binfo_o >= 0)
313-
*buildinfo = llext_peek(ldr, binfo_o);
332+
ret = llext_section_shndx(ldr, *llext, ".mod_buildinfo");
333+
if (ret >= 0) {
334+
llext_get_section_info(ldr, *llext, ret, &hdr, NULL, NULL);
335+
*buildinfo = llext_peek(ldr, hdr->sh_offset);
336+
}
314337

315338
*mod_manifest = NULL;
316-
ssize_t mod_o = llext_find_section(ldr, ".module");
317-
318-
if (mod_o >= 0)
319-
*mod_manifest = llext_peek(ldr, mod_o);
339+
ret = llext_section_shndx(ldr, *llext, ".module");
340+
if (ret >= 0) {
341+
llext_get_section_info(ldr, *llext, ret, &hdr, NULL, NULL);
342+
*mod_manifest = llext_peek(ldr, hdr->sh_offset);
343+
}
320344

321345
return *buildinfo && *mod_manifest ? 0 : -EPROTO;
322346
}
@@ -618,7 +642,14 @@ int llext_manager_free_module(const uint32_t component_id)
618642

619643
/* Protected by IPC serialization */
620644
if (mctx->llext->use_count > 1) {
621-
/* llext_unload() will return a positive number */
645+
/*
646+
* At least 2 users: llext_unload() will never actually free
647+
* the extension but only reduce the refcount and return its
648+
* new value (must be a positive number).
649+
* NOTE: if this is modified to allow extension unload, the
650+
* inspection data in the loader must be freed as well by
651+
* calling the llext_free_inspection_data() function.
652+
*/
622653
int ret = llext_unload(&mctx->llext);
623654

624655
if (ret <= 0) {

0 commit comments

Comments
 (0)