diff --git a/drivers/misc/mods/Makefile b/drivers/misc/mods/Makefile index 201e1c3e..868cba72 100644 --- a/drivers/misc/mods/Makefile +++ b/drivers/misc/mods/Makefile @@ -19,6 +19,7 @@ mods-$(CONFIG_DEBUG_FS) += mods_debugfs.o mods-$(CONFIG_DMA_ENGINE) += mods_dma.o mods-$(CONFIG_NET) += mods_netdevice.o mods-$(CONFIG_ARCH_TEGRA) += mods_oist.o +mods-$(CONFIG_OPTEE) += mods_optee.o mods-$(CONFIG_PCI) += mods_pci.o mods-$(CONFIG_ARCH_TEGRA_19x_SOC) += mods_ras.o mods-$(CONFIG_ARCH_TEGRA) += mods_smmu_drv.o diff --git a/drivers/misc/mods/mods_internal.h b/drivers/misc/mods/mods_internal.h index 56cef48b..7fdbc2b0 100644 --- a/drivers/misc/mods/mods_internal.h +++ b/drivers/misc/mods/mods_internal.h @@ -715,6 +715,12 @@ int esc_mods_tegra_prod_set_prod_exact(struct mods_client *client, int esc_mods_send_trustzone_msg(struct mods_client *client, struct MODS_TZ_PARAMS *p); #endif + +#ifdef CONFIG_OPTEE +/* OP-TEE TA call */ +int esc_mods_invoke_optee_ta(struct mods_client *client, + struct MODS_OPTEE_PARAMS *p); +#endif #endif #ifdef CONFIG_DEBUG_FS diff --git a/drivers/misc/mods/mods_krnl.c b/drivers/misc/mods/mods_krnl.c index 2fbce034..8247beaa 100644 --- a/drivers/misc/mods/mods_krnl.c +++ b/drivers/misc/mods/mods_krnl.c @@ -2585,6 +2585,13 @@ static long mods_krnl_ioctl(struct file *fp, break; #endif +#ifdef CONFIG_OPTEE + case MODS_ESC_INVOKE_OPTEE_TA: + MODS_IOCTL(MODS_ESC_INVOKE_OPTEE_TA, + esc_mods_invoke_optee_ta, MODS_OPTEE_PARAMS); + break; +#endif + case MODS_ESC_OIST_STATUS: MODS_IOCTL(MODS_ESC_OIST_STATUS, esc_mods_oist_status, MODS_TEGRA_OIST_STATUS); diff --git a/drivers/misc/mods/mods_optee.c b/drivers/misc/mods/mods_optee.c new file mode 100644 index 00000000..d0a1c87f --- /dev/null +++ b/drivers/misc/mods/mods_optee.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "mods_internal.h" + +#include +#include + +static const uuid_t mods_ta_uuid = + UUID_INIT(0xf14e9858, 0x1526, 0x4935, + 0xb1, 0x92, 0x4d, 0xf3, 0x86, 0x4f, 0x1f, 0xf9); + +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) +{ + if (ver->impl_id == TEE_IMPL_ID_OPTEE) + return 1; + else + return 0; +} + +int esc_mods_invoke_optee_ta(struct mods_client *client, + struct MODS_OPTEE_PARAMS *p) +{ + int ret; + u32 session_id; + u8 *temp_buf; + struct tee_context *ctx; + struct tee_ioctl_open_session_arg sess_arg; + struct tee_ioctl_invoke_arg invoke_arg; + struct tee_shm *shm; + struct tee_param params[4]; + + /* Open context with TEE driver */ + ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); + if (IS_ERR(ctx)) { + ret = -ENODEV; + goto fail; + } + + /* Open session with TA */ + memset(&sess_arg, 0, sizeof(sess_arg)); + export_uuid(sess_arg.uuid, &mods_ta_uuid); + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; + sess_arg.num_params = 0; + + ret = tee_client_open_session(ctx, &sess_arg, NULL); + if ((ret < 0) || (sess_arg.ret != 0)) { + cl_info("tee_client_open_session failed, err: %x\n", sess_arg.ret); + ret = -EINVAL; + goto out_ctx; + } + session_id = sess_arg.session; + + /* Allocate dynamic shared memory with TA */ + shm = tee_shm_alloc_kernel_buf(ctx, p->buf_size); + if (IS_ERR(shm)) { + cl_info("tee_shm_alloc_kernel_buf failed\n"); + ret = -ENOMEM; + goto out_session; + } + + /* Invoke comannd of TA */ + memset(&invoke_arg, 0, sizeof(invoke_arg)); + memset(¶ms, 0, sizeof(params)); + + invoke_arg.func = p->command_id; + invoke_arg.session = session_id; + invoke_arg.num_params = 4; + + params[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; + params[0].u.memref.shm = shm; + params[0].u.memref.size = p->buf_size; + params[0].u.memref.shm_offs = 0; + params[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; + + temp_buf = tee_shm_get_va(shm, 0); + if (IS_ERR(temp_buf)) { + cl_info("tee_shm_get_va failed\n"); + ret = PTR_ERR(temp_buf); + goto out_shm; + } + memmove(temp_buf, p->buf, p->buf_size); + + ret = tee_client_invoke_func(ctx, &invoke_arg, params); + if (ret < 0) { + cl_info("tee_client_invoke_func failed.\n"); + goto out_shm; + } + memmove(p->buf, temp_buf, p->buf_size); + p->tee_ret = invoke_arg.ret; + p->out_a = params[1].u.value.a; + p->out_b = params[1].u.value.b; + +out_shm: + tee_shm_free(shm); +out_session: + tee_client_close_session(ctx, session_id); +out_ctx: + tee_client_close_context(ctx); +fail: + return ret; +} diff --git a/include/uapi/misc/mods.h b/include/uapi/misc/mods.h index 7489f2b5..eba8f607 100644 --- a/include/uapi/misc/mods.h +++ b/include/uapi/misc/mods.h @@ -1806,6 +1806,23 @@ struct MODS_TZ_PARAMS { int status; }; +#define MAX_OPTEE_BUFFER_SIZE 512 +/* Used by MODS_ESC_INVOKE_OPTEE_TA. + * + * Available only on Tegra. + */ +struct MODS_OPTEE_PARAMS { + /* IN */ + __u8 buf[MAX_OPTEE_BUFFER_SIZE]; + __u32 buf_size; + __u32 command_id; + + /* OUT */ + __u32 tee_ret; + __u32 out_a; + __u32 out_b; +}; + /* Used by MODS_ESC_OIST_STATUS ioctl. * * Available only on Tegra. @@ -2023,5 +2040,6 @@ struct MODS_TEGRA_OIST_STATUS { #define MODS_ESC_GET_ACPI_DEV_CHILDREN MODSIO(WR, 138, MODS_GET_ACPI_DEV_CHILDREN) #define MODS_ESC_SEND_TZ_MSG MODSIO(WR, 139, MODS_TZ_PARAMS) #define MODS_ESC_OIST_STATUS MODSIO(WR, 140, MODS_TEGRA_OIST_STATUS) +#define MODS_ESC_INVOKE_OPTEE_TA MODSIO(WR, 141, MODS_OPTEE_PARAMS) #endif /* _UAPI_MODS_H_ */