Skip to content

Commit 235b6f4

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 72287ac commit 235b6f4

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
@@ -208,6 +208,105 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i
208208
return dev;
209209
}
210210

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

0 commit comments

Comments
 (0)