aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/renesas/Kconfig114
-rw-r--r--drivers/tee/optee/core.c7
-rw-r--r--drivers/tee/optee/optee_msg.h21
-rw-r--r--drivers/tee/optee/optee_private.h1
-rw-r--r--drivers/tee/optee/optee_smc.h3
-rw-r--r--drivers/tee/optee/rpc.c95
-rw-r--r--drivers/tee/tee_core.c49
-rw-r--r--drivers/tee/tee_shm.c32
-rw-r--r--include/linux/tee_drv.h3
-rw-r--r--include/uapi/linux/tee.h13
10 files changed, 250 insertions, 88 deletions
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 30984659df90..7d63a13e5b78 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-config SOC_RENESAS
+menuconfig SOC_RENESAS
bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
default y if ARCH_RENESAS
select SOC_BUS
@@ -49,12 +49,12 @@ if ARM && ARCH_RENESAS
#comment "Renesas ARM SoCs System Type"
config ARCH_EMEV2
- bool "Emma Mobile EV2"
+ bool "SoC Platform support for Emma Mobile EV2"
select HAVE_ARM_SCU if SMP
select SYS_SUPPORTS_EM_STI
config ARCH_R7S72100
- bool "RZ/A1H (R7S72100)"
+ bool "SoC Platform support for RZ/A1H"
select ARM_ERRATA_754322
select PM
select PM_GENERIC_DOMAINS
@@ -63,14 +63,14 @@ config ARCH_R7S72100
select SYS_SUPPORTS_SH_MTU2
config ARCH_R7S9210
- bool "RZ/A2 (R7S9210)"
+ bool "SoC Platform support for RZ/A2"
select PM
select PM_GENERIC_DOMAINS
select RENESAS_OSTM
select RENESAS_RZA1_IRQC
config ARCH_R8A73A4
- bool "R-Mobile APE6 (R8A73A40)"
+ bool "SoC Platform support for R-Mobile APE6"
select ARCH_RMOBILE
select ARM_ERRATA_798181 if SMP
select ARM_ERRATA_814220
@@ -78,49 +78,49 @@ config ARCH_R8A73A4
select RENESAS_IRQC
config ARCH_R8A7740
- bool "R-Mobile A1 (R8A77400)"
+ bool "SoC Platform support for R-Mobile A1"
select ARCH_RMOBILE
select ARM_ERRATA_754322
select RENESAS_INTC_IRQPIN
config ARCH_R8A7742
- bool "RZ/G1H (R8A77420)"
+ bool "SoC Platform support for RZ/G1H"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
select ARM_ERRATA_814220
select SYSC_R8A7742
config ARCH_R8A7743
- bool "RZ/G1M (R8A77430)"
+ bool "SoC Platform support for RZ/G1M"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
select SYSC_R8A7743
config ARCH_R8A7744
- bool "RZ/G1N (R8A77440)"
+ bool "SoC Platform support for RZ/G1N"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
select SYSC_R8A7743
config ARCH_R8A7745
- bool "RZ/G1E (R8A77450)"
+ bool "SoC Platform support for RZ/G1E"
select ARCH_RCAR_GEN2
select ARM_ERRATA_814220
select SYSC_R8A7745
config ARCH_R8A77470
- bool "RZ/G1C (R8A77470)"
+ bool "SoC Platform support for RZ/G1C"
select ARCH_RCAR_GEN2
select ARM_ERRATA_814220
select SYSC_R8A77470
config ARCH_R8A7778
- bool "R-Car M1A (R8A77781)"
+ bool "SoC Platform support for R-Car M1A"
select ARCH_RCAR_GEN1
select ARM_ERRATA_754322
config ARCH_R8A7779
- bool "R-Car H1 (R8A77790)"
+ bool "SoC Platform support for R-Car H1"
select ARCH_RCAR_GEN1
select ARM_ERRATA_754322
select ARM_GLOBAL_TIMER
@@ -129,7 +129,7 @@ config ARCH_R8A7779
select SYSC_R8A7779
config ARCH_R8A7790
- bool "R-Car H2 (R8A77900)"
+ bool "SoC Platform support for R-Car H2"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
select ARM_ERRATA_814220
@@ -137,38 +137,38 @@ config ARCH_R8A7790
select SYSC_R8A7790
config ARCH_R8A7791
- bool "R-Car M2-W (R8A77910)"
+ bool "SoC Platform support for R-Car M2-W"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
select I2C
select SYSC_R8A7791
config ARCH_R8A7792
- bool "R-Car V2H (R8A77920)"
+ bool "SoC Platform support for R-Car V2H"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
select SYSC_R8A7792
config ARCH_R8A7793
- bool "R-Car M2-N (R8A7793)"
+ bool "SoC Platform support for R-Car M2-N"
select ARCH_RCAR_GEN2
select ARM_ERRATA_798181 if SMP
select I2C
select SYSC_R8A7791
config ARCH_R8A7794
- bool "R-Car E2 (R8A77940)"
+ bool "SoC Platform support for R-Car E2"
select ARCH_RCAR_GEN2
select ARM_ERRATA_814220
select SYSC_R8A7794
config ARCH_R9A06G032
- bool "RZ/N1D (R9A06G032)"
+ bool "SoC Platform support for RZ/N1D"
select ARCH_RZN1
select ARM_ERRATA_814220
config ARCH_SH73A0
- bool "SH-Mobile AG5 (R8A73A00)"
+ bool "SoC Platform support for SH-Mobile AG5"
select ARCH_RMOBILE
select ARM_ERRATA_754322
select ARM_GLOBAL_TIMER
@@ -181,42 +181,42 @@ endif # ARM
if ARM64
config ARCH_R8A774A1
- bool "Renesas RZ/G2M SoC Platform"
+ bool "SoC Platform support for RZ/G2M"
select ARCH_RCAR_GEN3
select SYSC_R8A774A1
help
This enables support for the Renesas RZ/G2M SoC.
config ARCH_R8A774B1
- bool "Renesas RZ/G2N SoC Platform"
+ bool "SoC Platform support for RZ/G2N"
select ARCH_RCAR_GEN3
select SYSC_R8A774B1
help
This enables support for the Renesas RZ/G2N SoC.
config ARCH_R8A774C0
- bool "Renesas RZ/G2E SoC Platform"
+ bool "SoC Platform support for RZ/G2E"
select ARCH_RCAR_GEN3
select SYSC_R8A774C0
help
This enables support for the Renesas RZ/G2E SoC.
config ARCH_R8A774E1
- bool "Renesas RZ/G2H SoC Platform"
+ bool "SoC Platform support for RZ/G2H"
select ARCH_RCAR_GEN3
select SYSC_R8A774E1
help
This enables support for the Renesas RZ/G2H SoC.
config ARCH_R8A77950
- bool "Renesas R-Car H3 ES1.x SoC Platform"
+ bool "SoC Platform support for R-Car H3 ES1.x"
select ARCH_RCAR_GEN3
select SYSC_R8A7795
help
This enables support for the Renesas R-Car H3 SoC (revision 1.x).
config ARCH_R8A77951
- bool "Renesas R-Car H3 ES2.0+ SoC Platform"
+ bool "SoC Platform support for R-Car H3 ES2.0+"
select ARCH_RCAR_GEN3
select SYSC_R8A7795
help
@@ -224,49 +224,49 @@ config ARCH_R8A77951
later).
config ARCH_R8A77960
- bool "Renesas R-Car M3-W SoC Platform"
+ bool "SoC Platform support for R-Car M3-W"
select ARCH_RCAR_GEN3
select SYSC_R8A77960
help
This enables support for the Renesas R-Car M3-W SoC.
config ARCH_R8A77961
- bool "Renesas R-Car M3-W+ SoC Platform"
+ bool "SoC Platform support for R-Car M3-W+"
select ARCH_RCAR_GEN3
select SYSC_R8A77961
help
This enables support for the Renesas R-Car M3-W+ SoC.
config ARCH_R8A77965
- bool "Renesas R-Car M3-N SoC Platform"
+ bool "SoC Platform support for R-Car M3-N"
select ARCH_RCAR_GEN3
select SYSC_R8A77965
help
This enables support for the Renesas R-Car M3-N SoC.
config ARCH_R8A77970
- bool "Renesas R-Car V3M SoC Platform"
+ bool "SoC Platform support for R-Car V3M"
select ARCH_RCAR_GEN3
select SYSC_R8A77970
help
This enables support for the Renesas R-Car V3M SoC.
config ARCH_R8A77980
- bool "Renesas R-Car V3H SoC Platform"
+ bool "SoC Platform support for R-Car V3H"
select ARCH_RCAR_GEN3
select SYSC_R8A77980
help
This enables support for the Renesas R-Car V3H SoC.
config ARCH_R8A77990
- bool "Renesas R-Car E3 SoC Platform"
+ bool "SoC Platform support for R-Car E3"
select ARCH_RCAR_GEN3
select SYSC_R8A77990
help
This enables support for the Renesas R-Car E3 SoC.
config ARCH_R8A77995
- bool "Renesas R-Car D3 SoC Platform"
+ bool "SoC Platform support for R-Car D3"
select ARCH_RCAR_GEN3
select SYSC_R8A77995
help
@@ -276,97 +276,97 @@ endif # ARM64
# SoC
config SYSC_R8A7742
- bool "RZ/G1H System Controller support" if COMPILE_TEST
+ bool "System Controller support for RZ/G1H" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7743
- bool "RZ/G1M System Controller support" if COMPILE_TEST
+ bool "System Controller support for RZ/G1M" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7745
- bool "RZ/G1E System Controller support" if COMPILE_TEST
+ bool "System Controller support for RZ/G1E" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A77470
- bool "RZ/G1C System Controller support" if COMPILE_TEST
+ bool "System Controller support for RZ/G1C" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A774A1
- bool "RZ/G2M System Controller support" if COMPILE_TEST
+ bool "System Controller support for RZ/G2M" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A774B1
- bool "RZ/G2N System Controller support" if COMPILE_TEST
+ bool "System Controller support for RZ/G2N" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A774C0
- bool "RZ/G2E System Controller support" if COMPILE_TEST
+ bool "System Controller support for RZ/G2E" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A774E1
- bool "RZ/G2H System Controller support" if COMPILE_TEST
+ bool "System Controller support for RZ/G2H" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7779
- bool "R-Car H1 System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car H1" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7790
- bool "R-Car H2 System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car H2" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7791
- bool "R-Car M2-W/N System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car M2-W/N" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7792
- bool "R-Car V2H System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car V2H" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7794
- bool "R-Car E2 System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car E2" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A7795
- bool "R-Car H3 System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car H3" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A77960
- bool "R-Car M3-W System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car M3-W" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A77961
- bool "R-Car M3-W+ System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car M3-W+" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A77965
- bool "R-Car M3-N System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car M3-N" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A77970
- bool "R-Car V3M System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car V3M" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A77980
- bool "R-Car V3H System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car V3H" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A77990
- bool "R-Car E3 System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car E3" if COMPILE_TEST
select SYSC_RCAR
config SYSC_R8A77995
- bool "R-Car D3 System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car D3" if COMPILE_TEST
select SYSC_RCAR
# Family
config RST_RCAR
- bool "R-Car Reset Controller support" if COMPILE_TEST
+ bool "Reset Controller support for R-Car" if COMPILE_TEST
config SYSC_RCAR
- bool "R-Car System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Car" if COMPILE_TEST
config SYSC_RMOBILE
- bool "R-Mobile System Controller support" if COMPILE_TEST
+ bool "System Controller support for R-Mobile" if COMPILE_TEST
endif # SOC_RENESAS
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index b373b1b08b6d..cf4718c6d35d 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -216,6 +216,8 @@ static void optee_get_version(struct tee_device *teedev,
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
v.gen_caps |= TEE_GEN_CAP_REG_MEM;
+ if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
+ v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
*vers = v;
}
@@ -262,6 +264,11 @@ static int optee_open(struct tee_context *ctx)
mutex_init(&ctxdata->mutex);
INIT_LIST_HEAD(&ctxdata->sess_list);
+ if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
+ ctx->cap_memref_null = true;
+ else
+ ctx->cap_memref_null = false;
+
ctx->data = ctxdata;
return 0;
}
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
index 795bc19ae17a..7b2d919da2ac 100644
--- a/drivers/tee/optee/optee_msg.h
+++ b/drivers/tee/optee/optee_msg.h
@@ -419,4 +419,25 @@ struct optee_msg_arg {
*/
#define OPTEE_MSG_RPC_CMD_SHM_FREE 7
+/*
+ * Access a device on an i2c bus
+ *
+ * [in] param[0].u.value.a mode: RD(0), WR(1)
+ * [in] param[0].u.value.b i2c adapter
+ * [in] param[0].u.value.c i2c chip
+ *
+ * [in] param[1].u.value.a i2c control flags
+ *
+ * [in/out] memref[2] buffer to exchange the transfer data
+ * with the secure world
+ *
+ * [out] param[3].u.value.a bytes transferred by the driver
+ */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21
+/* I2C master transfer modes */
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD 0
+#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR 1
+/* I2C master control flags */
+#define OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT BIT(0)
+
#endif /* _OPTEE_MSG_H */
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index 8b71839a357e..e25b216a14ef 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -17,6 +17,7 @@
/* Some Global Platform error codes used in this driver */
#define TEEC_SUCCESS 0x00000000
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
+#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h
index c72122d9c997..777ad54d4c2c 100644
--- a/drivers/tee/optee/optee_smc.h
+++ b/drivers/tee/optee/optee_smc.h
@@ -215,6 +215,9 @@ struct optee_smc_get_shm_config_result {
*/
#define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM BIT(2)
+/* Secure world supports Shared Memory with a NULL buffer reference */
+#define OPTEE_SMC_SEC_CAP_MEMREF_NULL BIT(4)
+
#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c
index b4ade54d1f28..1e3614e4798f 100644
--- a/drivers/tee/optee/rpc.c
+++ b/drivers/tee/optee/rpc.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/tee_drv.h>
#include "optee_private.h"
@@ -49,6 +50,97 @@ bad:
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
}
+#if IS_REACHABLE(CONFIG_I2C)
+static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ struct i2c_client client = { 0 };
+ struct tee_param *params;
+ size_t i;
+ int ret = -EOPNOTSUPP;
+ u8 attr[] = {
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT,
+ };
+
+ if (arg->num_params != ARRAY_SIZE(attr)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ return;
+ }
+
+ if (optee_from_msg_param(params, arg->num_params, arg->params))
+ goto bad;
+
+ for (i = 0; i < arg->num_params; i++) {
+ if (params[i].attr != attr[i])
+ goto bad;
+ }
+
+ client.adapter = i2c_get_adapter(params[0].u.value.b);
+ if (!client.adapter)
+ goto bad;
+
+ if (params[1].u.value.a & OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT) {
+ if (!i2c_check_functionality(client.adapter,
+ I2C_FUNC_10BIT_ADDR)) {
+ i2c_put_adapter(client.adapter);
+ goto bad;
+ }
+
+ client.flags = I2C_CLIENT_TEN;
+ }
+
+ client.addr = params[0].u.value.c;
+ snprintf(client.name, I2C_NAME_SIZE, "i2c%d", client.adapter->nr);
+
+ switch (params[0].u.value.a) {
+ case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD:
+ ret = i2c_master_recv(&client, params[2].u.memref.shm->kaddr,
+ params[2].u.memref.size);
+ break;
+ case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR:
+ ret = i2c_master_send(&client, params[2].u.memref.shm->kaddr,
+ params[2].u.memref.size);
+ break;
+ default:
+ i2c_put_adapter(client.adapter);
+ goto bad;
+ }
+
+ if (ret < 0) {
+ arg->ret = TEEC_ERROR_COMMUNICATION;
+ } else {
+ params[3].u.value.a = ret;
+ if (optee_to_msg_param(arg->params, arg->num_params, params))
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ else
+ arg->ret = TEEC_SUCCESS;
+ }
+
+ i2c_put_adapter(client.adapter);
+ kfree(params);
+ return;
+bad:
+ kfree(params);
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+#else
+static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ arg->ret = TEEC_ERROR_NOT_SUPPORTED;
+}
+#endif
+
static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
{
struct wq_entry *w;
@@ -382,6 +474,9 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
case OPTEE_MSG_RPC_CMD_SHM_FREE:
handle_rpc_func_cmd_shm_free(ctx, arg);
break;
+ case OPTEE_MSG_RPC_CMD_I2C_TRANSFER:
+ handle_rpc_func_cmd_i2c_transfer(ctx, arg);
+ break;
default:
handle_rpc_supp_cmd(ctx, arg);
}
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 64637e09a095..ce0f0309b6ac 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -383,25 +383,38 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
/*
- * If we fail to get a pointer to a shared memory
- * object (and increase the ref count) from an
- * identifier we return an error. All pointers that
- * has been added in params have an increased ref
- * count. It's the callers responibility to do
- * tee_shm_put() on all resolved pointers.
+ * If a NULL pointer is passed to a TA in the TEE,
+ * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL
+ * indicating a NULL memory reference.
*/
- shm = tee_shm_get_from_id(ctx, ip.c);
- if (IS_ERR(shm))
- return PTR_ERR(shm);
-
- /*
- * Ensure offset + size does not overflow offset
- * and does not overflow the size of the referred
- * shared memory object.
- */
- if ((ip.a + ip.b) < ip.a ||
- (ip.a + ip.b) > shm->size) {
- tee_shm_put(shm);
+ if (ip.c != TEE_MEMREF_NULL) {
+ /*
+ * If we fail to get a pointer to a shared
+ * memory object (and increase the ref count)
+ * from an identifier we return an error. All
+ * pointers that has been added in params have
+ * an increased ref count. It's the callers
+ * responibility to do tee_shm_put() on all
+ * resolved pointers.
+ */
+ shm = tee_shm_get_from_id(ctx, ip.c);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ /*
+ * Ensure offset + size does not overflow
+ * offset and does not overflow the size of
+ * the referred shared memory object.
+ */
+ if ((ip.a + ip.b) < ip.a ||
+ (ip.a + ip.b) > shm->size) {
+ tee_shm_put(shm);
+ return -EINVAL;
+ }
+ } else if (ctx->cap_memref_null) {
+ /* Pass NULL pointer to OP-TEE */
+ shm = NULL;
+ } else {
return -EINVAL;
}
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 827ac3d0fea9..00472f5ce22e 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -12,6 +12,22 @@
#include <linux/uio.h>
#include "tee_private.h"
+static void release_registered_pages(struct tee_shm *shm)
+{
+ if (shm->pages) {
+ if (shm->flags & TEE_SHM_USER_MAPPED) {
+ unpin_user_pages(shm->pages, shm->num_pages);
+ } else {
+ size_t n;
+
+ for (n = 0; n < shm->num_pages; n++)
+ put_page(shm->pages[n]);
+ }
+
+ kfree(shm->pages);
+ }
+}
+
static void tee_shm_release(struct tee_shm *shm)
{
struct tee_device *teedev = shm->ctx->teedev;
@@ -32,17 +48,13 @@ static void tee_shm_release(struct tee_shm *shm)
poolm->ops->free(poolm, shm);
} else if (shm->flags & TEE_SHM_REGISTER) {
- size_t n;
int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm);
if (rc)
dev_err(teedev->dev.parent,
"unregister shm %p failed: %d", shm, rc);
- for (n = 0; n < shm->num_pages; n++)
- put_page(shm->pages[n]);
-
- kfree(shm->pages);
+ release_registered_pages(shm);
}
teedev_ctx_put(shm->ctx);
@@ -228,7 +240,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
}
if (flags & TEE_SHM_USER_MAPPED) {
- rc = get_user_pages_fast(start, num_pages, FOLL_WRITE,
+ rc = pin_user_pages_fast(start, num_pages, FOLL_WRITE,
shm->pages);
} else {
struct kvec *kiov;
@@ -292,18 +304,12 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
return shm;
err:
if (shm) {
- size_t n;
-
if (shm->id >= 0) {
mutex_lock(&teedev->mutex);
idr_remove(&teedev->idr, shm->id);
mutex_unlock(&teedev->mutex);
}
- if (shm->pages) {
- for (n = 0; n < shm->num_pages; n++)
- put_page(shm->pages[n]);
- kfree(shm->pages);
- }
+ release_registered_pages(shm);
}
kfree(shm);
teedev_ctx_put(ctx);
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index d074302989dd..cdd049a724b1 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -47,6 +47,8 @@ struct tee_shm_pool;
* and just return with an error code. It is needed for requests
* that arises from TEE based kernel drivers that should be
* non-blocking in nature.
+ * @cap_memref_null: flag indicating if the TEE Client support shared
+ * memory buffer with a NULL pointer.
*/
struct tee_context {
struct tee_device *teedev;
@@ -54,6 +56,7 @@ struct tee_context {
struct kref refcount;
bool releasing;
bool supp_nowait;
+ bool cap_memref_null;
};
struct tee_param_memref {
diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h
index b619f37ee03e..d67cadf221fc 100644
--- a/include/uapi/linux/tee.h
+++ b/include/uapi/linux/tee.h
@@ -51,6 +51,9 @@
#define TEE_GEN_CAP_GP (1 << 0)/* GlobalPlatform compliant TEE */
#define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */
#define TEE_GEN_CAP_REG_MEM (1 << 2)/* Supports registering shared memory */
+#define TEE_GEN_CAP_MEMREF_NULL (1 << 3)/* NULL MemRef support */
+
+#define TEE_MEMREF_NULL (__u64)(-1) /* NULL MemRef Buffer */
/*
* TEE Implementation ID
@@ -200,6 +203,16 @@ struct tee_ioctl_buf_data {
* a part of a shared memory by specifying an offset (@a) and size (@b) of
* the object. To supply the entire shared memory object set the offset
* (@a) to 0 and size (@b) to the previously returned size of the object.
+ *
+ * A client may need to present a NULL pointer in the argument
+ * passed to a trusted application in the TEE.
+ * This is also a requirement in GlobalPlatform Client API v1.0c
+ * (section 3.2.5 memory references), which can be found at
+ * http://www.globalplatform.org/specificationsdevice.asp
+ *
+ * If a NULL pointer is passed to a TA in the TEE, the (@c)
+ * IOCTL parameters value must be set to TEE_MEMREF_NULL indicating a NULL
+ * memory reference.
*/
struct tee_ioctl_param {
__u64 attr;