From 8cd649f71eb48c1f9ae405d96b4c450b7bd992e0 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Tue, 9 Dec 2025 16:53:33 +0100 Subject: [PATCH 1/4] userspace: proxy: Rename variables from user to user_ctx Update variable names to use user_ctx instead of user to improve clarity. Signed-off-by: Adrian Warecki --- .../module_adapter/library/userspace_proxy.c | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/audio/module_adapter/library/userspace_proxy.c b/src/audio/module_adapter/library/userspace_proxy.c index d6b1516dfb3c..2fac2f4e7144 100644 --- a/src/audio/module_adapter/library/userspace_proxy.c +++ b/src/audio/module_adapter/library/userspace_proxy.c @@ -44,7 +44,7 @@ DECLARE_TR_CTX(userspace_proxy_tr, SOF_UUID(userspace_proxy_uuid), LOG_LEVEL_INF static const struct module_interface userspace_proxy_interface; -static int userspace_proxy_memory_init(struct userspace_context *user, +static int userspace_proxy_memory_init(struct userspace_context *user_ctx, const struct comp_driver *drv) { /* Add module private heap to memory partitions */ @@ -79,10 +79,10 @@ static int userspace_proxy_memory_init(struct userspace_context *user, &heap_part }; - return k_mem_domain_init(user->comp_dom, ARRAY_SIZE(parts_ptr), parts_ptr); + return k_mem_domain_init(user_ctx->comp_dom, ARRAY_SIZE(parts_ptr), parts_ptr); } -static int userspace_proxy_add_sections(struct userspace_context *user, uint32_t instance_id, +static int userspace_proxy_add_sections(struct userspace_context *user_ctx, uint32_t instance_id, const struct sof_man_module *const mod) { struct k_mem_partition mem_partition; @@ -103,7 +103,7 @@ static int userspace_proxy_add_sections(struct userspace_context *user, uint32_t mem_partition.start = mod->segment[idx].v_base_addr; mem_partition.size = mod->segment[idx].flags.r.length * CONFIG_MM_DRV_PAGE_SIZE; - ret = k_mem_domain_add_partition(user->comp_dom, &mem_partition); + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &mem_partition); tr_dbg(&userspace_proxy_tr, "Add mod partition %p + %zx, attr = %u, ret = %d", UINT_TO_POINTER(mem_partition.start), mem_partition.size, @@ -116,7 +116,7 @@ static int userspace_proxy_add_sections(struct userspace_context *user, uint32_t lib_manager_get_instance_bss_address(instance_id, mod, &va_base, &mem_partition.size); mem_partition.start = POINTER_TO_UINT(va_base); mem_partition.attr = K_MEM_PARTITION_P_RW_U_RW; - ret = k_mem_domain_add_partition(user->comp_dom, &mem_partition); + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &mem_partition); tr_dbg(&userspace_proxy_tr, "Add bss partition %p + %zx, attr = %u, ret = %d", UINT_TO_POINTER(mem_partition.start), mem_partition.size, @@ -130,14 +130,14 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com const struct system_agent_params *agent_params, const void **agent_interface, const struct module_interface **ops) { - struct userspace_context *user; + struct userspace_context *context; struct k_mem_domain *domain; int ret; tr_dbg(&userspace_proxy_tr, "userspace create"); - user = k_heap_alloc(drv->user_heap, sizeof(struct userspace_context), K_FOREVER); - if (!user) + context = k_heap_alloc(drv->user_heap, sizeof(struct userspace_context), K_FOREVER); + if (!context) return -ENOMEM; /* Allocate memory domain struct */ @@ -146,13 +146,13 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com ret = -ENOMEM; goto error; } - user->comp_dom = domain; + context->comp_dom = domain; - ret = userspace_proxy_memory_init(user, drv); + ret = userspace_proxy_memory_init(context, drv); if (ret) goto error_dom; - ret = userspace_proxy_add_sections(user, agent_params->instance_id, manifest); + ret = userspace_proxy_add_sections(context, agent_params->instance_id, manifest); if (ret) goto error_dom; @@ -166,7 +166,7 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com } } - *user_ctx = user; + *user_ctx = context; /* Store a pointer to the module's interface. For the LMDK modules, the agent places a * pointer to the module interface at the address specified by agent_interface. Since this @@ -174,7 +174,7 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com * after the agent has been started. For other module types, the ops parameter points to a * valid module interface. */ - user->interface = *ops; + context->interface = *ops; /* All calls to the module interface must pass through the proxy. Set up our own interface. */ @@ -185,7 +185,7 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com error_dom: rfree(domain); error: - k_heap_free(drv->user_heap, user); + k_heap_free(drv->user_heap, context); return ret; } From 67b4c7d4275d94aadd5e25180df4ca80c24de2cc Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Wed, 10 Dec 2025 17:46:41 +0100 Subject: [PATCH 2/4] lib_manager: Replace component_id parameter with config Change lib_manager_start_agent signature to accept a config object instead of component_id. Get core id from the ipc configuration and pass it to the system agent at startup. Signed-off-by: Adrian Warecki --- src/library_manager/lib_manager.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index cde00a4c15a3..aeb3bc22ae1d 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -490,7 +490,7 @@ const struct sof_man_module *lib_manager_get_module_manifest(const uint32_t modu * \brief Starts system agent and returns module interface into agent_interface variable. * * \param[in] drv - Pointer to the component driver structure. - * \param[in] component_id - Identifier of the component. + * \param[in] config - Pointer to component ipc config structure * \param[in] args - Pointer to components' ipc configuration arguments. * \param[in] module_entry_point - Entry point address of the module. * \param[in] agent - Function pointer to the system agent start function. @@ -500,7 +500,8 @@ const struct sof_man_module *lib_manager_get_module_manifest(const uint32_t modu * * \return Error code returned by the system agent, 0 on success. */ -static int lib_manager_start_agent(const struct comp_driver *drv, const uint32_t component_id, +static int lib_manager_start_agent(const struct comp_driver *drv, + const struct comp_ipc_config *config, const struct sof_man_module *mod_manifest, const struct ipc_config_process *args, const uintptr_t module_entry_point, @@ -518,9 +519,9 @@ static int lib_manager_start_agent(const struct comp_driver *drv, const uint32_t mod_cfg.size = args->size >> 2; agent_params.entry_point = module_entry_point; - agent_params.module_id = IPC4_MOD_ID(component_id); - agent_params.instance_id = IPC4_INST_ID(component_id); - agent_params.core_id = 0; + agent_params.module_id = IPC4_MOD_ID(config->id); + agent_params.instance_id = IPC4_INST_ID(config->id); + agent_params.core_id = config->core; agent_params.log_handle = (uint32_t)drv->tctx; agent_params.mod_cfg = &mod_cfg; @@ -663,7 +664,7 @@ static struct comp_dev *lib_manager_module_create(const struct comp_driver *drv, /* At this point module resources are allocated and it is moved to L2 memory. */ if (agent) { - ret = lib_manager_start_agent(drv, config->id, mod, args, module_entry_point, agent, + ret = lib_manager_start_agent(drv, config, mod, args, module_entry_point, agent, agent_iface, &userspace, &ops); if (ret) goto err; From 8a3639a507a7fca3f2891752accc01afd4d24b91 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Tue, 14 Oct 2025 22:24:03 +0200 Subject: [PATCH 3/4] userspace: Move selected variables to userspace-accessible memory partition Relocate specific variables to a memory partition accessible from userspace to enable running the system agent in userspace. This change ensures that only the required structures is accessible for userspace modules, while privileged data remains in kernel-only memory. Signed-off-by: Adrian Warecki --- src/audio/module_adapter/iadk/system_agent.cpp | 3 ++- src/audio/module_adapter/library/native_system_service.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/audio/module_adapter/iadk/system_agent.cpp b/src/audio/module_adapter/iadk/system_agent.cpp index 14f8e70f49a1..caed8cf65860 100644 --- a/src/audio/module_adapter/iadk/system_agent.cpp +++ b/src/audio/module_adapter/iadk/system_agent.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,7 @@ namespace system { /* Structure storing handles to system service operations */ -const AdspSystemService SystemAgent::system_service_ = { +const APP_TASK_DATA AdspSystemService SystemAgent::system_service_ = { native_system_service_log_message, native_system_service_safe_memcpy, native_system_service_safe_memmove, diff --git a/src/audio/module_adapter/library/native_system_service.c b/src/audio/module_adapter/library/native_system_service.c index 5126fa5ff12b..1c4688e885d0 100644 --- a/src/audio/module_adapter/library/native_system_service.c +++ b/src/audio/module_adapter/library/native_system_service.c @@ -19,6 +19,7 @@ #include #include #include +#include #define RSIZE_MAX 0x7FFFFFFF @@ -162,7 +163,7 @@ AdspErrorCode native_system_service_get_interface(enum interface_id id, return ADSP_NO_ERROR; } -const struct native_system_service native_system_service = { +const APP_TASK_DATA struct native_system_service native_system_service = { .basic = { .log_message = native_system_service_log_message, .safe_memcpy = native_system_service_safe_memcpy, From 7bfaaae180eac3e9b18f8bba31e712f21b4633b2 Mon Sep 17 00:00:00 2001 From: Jaroslaw Stelter Date: Fri, 15 Sep 2023 14:49:23 +0200 Subject: [PATCH 4/4] userspace: proxy: Introduce user worker to service IPC The non-privileged modules code should be executed in separate thread executed in userspace mode. This way the code and data owned by such module will be isolated from other non-privileged modules in the system. The implementation creates user work queue thread that will service all IPC's for all such modules. Signed-off-by: Adrian Warecki Signed-off-by: Jaroslaw Stelter --- src/audio/module_adapter/CMakeLists.txt | 1 + .../module_adapter/library/userspace_proxy.c | 358 ++++++++++++++++-- .../library/userspace_proxy_user.c | 122 ++++++ .../module_adapter/library/userspace_proxy.h | 3 + .../library/userspace_proxy_user.h | 91 +++++ src/include/sof/schedule/dp_schedule.h | 1 + 6 files changed, 549 insertions(+), 27 deletions(-) create mode 100644 src/audio/module_adapter/library/userspace_proxy_user.c create mode 100644 src/include/sof/audio/module_adapter/library/userspace_proxy_user.h diff --git a/src/audio/module_adapter/CMakeLists.txt b/src/audio/module_adapter/CMakeLists.txt index 7400e27f7edd..2c79f2fbfefd 100644 --- a/src/audio/module_adapter/CMakeLists.txt +++ b/src/audio/module_adapter/CMakeLists.txt @@ -66,6 +66,7 @@ if(zephyr) ### Zephyr ### zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_PROXY library/userspace_proxy.c + library/userspace_proxy_user.c ) zephyr_library_sources_ifdef(CONFIG_PASSTHROUGH_CODEC diff --git a/src/audio/module_adapter/library/userspace_proxy.c b/src/audio/module_adapter/library/userspace_proxy.c index 2fac2f4e7144..0020d0745330 100644 --- a/src/audio/module_adapter/library/userspace_proxy.c +++ b/src/audio/module_adapter/library/userspace_proxy.c @@ -27,14 +27,19 @@ #include #include +#include #include #include #include #include #include +#include #include + /* Assume that all the code runs in supervisor mode and don't made a system calls. */ +#define __ZEPHYR_SUPERVISOR__ + LOG_MODULE_REGISTER(userspace_proxy, CONFIG_SOF_LOG_LEVEL); /* 6f6b6f4b-6f73-7466-20e1e62b9779f003 */ @@ -44,6 +49,139 @@ DECLARE_TR_CTX(userspace_proxy_tr, SOF_UUID(userspace_proxy_uuid), LOG_LEVEL_INF static const struct module_interface userspace_proxy_interface; +struct user_worker { + k_tid_t thread_id; /* ipc worker thread ID */ + uint32_t reference_count; /* module reference count */ + void *stack_ptr; /* pointer to worker stack */ + struct k_work_user_q work_queue; + struct k_event event; +}; + +static struct user_worker worker; + +static int user_worker_create(void) +{ + if (worker.reference_count) { + worker.reference_count++; + return 0; + } + + worker.stack_ptr = user_stack_allocate(CONFIG_SOF_STACK_SIZE, K_USER); + if (!worker.stack_ptr) { + tr_err(&userspace_proxy_tr, "Userspace worker stack allocation failed."); + return -ENOMEM; + } + + k_event_init(&worker.event); + k_work_user_queue_start(&worker.work_queue, worker.stack_ptr, CONFIG_SOF_STACK_SIZE, 0, + NULL); + + worker.thread_id = k_work_user_queue_thread_get(&worker.work_queue); + + k_thread_access_grant(worker.thread_id, &worker.event); + + worker.reference_count++; + return 0; +} + +static void user_worker_free(void) +{ + /* Module removed so decrement counter */ + worker.reference_count--; + + /* Free worker resources if no more active user space modules */ + if (worker.reference_count == 0) { + k_thread_abort(worker.thread_id); + user_stack_free(worker.stack_ptr); + } +} + +static int user_work_item_init(struct userspace_context *user_ctx, struct k_heap *user_heap) +{ + struct user_work_item *work_item = NULL; + int ret; + + ret = user_worker_create(); + if (ret) + return ret; + + work_item = sof_heap_alloc(user_heap, SOF_MEM_FLAG_COHERENT, sizeof(*work_item), 0); + if (!work_item) + return -ENOMEM; + + k_work_user_init(&work_item->work_item, userspace_proxy_worker_handler); + + work_item->event = &worker.event; + work_item->params.context = user_ctx; + user_ctx->work_item = work_item; + + return 0; +} + +static void user_work_item_free(struct userspace_context *user_ctx, struct k_heap *user_heap) +{ + sof_heap_free(user_heap, user_ctx->work_item); + user_worker_free(); +} + +static inline struct module_params *user_work_get_params(struct userspace_context *user_ctx) +{ + return &user_ctx->work_item->params; +} + +static int userspace_proxy_invoke(struct userspace_context *user_ctx, uint32_t cmd, + bool ipc_payload_access) +{ + struct module_params *params = user_work_get_params(user_ctx); + struct k_mem_partition ipc_part = { + .start = (uintptr_t)MAILBOX_HOSTBOX_BASE, + .size = MAILBOX_HOSTBOX_SIZE, + .attr = K_MEM_PARTITION_P_RO_U_RO, + }; + int ret; + + params->cmd = cmd; + + if (ipc_payload_access) { + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &ipc_part); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "add mailbox to domain error: %d", ret); + return ret; + } + } + + /* Switch worker thread to module memory domain */ + ret = k_mem_domain_add_thread(user_ctx->comp_dom, worker.thread_id); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "failed to switch memory domain: error: %d", ret); + goto done; + } + + ret = k_work_user_submit_to_queue(&worker.work_queue, &user_ctx->work_item->work_item); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "k_work_user_submit_to_queue(): error: %d", ret); + goto done; + } + + /* Timeout value is aligned with the ipc_wait_for_compound_msg function */ + if (!k_event_wait_safe(&worker.event, DP_TASK_EVENT_IPC_DONE, false, + Z_TIMEOUT_US(250 * 20))) { + tr_err(&userspace_proxy_tr, "ipc processing timedout."); + ret = -ETIMEDOUT; + } + +done: + if (ipc_payload_access) { + ret = k_mem_domain_remove_partition(user_ctx->comp_dom, &ipc_part); + if (ret < 0) + tr_err(&userspace_proxy_tr, "Mailbox remove from domain error: %d", ret); + } + + return ret; +} + +extern struct k_mem_partition common_partition; + static int userspace_proxy_memory_init(struct userspace_context *user_ctx, const struct comp_driver *drv) { @@ -73,12 +211,17 @@ static int userspace_proxy_memory_init(struct userspace_context *user_ctx, #endif struct k_mem_partition *parts_ptr[] = { + &common_partition, #ifdef HEAP_PART_CACHED &heap_part_cached, #endif &heap_part }; + tr_dbg(&userspace_proxy_tr, "Common partition %p + %zx, attr = %u", + UINT_TO_POINTER(common_partition.start), common_partition.size, + common_partition.attr); + return k_mem_domain_init(user_ctx->comp_dom, ARRAY_SIZE(parts_ptr), parts_ptr); } @@ -125,6 +268,27 @@ static int userspace_proxy_add_sections(struct userspace_context *user_ctx, uint return ret; } +static int userspace_proxy_start_agent(struct userspace_context *user_ctx, + system_agent_start_fn start_fn, + const struct system_agent_params *agent_params, + const void **agent_interface) +{ + const byte_array_t * const mod_cfg = (byte_array_t *)agent_params->mod_cfg; + struct module_params *params = user_work_get_params(user_ctx); + int ret; + + params->ext.agent.start_fn = start_fn; + params->ext.agent.params = *agent_params; + params->ext.agent.mod_cfg = *mod_cfg; + + ret = userspace_proxy_invoke(user_ctx, MODULE_CMD_AGENT_START, true); + if (ret) + return ret; + + *agent_interface = params->ext.agent.out_interface; + return 0; +} + int userspace_proxy_create(struct userspace_context **user_ctx, const struct comp_driver *drv, const struct sof_man_module *manifest, system_agent_start_fn start_fn, const struct system_agent_params *agent_params, @@ -156,13 +320,17 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com if (ret) goto error_dom; + ret = user_work_item_init(context, drv->user_heap); + if (ret) + goto error_dom; + /* Start the system agent, if provided. */ - if (start_fn) { - ret = start_fn(agent_params, agent_interface); + if (start_fn) { + ret = userspace_proxy_start_agent(context, start_fn, agent_params, agent_interface); if (ret) { tr_err(&userspace_proxy_tr, "System agent failed with error %d.", ret); - goto error_dom; + goto error_work_item; } } @@ -182,6 +350,8 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com return 0; +error_work_item: + user_work_item_free(context, drv->user_heap); error_dom: rfree(domain); error: @@ -192,6 +362,7 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com void userspace_proxy_destroy(const struct comp_driver *drv, struct userspace_context *user_ctx) { tr_dbg(&userspace_proxy_tr, "userspace proxy destroy"); + user_work_item_free(user_ctx, drv->user_heap); rfree(user_ctx->comp_dom); k_heap_free(drv->user_heap, user_ctx); } @@ -206,10 +377,18 @@ void userspace_proxy_destroy(const struct comp_driver *drv, struct userspace_con */ static int userspace_proxy_init(struct processing_module *mod) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); + params->mod = mod; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_INIT, true); + if (ret) + return ret; + /* Return status from module code operation. */ - return mod->user_ctx->interface->init(mod); + return params->status; } /** @@ -223,21 +402,40 @@ static int userspace_proxy_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->prepare) return 0; - return mod->user_ctx->interface->prepare(mod, sources, num_of_sources, sinks, num_of_sinks); + params->ext.proc.sources = sources; + params->ext.proc.num_of_sources = num_of_sources; + params->ext.proc.sinks = sinks; + params->ext.proc.num_of_sinks = num_of_sinks; + + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_PREPARE, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** - * Copy parameters to user worker accessible space. - * Queue module init() operation and return its result. - * Module init() code is performed in user workqueue. + * Forward processing request to the module's process() implementation. * - * @param mod - pointer to processing module structure. - * @return 0 for success, error otherwise. + * It is invoked by the DP thread running in userspace, so no + * additional queuing or context switching is performed here. + * + * @param mod Pointer to the processing module instance. + * @param sources Array of input sources for the module. + * @param num_of_sources Number of input sources. + * @param sinks Array of output sinks for the module. + * @param num_of_sinks Number of output sinks. + * + * @return 0 on success, negative error code on failure. */ static int userspace_proxy_process(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) @@ -255,10 +453,18 @@ static int userspace_proxy_process(struct processing_module *mod, struct sof_sou */ static int userspace_proxy_reset(struct processing_module *mod) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + if (!mod->user_ctx->interface->reset) return 0; - return mod->user_ctx->interface->reset(mod); + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_RESET, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -271,13 +477,19 @@ static int userspace_proxy_reset(struct processing_module *mod) */ static int userspace_proxy_free(struct processing_module *mod) { + struct module_params *params = user_work_get_params(mod->user_ctx); int ret = 0; comp_dbg(mod->dev, "start"); - if (mod->user_ctx->interface->free) - ret = mod->user_ctx->interface->free(mod); + if (mod->user_ctx->interface->free) { + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_FREE, false); + if (ret) + return ret; + ret = params->status; + } + /* Destroy workqueue if this was last active userspace module */ userspace_proxy_destroy(mod->dev->drv, mod->user_ctx); mod->user_ctx = NULL; @@ -309,14 +521,28 @@ static int userspace_proxy_set_configuration(struct processing_module *mod, uint size_t fragment_size, uint8_t *response, size_t response_size) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->set_configuration) return 0; - return mod->user_ctx->interface->set_configuration(mod, config_id, pos, data_offset_size, - fragment, fragment_size, - response, response_size); + params->ext.set_conf.config_id = config_id; + params->ext.set_conf.pos = pos; + params->ext.set_conf.data_off_size = data_offset_size; + params->ext.set_conf.fragment = fragment; + params->ext.set_conf.fragment_size = fragment_size; + params->ext.set_conf.response = response; + params->ext.set_conf.response_size = response_size; + + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_SET_CONF, true); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -338,13 +564,37 @@ static int userspace_proxy_get_configuration(struct processing_module *mod, uint uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size) { + struct module_params *params = user_work_get_params(mod->user_ctx); + struct k_mem_domain *domain = mod->user_ctx->comp_dom; + struct k_mem_partition ipc_resp_part = { + .start = (uintptr_t)ipc_get()->comp_data, + .size = SOF_IPC_MSG_MAX_SIZE, + .attr = K_MEM_PARTITION_P_RW_U_RW, + }; + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->get_configuration) return -EIO; - return mod->user_ctx->interface->get_configuration(mod, config_id, data_offset_size, - fragment, fragment_size); + params->ext.get_conf.config_id = config_id; + params->ext.get_conf.data_off_size = data_offset_size; + params->ext.get_conf.fragment = fragment; + params->ext.get_conf.fragment_size = fragment_size; + + ret = k_mem_domain_add_partition(domain, &ipc_resp_part); + if (ret < 0) { + comp_err(mod->dev, "add response buffer to domain error: %d", ret); + return ret; + } + + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_GET_CONF, true); + + k_mem_domain_remove_partition(domain, &ipc_resp_part); + + /* Return status from module code operation. */ + return ret ? ret : params->status; } /** @@ -359,12 +609,21 @@ static int userspace_proxy_get_configuration(struct processing_module *mod, uint static int userspace_proxy_set_processing_mode(struct processing_module *mod, enum module_processing_mode mode) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->set_processing_mode) return 0; - return mod->user_ctx->interface->set_processing_mode(mod, mode); + params->ext.proc_mode.mode = mode; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_SET_PROCMOD, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -378,12 +637,20 @@ static int userspace_proxy_set_processing_mode(struct processing_module *mod, static enum module_processing_mode userspace_proxy_get_processing_mode(struct processing_module *mod) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->get_processing_mode) return -EIO; - return mod->user_ctx->interface->get_processing_mode(mod); + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_GET_PROCMOD, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->ext.proc_mode.mode; } /** @@ -400,14 +667,27 @@ static bool userspace_proxy_is_ready_to_process(struct processing_module *mod, struct sof_sink **sinks, int num_of_sinks) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->is_ready_to_process) return generic_module_is_ready_to_process(mod, sources, num_of_sources, sinks, num_of_sinks); - return mod->user_ctx->interface->is_ready_to_process(mod, sources, num_of_sources, - sinks, num_of_sinks); + params->ext.proc.sources = sources; + params->ext.proc.num_of_sources = num_of_sources; + params->ext.proc.sinks = sinks; + params->ext.proc.num_of_sinks = num_of_sinks; + + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_PROC_READY, false); + if (ret) + return generic_module_is_ready_to_process(mod, sources, num_of_sources, sinks, + num_of_sinks); + + /* Return status from module code operation. */ + return params->status; } /** @@ -421,12 +701,21 @@ static bool userspace_proxy_is_ready_to_process(struct processing_module *mod, */ static int userspace_proxy_bind(struct processing_module *mod, struct bind_info *bind_data) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->bind) return 0; - return mod->user_ctx->interface->bind(mod, bind_data); + params->ext.bind_data = bind_data; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_BIND, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -440,12 +729,21 @@ static int userspace_proxy_bind(struct processing_module *mod, struct bind_info */ static int userspace_proxy_unbind(struct processing_module *mod, struct bind_info *unbind_data) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->unbind) return 0; - return mod->user_ctx->interface->unbind(mod, unbind_data); + params->ext.bind_data = unbind_data; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_UNBIND, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -458,12 +756,18 @@ static int userspace_proxy_unbind(struct processing_module *mod, struct bind_inf */ static int userspace_proxy_trigger(struct processing_module *mod, int cmd) { + struct module_params *params = user_work_get_params(mod->user_ctx); int ret = 0; comp_dbg(mod->dev, "start"); - if (mod->user_ctx->interface->trigger) - ret = mod->user_ctx->interface->trigger(mod, cmd); + if (mod->user_ctx->interface->trigger) { + params->ext.trigger_data = cmd; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_TRIGGER, false); + if (ret) + return ret; + ret = params->status; + } if (!ret) ret = module_adapter_set_state(mod, mod->dev, cmd); @@ -472,7 +776,7 @@ static int userspace_proxy_trigger(struct processing_module *mod, int cmd) return ret; } -/* Userspace Module Adapter API */ +/* Userspace Proxy Module API */ APP_TASK_DATA static const struct module_interface userspace_proxy_interface = { .init = userspace_proxy_init, .is_ready_to_process = userspace_proxy_is_ready_to_process, diff --git a/src/audio/module_adapter/library/userspace_proxy_user.c b/src/audio/module_adapter/library/userspace_proxy_user.c new file mode 100644 index 000000000000..bf5f2a26e0eb --- /dev/null +++ b/src/audio/module_adapter/library/userspace_proxy_user.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Adrian Warecki + +/** + * \file audio/module_adapter/library/userspace_proxy_user.c + * \brief Userspace proxy functions executed only in userspace context. + * \authors Adrian Warecki + */ + +/* Assume that all the code runs in user mode and unconditionally made a system calls. */ +#define __ZEPHYR_USER__ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +void userspace_proxy_handle_request(struct processing_module *mod, struct module_params *params) +{ + const struct module_interface *ops = params->context->interface; + + switch (params->cmd) { + case MODULE_CMD_AGENT_START: + /* Set pointer to user accessible mod_cfg structure. */ + params->ext.agent.params.mod_cfg = ¶ms->ext.agent.mod_cfg; + + params->status = params->ext.agent.start_fn(¶ms->ext.agent.params, + ¶ms->ext.agent.out_interface); + break; + + case MODULE_CMD_INIT: + params->status = ops->init(params->mod); + break; + + case MODULE_CMD_PREPARE: + params->status = ops->prepare(params->mod, params->ext.proc.sources, + params->ext.proc.num_of_sources, + params->ext.proc.sinks, + params->ext.proc.num_of_sinks); + break; + + case MODULE_CMD_PROC_READY: + params->status = ops->is_ready_to_process(params->mod, + params->ext.proc.sources, + params->ext.proc.num_of_sources, + params->ext.proc.sinks, + params->ext.proc.num_of_sinks); + break; + + case MODULE_CMD_BIND: + params->status = ops->bind(params->mod, params->ext.bind_data); + break; + + case MODULE_CMD_UNBIND: + params->status = ops->unbind(params->mod, params->ext.bind_data); + break; + + case MODULE_CMD_RESET: + params->status = ops->reset(params->mod); + break; + + case MODULE_CMD_FREE: + params->status = ops->free(params->mod); + break; + + case MODULE_CMD_SET_CONF: + params->status = ops->set_configuration(params->mod, + params->ext.set_conf.config_id, + params->ext.set_conf.pos, + params->ext.set_conf.data_off_size, + params->ext.set_conf.fragment, + params->ext.set_conf.fragment_size, + params->ext.set_conf.response, + params->ext.set_conf.response_size); + break; + + case MODULE_CMD_GET_CONF: + params->status = ops->get_configuration(params->mod, + params->ext.get_conf.config_id, + params->ext.get_conf.data_off_size, + params->ext.get_conf.fragment, + params->ext.get_conf.fragment_size); + break; + + case MODULE_CMD_SET_PROCMOD: + params->status = ops->set_processing_mode(params->mod, + params->ext.proc_mode.mode); + break; + + case MODULE_CMD_GET_PROCMOD: + params->ext.proc_mode.mode = ops->get_processing_mode(params->mod); + break; + + case MODULE_CMD_TRIGGER: + params->status = ops->trigger(params->mod, params->ext.trigger_data); + break; + + default: + params->status = -EINVAL; + break; + } +} + +void userspace_proxy_worker_handler(struct k_work_user *work_item) +{ + struct user_work_item *user_work_item = CONTAINER_OF(work_item, struct user_work_item, + work_item); + struct module_params *params = &user_work_item->params; + + userspace_proxy_handle_request(params->mod, params); + k_event_post(user_work_item->event, DP_TASK_EVENT_IPC_DONE); +} diff --git a/src/include/sof/audio/module_adapter/library/userspace_proxy.h b/src/include/sof/audio/module_adapter/library/userspace_proxy.h index 150812183a90..872646d1eec9 100644 --- a/src/include/sof/audio/module_adapter/library/userspace_proxy.h +++ b/src/include/sof/audio/module_adapter/library/userspace_proxy.h @@ -14,10 +14,12 @@ #include #include +#include #include #include #include +#include struct module_interface; struct comp_driver; @@ -28,6 +30,7 @@ struct system_agent_params; struct userspace_context { struct k_mem_domain *comp_dom; /* Module specific memory domain */ const struct module_interface *interface; /* Userspace module interface */ + struct user_work_item *work_item; /* work item for user worker thread */ }; #endif /* CONFIG_USERSPACE */ diff --git a/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h b/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h new file mode 100644 index 000000000000..6124d868925c --- /dev/null +++ b/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki + */ + +#ifndef __SOF_AUDIO_USERSPACE_PROXY_USER_H__ +#define __SOF_AUDIO_USERSPACE_PROXY_USER_H__ + +#if CONFIG_SOF_USERSPACE_PROXY +struct module_agent_params { + system_agent_start_fn start_fn; + struct system_agent_params params; + byte_array_t mod_cfg; + const void *out_interface; +}; + +struct module_large_cfg_set_params { + uint32_t config_id; + enum module_cfg_fragment_position pos; + uint32_t data_off_size; + const uint8_t *fragment; + size_t fragment_size; + uint8_t *response; + size_t response_size; +}; + +struct module_large_cfg_get_params { + uint32_t config_id; + uint32_t *data_off_size; + uint8_t *fragment; + size_t fragment_size; +}; + +struct module_processing_mode_params { + enum module_processing_mode mode; +}; + +struct module_process_params { + struct sof_source **sources; + int num_of_sources; + struct sof_sink **sinks; + int num_of_sinks; +}; + +enum userspace_proxy_cmd { + MODULE_CMD_AGENT_START, + MODULE_CMD_INIT, + MODULE_CMD_PREPARE, + MODULE_CMD_PROC_READY, + MODULE_CMD_SET_PROCMOD, + MODULE_CMD_GET_PROCMOD, + MODULE_CMD_SET_CONF, + MODULE_CMD_GET_CONF, + MODULE_CMD_BIND, + MODULE_CMD_UNBIND, + MODULE_CMD_RESET, + MODULE_CMD_FREE, + MODULE_CMD_TRIGGER +}; + +struct module_params { + enum userspace_proxy_cmd cmd; + int status; + struct processing_module *mod; + struct userspace_context *context; + union { + struct module_agent_params agent; + struct module_large_cfg_set_params set_conf; + struct module_large_cfg_get_params get_conf; + struct module_processing_mode_params proc_mode; + struct module_process_params proc; + struct bind_info *bind_data; + int trigger_data; + } ext; +}; + +struct user_work_item { + struct k_work_user work_item; /* ipc worker workitem */ + struct k_event *event; /* ipc worker done event */ + struct module_params params; +}; + +void userspace_proxy_handle_request(struct processing_module *mod, struct module_params *params); + +void userspace_proxy_worker_handler(struct k_work_user *work_item); + +#endif /* CONFIG_SOF_USERSPACE_PROXY */ + +#endif /* __SOF_AUDIO_USERSPACE_PROXY_USER_H__ */ diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index 99f1dcd2b16f..78a5ed892972 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -89,6 +89,7 @@ void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, enum { DP_TASK_EVENT_PROCESS = BIT(0), /* Need to process data */ DP_TASK_EVENT_CANCEL = BIT(1), /* Thread cancellation */ + DP_TASK_EVENT_IPC_DONE = BIT(3), /* IPC processing has completed. */ }; #endif /* __SOF_SCHEDULE_DP_SCHEDULE_H__ */