[DNM][Do Not Review][WiP][PoC] userspace LL scheduling: LLEXT & multicore - #10945
Open
lyakh wants to merge 29 commits into
Open
[DNM][Do Not Review][WiP][PoC] userspace LL scheduling: LLEXT & multicore#10945lyakh wants to merge 29 commits into
lyakh wants to merge 29 commits into
Conversation
Merged
lyakh
force-pushed
the
llext-ull
branch
2 times, most recently
from
July 14, 2026 09:58
a462fcf to
9f6770d
Compare
This was referenced Jul 14, 2026
This was referenced Aug 12, 2026
Collaborator
Author
|
After multiple PRs got merged we're down from 108 commits to 32 |
This was referenced Aug 20, 2026
scheduler_get_data() only finds scheduler data for kernel mode schedulers. Add a similar function for userspace schedulers. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
scheduler_dp_task_init() currently only runs in privileged mode, add a comment and a check for that. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
The entire user_access_to_mailbox() function is already under an #ifdef CONFIG_SOF_USERSPACE_LL condition. Remove an additional identical check inside the function. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Make vregion_alloc(), vregion_alloc_coherent(), vregion_alloc_align(), vregion_alloc_coherent_align(), and vregion_free() available as Zephyr system calls for user-space threads. Add K_SYSCALL_MEMORY_WRITE verification to all syscall handlers to validate the calling thread has access to the vregion's managed memory area. Add CONFIG_SOF_USERSPACE_INTERFACE_VREGION Kconfig option to control the feature. It is auto-selected by SOF_USERSPACE_LL when SOF_VREGIONS is enabled. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extract common syscall verification code into a function. Also add a a check that the underlying metadata object is inaccessible to the userspace context. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
vregion_get(), vregion_put() and vregion_set_interim() should also be callable from the userspace. Make them syscalls. Also remove redundant symbol exporting since the vregion API shouldn't be used directly by LLEXT modules. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
When userspace LL scheduling is enabled, some vregions have to be accessible to the LL userspace domain. Add a new system call to create vregions with such a mapping and add unmapping to freeing for such mapped vregions. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
z_impl_* functions are declared in automatically generated Zephyr headers, no need to declare them again. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Make vregion_alloc() and vregion_alloc_coherent() static inlines, calling their respective aligned versions with zero alignment. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Before dereferencing the data blob make sure that it matches the expected size, not just isn't exceeding the maximum size. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Make the options from app/overlays/ptl/ll_userspace_overlay.conf the default for the Intel Panther Lake (ptl) and Wildcat Lake (wcl) build targets, so user-space Low-Latency audio pipelines are enabled without having to pass the overlay explicitly. As noted in the overlay header, once user-space LL is enabled for a target by default the settings belong in the SOF board file directly. For ptl the board already provides the user-space base (USERSPACE, dynamic threads, MMU L2 tables, domain partitions), so only the LL overlay options are added and the conflicting telemetry / cold-store / llext / modules defaults are flipped to match the overlay. wcl had no user-space base at all; since CONFIG_SOF_USERSPACE_LL depends on CONFIG_USERSPACE it would otherwise be silently dropped. Mirror ptl's user-space base into the wcl board file as well so LL actually takes effect there. The ll_userspace_overlay.conf file is kept unchanged; it now re-applies identical values and remains usable by development build scripts. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
.cold and .coldrodata partitions can be empty, avoid a failure in such cases. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
lyakh
requested review from
LaurentiuM1234,
abonislawski,
bardliao,
dbaluta,
fkwasowi,
iuliana-prodan,
kv2019i,
lbetlej,
lgirdwood,
marcinszkudlinski,
mmaka1,
pblaszko,
plbossart,
ranj063 and
tmleman
as code owners
August 27, 2026 13:40
Contributor
There was a problem hiding this comment.
Pull request overview
This PR is a WiP/PoC that extends the SOF Zephyr userspace low-latency (LL) work to support LLEXT and multi-core operation, including new syscalls and userspace IPC/LL thread infrastructure per core.
Changes:
- Adds a userspace-accessible vregion syscall interface and vregion-to-mem-domain mapping support.
- Introduces per-core userspace IPC threads and secondary-core initialization plumbing for userspace LL.
- Refactors DP/LL scheduler interactions for multicore and userspace execution contexts, plus library manager changes to support userspace/module-loading flow.
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| zephyr/syscall/vregion.c | Adds Zephyr syscall verifiers/marshalling for vregion operations. |
| zephyr/lib/vregion.c | Implements z_impl_* syscall backends, vregion mapping into a mem domain, and userspace verification. |
| zephyr/lib/userspace_helper.c | Adjusts mailbox partition mapping logic for IPC4 userspace access. |
| zephyr/Kconfig | Adds/selects userspace vregion interface Kconfig option. |
| zephyr/CMakeLists.txt | Registers new syscall headers/sources for vregion and other headers needed by syscalls. |
| uuid-registry.txt | Adds UUID entry used for secondary-core init task. |
| src/schedule/zephyr_ll.c | Updates LL tick path and scheduler data source for userspace LL. |
| src/schedule/zephyr_dp_schedule.h | Removes internal prototypes no longer intended for this header. |
| src/schedule/zephyr_dp_schedule.c | Converts scheduler_dp_ll_tick to a syscall-capable z_impl/z_vrfy API; uses userspace scheduler data. |
| src/schedule/zephyr_dp_schedule_application.c | Updates DP IPC paths and adds syscall verifier for DP internal free. |
| src/schedule/zephyr_domain.c | Adds helper to retrieve the LL domain thread for current core. |
| src/library_manager/llext_manager.c | Changes userspace LL domain add/remove behavior for LLEXT mappings. |
| src/library_manager/lib_manager.c | Refactors module creation to a reusable helper and adds syscall for module free; adjusts userspace/module interactions. |
| src/ipc/ipc4/helper.c | Adds helper to pre-load modules in kernel context for userspace LL flows. |
| src/ipc/ipc4/handler-user.c | Routes more IPC4 messages to per-core userspace handling and adjusts init path for LL vs DP. |
| src/ipc/ipc-common.c | Implements per-core userspace IPC threads, per-core stacks/events/threads, and secondary-core userspace init. |
| src/init/init.c | Hooks secondary-core init to start userspace IPC/LL infrastructure when enabled. |
| src/include/sof/schedule/schedule.h | Adds scheduler_list_get_data() and scheduler_get_user_data() helper for userspace schedulers. |
| src/include/sof/schedule/ll_schedule_domain.h | Exposes zephyr_ll_domain_thread(). |
| src/include/sof/schedule/dp_schedule.h | Exposes scheduler_dp_ll_tick and scheduler_dp_internal_free as syscalls for Zephyr full-app builds. |
| src/include/sof/lib/vregion.h | Exposes vregion syscalls (create_map/get/put/alloc/free/set_interim) and verification helper. |
| src/include/sof/lib_manager.h | Exposes lib_manager_mod_create_priv() and lib_manager_free_module syscall/z_impl mapping. |
| src/include/sof/ipc/common.h | Extends ipc_user struct for per-core threads/events/audio threads; updates ipc_user_forward_cmd signature; declares secondary init helpers. |
| src/include/ipc4/handler.h | Declares ipc4_user_module_load(). |
| src/audio/pipeline/pipeline-graph.c | Adds LL domain include needed by userspace LL changes. |
| src/audio/mux/mux_ipc4.c | Tightens IPC4 mux blob size validation. |
| src/audio/module_adapter/module_adapter.c | Switches DP module heap to vregion_create_map() under userspace constraints. |
| src/audio/buffers/comp_buffer.c | Fixes alloc context free path when vregion-backed allocations are used. |
| app/overlays/ptl/ll_userspace_overlay.conf | Updates overlay config for the evolving userspace LL setup. |
Suppressed comments (2)
zephyr/lib/vregion.c:279
- vregion_unmap(vr) runs after vpage_free(vr->base). This leaves a window where userspace can still access the partition while the backing memory is already freed/reusable, and unmapping may also rely on the region still being valid. Unmap partitions before freeing the backing pages.
LOG_DBG(" lifetime used %zu free count %d", vr->lifetime.used, vr->lifetime.free_count);
vpage_free(vr->base);
vregion_unmap(vr);
rfree(vr);
src/ipc/ipc-common.c:342
- ipc_user_forward_cmd() uses 'core' to index init_needed[] and event[] with no bounds checking. core ultimately comes from IPC fields and can be out of range, leading to out-of-bounds access and memory corruption.
int ipc_user_forward_cmd(uint32_t primary, uint32_t extension, unsigned int core)
{
struct ipc *ipc = ipc_get();
struct ipc_user *pdata = ipc->ipc_user_pdata;
k_spinlock_key_t key;
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+202
to
+224
| struct k_mem_domain *domain = zephyr_ll_mem_domain(); | ||
| struct k_mem_partition part = { | ||
| .start = *vreg_start, | ||
| .size = *vreg_size, | ||
| .attr = K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB, | ||
| }; | ||
| int ret = k_mem_domain_add_partition(domain, &part); | ||
|
|
||
| if (ret < 0) { | ||
| vregion_put(vr); | ||
| return NULL; | ||
| } | ||
|
|
||
| part.start = (uintptr_t)sys_cache_uncached_ptr_get((void *)part.start); | ||
| part.attr = K_MEM_PARTITION_P_RW_U_RW; | ||
|
|
||
| ret = k_mem_domain_add_partition(domain, &part); | ||
| if (ret < 0) { | ||
| vregion_put(vr); | ||
| return NULL; | ||
| } | ||
|
|
||
| vr->domain = domain; |
Comment on lines
+559
to
+563
|
|
||
| size_t vr_size = 0; | ||
| uintptr_t vr_start; | ||
|
|
||
| vregion_mem_info(vr, &vr_size, &vr_start); |
Comment on lines
+51
to
+56
| struct vregion *z_vrfy_vregion_create_map(uintptr_t *vreg_start, size_t *vreg_size) | ||
| { | ||
| K_OOPS(K_SYSCALL_MEMORY_WRITE(vreg_start, sizeof(*vreg_start))); | ||
| K_OOPS(K_SYSCALL_MEMORY_WRITE(vreg_size, sizeof(*vreg_size))); | ||
| return z_impl_vregion_create_map(vreg_start, vreg_size); | ||
| } |
Comment on lines
+245
to
+248
| void z_vrfy_scheduler_dp_ll_tick(unsigned int core) | ||
| { | ||
| z_impl_scheduler_dp_ll_tick(core); | ||
| } |
Comment on lines
716
to
720
| case MOD_TYPE_IADK: | ||
| agent = &system_agent_start; | ||
| ops = &processing_module_adapter_interface; | ||
| agent_iface = (const void **)&adapter_priv; | ||
| *ops = &processing_module_adapter_interface; | ||
| agent_iface = (const void **)adapter_priv; | ||
| break; |
Comment on lines
+266
to
+270
| struct userspace_context *userspace = NULL; | ||
| const struct module_interface *ops = NULL; | ||
|
|
||
| return lib_manager_mod_create_priv(drv, &ipc_config, &spec, NULL, &userspace, &ops); | ||
| } |
Comment on lines
540
to
+542
|
|
||
| assert_can_be_cold(); | ||
|
|
Make scheduler_dp_internal_free() a syscall in the "application" DP implementation. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Make scheduling LL thread and synchronisation objects per-core and forward IPCs and scheduling events accordingly. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
In case of userspace LL scheduling the (also userspace) IPC thread needs access rights to DP assets like the thread itself and its stack and synchronisation primitives. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
The LL userspace thread has to interact with the DP one. Grant required rights. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Switching to the userspace mode in DP and LL cases differs. Add a comment to explain that. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extract common initialisation code from comp_new_ipc4_user() and comp_new_ipc4() into a new function. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
When running in syscall context on behalf of a userspace thread dynamically mapped memory doesn't automatically become accessible. To make it accessible it has to be added to the thread memory domain. This is a problem for loadable modules with executable cold sections. To be able to execute them they have to be mapped to threads with the executable bit set. While for linking that memory has to be mapped writable. To solve the problem we perform linking from the kernel IPC context before forwarding to the userspace IPC thread. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
LLEXT is now working with userspace LL and can be enabled. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
This reverts commit b647695127b6c23f4ebeb510f3cbd0c08a23dc24.
CONFIG_COLD_STORE_EXECUTE_DRAM can now be re-enabled for userspace LL. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
The DP scheduler can now be user with userspace LL. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
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 includes #10558 and my patches on top to enable LLEXT and multicore. Current status: passes simple tests with nocodec with both core 0 and core 1 streaming. 2 streams simultaneously run into a problem when the first of them terminates. WiP.