Skip to content

Commit 09f4d94

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 <l.burelli@arduino.cc>
1 parent 68bcdc5 commit 09f4d94

File tree

1 file changed

+58
-43
lines changed

1 file changed

+58
-43
lines changed

src/library_manager/llext_manager.c

Lines changed: 58 additions & 43 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,38 @@ 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 = llext_manager_align_map(vma, size, SYS_MM_MEM_PERM_RW);
80-
const elf_shdr_t *shdr;
8183

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

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

8991
/* 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++) {
91-
if ((uintptr_t)shdr->sh_addr < (uintptr_t)vma ||
92-
(uintptr_t)shdr->sh_addr >= (uintptr_t)vma + size)
93-
continue;
92+
for (i = 0; i < llext_section_count(ext); i++) {
93+
const elf_shdr_t *shdr;
94+
enum llext_mem s_region = LLEXT_MEM_COUNT;
95+
size_t s_offset = 0;
9496

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

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

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-
}
102+
ret = memcpy_s((__sparse_force void *)shdr->sh_addr, size - s_offset,
103+
(const uint8_t *)region_addr + s_offset, shdr->sh_size);
104+
if (ret < 0)
105+
return ret;
107106
}
108107

109108
/*
@@ -165,23 +164,24 @@ static int llext_manager_load_module(struct lib_manager_module *mctx)
165164
}
166165
}
167166

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

170170
/* 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);
171+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_TEXT,
172+
va_base_text, text_size, SYS_MM_MEM_PERM_EXEC);
173173
if (ret < 0)
174174
return ret;
175175

176176
/* 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);
177+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_RODATA,
178+
va_base_rodata, rodata_size, 0);
179179
if (ret < 0)
180180
goto e_text;
181181

182182
/* 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);
183+
ret = llext_manager_load_data_from_storage(ldr, ext, LLEXT_MEM_DATA,
184+
va_base_data, data_size, SYS_MM_MEM_PERM_RW);
185185
if (ret < 0)
186186
goto e_rodata;
187187

@@ -244,6 +244,7 @@ static int llext_manager_link(const char *name,
244244
{
245245
struct llext **llext = &mctx->llext;
246246
struct llext_loader *ldr = &mctx->ebl->loader;
247+
const elf_shdr_t *hdr;
247248
int ret;
248249

249250
if (*llext && !mctx->mapped) {
@@ -267,56 +268,63 @@ static int llext_manager_link(const char *name,
267268
.relocate_local = !*llext,
268269
.pre_located = true,
269270
.section_detached = llext_manager_section_detached,
271+
.keep_section_info = true,
270272
};
271273

272274
ret = llext_load(ldr, name, llext, &ldr_parm);
273275
if (ret)
274276
return ret;
275277
}
276278

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;
279+
/* All code sections */
280+
llext_get_region_info(ldr, *llext, LLEXT_MEM_TEXT, &hdr, NULL, NULL);
281+
mctx->segment[LIB_MANAGER_TEXT].addr = hdr->sh_addr;
282+
mctx->segment[LIB_MANAGER_TEXT].size = hdr->sh_size;
279283

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

284288
/* 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;
289+
llext_get_region_info(ldr, *llext, LLEXT_MEM_RODATA, &hdr, NULL, NULL);
290+
mctx->segment[LIB_MANAGER_RODATA].addr = hdr->sh_addr;
291+
mctx->segment[LIB_MANAGER_RODATA].size = hdr->sh_size;
288292

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

293297
/* 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;
298+
llext_get_region_info(ldr, *llext, LLEXT_MEM_DATA, &hdr, NULL, NULL);
299+
mctx->segment[LIB_MANAGER_DATA].addr = hdr->sh_addr;
300+
mctx->segment[LIB_MANAGER_DATA].size = hdr->sh_size;
297301

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

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;
306+
/* Writable uninitialized data section */
307+
llext_get_region_info(ldr, *llext, LLEXT_MEM_BSS, &hdr, NULL, NULL);
308+
mctx->segment[LIB_MANAGER_BSS].addr = hdr->sh_addr;
309+
mctx->segment[LIB_MANAGER_BSS].size = hdr->sh_size;
304310

305311
tr_dbg(&lib_manager_tr, ".bss: start: %#lx size %#x",
306312
mctx->segment[LIB_MANAGER_BSS].addr,
307313
mctx->segment[LIB_MANAGER_BSS].size);
308314

309315
*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);
316+
ret = llext_section_shndx(ldr, *llext, ".mod_buildinfo");
317+
if (ret >= 0) {
318+
llext_get_section_info(ldr, *llext, ret, &hdr, NULL, NULL);
319+
*buildinfo = llext_peek(ldr, hdr->sh_offset);
320+
}
314321

315322
*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);
323+
ret = llext_section_shndx(ldr, *llext, ".module");
324+
if (ret >= 0) {
325+
llext_get_section_info(ldr, *llext, ret, &hdr, NULL, NULL);
326+
*mod_manifest = llext_peek(ldr, hdr->sh_offset);
327+
}
320328

321329
return *buildinfo && *mod_manifest ? 0 : -EPROTO;
322330
}
@@ -618,7 +626,14 @@ int llext_manager_free_module(const uint32_t component_id)
618626

619627
/* Protected by IPC serialization */
620628
if (mctx->llext->use_count > 1) {
621-
/* llext_unload() will return a positive number */
629+
/*
630+
* At least 2 users: llext_unload() will never actually free
631+
* the extension but only reduce the refcount and return its
632+
* new value (must be a positive number).
633+
* NOTE: if this is modified to allow extension unload, the
634+
* inspection data in the loader must be freed as well by
635+
* calling the llext_free_inspection_data() function.
636+
*/
622637
int ret = llext_unload(&mctx->llext);
623638

624639
if (ret <= 0) {

0 commit comments

Comments
 (0)