@@ -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,154 @@ __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+ memcpy_s (& mi , sizeof (mi ), ipc4 , sizeof (* ipc4 ));
1537+ if (!cpu_is_me (mi .extension .r .core_id )) {
1538+ ret = ipc4_init_module_instance (ipc4 );
1539+ } else {
1540+ struct ipc * ipc = ipc_get ();
1541+ uint32_t comp_id = IPC4_COMP_ID (mi .primary .r .module_id ,
1542+ mi .primary .r .instance_id );
1543+ const struct comp_driver * drv = ipc4_get_comp_drv (
1544+ IPC4_MOD_ID (comp_id ));
1545+
1546+ if (!drv ) {
1547+ ret = IPC4_MOD_NOT_INITIALIZED ;
1548+ } else {
1549+ struct ipc_user * pdata = ipc -> ipc_user_pdata ;
1550+
1551+ /* Copy comp_driver and tr_ctx into
1552+ * user-accessible ipc_user buffer —
1553+ * originals are in kernel .rodata/.data
1554+ * and not readable from user mode.
1555+ */
1556+ struct comp_driver * drv_copy =
1557+ (struct comp_driver * )pdata -> init_drv_data ;
1558+ struct tr_ctx * tctx_copy =
1559+ (struct tr_ctx * )(pdata -> init_drv_data +
1560+ sizeof (struct comp_driver ));
1561+
1562+ memcpy_s (drv_copy , sizeof (* drv_copy ),
1563+ drv , sizeof (* drv ));
1564+ if (drv -> tctx ) {
1565+ memcpy_s (tctx_copy , sizeof (* tctx_copy ),
1566+ drv -> tctx , sizeof (* drv -> tctx ));
1567+ drv_copy -> tctx = tctx_copy ;
1568+ }
1569+
1570+ pdata -> init_drv = drv ;
1571+ ret = ipc_user_forward_cmd (ipc4 -> primary .dat ,
1572+ ipc4 -> extension .dat );
1573+ }
1574+ }
1575+ }
1576+ #else
15061577 ret = ipc4_init_module_instance (ipc4 );
1578+ #endif
15071579 break ;
15081580 case SOF_IPC4_MOD_CONFIG_GET :
1581+ #ifdef CONFIG_SOF_USERSPACE_LL
1582+ /* Forward to user thread for privilege-separated execution */
1583+ ret = ipc_user_forward_cmd (ipc4 -> primary .dat , ipc4 -> extension .dat );
1584+ if (!ret ) {
1585+ struct ipc * ipc = ipc_get ();
1586+ struct ipc_user * pdata = ipc -> ipc_user_pdata ;
1587+
1588+ msg_reply -> extension = pdata -> reply_ext ;
1589+ }
1590+ #else
15091591 ret = ipc4_set_get_config_module_instance (ipc4 , false);
1592+ #endif
15101593 break ;
15111594 case SOF_IPC4_MOD_CONFIG_SET :
1595+ #ifdef CONFIG_SOF_USERSPACE_LL
1596+ /* Forward to user thread for privilege-separated execution */
1597+ ret = ipc_user_forward_cmd (ipc4 -> primary .dat , ipc4 -> extension .dat );
1598+ #else
15121599 ret = ipc4_set_get_config_module_instance (ipc4 , true);
1600+ #endif
15131601 break ;
15141602 case SOF_IPC4_MOD_LARGE_CONFIG_GET :
1603+ #ifdef CONFIG_SOF_USERSPACE_LL
1604+ {
1605+ struct ipc4_module_large_config config ;
1606+
1607+ memcpy_s (& config , sizeof (config ), ipc4 , sizeof (* ipc4 ));
1608+ if (config .primary .r .module_id ) {
1609+ /* Module case: forward to user thread */
1610+ ret = ipc_user_forward_cmd (ipc4 -> primary .dat ,
1611+ ipc4 -> extension .dat );
1612+ if (!ret ) {
1613+ struct ipc * ipc = ipc_get ();
1614+ struct ipc_user * pdata = ipc -> ipc_user_pdata ;
1615+
1616+ msg_reply -> extension = pdata -> reply_ext ;
1617+ msg_reply -> tx_size = pdata -> reply_tx_size ;
1618+ msg_reply -> tx_data = pdata -> reply_tx_data ;
1619+ }
1620+ } else {
1621+ /* Base firmware (module_id==0): keep in kernel —
1622+ * ipc4_get_comp_drv() accesses IMR manifest which
1623+ * has no user-space partition.
1624+ */
1625+ ret = ipc4_get_large_config_module_instance (ipc4 );
1626+ }
1627+ }
1628+ #else
15151629 ret = ipc4_get_large_config_module_instance (ipc4 );
1630+ #endif
15161631 break ;
15171632 case SOF_IPC4_MOD_LARGE_CONFIG_SET :
1633+ #ifdef CONFIG_SOF_USERSPACE_LL
1634+ {
1635+ struct ipc4_module_large_config config ;
1636+
1637+ memcpy_s (& config , sizeof (config ), ipc4 , sizeof (* ipc4 ));
1638+ if (config .primary .r .module_id ) {
1639+ ret = ipc_user_forward_cmd (ipc4 -> primary .dat ,
1640+ ipc4 -> extension .dat );
1641+ } else {
1642+ /* Base firmware: keep in kernel (IMR access) */
1643+ ret = ipc4_set_large_config_module_instance (ipc4 );
1644+ }
1645+ }
1646+ #else
15181647 ret = ipc4_set_large_config_module_instance (ipc4 );
1648+ #endif
15191649 break ;
15201650 case SOF_IPC4_MOD_BIND :
1651+ #ifdef CONFIG_SOF_USERSPACE_LL
1652+ ret = ipc_user_forward_cmd (ipc4 -> primary .dat , ipc4 -> extension .dat );
1653+ #else
15211654 ret = ipc4_bind_module_instance (ipc4 );
1655+ #endif
15221656 break ;
15231657 case SOF_IPC4_MOD_UNBIND :
1658+ #ifdef CONFIG_SOF_USERSPACE_LL
1659+ ret = ipc_user_forward_cmd (ipc4 -> primary .dat , ipc4 -> extension .dat );
1660+ #else
15241661 ret = ipc4_unbind_module_instance (ipc4 );
1662+ #endif
15251663 break ;
15261664 case SOF_IPC4_MOD_DELETE_INSTANCE :
1665+ #ifdef CONFIG_SOF_USERSPACE_LL
1666+ ret = ipc_user_forward_cmd (ipc4 -> primary .dat , ipc4 -> extension .dat );
1667+ #else
15271668 ret = ipc4_delete_module_instance (ipc4 );
1669+ #endif
15281670 break ;
15291671 case SOF_IPC4_MOD_ENTER_MODULE_RESTORE :
15301672 case SOF_IPC4_MOD_EXIT_MODULE_RESTORE :
0 commit comments