3737#include <stddef.h>
3838#include <stdint.h>
3939
40- /*
41- * FIXME: this definition is copied from tools/rimage/src/include/rimage/manifest.h
42- * which we cannot easily include here, because it also pulls in
43- * tools/rimage/src/include/rimage/elf.h which then conflicts with
44- * zephyr/include/zephyr/llext/elf.h
45- */
46- #define FILE_TEXT_OFFSET_V1_8 0x8000
47-
4840LOG_MODULE_DECLARE (lib_manager , CONFIG_SOF_LOG_LEVEL );
4941
5042extern struct tr_ctx lib_manager_tr ;
@@ -295,21 +287,48 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx,
295287 const struct sof_man_fw_desc * desc ,
296288 const struct sof_man_module * mod_array )
297289{
290+ unsigned int i , n_mod ;
291+ size_t offs ;
292+
293+ /* count modules */
294+ for (i = 0 , n_mod = 0 , offs = ~0 ; i < desc -> header .num_module_entries ; i ++ )
295+ if (mod_array [i ].segment [LIB_MANAGER_TEXT ].file_offset != offs ) {
296+ offs = mod_array [i ].segment [LIB_MANAGER_TEXT ].file_offset ;
297+ n_mod ++ ;
298+ }
299+
298300 /*
299301 * Loadable modules are loaded to DRAM once and never unloaded from it.
300302 * Context, related to them, is never freed
301303 */
302304 ctx -> mod = rmalloc (SOF_MEM_ZONE_RUNTIME_SHARED , SOF_MEM_FLAG_COHERENT ,
303- SOF_MEM_CAPS_RAM , sizeof (ctx -> mod [0 ]));
305+ SOF_MEM_CAPS_RAM , n_mod * sizeof (ctx -> mod [0 ]));
304306 if (!ctx -> mod )
305307 return - ENOMEM ;
306308
307- ctx -> n_mod = 1 ;
308- ctx -> mod [0 ].start_idx = 0 ;
309+ ctx -> n_mod = n_mod ;
310+
311+ for (i = 0 , n_mod = 0 , offs = ~0 ; i < desc -> header .num_module_entries ; i ++ )
312+ if (mod_array [i ].segment [LIB_MANAGER_TEXT ].file_offset != offs ) {
313+ offs = mod_array [i ].segment [LIB_MANAGER_TEXT ].file_offset ;
314+ ctx -> mod [n_mod ].segment [LIB_MANAGER_TEXT ].size = 0 ;
315+ ctx -> mod [n_mod ++ ].start_idx = i ;
316+ }
309317
310318 return 0 ;
311319}
312320
321+ static unsigned int llext_manager_mod_find (const struct lib_manager_mod_ctx * ctx , unsigned int idx )
322+ {
323+ unsigned int i ;
324+
325+ for (i = 0 ; i < ctx -> n_mod ; i ++ )
326+ if (ctx -> mod [i ].start_idx > idx )
327+ break ;
328+
329+ return i - 1 ;
330+ }
331+
313332uintptr_t llext_manager_allocate_module (struct processing_module * proc ,
314333 const struct comp_ipc_config * ipc_config ,
315334 const void * ipc_specific_config )
@@ -325,25 +344,70 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc,
325344
326345 struct sof_man_module * mod_array = (struct sof_man_module * )((char * )desc +
327346 SOF_MAN_MODULE_OFFSET (0 ));
328- size_t mod_size = desc -> header .preload_page_count * PAGE_SZ - FILE_TEXT_OFFSET_V1_8 ;
329- uintptr_t dram_base = (uintptr_t )desc - SOF_MAN_ELF_TEXT_OFFSET ;
330- struct llext_buf_loader ebl = LLEXT_BUF_LOADER ((uint8_t * )dram_base + FILE_TEXT_OFFSET_V1_8 ,
331- mod_size );
332347 uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX (module_id );
348+ size_t mod_offset = mod_array [entry_index ].segment [LIB_MANAGER_TEXT ].file_offset ;
333349 const struct sof_man_module_manifest * mod_manifest ;
334350 const struct sof_module_api_build_info * buildinfo ;
335351 struct module_data * md = & proc -> priv ;
352+ size_t mod_size ;
353+ int i , inst_idx ;
336354 int ret ;
337355
338356 tr_dbg (& lib_manager_tr , "mod_id: %#x" , ipc_config -> id );
339357
340358 if (!ctx -> mod )
341359 llext_manager_mod_init (ctx , desc , mod_array );
342360
343- struct lib_manager_module * mctx = ctx -> mod ;
361+ if (entry_index >= desc -> header .num_module_entries ) {
362+ tr_err (& lib_manager_tr , "Invalid driver index %u exceeds %d" ,
363+ entry_index , desc -> header .num_module_entries - 1 );
364+ return 0 ;
365+ }
344366
345- /* LLEXT linking is only needed once for all the modules in the library */
346- ret = llext_manager_link (& ebl , mod_array [0 ].name , module_id , md ,
367+ unsigned int mod_idx = llext_manager_mod_find (ctx , entry_index );
368+ struct lib_manager_module * mctx = ctx -> mod + mod_idx ;
369+
370+ /*
371+ * We don't know the number of ELF files that this library is built of.
372+ * We know the number of module drivers, but each of those ELF files can
373+ * also contain multiple such drivers. Each driver brings two copies of
374+ * its manifest with it: one in the ".module" ELF section and one in an
375+ * array of manifests at the beginning of the library. This latter array
376+ * is created from a TOML configuration file. The order is preserved -
377+ * this is guaranteed by rimage.
378+ * All module drivers within a single ELF file have equal .file_offset,
379+ * this makes it possible to find borders between them.
380+ * We know the global index of the requested driver in that array, but
381+ * we need to find the matching manifest in ".module" because only it
382+ * contains the entry point. For safety we calculate the ELF driver
383+ * index and then also check the driver name.
384+ * We also need the driver size. For this we search the manifest array
385+ * for the next ELF file, then the difference between offsets gives us
386+ * the driver size.
387+ */
388+ for (i = entry_index - 1 ; i >= 0 ; i -- )
389+ if (mod_array [i ].segment [LIB_MANAGER_TEXT ].file_offset != mod_offset )
390+ break ;
391+
392+ /* Driver index within a single module */
393+ inst_idx = entry_index - i - 1 ;
394+
395+ /* Find the next module or stop at the end */
396+ for (i = entry_index + 1 ; i < desc -> header .num_module_entries ; i ++ )
397+ if (mod_array [i ].segment [LIB_MANAGER_TEXT ].file_offset != mod_offset )
398+ break ;
399+
400+ if (i == desc -> header .num_module_entries )
401+ mod_size = desc -> header .preload_page_count * PAGE_SZ - mod_offset ;
402+ else
403+ mod_size = ALIGN_UP (mod_array [i ].segment [LIB_MANAGER_TEXT ].file_offset - mod_offset ,
404+ PAGE_SZ );
405+
406+ uintptr_t dram_base = (uintptr_t )desc - SOF_MAN_ELF_TEXT_OFFSET ;
407+ struct llext_buf_loader ebl = LLEXT_BUF_LOADER ((uint8_t * )dram_base + mod_offset , mod_size );
408+
409+ /* LLEXT linking is only needed once for all the drivers in each module */
410+ ret = llext_manager_link (& ebl , mod_array [entry_index - inst_idx ].name , mctx , md ,
347411 (const void * * )& buildinfo , & mod_manifest );
348412 if (ret < 0 ) {
349413 tr_err (& lib_manager_tr , "linking failed: %d" , ret );
@@ -367,16 +431,31 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc,
367431 mctx -> mod_manifest = mod_manifest ;
368432 }
369433
370- return mctx -> mod_manifest [entry_index ].module .entry_point ;
434+ if (strncmp (mod_array [entry_index ].name , mctx -> mod_manifest [inst_idx ].module .name ,
435+ sizeof (mod_array [0 ].name ))) {
436+ tr_err (& lib_manager_tr , "Name mismatch %s vs. %s" ,
437+ mod_array [entry_index ].name , mctx -> mod_manifest [inst_idx ].module .name );
438+ return 0 ;
439+ }
440+
441+ return mctx -> mod_manifest [inst_idx ].module .entry_point ;
371442}
372443
373444int llext_manager_free_module (const uint32_t component_id )
374445{
375446 const uint32_t module_id = IPC4_MOD_ID (component_id );
447+ struct sof_man_fw_desc * desc = (struct sof_man_fw_desc * )lib_manager_get_library_manifest (module_id );
376448 struct lib_manager_mod_ctx * ctx = lib_manager_get_mod_ctx (module_id );
377- const unsigned int base_module_id = LIB_MANAGER_GET_LIB_ID (module_id ) <<
378- LIB_MANAGER_LIB_ID_SHIFT ;
379- struct lib_manager_module * mctx = ctx -> mod ;
449+ uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX (module_id );
450+
451+ if (entry_index >= desc -> header .num_module_entries ) {
452+ tr_err (& lib_manager_tr , "Invalid driver index %u exceeds %d" ,
453+ entry_index , desc -> header .num_module_entries - 1 );
454+ return - ENOENT ;
455+ }
456+
457+ unsigned int mod_idx = llext_manager_mod_find (ctx , entry_index );
458+ struct lib_manager_module * mctx = ctx -> mod + mod_idx ;
380459
381460 tr_dbg (& lib_manager_tr , "mod_id: %#x" , component_id );
382461
0 commit comments