diff --git a/src/include/sof/llext_manager.h b/src/include/sof/llext_manager.h new file mode 100644 index 000000000..6d1e90d70 --- /dev/null +++ b/src/include/sof/llext_manager.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Intel Corporation. All rights reserved. + */ + +#ifndef __SOF_LLEXT_MANAGER_H__ +#define __SOF_LLEXT_MANAGER_H__ + +#include + +struct comp_driver; +struct comp_ipc_config; + +uint32_t llext_manager_allocate_module(const struct comp_driver *drv, + struct comp_ipc_config *ipc_config, + const void *ipc_specific_config); +int llext_manager_free_module(const struct comp_driver *drv, + struct comp_ipc_config *ipc_config); + +#endif diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index b07d8db15..7d260d0f7 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -337,6 +338,11 @@ static int lib_manager_free_module_instance(uint32_t module_id, uint32_t instanc return sys_mm_drv_unmap_region((__sparse_force void *)va_base, bss_size); } +static bool module_is_llext(struct sof_man_module *mod) +{ + return mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT; +} + uint32_t lib_manager_allocate_module(const struct comp_driver *drv, struct comp_ipc_config *ipc_config, const void *ipc_specific_config) @@ -360,6 +366,9 @@ uint32_t lib_manager_allocate_module(const struct comp_driver *drv, mod = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(entry_index)); + if (module_is_llext(mod)) + return llext_manager_allocate_module(drv, ipc_config, ipc_specific_config); + ret = lib_manager_load_module(module_id, mod); if (ret < 0) return 0; @@ -401,6 +410,9 @@ 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)); + if (module_is_llext(mod)) + return llext_manager_free_module(drv, ipc_config); + ret = lib_manager_unload_module(mod); if (ret < 0) return ret; diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c new file mode 100644 index 000000000..c68e3bcf5 --- /dev/null +++ b/src/library_manager/llext_manager.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Author: Jaroslaw Stelter +// Pawel Dobrowolski + +/* + * Dynamic module loading functions. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(lib_manager, CONFIG_SOF_LOG_LEVEL); + +extern struct tr_ctx lib_manager_tr; + +#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE + +static int llext_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); + if (ret < 0) + return ret; + + ret = memcpy_s((__sparse_force void *)vma, size, s_addr, size); + if (ret < 0) + return ret; + + dcache_writeback_region(vma, size); + + /* TODO: Change attributes for memory to FLAGS */ + return 0; +} + +static int llext_manager_load_module(uint32_t module_id, struct sof_man_module *mod, + struct sof_man_fw_desc *desc) +{ + 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; + int ret; + + st_text_size = st_text_size * PAGE_SZ; + st_rodata_size = st_rodata_size * PAGE_SZ; + + /* Copy Code */ + ret = llext_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) + return ret; + + /* Copy RODATA */ + ret = llext_manager_load_data_from_storage(va_base_rodata, src_rodata, + st_rodata_size, SYS_MM_MEM_PERM_RW); + if (ret < 0) + goto e_text; + + return 0; + +e_text: + sys_mm_drv_unmap_region((__sparse_force void *)va_base_text, st_text_size); + + return ret; +} + +static int llext_manager_unload_module(uint32_t module_id, struct sof_man_module *mod, + struct sof_man_fw_desc *desc) +{ + 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; + + 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; + + return sys_mm_drv_unmap_region((__sparse_force void *)va_base_rodata, st_rodata_size); +} + +static void __sparse_cache *llext_manager_get_instance_bss_address(uint32_t module_id, + uint32_t instance_id, + struct sof_man_module *mod) +{ + uint32_t instance_bss_size = + mod->segment[SOF_MAN_SEGMENT_BSS].flags.r.length / mod->instance_max_count; + uint32_t inst_offset = instance_bss_size * PAGE_SZ * instance_id; + void __sparse_cache *va_base = + (void __sparse_cache *)(mod->segment[SOF_MAN_SEGMENT_BSS].v_base_addr + + inst_offset); + + tr_dbg(&lib_manager_tr, + "llext_manager_get_instance_bss_address(): instance_bss_size: %#x, pointer: %p", + instance_bss_size, (__sparse_force void *)va_base); + + return va_base; +} + +static int llext_manager_allocate_module_instance(uint32_t module_id, uint32_t instance_id, + uint32_t is_pages, struct sof_man_module *mod) +{ + uint32_t bss_size = + (mod->segment[SOF_MAN_SEGMENT_BSS].flags.r.length / mod->instance_max_count) + * PAGE_SZ; + void __sparse_cache *va_base = llext_manager_get_instance_bss_address(module_id, + instance_id, mod); + + if ((is_pages * PAGE_SZ) > bss_size) { + tr_err(&lib_manager_tr, + "llext_manager_allocate_module_instance(): invalid is_pages: %u, required: %u", + is_pages, bss_size / PAGE_SZ); + return -ENOMEM; + } + + /* + * Map bss memory and clear it. + */ + if (sys_mm_drv_map_region((__sparse_force void *)va_base, POINTER_TO_UINT(NULL), + bss_size, SYS_MM_MEM_PERM_RW) < 0) + return -ENOMEM; + + memset((__sparse_force void *)va_base, 0, bss_size); + + return 0; +} + +static int llext_manager_free_module_instance(uint32_t module_id, uint32_t instance_id, + struct sof_man_module *mod) +{ + uint32_t bss_size = + (mod->segment[SOF_MAN_SEGMENT_BSS].flags.r.length / mod->instance_max_count) + * PAGE_SZ; + void __sparse_cache *va_base = llext_manager_get_instance_bss_address(module_id, + instance_id, mod); + /* + * Unmap bss memory. + */ + return sys_mm_drv_unmap_region((__sparse_force void *)va_base, bss_size); +} + +uint32_t llext_manager_allocate_module(const struct comp_driver *drv, + struct comp_ipc_config *ipc_config, + const void *ipc_specific_config) +{ + struct sof_man_fw_desc *desc; + struct sof_man_module *mod; + const struct ipc4_base_module_cfg *base_cfg = ipc_specific_config; + int ret; + uint32_t module_id = IPC4_MOD_ID(ipc_config->id); + uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); + + tr_dbg(&lib_manager_tr, "llext_manager_allocate_module(): mod_id: %#x", + ipc_config->id); + + desc = lib_manager_get_library_module_desc(module_id); + if (!desc) { + tr_err(&lib_manager_tr, + "llext_manager_allocate_module(): failed to get module descriptor"); + return 0; + } + + mod = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(entry_index)); + + ret = llext_manager_load_module(module_id, mod, desc); + if (ret < 0) + return 0; + + ret = llext_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, + "llext_manager_allocate_module(): module allocation failed: %d", ret); + return 0; + } + return mod->entry_point; +} + +int llext_manager_free_module(const struct comp_driver *drv, + struct comp_ipc_config *ipc_config) +{ + struct sof_man_fw_desc *desc; + struct sof_man_module *mod; + uint32_t module_id = IPC4_MOD_ID(ipc_config->id); + uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); + int ret; + + tr_dbg(&lib_manager_tr, "llext_manager_free_module(): mod_id: %#x", ipc_config->id); + + desc = lib_manager_get_library_module_desc(module_id); + mod = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(entry_index)); + + ret = llext_manager_unload_module(module_id, mod, desc); + if (ret < 0) + return ret; + + ret = llext_manager_free_module_instance(module_id, IPC4_INST_ID(ipc_config->id), mod); + if (ret < 0) { + tr_err(&lib_manager_tr, + "llext_manager_free_module(): free module instance failed: %d", ret); + return ret; + } + return 0; +} diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index ab0062c65..4d1fe49f6 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -630,6 +630,12 @@ zephyr_library_sources_ifdef(CONFIG_LIBRARY_MANAGER ${SOF_SRC_PATH}/library_manager/lib_notification.c ) +if (CONFIG_MM_DRV) +zephyr_library_sources_ifdef(CONFIG_LIBRARY_MANAGER + ${SOF_SRC_PATH}/library_manager/llext_manager.c +) +endif() + zephyr_include_directories_ifdef(CONFIG_INTEL_MODULES ${SOF_SRC_PATH}/include/sof/audio/module_adapter/iadk/ ${SOF_SRC_PATH}/include/sof/audio/module_adapter/library/