Skip to content

Commit 63d0e16

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 ffc8f96 commit 63d0e16

1 file changed

Lines changed: 143 additions & 0 deletions

File tree

src/ipc/ipc4/handler-user.c

Lines changed: 143 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,155 @@ __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 = (struct comp_driver *)pdata->init_drv_data;
1559+
struct tr_ctx *tctx_copy =
1560+
(struct tr_ctx *)(pdata->init_drv_data +
1561+
sizeof(struct comp_driver));
1562+
1563+
ret = memcpy_s(drv_copy, sizeof(*drv_copy), drv, sizeof(*drv));
1564+
if (!ret && drv->tctx) {
1565+
ret = memcpy_s(tctx_copy, sizeof(*tctx_copy),
1566+
drv->tctx, sizeof(*drv->tctx));
1567+
drv_copy->tctx = tctx_copy;
1568+
}
1569+
1570+
if (ret < 0)
1571+
break;
1572+
1573+
pdata->init_drv = drv;
1574+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1575+
}
1576+
}
1577+
#else
15061578
ret = ipc4_init_module_instance(ipc4);
1579+
#endif
15071580
break;
15081581
case SOF_IPC4_MOD_CONFIG_GET:
1582+
#ifdef CONFIG_SOF_USERSPACE_LL
1583+
/* Forward to user thread for privilege-separated execution */
1584+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1585+
if (!ret) {
1586+
struct ipc *ipc = ipc_get();
1587+
struct ipc_user *pdata = ipc->ipc_user_pdata;
1588+
1589+
msg_reply->extension = pdata->reply_ext;
1590+
}
1591+
#else
15091592
ret = ipc4_set_get_config_module_instance(ipc4, false);
1593+
#endif
15101594
break;
15111595
case SOF_IPC4_MOD_CONFIG_SET:
1596+
#ifdef CONFIG_SOF_USERSPACE_LL
1597+
/* Forward to user thread for privilege-separated execution */
1598+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1599+
#else
15121600
ret = ipc4_set_get_config_module_instance(ipc4, true);
1601+
#endif
15131602
break;
15141603
case SOF_IPC4_MOD_LARGE_CONFIG_GET:
1604+
#ifdef CONFIG_SOF_USERSPACE_LL
1605+
{
1606+
struct ipc4_module_large_config config;
1607+
1608+
memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4));
1609+
if (config.primary.r.module_id) {
1610+
/* Module case: forward to user thread */
1611+
ret = ipc_user_forward_cmd(ipc4->primary.dat,
1612+
ipc4->extension.dat);
1613+
if (!ret) {
1614+
struct ipc *ipc = ipc_get();
1615+
struct ipc_user *pdata = ipc->ipc_user_pdata;
1616+
1617+
msg_reply->extension = pdata->reply_ext;
1618+
msg_reply->tx_size = pdata->reply_tx_size;
1619+
msg_reply->tx_data = pdata->reply_tx_data;
1620+
}
1621+
} else {
1622+
/* Base firmware (module_id==0): keep in kernel —
1623+
* ipc4_get_comp_drv() accesses IMR manifest which
1624+
* has no user-space partition.
1625+
*/
1626+
ret = ipc4_get_large_config_module_instance(ipc4);
1627+
}
1628+
}
1629+
#else
15151630
ret = ipc4_get_large_config_module_instance(ipc4);
1631+
#endif
15161632
break;
15171633
case SOF_IPC4_MOD_LARGE_CONFIG_SET:
1634+
#ifdef CONFIG_SOF_USERSPACE_LL
1635+
{
1636+
struct ipc4_module_large_config config;
1637+
1638+
memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4));
1639+
if (config.primary.r.module_id) {
1640+
ret = ipc_user_forward_cmd(ipc4->primary.dat,
1641+
ipc4->extension.dat);
1642+
} else {
1643+
/* Base firmware: keep in kernel (IMR access) */
1644+
ret = ipc4_set_large_config_module_instance(ipc4);
1645+
}
1646+
}
1647+
#else
15181648
ret = ipc4_set_large_config_module_instance(ipc4);
1649+
#endif
15191650
break;
15201651
case SOF_IPC4_MOD_BIND:
1652+
#ifdef CONFIG_SOF_USERSPACE_LL
1653+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1654+
#else
15211655
ret = ipc4_bind_module_instance(ipc4);
1656+
#endif
15221657
break;
15231658
case SOF_IPC4_MOD_UNBIND:
1659+
#ifdef CONFIG_SOF_USERSPACE_LL
1660+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1661+
#else
15241662
ret = ipc4_unbind_module_instance(ipc4);
1663+
#endif
15251664
break;
15261665
case SOF_IPC4_MOD_DELETE_INSTANCE:
1666+
#ifdef CONFIG_SOF_USERSPACE_LL
1667+
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat);
1668+
#else
15271669
ret = ipc4_delete_module_instance(ipc4);
1670+
#endif
15281671
break;
15291672
case SOF_IPC4_MOD_ENTER_MODULE_RESTORE:
15301673
case SOF_IPC4_MOD_EXIT_MODULE_RESTORE:

0 commit comments

Comments
 (0)