Skip to content
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

1st part of llext #8180 #8759

Merged
merged 8 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/include/sof/llext_manager.h
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions src/library_manager/lib_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -265,6 +266,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)
Expand All @@ -288,6 +294,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;
Expand Down Expand Up @@ -329,6 +338,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;
Expand Down
241 changes: 241 additions & 0 deletions src/library_manager/llext_manager.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2022 Intel Corporation. All rights reserved.
//
// Author: Jaroslaw Stelter <[email protected]>
// Pawel Dobrowolski<[email protected]>

/*
* Dynamic module loading functions.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this could be more explict and mention "Dynamic module loading functions using Zephyr Linkable Loadable Extensions (LLEXT) interface".

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kv2019i I propose to address any cosmetic improvements in a follow-up PR, will do one first thing after this is merged

*/

#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;
}
6 changes: 6 additions & 0 deletions zephyr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down