Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions src/include/sof/schedule/ll_schedule_domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ struct ll_schedule_domain *zephyr_domain_init(int clk);
#define timer_domain_init(timer, clk) zephyr_domain_init(clk)
#ifdef CONFIG_SOF_USERSPACE_LL
struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain);
struct k_thread *zephyr_domain_thread_tid_for_core(int core);
struct k_mem_domain *zephyr_ll_mem_domain(void);
#endif /* CONFIG_SOF_USERSPACE_LL */
#ifdef CONFIG_SOF_FULL_ZEPHYR_APPLICATION
Expand Down
27 changes: 27 additions & 0 deletions src/schedule/zephyr_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,14 @@ static int zephyr_domain_unregister(struct ll_schedule_domain *domain,

#else /* CONFIG_SOF_USERSPACE_LL */

/*
* Kernel-owned per-core LL thread table. Populated from the privileged
* domain-thread init path and consulted by z_impl_zephyr_ll_task_sem_alloc()
* so that privileged code never has to traverse the user-accessible
* scheduler/domain objects to find the LL thread of a given core.
*/
static struct k_thread *ll_thread_tid[CONFIG_CORE_COUNT];

/*
* Privileged thread initialization for userspace LL scheduling.
* Creates the scheduling thread, sets up timer, grants access to kernel
Expand Down Expand Up @@ -343,6 +351,9 @@ static int zephyr_domain_thread_init(struct ll_schedule_domain *domain,
INT_TO_POINTER(core), NULL, CONFIG_LL_THREAD_PRIORITY,
K_USER, K_FOREVER);

/* record in the kernel-only table for syscall-context lookups */
ll_thread_tid[core] = dt->ll_thread;

#ifdef CONFIG_SCHED_CPU_MASK
k_thread_cpu_pin(thread, core);
#endif
Expand Down Expand Up @@ -477,6 +488,7 @@ static void zephyr_domain_thread_free(struct ll_schedule_domain *domain,
k_thread_abort(dt->ll_thread);
k_object_free(dt->ll_thread);
dt->ll_thread = NULL;
ll_thread_tid[core] = NULL;
}

if (dt->sem) {
Expand All @@ -498,6 +510,21 @@ struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain)
return dt->ll_thread;
}

/*
* Return the LL scheduling thread for an explicitly given core.
*
* Reads a kernel-only table keyed by core, so it is safe to call from a
* privileged syscall context without dereferencing any user-accessible
* scheduler or domain object, and without relying on cpu_get_id().
*/
struct k_thread *zephyr_domain_thread_tid_for_core(int core)
{
if (core < 0 || core >= CONFIG_CORE_COUNT)
return NULL;

return ll_thread_tid[core];
}

#endif /* CONFIG_SOF_USERSPACE_LL */

#if CONFIG_CROSS_CORE_STREAM
Expand Down
19 changes: 19 additions & 0 deletions src/schedule/zephyr_ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,25 @@ int z_impl_zephyr_ll_task_sem_alloc(struct task *task)

k_sem_init(ts->sem, 0, 1);

#if CONFIG_SOF_USERSPACE_LL
/*
* The per-task semaphore is signalled from zephyr_ll_task_done(),
* which runs in the (unprivileged) LL scheduler thread when a task is
* freed while it is still running. k_object_alloc() only grants access
* to the calling thread (the IPC handler that creates the task), so the
* LL thread must be granted access explicitly, otherwise its
* k_sem_give() traps with a userspace permission fault.
*
* Resolve the LL thread from kernel-only per-core state keyed by the
* task's target core; never traverse the user-accessible scheduler or
* domain objects from privileged context.
*/
struct k_thread *ll_tid = zephyr_domain_thread_tid_for_core(task->core);

if (ll_tid)
k_thread_access_grant(ll_tid, ts->sem);
#endif

ts->task = task;
pdata->sem_p = ts->sem;
/* List is protected by IPC serialization */
Expand Down
Loading