lib-manager: fork a copy for LLEXT support

This forks a slightly earlier version of library loading code for
upcoming LLEXT support.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
This commit is contained in:
Guennadi Liakhovetski 2024-01-25 10:03:02 +01:00 committed by Kai Vehmanen
parent ab29f8db82
commit bd5c24b282
4 changed files with 279 additions and 0 deletions

View File

@ -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 <stdint.h>
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

View File

@ -19,6 +19,7 @@
#include <rtos/spinlock.h>
#include <sof/lib/cpu-clk-manager.h>
#include <sof/lib_manager.h>
#include <sof/llext_manager.h>
#include <sof/audio/module_adapter/module/generic.h>
#include <sof/audio/module_adapter/module/modules.h>
@ -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;

View File

@ -0,0 +1,241 @@
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2022 Intel Corporation. All rights reserved.
//
// Author: Jaroslaw Stelter <jaroslaw.stelter@intel.com>
// Pawel Dobrowolski<pawelx.dobrowolski@intel.com>
/*
* Dynamic module loading functions.
*/
#include <sof/audio/buffer.h>
#include <sof/audio/component_ext.h>
#include <sof/common.h>
#include <sof/compiler_attributes.h>
#include <sof/ipc/topology.h>
#include <rtos/sof.h>
#include <rtos/spinlock.h>
#include <sof/lib/cpu-clk-manager.h>
#include <sof/lib_manager.h>
#include <sof/llext_manager.h>
#include <sof/audio/module_adapter/module/generic.h>
#include <sof/audio/module_adapter/module/modules.h>
#include <zephyr/cache.h>
#include <zephyr/drivers/mm/system_mm.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
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;
}

View File

@ -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/