Skip to content

[DNM][Do Not Review][WiP][PoC] userspace LL scheduling: LLEXT & multicore - #10945

Open
lyakh wants to merge 16 commits into
thesofproject:mainfrom
lyakh:llext-ull
Open

[DNM][Do Not Review][WiP][PoC] userspace LL scheduling: LLEXT & multicore#10945
lyakh wants to merge 16 commits into
thesofproject:mainfrom
lyakh:llext-ull

Conversation

@lyakh

@lyakh lyakh commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

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.

@lyakh

lyakh commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

After multiple PRs got merged we're down from 108 commits to 32

@lyakh

lyakh commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

let me mark it "ready" to have some on-device testing

@lyakh
lyakh marked this pull request as ready for review August 27, 2026 13:40
Copilot AI lite review requested due to automatic review settings August 27, 2026 13:40
@lyakh lyakh changed the title [DNM][WiP][PoC] userspace LL scheduling: LLEXT & multicore [DNM][Do Not Review][WiP][PoC] userspace LL scheduling: LLEXT & multicore Aug 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 thread zephyr/lib/vregion.c
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 thread zephyr/lib/vregion.c
Comment on lines +559 to +563

size_t vr_size = 0;
uintptr_t vr_start;

vregion_mem_info(vr, &vr_size, &vr_start);
Comment thread zephyr/syscall/vregion.c
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 thread src/ipc/ipc4/helper.c
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 thread src/ipc/ipc-common.c
Comment on lines 540 to +542

assert_can_be_cold();

@lyakh
lyakh force-pushed the llext-ull branch 4 times, most recently from 5064a54 to e62b4cd Compare August 28, 2026 08:01
lyakh added 16 commits August 28, 2026 10:10
.cold and .coldrodata partitions can be empty, avoid a failure in
such cases.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extract a privileged LLEXT-related part from
lib_manager_module_create() into a separate function to be called
from kernel context. At the same time lib_manager_mod_free_priv()
already executes privileged operations; to make it callable in
userspace, convert lib_manager_free_module() to a system call.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
ipc4_init_module_instance() should be called when
CONFIG_SOF_USERSPACE_LL isn't selected but also when initializing a
DP module.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
If LL runs in userspace, it needs access to loaded LLEXT modules,
running in DP more too.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
The DP scheduler runs tasks in userspace mode, it's registered with
the user scheduler list, therefore it should use
scheduler_get_user_data(), not scheduler_get_data().

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
scheduler_dp_ll_tick(() has to recalculate DP deadlines and
reschedule DP threads. Make it a syscall to be able to call it from
the userspace LL scheduler.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DNM Do Not Merge tag

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants