Skip to content

Commit 81db0de

Browse files
committed
ipc4: dispatch forwarded IPC commands in the user thread
Provide the IPC4 implementation of ipc_user_thread_dispatch(), the protocol-specific hook called from the generic user-space IPC thread. It reconstructs the IPC4 message from the forwarded primary/extension words and runs the privilege-separated portion of each supported command: pipeline create/delete/set-state, module config get/set, large-config get/set, bind/unbind, and init/delete instance. Component creation goes through comp_new_ipc4_user() so module code runs in user context. This moves the IPC4 command switch out of the protocol-agnostic ipc-common.c into the IPC4 handler where it belongs. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
1 parent 235b6f4 commit 81db0de

1 file changed

Lines changed: 139 additions & 0 deletions

File tree

src/ipc/ipc4/handler-user.c

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,3 +1537,142 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4,
15371537

15381538
return ret;
15391539
}
1540+
1541+
#ifdef CONFIG_SOF_USERSPACE_LL
1542+
/*
1543+
* IPC4 implementation of the user-thread dispatch hook. Runs in the
1544+
* user-space IPC thread; reconstructs the IPC4 message from the forwarded
1545+
* words and executes the privilege-separated part of each command.
1546+
*/
1547+
int ipc_user_thread_dispatch(struct ipc_user *ipc_user)
1548+
{
1549+
struct ipc4_message_request msg;
1550+
int result = -EINVAL;
1551+
1552+
/* Reconstruct the IPC4 message from copied words */
1553+
msg.primary.dat = ipc_user->ipc_msg_pri;
1554+
msg.extension.dat = ipc_user->ipc_msg_ext;
1555+
1556+
ipc_user->reply_ext = 0;
1557+
1558+
if (msg.primary.r.msg_tgt == SOF_IPC4_MESSAGE_TARGET_MODULE_MSG) {
1559+
/* Module message dispatch */
1560+
switch (msg.primary.r.type) {
1561+
case SOF_IPC4_MOD_CONFIG_GET:
1562+
result = ipc4_process_module_config(&msg, false,
1563+
&ipc_user->reply_ext);
1564+
break;
1565+
case SOF_IPC4_MOD_CONFIG_SET:
1566+
result = ipc4_process_module_config(&msg, true, NULL);
1567+
break;
1568+
case SOF_IPC4_MOD_BIND: {
1569+
struct ipc4_module_bind_unbind bu;
1570+
1571+
memcpy_s(&bu, sizeof(bu), &msg, sizeof(msg));
1572+
result = ipc_comp_connect(ipc_user->ipc,
1573+
(ipc_pipe_comp_connect *)&bu);
1574+
break;
1575+
}
1576+
case SOF_IPC4_MOD_UNBIND: {
1577+
struct ipc4_module_bind_unbind bu;
1578+
1579+
memcpy_s(&bu, sizeof(bu), &msg, sizeof(msg));
1580+
result = ipc_comp_disconnect(ipc_user->ipc,
1581+
(ipc_pipe_comp_connect *)&bu);
1582+
break;
1583+
}
1584+
case SOF_IPC4_MOD_INIT_INSTANCE: {
1585+
/* User thread creates the component —
1586+
* drv->ops.create() runs in user-space so untrusted
1587+
* module code does not execute with kernel privileges.
1588+
*
1589+
* init_drv = original kernel pointer
1590+
* init_drv_data = user-accessible copy
1591+
*/
1592+
const struct comp_driver *orig_drv = ipc_user->init_drv;
1593+
const struct comp_driver *drv_copy =
1594+
(const struct comp_driver *)ipc_user->init_drv_data;
1595+
struct comp_dev *dev;
1596+
1597+
ipc_user->init_drv = NULL;
1598+
if (!orig_drv) {
1599+
result = IPC4_MOD_NOT_INITIALIZED;
1600+
break;
1601+
}
1602+
1603+
dev = comp_new_ipc4_user(&msg, drv_copy);
1604+
if (!dev) {
1605+
result = IPC4_MOD_NOT_INITIALIZED;
1606+
break;
1607+
}
1608+
1609+
/* Restore original kernel driver pointer. comp_init()
1610+
* set dev->drv to the copy; runtime code expects the
1611+
* canonical kernel address.
1612+
*/
1613+
dev->drv = orig_drv;
1614+
1615+
result = ipc4_add_comp_dev(dev);
1616+
if (result != IPC4_SUCCESS)
1617+
break;
1618+
1619+
comp_update_ibs_obs_cpc(dev);
1620+
result = 0;
1621+
break;
1622+
}
1623+
case SOF_IPC4_MOD_DELETE_INSTANCE: {
1624+
struct ipc4_module_delete_instance module;
1625+
uint32_t comp_id;
1626+
1627+
memcpy_s(&module, sizeof(module), &msg, sizeof(msg));
1628+
comp_id = IPC4_COMP_ID(module.primary.r.module_id,
1629+
module.primary.r.instance_id);
1630+
result = ipc_comp_free(ipc_user->ipc, comp_id);
1631+
if (result < 0)
1632+
result = IPC4_INVALID_RESOURCE_ID;
1633+
break;
1634+
}
1635+
case SOF_IPC4_MOD_LARGE_CONFIG_GET:
1636+
result = ipc4_process_large_config_get(&msg,
1637+
&ipc_user->reply_ext,
1638+
&ipc_user->reply_tx_size,
1639+
&ipc_user->reply_tx_data);
1640+
break;
1641+
case SOF_IPC4_MOD_LARGE_CONFIG_SET:
1642+
result = ipc4_process_large_config_set(&msg);
1643+
break;
1644+
default:
1645+
LOG_ERR("IPC user: unsupported module cmd type %d",
1646+
msg.primary.r.type);
1647+
result = -EINVAL;
1648+
break;
1649+
}
1650+
} else {
1651+
/* Global message dispatch */
1652+
switch (msg.primary.r.type) {
1653+
case SOF_IPC4_GLB_CREATE_PIPELINE:
1654+
result = ipc_pipeline_new(ipc_user->ipc,
1655+
(ipc_pipe_new *)&msg);
1656+
break;
1657+
case SOF_IPC4_GLB_DELETE_PIPELINE: {
1658+
struct ipc4_pipeline_delete *pipe =
1659+
(struct ipc4_pipeline_delete *)&msg;
1660+
1661+
result = ipc_pipeline_free(ipc_user->ipc,
1662+
pipe->primary.r.instance_id);
1663+
break;
1664+
}
1665+
case SOF_IPC4_GLB_SET_PIPELINE_STATE:
1666+
result = ipc4_set_pipeline_state(&msg);
1667+
break;
1668+
default:
1669+
LOG_ERR("IPC user: unsupported glb cmd type %d",
1670+
msg.primary.r.type);
1671+
result = -EINVAL;
1672+
break;
1673+
}
1674+
}
1675+
1676+
return result;
1677+
}
1678+
#endif /* CONFIG_SOF_USERSPACE_LL */

0 commit comments

Comments
 (0)