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
194195e_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