Skip to content

userspace: proxy: Add support for llext modules#10643

Open
softwarecki wants to merge 4 commits intothesofproject:mainfrom
softwarecki:userspace-llext
Open

userspace: proxy: Add support for llext modules#10643
softwarecki wants to merge 4 commits intothesofproject:mainfrom
softwarecki:userspace-llext

Conversation

@softwarecki
Copy link
Collaborator

  • Add support for userspace llext loadable modules to the userspace proxy.
  • Extend the SOF_LLEXT_MODULE_MANIFEST macro with an optional variadic parameter to specify the user_mode flag for llext modules. When the argument is omitted, user_mode defaults to 0, preserving backward compatibility with existing module manifests.
  • Allow fast_get sram buffer sharing across multiple userspace module instances when CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP is enabled.
  • Simplify checking whether a calling thread runs in userspace by verifying
    if the K_USER flag is set.
  • Add a memory partition for the module driver heap k_heap structure to the module's memory domain to allow it to be referenced by syscalls.
  • Update the userspace_proxy_memory_init function to reflect the removal of memory double mapping in Zephyr by replacing the CONFIG_XTENSA_MMU_DOUBLE_MAP with a simple CONFIG_SOF_ZEPHYR_HEAP_CACHED check.

…FEST

Extend the SOF_LLEXT_MODULE_MANIFEST macro with an optional variadic
parameter to specify the user_mode flag for llext modules. When the
argument is omitted, user_mode defaults to 0, preserving backward
compatibility with existing module manifests.

Update the rimage to propagate the user_mode field from the module manifest
to manifest structure in the final firmware binary image.

Signed-off-by: Adrian Warecki <adrian.warecki@intel.com>
Add support for userspace llext loadable modules to the userspace proxy.
Call lib_manager_start_agent unconditionally, even when the system agent
is not used, as this function is responsible for creating the userspace
module proxy.

Signed-off-by: Adrian Warecki <adrian.warecki@intel.com>
Allow fast_get sram buffer sharing across multiple userspace module
instances when CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP is enabled. The module
driver heap is shared by all instances of a given module, so allocated
buffers can safely be reused between them.

Simplify checking whether a calling thread runs in userspace by verifying
if the K_USER flag is set.

Signed-off-by: Adrian Warecki <adrian.warecki@intel.com>
Copilot AI review requested due to automatic review settings March 23, 2026 12:29
Add a memory partition for the module driver heap k_heap structure to the
module's memory domain to allow it to be referenced by syscalls. When a new
memory domain is created, only L2 entries mapped with OPTION_SAVE_ATTRS are
copied. Memory mapped dynamically during firmware execution is not
accessible in new memory domains by default.

Update the code to reflect the removal of memory double mapping in Zephyr
by replacing the CONFIG_XTENSA_MMU_DOUBLE_MAP with a simple
CONFIG_SOF_ZEPHYR_HEAP_CACHED check.

Signed-off-by: Adrian Warecki <adrian.warecki@intel.com>
Copy link
Contributor

Copilot AI left a comment

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 adds support for userspace llext modules in the userspace proxy and updates related memory-domain and fast_get behavior to accommodate shared heaps and Zephyr MMU changes.

Changes:

  • Extend llext module manifests to optionally set a user_mode flag and propagate it into rimage manifests.
  • Update userspace proxy memory-domain setup (including adding a partition for the module driver heap k_heap structure) and add llext domain integration.
  • Adjust fast_get() behavior for userspace/driver-heap configurations and simplify userspace-thread detection.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
zephyr/lib/userspace_helper.c Removes a now-unneeded macro alias related to heap caching configuration.
zephyr/lib/fast-get.c Adjusts buffer sharing/caching logic and userspace-thread detection.
tools/rimage/src/manifest.c Propagates user_mode into generated module manifests.
src/library_manager/lib_manager.c Makes agent start conditional and ensures LLEXT uses no agent interface.
src/include/module/module/llext.h Extends LLEXT manifest macro with optional user_mode argument.
src/audio/module_adapter/library/userspace_proxy.c Adds llext manager integration, updates memory-domain partitioning, and handles agent-less modules.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

/* We only get there for large buffers */
if (k_current_get()->mem_domain_info.mem_domain->num_partitions > 1) {
/* We only get there for large buffers or module driver heap is in use */
if (k_current_get()->base.user_options & K_USER && size > FAST_GET_MAX_COPY_SIZE) {
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The comment states this branch applies to 'large buffers or module driver heap is in use', but the condition only gates on size > FAST_GET_MAX_COPY_SIZE. If the driver-heap configuration is intended to share buffers across userspace instances independent of size, the condition should incorporate CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP (or the comment should be corrected). As written, the driver-heap case is ignored by this userspace-thread path.

Suggested change
if (k_current_get()->base.user_options & K_USER && size > FAST_GET_MAX_COPY_SIZE) {
if ((k_current_get()->base.user_options & K_USER) &&
(size > FAST_GET_MAX_COPY_SIZE ||
IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP))) {

Copilot uses AI. Check for mistakes.
Comment on lines +432 to +436
if (agent_fn)
ret = userspace_proxy_add_sections(context, agent_params->instance_id, manifest);
else
/* llext modules do not use the system agent. */
ret = llext_manager_add_domain(agent_params->module_id, domain);
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

agent_fn is explicitly allowed to be NULL (llext path), but userspace_proxy_start_agent() is still called unconditionally with agent_fn. This can lead to a NULL function-pointer call unless userspace_proxy_start_agent() internally guards it. Consider skipping userspace_proxy_start_agent() entirely when agent_fn == NULL and ensuring any required agent_interface/ops setup for llext is handled in the llext path.

Copilot uses AI. Check for mistakes.
Comment on lines +445 to 448
ret = userspace_proxy_start_agent(context, agent_fn, agent_params, agent_interface);
if (ret) {
tr_err(&userspace_proxy_tr, "System agent failed with error %d.", ret);
goto error_work_item;
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

agent_fn is explicitly allowed to be NULL (llext path), but userspace_proxy_start_agent() is still called unconditionally with agent_fn. This can lead to a NULL function-pointer call unless userspace_proxy_start_agent() internally guards it. Consider skipping userspace_proxy_start_agent() entirely when agent_fn == NULL and ensuring any required agent_interface/ops setup for llext is handled in the llext path.

Suggested change
ret = userspace_proxy_start_agent(context, agent_fn, agent_params, agent_interface);
if (ret) {
tr_err(&userspace_proxy_tr, "System agent failed with error %d.", ret);
goto error_work_item;
if (agent_fn) {
ret = userspace_proxy_start_agent(context, agent_fn, agent_params, agent_interface);
if (ret) {
tr_err(&userspace_proxy_tr, "System agent failed with error %d.", ret);
goto error_work_item;
}

Copilot uses AI. Check for mistakes.
k_mem_region_align(&heap_struct_part.start, &heap_struct_part.size,
POINTER_TO_UINT(drv->user_heap),
sizeof(*drv->user_heap), CONFIG_MM_DRV_PAGE_SIZE);
heap_struct_part.attr = K_MEM_PARTITION_P_RW_U_NA |
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The added partition is intended so that drv->user_heap 'can be referenced by syscalls' from the userspace domain, but it is created with U_NA (no user access). For syscall argument validation and/or user-mode access to succeed, the partition typically needs user permissions (e.g., K_MEM_PARTITION_P_RW_U_RO or K_MEM_PARTITION_P_RW_U_RW, depending on the expected access pattern). With U_NA, userspace likely cannot legally reference the k_heap object.

Suggested change
heap_struct_part.attr = K_MEM_PARTITION_P_RW_U_NA |
heap_struct_part.attr = K_MEM_PARTITION_P_RW_U_RO |

Copilot uses AI. Check for mistakes.
heap_struct_part.attr = K_MEM_PARTITION_P_RW_U_NA |
user_get_partition_attr(heap_struct_part.start);

tr_err(&userspace_proxy_tr, "Heap struct partition %#lx + %zx, attr = %u",
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

This looks like informational tracing (similar to the surrounding tr_dbg() partition logs) but is emitted as tr_err(). Logging this at error level can create noisy logs and false-positive error signals in production. Consider downgrading this to tr_dbg() (or tr_info() if you want it visible by default).

Suggested change
tr_err(&userspace_proxy_tr, "Heap struct partition %#lx + %zx, attr = %u",
tr_dbg(&userspace_proxy_tr, "Heap struct partition %#lx + %zx, attr = %u",

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants