diff options
-rw-r--r-- | drivers/soc/renesas/Kconfig | 114 | ||||
-rw-r--r-- | drivers/tee/optee/core.c | 7 | ||||
-rw-r--r-- | drivers/tee/optee/optee_msg.h | 21 | ||||
-rw-r--r-- | drivers/tee/optee/optee_private.h | 1 | ||||
-rw-r--r-- | drivers/tee/optee/optee_smc.h | 3 | ||||
-rw-r--r-- | drivers/tee/optee/rpc.c | 95 | ||||
-rw-r--r-- | drivers/tee/tee_core.c | 49 | ||||
-rw-r--r-- | drivers/tee/tee_shm.c | 32 | ||||
-rw-r--r-- | include/linux/tee_drv.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/tee.h | 13 |
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; |