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