@@ -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
115119static 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