|
| 1 | +# Loadable Library & Userspace Proxy (`module_adapter/library`) |
| 2 | + |
| 3 | +The `library` directory within the module adapter manages the lifecycle and execution isolation for dynamically loaded algorithms, often referred to as "LLEXT modules" or "Userspace Modules". |
| 4 | + |
| 5 | +It acts as a secure intermediary layer between the native SOF/Zephyr kernel execution mode (supervisor mode) and the 3rd-party module running in an isolated user-mode context. By relying on Zephyr's Userspace mechanisms (`k_mem_domain`, `K_USER` threads), a faulting or misbehaving loadable extension cannot crash the entire firmware. |
| 6 | + |
| 7 | +## Architecture & Userspace Sandbox |
| 8 | + |
| 9 | +The Userspace Proxy architecture involves: |
| 10 | + |
| 11 | +- **`struct userspace_context`**: This encapsulates the memory domain (`k_mem_domain`) mapped exclusively for this module (code, rodata, BSS, and private heap memory). |
| 12 | +- **`user_work_item`**: A Zephyr `k_work_user` mechanism. IPC configuration commands and data processing calls are packaged into a work item and executed safely inside the memory boundaries via `userspace_proxy_worker_handler`. |
| 13 | + |
| 14 | +```mermaid |
| 15 | +graph TD |
| 16 | + subgraph SOF Supervisor Domain |
| 17 | + P["Pipeline DP Scheduler"] |
| 18 | + MADP["Module Adapter Context"] |
| 19 | + PROXY["Userspace Proxy (userspace_proxy_invoke)"] |
| 20 | + end |
| 21 | +
|
| 22 | + subgraph Zephyr Userspace Domain |
| 23 | + SYSAGENT["LLEXT System Agent"] |
| 24 | + HANDLER["Worker Handler (userspace_proxy_handle_request)"] |
| 25 | + MOD["External Loadable Module (struct module_interface)"] |
| 26 | + end |
| 27 | +
|
| 28 | + P -->|Triggers process| MADP |
| 29 | + MADP -->|Invokes Proxy| PROXY |
| 30 | +
|
| 31 | + PROXY -->|Packages params & k_work| HANDLER |
| 32 | +
|
| 33 | + HANDLER -->|Safe Call Context| MOD |
| 34 | + SYSAGENT -.->|Bootstraps| MOD |
| 35 | +
|
| 36 | + style SOF Supervisor Domain fill:#1d2951,stroke:#333 |
| 37 | + style Zephyr Userspace Domain fill:#2e0b1a,stroke:#333 |
| 38 | +``` |
| 39 | + |
| 40 | +## State Transitions & IPC Handling |
| 41 | + |
| 42 | +IPC messages arriving from the host (e.g. `SET_CONF`, `GET_CONF`, `MODULE_INIT`, `MODULE_BIND`) first hit the Module Adapter running in Supervisor Mode. The adapter checks its configuration and invokes the Userspace Proxy. The proxy performs the following context switch: |
| 43 | + |
| 44 | +```mermaid |
| 45 | +sequenceDiagram |
| 46 | + participant IPC as SOF IPC Task |
| 47 | + participant MA as Module Adapter |
| 48 | + participant Proxy as Userspace Proxy |
| 49 | + participant Worker as Zephyr k_work_user Thread |
| 50 | + participant UserMod as LLEXT Module |
| 51 | +
|
| 52 | + IPC->>MA: IPC SET_CONF config_id |
| 53 | + MA->>Proxy: userspace_proxy_set_configuration |
| 54 | +
|
| 55 | + note over Proxy: 1. Package proxy params |
| 56 | + note over Proxy: 2. Add Mailbox memory to `k_mem_domain` |
| 57 | + note over Proxy: 3. Post `k_work_user` / event |
| 58 | +
|
| 59 | + Proxy->>Worker: Context Switch -> User Mode |
| 60 | +
|
| 61 | + Worker->>UserMod: module_interface set_configuration |
| 62 | +
|
| 63 | + note over UserMod: Parse config payload safely |
| 64 | +
|
| 65 | + UserMod-->>Worker: Return status |
| 66 | + Worker-->>Proxy: Signal Task Done |
| 67 | +
|
| 68 | + note over Proxy: Remove Mailbox memory from domain |
| 69 | +
|
| 70 | + Proxy-->>MA: Return execution |
| 71 | + MA-->>IPC: Send Reply/Status to Host |
| 72 | +``` |
| 73 | + |
| 74 | +### Memory Domain Adjustments |
| 75 | + |
| 76 | +A crucial aspect of the userspace proxy is dynamic memory permission elevation: |
| 77 | + |
| 78 | +- Normally, the userspace module can only access its own `heap`, `data`, and `bss` partitions. |
| 79 | +- When an IPC like `GET_CONF` requests large IPC buffers, the proxy temporarily adds the hardware `MAILBOX_HOSTBOX` into the module's `k_mem_domain` using `k_mem_domain_add_partition()`. |
| 80 | +- Once the userspace thread returns, that hardware window is immediately removed from the memory domain to minimize the vulnerability window. |
0 commit comments