Skip to content

Commit 23478ef

Browse files
committed
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 <[email protected]>
1 parent 2e829d2 commit 23478ef

File tree

1 file changed

+60
-44
lines changed

1 file changed

+60
-44
lines changed

src/library_manager/llext_manager.c

Lines changed: 60 additions & 44 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,41 +71,39 @@ 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+
static int llext_manager_load_data_from_storage(const struct llext_loader *ldr,
75+
const struct llext *ext,
76+
enum llext_mem region,
7477
void __sparse_cache *vma,
75-
const uint8_t *load_base,
7678
size_t size, uint32_t flags)
7779
{
7880
unsigned int i;
81+
const void *region_addr;
7982
int ret;
80-
const elf_shdr_t *shdr;
8183

8284
ret = llext_manager_align_map(vma, size, SYS_MM_MEM_PERM_RW);
8385
if (ret < 0) {
8486
tr_err(&lib_manager_tr, "cannot map %u of %p", size, (__sparse_force void *)vma);
8587
return ret;
8688
}
8789

88-
size_t init_offset = 0;
90+
llext_get_region_info(ldr, ext, region, NULL, &region_addr, NULL);
8991

9092
/* Need to copy sections within regions individually, offsets may differ */
91-
for (i = 0, shdr = llext_section_headers(ext); i < llext_section_count(ext); i++, shdr++) {
92-
if ((uintptr_t)shdr->sh_addr < (uintptr_t)vma ||
93-
(uintptr_t)shdr->sh_addr >= (uintptr_t)vma + size)
94-
continue;
93+
for (i = 0; i < llext_section_count(ext); i++) {
94+
const elf_shdr_t *shdr;
95+
enum llext_mem s_region = LLEXT_MEM_COUNT;
96+
size_t s_offset = 0;
9597

96-
if (!init_offset)
97-
init_offset = shdr->sh_offset;
98+
llext_get_section_info(ldr, ext, i, &shdr, &s_region, &s_offset);
9899

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

102-
if (shdr->sh_type != SHT_NOBITS) {
103-
ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - offset,
104-
load_base + offset, shdr->sh_size);
105-
if (ret < 0)
106-
return ret;
107-
}
103+
ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - s_offset,
104+
(const uint8_t *)region_addr + s_offset, shdr->sh_size);
105+
if (ret < 0)
106+
return ret;
108107
}
109108

110109
/*
@@ -166,29 +165,31 @@ static int llext_manager_load_module(struct lib_manager_module *mctx)
166165
}
167166
}
168167

168+
const struct llext_loader *ldr = &mctx->ebl->loader;
169169
const struct llext *ext = mctx->llext;
170170

171171
/* Copy Code */
172-
ret = llext_manager_load_data_from_storage(ext, va_base_text, ext->mem[LLEXT_MEM_TEXT],
173-
text_size, SYS_MM_MEM_PERM_EXEC);
172+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_TEXT,
173+
va_base_text, text_size, SYS_MM_MEM_PERM_EXEC);
174174
if (ret < 0)
175175
return ret;
176176

177177
/* Copy read-only data */
178-
ret = llext_manager_load_data_from_storage(ext, va_base_rodata, ext->mem[LLEXT_MEM_RODATA],
179-
rodata_size, 0);
178+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_RODATA,
179+
va_base_rodata, rodata_size, 0);
180180
if (ret < 0)
181181
goto e_text;
182182

183183
/* Copy writable data */
184-
ret = llext_manager_load_data_from_storage(ext, va_base_data, ext->mem[LLEXT_MEM_DATA],
185-
data_size, SYS_MM_MEM_PERM_RW);
184+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_DATA,
185+
va_base_data, data_size, SYS_MM_MEM_PERM_RW);
186186
if (ret < 0)
187187
goto e_rodata;
188188

189+
/* Clear uninitialized data */
189190
memset((__sparse_force void *)bss_addr, 0, bss_size);
190-
mctx->mapped = true;
191191

192+
mctx->mapped = true;
192193
return 0;
193194

194195
e_rodata:
@@ -245,6 +246,7 @@ static int llext_manager_link(const char *name,
245246
{
246247
struct llext **llext = &mctx->llext;
247248
struct llext_loader *ldr = &mctx->ebl->loader;
249+
const elf_shdr_t *hdr;
248250
int ret;
249251

250252
if (*llext && !mctx->mapped) {
@@ -268,56 +270,63 @@ static int llext_manager_link(const char *name,
268270
.relocate_local = !*llext,
269271
.pre_located = true,
270272
.section_detached = llext_manager_section_detached,
273+
.keep_section_info = true,
271274
};
272275

273276
ret = llext_load(ldr, name, llext, &ldr_parm);
274277
if (ret)
275278
return ret;
276279
}
277280

278-
mctx->segment[LIB_MANAGER_TEXT].addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr;
279-
mctx->segment[LIB_MANAGER_TEXT].size = ldr->sects[LLEXT_MEM_TEXT].sh_size;
281+
/* All code sections */
282+
llext_get_region_info(ldr, *llext, LLEXT_MEM_TEXT, &hdr, NULL, NULL);
283+
mctx->segment[LIB_MANAGER_TEXT].addr = hdr->sh_addr;
284+
mctx->segment[LIB_MANAGER_TEXT].size = hdr->sh_size;
280285

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

285290
/* All read-only data sections */
286-
mctx->segment[LIB_MANAGER_RODATA].addr =
287-
ldr->sects[LLEXT_MEM_RODATA].sh_addr;
288-
mctx->segment[LIB_MANAGER_RODATA].size = ldr->sects[LLEXT_MEM_RODATA].sh_size;
291+
llext_get_region_info(ldr, *llext, LLEXT_MEM_RODATA, &hdr, NULL, NULL);
292+
mctx->segment[LIB_MANAGER_RODATA].addr = hdr->sh_addr;
293+
mctx->segment[LIB_MANAGER_RODATA].size = hdr->sh_size;
289294

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

294299
/* All writable data sections */
295-
mctx->segment[LIB_MANAGER_DATA].addr =
296-
ldr->sects[LLEXT_MEM_DATA].sh_addr;
297-
mctx->segment[LIB_MANAGER_DATA].size = ldr->sects[LLEXT_MEM_DATA].sh_size;
300+
llext_get_region_info(ldr, *llext, LLEXT_MEM_DATA, &hdr, NULL, NULL);
301+
mctx->segment[LIB_MANAGER_DATA].addr = hdr->sh_addr;
302+
mctx->segment[LIB_MANAGER_DATA].size = hdr->sh_size;
298303

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

303-
mctx->segment[LIB_MANAGER_BSS].addr = ldr->sects[LLEXT_MEM_BSS].sh_addr;
304-
mctx->segment[LIB_MANAGER_BSS].size = ldr->sects[LLEXT_MEM_BSS].sh_size;
308+
/* Writable uninitialized data section */
309+
llext_get_region_info(ldr, *llext, LLEXT_MEM_BSS, &hdr, NULL, NULL);
310+
mctx->segment[LIB_MANAGER_BSS].addr = hdr->sh_addr;
311+
mctx->segment[LIB_MANAGER_BSS].size = hdr->sh_size;
305312

306313
tr_dbg(&lib_manager_tr, ".bss: start: %#lx size %#x",
307314
mctx->segment[LIB_MANAGER_BSS].addr,
308315
mctx->segment[LIB_MANAGER_BSS].size);
309316

310317
*buildinfo = NULL;
311-
ssize_t binfo_o = llext_find_section(ldr, ".mod_buildinfo");
312-
313-
if (binfo_o >= 0)
314-
*buildinfo = llext_peek(ldr, binfo_o);
318+
ret = llext_section_shndx(ldr, *llext, ".mod_buildinfo");
319+
if (ret >= 0) {
320+
llext_get_section_info(ldr, *llext, ret, &hdr, NULL, NULL);
321+
*buildinfo = llext_peek(ldr, hdr->sh_offset);
322+
}
315323

316324
*mod_manifest = NULL;
317-
ssize_t mod_o = llext_find_section(ldr, ".module");
318-
319-
if (mod_o >= 0)
320-
*mod_manifest = llext_peek(ldr, mod_o);
325+
ret = llext_section_shndx(ldr, *llext, ".module");
326+
if (ret >= 0) {
327+
llext_get_section_info(ldr, *llext, ret, &hdr, NULL, NULL);
328+
*mod_manifest = llext_peek(ldr, hdr->sh_offset);
329+
}
321330

322331
return *buildinfo && *mod_manifest ? 0 : -EPROTO;
323332
}
@@ -622,7 +631,14 @@ int llext_manager_free_module(const uint32_t component_id)
622631

623632
/* Protected by IPC serialization */
624633
if (mctx->llext->use_count > 1) {
625-
/* llext_unload() will return a positive number */
634+
/*
635+
* At least 2 users: llext_unload() will never actually free
636+
* the extension but only reduce the refcount and return its
637+
* new value (must be a positive number).
638+
* NOTE: if this is modified to allow extension unload, the
639+
* inspection data in the loader must be freed as well by
640+
* calling the llext_free_inspection_data() function.
641+
*/
626642
int ret = llext_unload(&mctx->llext);
627643

628644
if (ret <= 0) {

0 commit comments

Comments
 (0)