Skip to content

Commit d9063e0

Browse files
committed
ipc4: create components in user-space thread context
Add comp_new_ipc4_user(), called from the user-space IPC thread to create a component from user context. It receives a pre-resolved driver pointer from the kernel handler (which does the privileged IMR manifest / driver list lookup), parses the IPC4 init-instance message, reads the module init parameter block from the HOSTBOX, and calls drv->ops.create() so untrusted module init code does not execute with kernel privileges. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
1 parent 86587ca commit d9063e0

2 files changed

Lines changed: 105 additions & 0 deletions

File tree

src/include/sof/ipc/topology.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ struct ipc_comp_dev;
5050
const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id);
5151
struct comp_dev *ipc4_get_comp_dev(uint32_t comp_id);
5252
int ipc4_add_comp_dev(struct comp_dev *dev);
53+
#ifdef CONFIG_SOF_USERSPACE_LL
54+
struct ipc4_message_request;
55+
struct comp_driver;
56+
struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4,
57+
const struct comp_driver *drv);
58+
#endif
5359
int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma);
5460
int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma);
5561
int ipc4_create_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma);

src/ipc/ipc4/helper.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,105 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i
222222
return dev;
223223
}
224224

225+
#ifdef CONFIG_SOF_USERSPACE_LL
226+
/**
227+
* comp_new_ipc4_user - Create component in user-space IPC thread context.
228+
*
229+
* Called from the user-space IPC thread. Receives a pre-resolved driver
230+
* pointer from the kernel handler. Performs IPC4 message parsing, HOSTBOX
231+
* data read, and calls drv->ops.create() in user-space context.
232+
*
233+
* @param ipc4 IPC4 message request (reconstructed from ipc_user pri/ext words)
234+
* @param drv Component driver resolved by kernel via ipc4_get_comp_drv()
235+
* @return Created component device, or NULL on failure
236+
*/
237+
__cold struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4,
238+
const struct comp_driver *drv)
239+
{
240+
struct ipc4_module_init_instance module_init;
241+
struct comp_ipc_config ipc_config;
242+
struct comp_dev *dev;
243+
uint32_t comp_id;
244+
char *data;
245+
int ret;
246+
247+
assert_can_be_cold();
248+
249+
ret = memcpy_s(&module_init, sizeof(module_init), ipc4, sizeof(*ipc4));
250+
if (ret < 0)
251+
return NULL;
252+
253+
comp_id = IPC4_COMP_ID(module_init.primary.r.module_id,
254+
module_init.primary.r.instance_id);
255+
256+
if (ipc4_get_comp_dev(comp_id)) {
257+
tr_err(&ipc_tr, "comp 0x%x exists", comp_id);
258+
return NULL;
259+
}
260+
261+
if (module_init.extension.r.core_id >= CONFIG_CORE_COUNT) {
262+
tr_err(&ipc_tr, "ipc: comp->core = %u",
263+
(uint32_t)module_init.extension.r.core_id);
264+
return NULL;
265+
}
266+
267+
memset(&ipc_config, 0, sizeof(ipc_config));
268+
ipc_config.id = comp_id;
269+
ipc_config.pipeline_id = module_init.extension.r.ppl_instance_id;
270+
ipc_config.core = module_init.extension.r.core_id;
271+
ipc_config.ipc_config_size =
272+
module_init.extension.r.param_block_size * sizeof(uint32_t);
273+
ipc_config.ipc_extended_init = module_init.extension.r.extended_init;
274+
if (ipc_config.ipc_config_size > MAILBOX_HOSTBOX_SIZE) {
275+
tr_err(&ipc_tr,
276+
"IPC payload size %u too big for the message window",
277+
ipc_config.ipc_config_size);
278+
return NULL;
279+
}
280+
#ifdef CONFIG_DCACHE_LINE_SIZE
281+
if (!IS_ENABLED(CONFIG_LIBRARY))
282+
sys_cache_data_invd_range(
283+
(__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE,
284+
ALIGN_UP(ipc_config.ipc_config_size,
285+
CONFIG_DCACHE_LINE_SIZE));
286+
#endif
287+
data = ipc4_get_comp_new_data();
288+
289+
#if CONFIG_ZEPHYR_DP_SCHEDULER
290+
if (module_init.extension.r.proc_domain)
291+
ipc_config.proc_domain = COMP_PROCESSING_DOMAIN_DP;
292+
else
293+
ipc_config.proc_domain = COMP_PROCESSING_DOMAIN_LL;
294+
#else
295+
if (module_init.extension.r.proc_domain) {
296+
tr_err(&ipc_tr,
297+
"ipc: DP scheduling is disabled, cannot create comp 0x%x",
298+
comp_id);
299+
return NULL;
300+
}
301+
ipc_config.proc_domain = COMP_PROCESSING_DOMAIN_LL;
302+
#endif
303+
304+
if (drv->type == SOF_COMP_MODULE_ADAPTER) {
305+
const struct ipc_config_process spec = {
306+
.data = (const unsigned char *)data,
307+
.size = ipc_config.ipc_config_size,
308+
};
309+
310+
dev = drv->ops.create(drv, &ipc_config, (const void *)&spec);
311+
} else {
312+
dev = drv->ops.create(drv, &ipc_config, (const void *)data);
313+
}
314+
if (!dev)
315+
return NULL;
316+
317+
list_init(&dev->bsource_list);
318+
list_init(&dev->bsink_list);
319+
320+
return dev;
321+
}
322+
#endif /* CONFIG_SOF_USERSPACE_LL */
323+
225324
/* Called from ipc4_set_pipeline_state(), so cannot be cold */
226325
struct ipc_comp_dev *ipc_get_comp_by_ppl_id(struct ipc *ipc, uint16_t type,
227326
uint32_t ppl_id,

0 commit comments

Comments
 (0)