-
Notifications
You must be signed in to change notification settings - Fork 349
library_manager: Update module load flow #8544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,11 +51,12 @@ static struct ext_library loader_ext_lib; | |
|
|
||
| #define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE | ||
|
|
||
| static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_addr, | ||
| uint32_t size, uint32_t flags) | ||
| static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_addr, uint32_t size, | ||
| uint32_t flags) | ||
| { | ||
| int ret = sys_mm_drv_map_region((__sparse_force void *)vma, POINTER_TO_UINT(NULL), | ||
| size, flags); | ||
| /* Region must be first mapped as writable in order to initialize its contents. */ | ||
| int ret = sys_mm_drv_map_region((__sparse_force void *)vma, POINTER_TO_UINT(NULL), size, | ||
| flags | SYS_MM_MEM_PERM_RW); | ||
| if (ret < 0) | ||
| return ret; | ||
|
|
||
|
|
@@ -65,119 +66,144 @@ static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_ | |
|
|
||
| dcache_writeback_region(vma, size); | ||
|
|
||
| /* TODO: Change attributes for memory to FLAGS */ | ||
| /* TODO: Change attributes for memory to FLAGS. Implementation of required function in tlb | ||
| * driver is in progress. | ||
| * sys_mm_drv_update_region_flags(vma, size, flags); | ||
| */ | ||
| return 0; | ||
| } | ||
|
|
||
| static int lib_manager_load_module(uint32_t module_id, struct sof_man_module *mod, | ||
| struct sof_man_fw_desc *desc) | ||
| static int lib_manager_load_module(const uint32_t module_id, | ||
| const struct sof_man_module *const mod) | ||
| { | ||
| struct ext_library *ext_lib = ext_lib_get(); | ||
| uint32_t lib_id = LIB_MANAGER_GET_LIB_ID(module_id); | ||
| size_t load_offset = (size_t)((void *)ext_lib->desc[lib_id]); | ||
| void __sparse_cache *va_base_text = (void __sparse_cache *) | ||
| mod->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr; | ||
| void *src_txt = (void *)(mod->segment[SOF_MAN_SEGMENT_TEXT].file_offset + load_offset); | ||
| size_t st_text_size = mod->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length; | ||
| void __sparse_cache *va_base_rodata = (void __sparse_cache *) | ||
| mod->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr; | ||
| void *src_rodata = | ||
| (void *)(mod->segment[SOF_MAN_SEGMENT_RODATA].file_offset + load_offset); | ||
| size_t st_rodata_size = mod->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length; | ||
| const struct ext_library *const ext_lib = ext_lib_get(); | ||
| const uint32_t lib_id = LIB_MANAGER_GET_LIB_ID(module_id); | ||
| const uintptr_t load_offset = POINTER_TO_UINT(ext_lib->desc[lib_id]); | ||
| void *src; | ||
| void __sparse_cache *va_base; | ||
| size_t size; | ||
| uint32_t flags; | ||
| int ret, idx; | ||
|
|
||
| for (idx = 0; idx < ARRAY_SIZE(mod->segment); ++idx) { | ||
| if (!mod->segment[idx].flags.r.load) | ||
| continue; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this skips .bss, so effectively you made a loop for 2 elements. Should we go a step further and integrate .bss here too by either copying data for .data and .text or clearing the buffer for .bss?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lyakh The .bss section is handled differently. Its size is divided by the maximum number of module instances and only the selected fragment for a given instance is mapped.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well, that special .bss handling seems strange to me - it's too ad-hoc IMHO. This means, that you cannot have the same file used both as a loadable module and built-in, because its .bss will be handled differently. Besides it's too special - developers would need to think about it every time they put something in .bss. We discussed this with @pjdobrowolski briefly and maybe we can and should drop that behaviour.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @softwarecki @lyakh any update here, should we put a big inline comment here spelling out this difference and its expected behavior from ROM i.e. its done for current compatibility reasons
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any communication between modules, build-in or loadable should be done by using native-system-services. I'm no sure if making shared bss is good practice for such behavior. Especially if we load and unload modules on fly, what will happen with common bss? Each module will leave it own stuff in there until we will have an overflow/
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DSP has restricted 3MB of ram which is shared between modules. BSS is defining how much of we use. Can you explain me how removing BSS sections from elf will improve working on such small space?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lyakh You wrote: "This means, that you cannot have the same file used both as a loadable module and built-in...". Where you see use case to have the same code used as loadable and built-in at the same time? I think we do loadable to not have given module built into base FW all the time.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pjdobrowolski @jxstelter I think there's some confusion here. I'm not proposing to remove .bss or to share .bss between modules or anything special of that kind. I just propose to do what C does: you program and it's placed in .bss and it's available there to that file (because it's and it's also in .bss and accessible globally. In all cases there's exactly 1 copy of that object. What I don't understand why loadable modules are linking those objects with module instances. That means, that e.g. if you make volume a loadable module. And you activate 3 pipelines and each of them has a volume component in it so you have 3 instances. So then you give to each instance i.e. to each volume component in each pipeline a separate part of that .bss, i.e. a part of those objects. I understand why it is done, but I don't find this a good idea. It is done to "emulate" a poor-man allocation, so you want to put something like in those modules and then give each instance one of those objects. But I don't find that a good approach. I think it's confusing and misinterpreting the meaning of the ELF .bss section
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you would look more carefully in history of commits, you would find out, that connecting .bss with instances was introduce much before idea of "poor-man allocation".
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, so I think we probably need to make relationship between bss and instances more visible with inline comments in the code here, this way we can avoid any misunderstandings as we continue and add logic for services API and IADK modules. |
||
|
|
||
| flags = 0; | ||
|
|
||
| if (mod->segment[idx].flags.r.code) | ||
| flags = SYS_MM_MEM_PERM_EXEC; | ||
| else if (!mod->segment[idx].flags.r.readonly) | ||
| flags = SYS_MM_MEM_PERM_RW; | ||
|
|
||
| src = UINT_TO_POINTER(mod->segment[idx].file_offset + load_offset); | ||
| va_base = (void __sparse_cache *)UINT_TO_POINTER(mod->segment[idx].v_base_addr); | ||
| size = mod->segment[idx].flags.r.length * PAGE_SZ; | ||
| ret = lib_manager_load_data_from_storage(va_base, src, size, flags); | ||
| if (ret < 0) | ||
| goto err; | ||
| } | ||
|
|
||
| return 0; | ||
|
|
||
| err: | ||
| for (--idx; idx >= 0; --idx) { | ||
| if (!mod->segment[idx].flags.r.load) | ||
| continue; | ||
|
|
||
| va_base = (void __sparse_cache *)UINT_TO_POINTER(mod->segment[idx].v_base_addr); | ||
| size = mod->segment[idx].flags.r.length * PAGE_SZ; | ||
| sys_mm_drv_unmap_region((__sparse_force void *)va_base, size); | ||
| } | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
| static int lib_manager_unload_module(const struct sof_man_module *const mod) | ||
| { | ||
| void __sparse_cache *va_base; | ||
| size_t size; | ||
| uint32_t idx; | ||
| int ret; | ||
|
|
||
| st_text_size = st_text_size * PAGE_SZ; | ||
| st_rodata_size = st_rodata_size * PAGE_SZ; | ||
| for (idx = 0; idx < ARRAY_SIZE(mod->segment); ++idx) { | ||
| if (!mod->segment[idx].flags.r.load) | ||
| continue; | ||
|
|
||
| /* Copy Code */ | ||
| ret = lib_manager_load_data_from_storage(va_base_text, src_txt, st_text_size, | ||
| SYS_MM_MEM_PERM_RW | SYS_MM_MEM_PERM_EXEC); | ||
| if (ret < 0) | ||
| goto err; | ||
| va_base = (void __sparse_cache *)UINT_TO_POINTER(mod->segment[idx].v_base_addr); | ||
| size = mod->segment[idx].flags.r.length * PAGE_SZ; | ||
| ret = sys_mm_drv_unmap_region((__sparse_force void *)va_base, size); | ||
| if (ret < 0) | ||
| return ret; | ||
| } | ||
|
|
||
| /* Copy RODATA */ | ||
| ret = lib_manager_load_data_from_storage(va_base_rodata, src_rodata, | ||
| st_rodata_size, SYS_MM_MEM_PERM_RW); | ||
| if (ret < 0) | ||
| goto err; | ||
| return 0; | ||
| } | ||
|
|
||
| /* There are modules marked as lib_code. This is code shared between several modules inside | ||
| * the library. Load all lib_code modules with first none lib_code module load. | ||
| */ | ||
| if (!mod->type.lib_code) | ||
| ext_lib->mods_exec_load_cnt++; | ||
|
|
||
| if (ext_lib->mods_exec_load_cnt == 1) { | ||
| struct sof_man_module *module_entry = | ||
| (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); | ||
| for (size_t idx = 0; idx < desc->header.num_module_entries; | ||
| ++idx, ++module_entry) { | ||
| if (module_entry->type.lib_code) { | ||
| ret = lib_manager_load_module(lib_id << LIB_MANAGER_LIB_ID_SHIFT | | ||
| idx, mod, desc); | ||
| if (ret < 0) | ||
| goto err; | ||
| } | ||
| #ifdef CONFIG_LIBCODE_MODULE_SUPPORT | ||
| /* There are modules marked as lib_code. This is code shared between several modules inside | ||
| * the library. Load all lib_code modules with first none lib_code module load. | ||
| */ | ||
| static int lib_manager_load_libcode_modules(const uint32_t module_id, | ||
| const struct sof_man_fw_desc *const desc) | ||
| { | ||
| struct ext_library *const ext_lib = ext_lib_get(); | ||
| const struct sof_man_module *module_entry = (struct sof_man_module *) | ||
| ((char *)desc + SOF_MAN_MODULE_OFFSET(0)); | ||
| const uint32_t lib_id = LIB_MANAGER_GET_LIB_ID(module_id); | ||
| int ret, idx; | ||
|
|
||
| if (++ext_lib->mods_exec_load_cnt > 1) | ||
| return 0; | ||
|
|
||
| for (idx = 0; idx < desc->header.num_module_entries; ++idx, ++module_entry) { | ||
| if (module_entry->type.lib_code) { | ||
| ret = lib_manager_load_module(lib_id << LIB_MANAGER_LIB_ID_SHIFT | idx, | ||
| module_entry); | ||
| if (ret < 0) | ||
| goto err; | ||
| } | ||
| } | ||
|
|
||
| return 0; | ||
|
|
||
| err: | ||
| sys_mm_drv_unmap_region((__sparse_force void *)va_base_text, st_text_size); | ||
| sys_mm_drv_unmap_region((__sparse_force void *)va_base_rodata, st_rodata_size); | ||
| for (--idx, --module_entry; idx >= 0; --idx, --module_entry) { | ||
| if (module_entry->type.lib_code) { | ||
| ret = lib_manager_unload_module(module_entry); | ||
| if (ret < 0) | ||
| goto err; | ||
| } | ||
| } | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
| static int lib_manager_unload_module(uint32_t module_id, struct sof_man_module *mod, | ||
| struct sof_man_fw_desc *desc) | ||
| /* There are modules marked as lib_code. This is code shared between several modules inside | ||
| * the library. Unload all lib_code modules with last none lib_code module unload. | ||
| */ | ||
| static int lib_manager_unload_libcode_modules(const uint32_t module_id, | ||
softwarecki marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const struct sof_man_fw_desc *const desc) | ||
| { | ||
| struct ext_library *ext_lib = ext_lib_get(); | ||
| uint32_t lib_id = LIB_MANAGER_GET_LIB_ID(module_id); | ||
| void __sparse_cache *va_base_text = (void __sparse_cache *) | ||
| mod->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr; | ||
| size_t st_text_size = mod->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length; | ||
| void __sparse_cache *va_base_rodata = (void __sparse_cache *) | ||
| mod->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr; | ||
| size_t st_rodata_size = mod->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length; | ||
| int ret; | ||
| struct ext_library *const ext_lib = ext_lib_get(); | ||
| const struct sof_man_module *module_entry = (struct sof_man_module *) | ||
| ((char *)desc + SOF_MAN_MODULE_OFFSET(0)); | ||
| int ret, idx; | ||
|
|
||
| st_text_size = st_text_size * PAGE_SZ; | ||
| st_rodata_size = st_rodata_size * PAGE_SZ; | ||
|
|
||
| ret = sys_mm_drv_unmap_region((__sparse_force void *)va_base_text, st_text_size); | ||
| if (ret < 0) | ||
| return ret; | ||
|
|
||
| ret = sys_mm_drv_unmap_region((__sparse_force void *)va_base_rodata, st_rodata_size); | ||
| if (ret < 0) | ||
| return ret; | ||
|
|
||
| /* There are modules marked as lib_code. This is code shared between several modules inside | ||
| * the library. Unload all lib_code modules with last none lib_code module unload. | ||
| */ | ||
| if (mod->type.lib_code) | ||
| return ret; | ||
| if (--ext_lib->mods_exec_load_cnt > 0) | ||
| return 0; | ||
|
|
||
| if (!mod->type.lib_code && ext_lib->mods_exec_load_cnt > 0) | ||
| ext_lib->mods_exec_load_cnt--; | ||
|
|
||
| if (ext_lib->mods_exec_load_cnt == 0) { | ||
| struct sof_man_module *module_entry = | ||
| (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(0)); | ||
| for (size_t idx = 0; idx < desc->header.num_module_entries; | ||
| ++idx, ++module_entry) { | ||
| if (module_entry->type.lib_code) { | ||
| ret = | ||
| lib_manager_unload_module(lib_id << LIB_MANAGER_LIB_ID_SHIFT | | ||
| idx, mod, desc); | ||
| } | ||
| for (idx = 0; idx < desc->header.num_module_entries; ++idx, ++module_entry) { | ||
| if (module_entry->type.lib_code) { | ||
| ret = lib_manager_unload_module(module_entry); | ||
| if (ret < 0) | ||
| return ret; | ||
| } | ||
| } | ||
|
|
||
| return ret; | ||
| return 0; | ||
| } | ||
| #endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ | ||
|
|
||
| static void __sparse_cache *lib_manager_get_instance_bss_address(uint32_t module_id, | ||
| uint32_t instance_id, | ||
|
|
@@ -262,18 +288,31 @@ uint32_t lib_manager_allocate_module(const struct comp_driver *drv, | |
|
|
||
| mod = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(entry_index)); | ||
|
|
||
| ret = lib_manager_load_module(module_id, mod, desc); | ||
| ret = lib_manager_load_module(module_id, mod); | ||
| if (ret < 0) | ||
| return 0; | ||
|
|
||
| #ifdef CONFIG_LIBCODE_MODULE_SUPPORT | ||
| ret = lib_manager_load_libcode_modules(module_id, desc); | ||
| if (ret < 0) | ||
| goto err; | ||
| #endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ | ||
|
|
||
| ret = lib_manager_allocate_module_instance(module_id, IPC4_INST_ID(ipc_config->id), | ||
| base_cfg->is_pages, mod); | ||
| if (ret < 0) { | ||
| tr_err(&lib_manager_tr, | ||
| "lib_manager_allocate_module(): module allocation failed: %d", ret); | ||
| return 0; | ||
| #ifdef CONFIG_LIBCODE_MODULE_SUPPORT | ||
| lib_manager_unload_libcode_modules(module_id, desc); | ||
| #endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ | ||
| goto err; | ||
| } | ||
| return mod->entry_point; | ||
|
|
||
| err: | ||
| lib_manager_unload_module(mod); | ||
| return 0; | ||
| } | ||
|
|
||
| int lib_manager_free_module(const struct comp_driver *drv, | ||
|
|
@@ -290,9 +329,15 @@ int lib_manager_free_module(const struct comp_driver *drv, | |
| desc = lib_manager_get_library_module_desc(module_id); | ||
| mod = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(entry_index)); | ||
|
|
||
| ret = lib_manager_unload_module(module_id, mod, desc); | ||
| ret = lib_manager_unload_module(mod); | ||
| if (ret < 0) | ||
| return ret; | ||
|
|
||
| #ifdef CONFIG_LIBCODE_MODULE_SUPPORT | ||
| ret = lib_manager_unload_libcode_modules(module_id, desc); | ||
| if (ret < 0) | ||
| return ret; | ||
| #endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ | ||
|
|
||
| ret = lib_manager_free_module_instance(module_id, IPC4_INST_ID(ipc_config->id), mod); | ||
| if (ret < 0) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.