Skip to content

Commit efdd322

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 028feeb commit efdd322

1 file changed

Lines changed: 145 additions & 0 deletions

File tree

src/ipc/ipc4/handler-user.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,3 +1537,148 @@ __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+
result = memcpy_s(&bu, sizeof(bu), &msg, sizeof(msg));
1572+
if (result < 0)
1573+
break;
1574+
1575+
result = ipc_comp_connect(ipc_user->ipc,
1576+
(ipc_pipe_comp_connect *)&bu);
1577+
break;
1578+
}
1579+
case SOF_IPC4_MOD_UNBIND: {
1580+
struct ipc4_module_bind_unbind bu;
1581+
1582+
result = memcpy_s(&bu, sizeof(bu), &msg, sizeof(msg));
1583+
if (result < 0)
1584+
break;
1585+
1586+
result = ipc_comp_disconnect(ipc_user->ipc,
1587+
(ipc_pipe_comp_connect *)&bu);
1588+
break;
1589+
}
1590+
case SOF_IPC4_MOD_INIT_INSTANCE: {
1591+
/* User thread creates the component —
1592+
* drv->ops.create() runs in user-space so untrusted
1593+
* module code does not execute with kernel privileges.
1594+
*
1595+
* init_drv = original kernel pointer
1596+
* init_drv_data = user-accessible copy
1597+
*/
1598+
const struct comp_driver *orig_drv = ipc_user->init_drv;
1599+
const struct comp_driver *drv_copy =
1600+
(const struct comp_driver *)ipc_user->init_drv_data;
1601+
struct comp_dev *dev;
1602+
1603+
ipc_user->init_drv = NULL;
1604+
if (!orig_drv) {
1605+
result = IPC4_MOD_NOT_INITIALIZED;
1606+
break;
1607+
}
1608+
1609+
dev = comp_new_ipc4_user(&msg, drv_copy);
1610+
if (!dev) {
1611+
result = IPC4_MOD_NOT_INITIALIZED;
1612+
break;
1613+
}
1614+
1615+
/* Restore original kernel driver pointer. comp_init()
1616+
* set dev->drv to the copy; runtime code expects the
1617+
* canonical kernel address.
1618+
*/
1619+
dev->drv = orig_drv;
1620+
1621+
result = ipc4_add_comp_dev(dev);
1622+
if (result != IPC4_SUCCESS)
1623+
break;
1624+
1625+
comp_update_ibs_obs_cpc(dev);
1626+
result = 0;
1627+
break;
1628+
}
1629+
case SOF_IPC4_MOD_DELETE_INSTANCE: {
1630+
struct ipc4_module_delete_instance module;
1631+
uint32_t comp_id;
1632+
1633+
memcpy_s(&module, sizeof(module), &msg, sizeof(msg));
1634+
comp_id = IPC4_COMP_ID(module.primary.r.module_id,
1635+
module.primary.r.instance_id);
1636+
result = ipc_comp_free(ipc_user->ipc, comp_id);
1637+
if (result < 0)
1638+
result = IPC4_INVALID_RESOURCE_ID;
1639+
break;
1640+
}
1641+
case SOF_IPC4_MOD_LARGE_CONFIG_GET:
1642+
result = ipc4_process_large_config_get(&msg,
1643+
&ipc_user->reply_ext,
1644+
&ipc_user->reply_tx_size,
1645+
&ipc_user->reply_tx_data);
1646+
break;
1647+
case SOF_IPC4_MOD_LARGE_CONFIG_SET:
1648+
result = ipc4_process_large_config_set(&msg);
1649+
break;
1650+
default:
1651+
LOG_ERR("IPC user: unsupported module cmd type %d",
1652+
msg.primary.r.type);
1653+
result = -EINVAL;
1654+
break;
1655+
}
1656+
} else {
1657+
/* Global message dispatch */
1658+
switch (msg.primary.r.type) {
1659+
case SOF_IPC4_GLB_CREATE_PIPELINE:
1660+
result = ipc_pipeline_new(ipc_user->ipc,
1661+
(ipc_pipe_new *)&msg);
1662+
break;
1663+
case SOF_IPC4_GLB_DELETE_PIPELINE: {
1664+
struct ipc4_pipeline_delete *pipe =
1665+
(struct ipc4_pipeline_delete *)&msg;
1666+
1667+
result = ipc_pipeline_free(ipc_user->ipc,
1668+
pipe->primary.r.instance_id);
1669+
break;
1670+
}
1671+
case SOF_IPC4_GLB_SET_PIPELINE_STATE:
1672+
result = ipc4_set_pipeline_state(&msg);
1673+
break;
1674+
default:
1675+
LOG_ERR("IPC user: unsupported glb cmd type %d",
1676+
msg.primary.r.type);
1677+
result = -EINVAL;
1678+
break;
1679+
}
1680+
}
1681+
1682+
return result;
1683+
}
1684+
#endif /* CONFIG_SOF_USERSPACE_LL */

0 commit comments

Comments
 (0)