ipc: add support for userspace IPC handling#10994
Open
kv2019i wants to merge 12 commits into
Open
Conversation
…e LL When CONFIG_SOF_USERSPACE_LL is enabled the IPC context must live in user-accessible application memory rather than being allocated from the kernel heap and reached via sof->ipc. Place struct ipc in a dedicated K_APP_BMEM partition and provide an out-of-line ipc_get() returning it; drop the sof->ipc pointer in this configuration. Add the generic ll_alloc allocation context to struct ipc and set it up in ipc_init() from the LL user heap, so LL components (host, dai, chain_dma) can allocate their buffers from a user-accessible heap. IPC objects (the context itself and comp_data) are allocated accordingly. A no-op ipc_user_init() stub is added here and implemented later. No IPC-major-specific knowledge is added here. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Add the struct ipc_user descriptor (and its ipc_user_pdata slot in struct ipc) that the IPC4 kernel handler uses to forward commands to the user-space IPC thread: the two IPC4 message words, the reply fields, and a user-readable copy of the resolved comp_driver + tr_ctx used by user-space component creation. In ipc4 helper, allow component buffers to be allocated from the LL user heap (ipc->ll_alloc) and create them on the component's configured core rather than the current CPU, so buffer creation works from the user thread when CONFIG_SOF_USERSPACE_LL is enabled. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
…stic Extract the per-message processing logic for module CONFIG_GET/SET and LARGE_CONFIG_GET/SET into standalone functions that return their results via output parameters instead of writing the global msg_reply directly, and give SET_PIPELINE_STATE external linkage. This is a pure refactor with no functional change. The new ipc4_process_module_config(), ipc4_process_large_config_get(), ipc4_process_large_config_set() and ipc4_set_pipeline_state() can be called from any execution context, which is needed to later dispatch these messages from a separate IPC user-space thread. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The IPC reply and compound-message completion entry points need to be callable from the IPC user-space thread. Declare ipc_msg_reply(), ipc_compound_pre_start(), ipc_compound_post_start() and ipc_wait_for_compound_msg() as Zephyr syscalls when CONFIG_SOF_USERSPACE_LL is enabled, renaming the implementations to z_impl_* and adding z_vrfy_* verification wrappers. A new ipc_reply.h carries the ipc_msg_reply declaration so it can be pulled in as a syscall header. Register the new syscall headers in CMakeLists.txt. No functional change for non-userspace builds, where the functions keep direct external linkage via z_impl_* defines. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The pipeline, component and chain-DMA bookkeeping objects must be reachable from the user-space IPC thread, so allocate them from the system user heap via sof_heap_alloc()/sof_heap_free() instead of the generic rzalloc()/rfree(). As sof_heap_alloc() does not zero the allocation, add an explicit memset() to preserve the previous behaviour. Give ipc4_add_comp_dev() external linkage (declared in topology.h) so the user thread can register a created component, and skip the buffer tr_ctx copy for user-space LL builds where the kernel tr_ctx is not mapped. No functional change for non-userspace builds. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The user-space IPC thread reads the IPC4 module init parameter block directly from MAILBOX_HOSTBOX_BASE (comp_new_ipc4() / comp_new_ipc4_user()), so the HOSTBOX region must be reachable from the user LL memory domain. Map two partitions when CONFIG_SOF_USERSPACE_LL && CONFIG_IPC_MAJOR_4: an uncached read-only view for the parameter reads, and a cached RW view because the sys_cache_data_invd_range() syscall verifier requires write access to the invalidated range. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Add function user_ll_grant_access() to allow other threads to access the scheduler mutex. This is needed if work is submitted from other threads to the scheduler. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Add a dedicated user-space thread for handling IPC commands that operate on audio pipelines when CONFIG_SOF_USERSPACE_LL is enabled. This provides only the protocol-agnostic infrastructure: - ipc_user_init() creates the K_USER thread, allocates its k_sem/k_event handshake objects, sets up the memory domain and access grants, and spins up the LL scheduler context. - ipc_user_forward_cmd() forwards the two raw IPC message words from the kernel IPC handler to the user thread via k_event signaling, sets IPC_TASK_IN_THREAD so the host is not signaled until the user thread completes, and collects the result through a k_sem handshake. - ipc_user_thread_fn() runs the wait loop and delegates the actual command interpretation to ipc_user_thread_dispatch(), a __weak hook overridden by the active IPC major. No IPC-major-specific knowledge lives here; the IPC4 dispatch is added in a following commit. The generic infra can be extended to cover other IPC protocol variants. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Add comp_new_ipc4_user(), called from the user-space IPC thread to create a component from user context. It receives a pre-resolved driver pointer from the kernel handler (which does the privileged IMR manifest / driver list lookup), parses the IPC4 init-instance message, reads the module init parameter block from the HOSTBOX, and calls drv->ops.create() so untrusted module init code does not execute with kernel privileges. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Provide the IPC4 implementation of ipc_user_thread_dispatch(), the protocol-specific hook called from the generic user-space IPC thread. It reconstructs the IPC4 message from the forwarded primary/extension words and runs the privilege-separated portion of each supported command: pipeline create/delete/set-state, module config get/set, large-config get/set, bind/unbind, and init/delete instance. Component creation goes through comp_new_ipc4_user() so module code runs in user context. This moves the IPC4 command switch out of the protocol-agnostic ipc-common.c into the IPC4 handler where it belongs. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Route the IPC4 commands that operate on audio pipelines to the user-space IPC thread via ipc_user_forward_cmd() when CONFIG_SOF_USERSPACE_LL is enabled: create/delete/set-state pipeline, config get/set, large-config get/set, bind/unbind and init/delete instance. For MOD_INIT_INSTANCE the kernel still resolves the driver (needs IMR manifest access) and copies comp_driver + tr_ctx into the user-readable ipc_user buffer before forwarding; cross-core creation stays in kernel. LARGE_CONFIG get/set for base firmware (module_id 0) also stay in kernel because they touch the IMR manifest. CONFIG_GET / LARGE_CONFIG_GET copy the reply extension (and tx payload) back from the user thread. The now-unused ipc4_new_pipeline()/ipc4_delete_pipeline() kernel helpers are compiled out in the user-space configuration. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
If CONFIG_SOF_BOOT_TEST_STANDALONE is set, ipc_init() is terminated early. This ensures SOF will not start to generate or respond to IPC messages that could potentially interfere with standalone test cases (some of which send and receive IPCs). The current implementation leaves the component list uninitialized and this can cause trouble to standalone tests that want to utilzie common IPC code to build messages. Fix this problem by executing more of ipc_init() also in the standalone mode. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends the Zephyr userspace LL execution model to IPC handling by forwarding selected IPC4 commands to a dedicated Zephyr user-space thread, enabling module init/config and some pipeline operations to run with reduced privileges. The changes integrate Zephyr syscall boundaries, userspace memory-domain grants (mailbox/HOSTBOX), and userspace-aware allocation paths to support privilege-separated IPC execution without affecting default kernel-space SOF builds.
Changes:
- Add a generic “IPC user thread” forwarding mechanism (kernel IPC task → userspace IPC thread) and wire IPC4 command subsets to use it under
CONFIG_SOF_USERSPACE_LL. - Introduce/adjust Zephyr syscall interfaces for IPC reply + IPC4 compound message helpers to support userspace callers.
- Update IPC4 helper allocation/core bookkeeping to support userspace execution and user-heap allocations.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| zephyr/lib/userspace_helper.c | Grants userspace access to HOSTBOX (cached + uncached mappings) for IPC4 module init/config payload reads. |
| zephyr/Kconfig | Adds SOF_IPC_USER_THREAD_STACK_SIZE Kconfig for the IPC userspace thread stack. |
| zephyr/include/rtos/sof.h | Hides sof->ipc when userspace LL is enabled (IPC context is no longer stored there). |
| zephyr/CMakeLists.txt | Adds syscall header generation for new IPC reply and IPC4 handler syscall declarations. |
| src/schedule/zephyr_ll.c | Adds user_ll_grant_access() to grant userspace thread access to LL scheduler locks. |
| src/ipc/ipc4/helper.c | Adds userspace component creation entrypoint and shifts several allocations/frees to user-heap helpers. |
| src/ipc/ipc4/handler-user.c | Forwards selected IPC4 commands to userspace and adds userspace-side dispatch/processing helpers. |
| src/ipc/ipc4/handler-kernel.c | Converts select IPC helpers to Zephyr syscall implementations with verification wrappers. |
| src/ipc/ipc3/helper.c | Renames IPC reply implementation to z_impl_ipc_msg_reply() for syscall compatibility. |
| src/ipc/ipc-helper.c | Adjusts buffer trace ctx init for userspace LL and updates component container free to user-heap free helper. |
| src/ipc/ipc-common.c | Implements IPC userspace thread infrastructure, forwarding API, and userspace-aware IPC init path. |
| src/include/sof/schedule/ll_schedule_domain.h | Exposes user_ll_grant_access() prototype. |
| src/include/sof/ipc/topology.h | Exposes IPC4 userspace creation helpers and ipc4_add_comp_dev() for userspace dispatch. |
| src/include/sof/ipc/ipc_reply.h | New header providing syscall-friendly ipc_msg_reply() declaration/mapping. |
| src/include/sof/ipc/common.h | Adds struct ipc_user, userspace IPC APIs, and wires IPC reply via the new header. |
| src/include/ipc4/handler.h | Exposes new IPC4 helpers and declares syscall variants for compound-message helpers under userspace LL. |
Comment on lines
+360
to
+364
| ret = k_sem_take(pdata->sem, K_MSEC(10)); | ||
| if (ret) { | ||
| LOG_ERR("IPC user: sem error %d\n", ret); | ||
| return ret; | ||
| } |
Comment on lines
+462
to
+466
| user_grant_dai_access_all(&ipc_user_thread); | ||
| user_grant_dma_access_all(&ipc_user_thread); | ||
| user_access_to_mailbox(zephyr_ll_mem_domain(), &ipc_user_thread); | ||
| user_ll_grant_access(&ipc_user_thread, PLATFORM_PRIMARY_CORE_ID); | ||
| k_mem_domain_add_thread(zephyr_ll_mem_domain(), &ipc_user_thread); |
Comment on lines
+535
to
538
| if (!ipc->comp_data) { | ||
| tr_err(&ipc_tr, "Unable to allocate IPC component data"); | ||
| rfree(sof->ipc); | ||
| sof_heap_free(heap, ipc); | ||
| return -ENOMEM; |
Comment on lines
+582
to
+584
| ipc_user_init(); | ||
|
|
||
| return platform_ipc_init(ipc); |
Comment on lines
+1536
to
+1537
| memcpy_s(&mi, sizeof(mi), ipc4, sizeof(*ipc4)); | ||
| if (!cpu_is_me(mi.extension.r.core_id)) { |
Comment on lines
+1710
to
+1717
| case SOF_IPC4_MOD_BIND: { | ||
| struct ipc4_module_bind_unbind bu; | ||
|
|
||
| memcpy_s(&bu, sizeof(bu), &msg, sizeof(msg)); | ||
| result = ipc_comp_connect(ipc_user->ipc, | ||
| (ipc_pipe_comp_connect *)&bu); | ||
| break; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains one of the remaining big subsets from #10558 and implements ability to handle a subset of IPC in a Zephyr user-space thread. This is an important enabler for running the SOF audio pipelines in user-space and allows us to run all audio module code in user context (including the module initialization and configuration functions).
This PR has no impact to default SOF builds where LL audio pipelines are run in kernel space.