Skip to content

Commit ea88d84

Browse files
lyakhkv2019i
authored andcommitted
userspace: perform library loading in kernel context
When running in syscall context on behalf of a userspace thread dynamically mapped memory doesn't automatically become accessible. To make it accessible it has to be added to the thread memory domain. This is a problem for loadable modules with executable cold sections. To be able to execute them they have to be mapped to threads with the executable bit set. While for linking that memory has to be mapped writable. To solve the problem we perform linking from the kernel IPC context before forwarding to the userspace IPC thread. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
1 parent 8e868ce commit ea88d84

3 files changed

Lines changed: 55 additions & 32 deletions

File tree

src/include/ipc4/handler.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ struct ipc4_message_request;
1616
*/
1717
int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, struct ipc_msg *reply);
1818

19+
/**
20+
* \brief Load a dynamically loadable module.
21+
* @param[in] drv Component driver.
22+
* @param[in] mi SOF_IPC4_MOD_INIT_INSTANCE data
23+
*/
24+
int ipc4_user_module_load(const struct comp_driver *drv,
25+
const struct ipc4_module_init_instance *mi);
26+
1927
/**
2028
* @brief Process MOD_CONFIG_GET or MOD_CONFIG_SET in any execution context.
2129
* @param[in] ipc4 IPC4 message request.

src/ipc/ipc4/handler-user.c

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,7 +1576,6 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4,
15761576
* Component creation (drv->ops.create) runs in user thread
15771577
* so untrusted module code does not execute in kernel context.
15781578
*/
1579-
struct ipc *ipc = ipc_get();
15801579
uint32_t comp_id = IPC4_COMP_ID(mi->primary.r.module_id,
15811580
mi->primary.r.instance_id);
15821581
const struct comp_driver *drv = ipc4_get_comp_drv(IPC4_MOD_ID(comp_id));
@@ -1586,26 +1585,18 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4,
15861585
break;
15871586
}
15881587

1589-
/* Copy comp_driver and tr_ctx into user-accessible ipc_user buffer
1590-
* originals are in kernel .rodata/.data and not readable from user mode.
1591-
*/
1592-
struct ipc_user *pdata = ipc->ipc_user_pdata;
1593-
struct comp_driver *drv_copy = (struct comp_driver *)pdata->init_drv_data;
1594-
struct tr_ctx *tctx_copy =
1595-
(struct tr_ctx *)(pdata->init_drv_data +
1596-
sizeof(struct comp_driver));
1597-
1598-
ret = memcpy_s(drv_copy, sizeof(*drv_copy), drv, sizeof(*drv));
1599-
if (!ret && drv->tctx) {
1600-
ret = memcpy_s(tctx_copy, sizeof(*tctx_copy),
1601-
drv->tctx, sizeof(*drv->tctx));
1602-
drv_copy->tctx = tctx_copy;
1603-
}
1588+
struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(comp_id);
16041589

1605-
if (ret < 0)
1606-
break;
1590+
if (ctx && drv->type == SOF_COMP_MODULE_ADAPTER) {
1591+
int err = ipc4_user_module_load(drv, mi);
1592+
1593+
if (err < 0) {
1594+
ret = IPC4_MOD_NOT_INITIALIZED;
1595+
break;
1596+
}
1597+
}
16071598

1608-
pdata->init_drv = drv;
1599+
ipc_get()->ipc_user_pdata->init_drv = drv;
16091600
ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat,
16101601
mi->extension.r.core_id);
16111602
#endif
@@ -1779,36 +1770,28 @@ int ipc_user_thread_dispatch(struct ipc_user *ipc_user)
17791770
* module code does not execute with kernel privileges.
17801771
*
17811772
* init_drv = original kernel pointer
1782-
* init_drv_data = user-accessible copy
17831773
*/
1784-
const struct comp_driver *orig_drv = ipc_user->init_drv;
1785-
const struct comp_driver *drv_copy =
1786-
(const struct comp_driver *)ipc_user->init_drv_data;
1787-
struct comp_dev *dev;
1774+
const struct comp_driver *drv = ipc_user->init_drv;
17881775

17891776
ipc_user->init_drv = NULL;
1790-
if (!orig_drv) {
1777+
if (!drv) {
17911778
result = IPC4_MOD_NOT_INITIALIZED;
17921779
break;
17931780
}
17941781

1795-
dev = comp_new_ipc4_user(&msg, drv_copy);
1782+
struct comp_dev *dev = comp_new_ipc4_user(&msg, drv);
1783+
17961784
if (!dev) {
17971785
result = IPC4_MOD_NOT_INITIALIZED;
17981786
break;
17991787
}
18001788

1801-
/* Restore original kernel driver pointer. comp_init()
1802-
* set dev->drv to the copy; runtime code expects the
1803-
* canonical kernel address.
1804-
*/
1805-
dev->drv = orig_drv;
1806-
18071789
result = ipc4_add_comp_dev(dev);
18081790
if (result != IPC4_SUCCESS)
18091791
break;
18101792

18111793
comp_update_ibs_obs_cpc(dev);
1794+
18121795
result = 0;
18131796
break;
18141797
}

src/ipc/ipc4/helper.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,38 @@ __cold struct comp_dev *comp_new_ipc4(const struct ipc4_module_init_instance *mo
236236
}
237237

238238
#ifdef CONFIG_SOF_USERSPACE_LL
239+
240+
int ipc4_user_module_load(const struct comp_driver *drv,
241+
const struct ipc4_module_init_instance *mi)
242+
{
243+
/*
244+
* A large part of module instantiation is executed in the userspace
245+
* mode, including calling the module's .init() method. But another part
246+
* of it has to be executed in the kernel mode, including calling
247+
* lib_manager_mod_create_priv(). This is the privileged part of module
248+
* instantiation.
249+
*/
250+
struct comp_ipc_config ipc_config;
251+
int ret = ipc4_comp_new_config(&ipc_config, mi);
252+
253+
if (ret < 0)
254+
return ret;
255+
256+
const struct ipc_config_process spec = {
257+
.data = ipc4_get_comp_new_data(),
258+
.size = ipc_config.ipc_config_size,
259+
};
260+
261+
#if CONFIG_DCACHE_LINE_SIZE && !CONFIG_LIBRARY
262+
sys_cache_data_invd_range((__sparse_force void __sparse_cache *)spec.data, spec.size);
263+
#endif
264+
265+
struct userspace_context *userspace = NULL;
266+
const struct module_interface *ops = NULL;
267+
268+
return lib_manager_mod_create_priv(drv, &ipc_config, &spec, NULL, &userspace, &ops);
269+
}
270+
239271
/**
240272
* comp_new_ipc4_user - Create component in user-space IPC thread context.
241273
*

0 commit comments

Comments
 (0)