Skip to content

Commit 04f7e20

Browse files
committed
ipc4: forward pipeline and module commands to the user thread
Route the IPC4 commands that operate on audio pipelines to the user-space IPC thread via ipc_user_forward_cmd() when CONFIG_SOF_USERSPACE_LL is enabled: create/delete/set-state pipeline, config get/set, large-config get/set, bind/unbind and init/delete instance. For MOD_INIT_INSTANCE the kernel still resolves the driver (needs IMR manifest access) and copies comp_driver + tr_ctx into the user-readable ipc_user buffer before forwarding; cross-core creation stays in kernel. LARGE_CONFIG get/set for base firmware (module_id 0) also stay in kernel because they touch the IMR manifest. CONFIG_GET / LARGE_CONFIG_GET copy the reply extension (and tx payload) back from the user thread. The now-unused ipc4_new_pipeline()/ipc4_delete_pipeline() kernel helpers are compiled out in the user-space configuration. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
1 parent 207880e commit 04f7e20

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

src/ipc/ipc4/handler-user.c

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ static inline const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data(
9090
/*
9191
* Global IPC Operations.
9292
*/
93+
#ifndef CONFIG_SOF_USERSPACE_LL
9394
__cold static int ipc4_new_pipeline(struct ipc4_message_request *ipc4)
9495
{
9596
struct ipc *ipc = ipc_get();
@@ -98,7 +99,9 @@ __cold static int ipc4_new_pipeline(struct ipc4_message_request *ipc4)
9899

99100
return ipc_pipeline_new(ipc, (ipc_pipe_new *)ipc4);
100101
}
102+
#endif
101103

104+
#ifndef CONFIG_SOF_USERSPACE_LL
102105
__cold static int ipc4_delete_pipeline(struct ipc4_message_request *ipc4)
103106
{
104107
struct ipc4_pipeline_delete *pipe;
@@ -111,6 +114,7 @@ __cold static int ipc4_delete_pipeline(struct ipc4_message_request *ipc4)
111114

112115
return ipc_pipeline_free(ipc, pipe->primary.r.instance_id);
113116
}
117+
#endif
114118

115119
static int ipc4_pcm_params(struct ipc_comp_dev *pcm_dev)
116120
{
@@ -689,13 +693,25 @@ int ipc4_user_process_glb_message(struct ipc4_message_request *ipc4,
689693

690694
/* pipeline settings */
691695
case SOF_IPC4_GLB_CREATE_PIPELINE:
696+
#ifdef CONFIG_SOF_USERSPACE_LL
697+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
698+
#else
692699
ret = ipc4_new_pipeline(ipc4);
700+
#endif
693701
break;
694702
case SOF_IPC4_GLB_DELETE_PIPELINE:
703+
#ifdef CONFIG_SOF_USERSPACE_LL
704+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
705+
#else
695706
ret = ipc4_delete_pipeline(ipc4);
707+
#endif
696708
break;
697709
case SOF_IPC4_GLB_SET_PIPELINE_STATE:
710+
#ifdef CONFIG_SOF_USERSPACE_LL
711+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
712+
#else
698713
ret = ipc4_set_pipeline_state(ipc4);
714+
#endif
699715
break;
700716

701717
case SOF_IPC4_GLB_GET_PIPELINE_STATE:
@@ -1503,28 +1519,158 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4,
15031519

15041520
switch (type) {
15051521
case SOF_IPC4_MOD_INIT_INSTANCE:
1522+
#ifdef CONFIG_SOF_USERSPACE_LL
1523+
{
1524+
/* User-space init: kernel does driver lookup only (requires
1525+
* access to IMR manifest and driver list in kernel memory).
1526+
* Component creation (drv->ops.create) runs in user thread
1527+
* so untrusted module code does not execute in kernel context.
1528+
* Cross-core creation stays fully in kernel.
1529+
*/
1530+
struct ipc4_module_init_instance mi;
1531+
1532+
BUILD_ASSERT(sizeof(struct comp_driver) + sizeof(struct tr_ctx) <=
1533+
sizeof(((struct ipc_user *)0)->init_drv_data),
1534+
"ipc_user.init_drv_data too small for driver copy");
1535+
1536+
ret = memcpy_s(&mi, sizeof(mi), ipc4, sizeof(*ipc4));
1537+
if (ret < 0)
1538+
break;
1539+
1540+
if (!cpu_is_me(mi.extension.r.core_id)) {
1541+
ret = ipc4_init_module_instance(ipc4);
1542+
} else {
1543+
struct ipc *ipc = ipc_get();
1544+
uint32_t comp_id = IPC4_COMP_ID(mi.primary.r.module_id,
1545+
mi.primary.r.instance_id);
1546+
const struct comp_driver *drv = ipc4_get_comp_drv(
1547+
IPC4_MOD_ID(comp_id));
1548+
struct ipc_user *pdata = ipc->ipc_user_pdata;
1549+
1550+
if (!drv) {
1551+
ret = IPC4_MOD_NOT_INITIALIZED;
1552+
break;
1553+
}
1554+
1555+
/* Copy comp_driver and tr_ctx into user-accessible ipc_user buffer
1556+
* originals are in kernel .rodata/.data and not readable from user mode.
1557+
*/
1558+
struct comp_driver *drv_copy =
1559+
(struct comp_driver *)pdata->init_drv_data;
1560+
struct tr_ctx *tctx_copy =
1561+
(struct tr_ctx *)(pdata->init_drv_data +
1562+
sizeof(struct comp_driver));
1563+
1564+
ret = memcpy_s(drv_copy, sizeof(*drv_copy),
1565+
drv, sizeof(*drv));
1566+
if (!ret && drv->tctx) {
1567+
ret = memcpy_s(tctx_copy, sizeof(*tctx_copy),
1568+
drv->tctx, sizeof(*drv->tctx));
1569+
drv_copy->tctx = tctx_copy;
1570+
}
1571+
1572+
if (ret < 0)
1573+
break;
1574+
1575+
pdata->init_drv = drv;
1576+
ret = ipc_user_forward_cmd(ipc4->primary.dat,
1577+
ipc4->extension.dat);
1578+
}
1579+
}
1580+
#else
15061581
ret = ipc4_init_module_instance(ipc4);
1582+
#endif
15071583
break;
15081584
case SOF_IPC4_MOD_CONFIG_GET:
1585+
#ifdef CONFIG_SOF_USERSPACE_LL
1586+
/* Forward to user thread for privilege-separated execution */
1587+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1588+
if (!ret) {
1589+
struct ipc *ipc = ipc_get();
1590+
struct ipc_user *pdata = ipc->ipc_user_pdata;
1591+
1592+
msg_reply->extension = pdata->reply_ext;
1593+
}
1594+
#else
15091595
ret = ipc4_set_get_config_module_instance(ipc4, false);
1596+
#endif
15101597
break;
15111598
case SOF_IPC4_MOD_CONFIG_SET:
1599+
#ifdef CONFIG_SOF_USERSPACE_LL
1600+
/* Forward to user thread for privilege-separated execution */
1601+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1602+
#else
15121603
ret = ipc4_set_get_config_module_instance(ipc4, true);
1604+
#endif
15131605
break;
15141606
case SOF_IPC4_MOD_LARGE_CONFIG_GET:
1607+
#ifdef CONFIG_SOF_USERSPACE_LL
1608+
{
1609+
struct ipc4_module_large_config config;
1610+
1611+
memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4));
1612+
if (config.primary.r.module_id) {
1613+
/* Module case: forward to user thread */
1614+
ret = ipc_user_forward_cmd(ipc4->primary.dat,
1615+
ipc4->extension.dat);
1616+
if (!ret) {
1617+
struct ipc *ipc = ipc_get();
1618+
struct ipc_user *pdata = ipc->ipc_user_pdata;
1619+
1620+
msg_reply->extension = pdata->reply_ext;
1621+
msg_reply->tx_size = pdata->reply_tx_size;
1622+
msg_reply->tx_data = pdata->reply_tx_data;
1623+
}
1624+
} else {
1625+
/* Base firmware (module_id==0): keep in kernel —
1626+
* ipc4_get_comp_drv() accesses IMR manifest which
1627+
* has no user-space partition.
1628+
*/
1629+
ret = ipc4_get_large_config_module_instance(ipc4);
1630+
}
1631+
}
1632+
#else
15151633
ret = ipc4_get_large_config_module_instance(ipc4);
1634+
#endif
15161635
break;
15171636
case SOF_IPC4_MOD_LARGE_CONFIG_SET:
1637+
#ifdef CONFIG_SOF_USERSPACE_LL
1638+
{
1639+
struct ipc4_module_large_config config;
1640+
1641+
memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4));
1642+
if (config.primary.r.module_id) {
1643+
ret = ipc_user_forward_cmd(ipc4->primary.dat,
1644+
ipc4->extension.dat);
1645+
} else {
1646+
/* Base firmware: keep in kernel (IMR access) */
1647+
ret = ipc4_set_large_config_module_instance(ipc4);
1648+
}
1649+
}
1650+
#else
15181651
ret = ipc4_set_large_config_module_instance(ipc4);
1652+
#endif
15191653
break;
15201654
case SOF_IPC4_MOD_BIND:
1655+
#ifdef CONFIG_SOF_USERSPACE_LL
1656+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1657+
#else
15211658
ret = ipc4_bind_module_instance(ipc4);
1659+
#endif
15221660
break;
15231661
case SOF_IPC4_MOD_UNBIND:
1662+
#ifdef CONFIG_SOF_USERSPACE_LL
1663+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1664+
#else
15241665
ret = ipc4_unbind_module_instance(ipc4);
1666+
#endif
15251667
break;
15261668
case SOF_IPC4_MOD_DELETE_INSTANCE:
1669+
#ifdef CONFIG_SOF_USERSPACE_LL
1670+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1671+
#else
15271672
ret = ipc4_delete_module_instance(ipc4);
1673+
#endif
15281674
break;
15291675
case SOF_IPC4_MOD_ENTER_MODULE_RESTORE:
15301676
case SOF_IPC4_MOD_EXIT_MODULE_RESTORE:

0 commit comments

Comments
 (0)