OP-TEE's legacy RPMB supplicant interface assumes the RPMB device is eMMC and derives the key from an eMMC-shaped device ID, so it can never reproduce the key Linux derives for a UFS device; secure storage on UFS-only platforms instead needs the transport-agnostic RPMB subsystem interface, through which the normal world describes the real RPMB device to OP-TEE. Add a UFS backend for it so OP-TEE derives a key matching Linux and can use RPMB secure storage on UFS, leaving the legacy eMMC path untouched.
This subsystem backend currently supports UFS drives only; eMMC still uses the legacy interface. Signed-off-by: Jorge Ramirez-Ortiz <[email protected]> --- drivers/tee/optee/Makefile | 1 + drivers/tee/optee/optee_msg_supplicant.h | 8 ++ drivers/tee/optee/optee_private.h | 41 +++++++ drivers/tee/optee/rpmb_ufs.c | 141 +++++++++++++++++++++++ drivers/tee/optee/supplicant.c | 9 ++ drivers/ufs/Kconfig | 8 ++ 6 files changed, 208 insertions(+) create mode 100644 drivers/tee/optee/rpmb_ufs.c diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile index d0c7f8dfb12..f2af10999a9 100644 --- a/drivers/tee/optee/Makefile +++ b/drivers/tee/optee/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_OPTEE) += core.o obj-y += supplicant.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb_emmc.o +obj-$(CONFIG_SUPPORT_UFS_RPMB) += rpmb_ufs.o diff --git a/drivers/tee/optee/optee_msg_supplicant.h b/drivers/tee/optee/optee_msg_supplicant.h index 963cfd47824..b720d5d7b3f 100644 --- a/drivers/tee/optee/optee_msg_supplicant.h +++ b/drivers/tee/optee/optee_msg_supplicant.h @@ -152,6 +152,14 @@ */ #define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21 +#define OPTEE_MSG_RPC_CMD_RPMB_PROBE_RESET 22 +#define OPTEE_MSG_RPC_CMD_RPMB_PROBE_NEXT 23 +#define OPTEE_MSG_RPC_CMD_RPMB_FRAMES 24 + +#define OPTEE_RPC_SHM_TYPE_APPL 0 + +#define OPTEE_RPC_RPMB_UFS 1 + /* * Was OPTEE_MSG_RPC_CMD_SQL_FS, which isn't supported any longer */ diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 1f07a27ee4b..2888257aefe 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -9,6 +9,17 @@ #include <tee.h> #include <log.h> +#ifdef CONFIG_SUPPORT_UFS_RPMB +/** + * struct optee_private - OP-TEE driver private data + * @rpmb_next_region: next UFS RPMB region to report on PROBE_NEXT + * @rpmb_cur_region: UFS RPMB region selected by the last PROBE_NEXT + */ +struct optee_private { + unsigned int rpmb_next_region; + unsigned int rpmb_cur_region; +}; +#else /** * struct optee_private - OP-TEE driver private data * @rpmb_mmc: mmc device for the RPMB partition @@ -22,6 +33,7 @@ struct optee_private { int rpmb_dev_id; int rpmb_original_part; }; +#endif struct optee_msg_arg; @@ -60,6 +72,35 @@ static inline void optee_suppl_rpmb_release(struct udevice *dev) } #endif +#ifdef CONFIG_SUPPORT_UFS_RPMB +void optee_suppl_cmd_rpmb_probe_reset(struct udevice *dev, + struct optee_msg_arg *arg); + +void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev, + struct optee_msg_arg *arg); + +void optee_suppl_cmd_rpmb_frames(struct udevice *dev, + struct optee_msg_arg *arg); +#else +static inline void optee_suppl_cmd_rpmb_probe_reset(struct udevice *dev, + struct optee_msg_arg *arg) +{ + arg->ret = TEE_ERROR_NOT_IMPLEMENTED; +} + +static inline void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev, + struct optee_msg_arg *arg) +{ + arg->ret = TEE_ERROR_NOT_IMPLEMENTED; +} + +static inline void optee_suppl_cmd_rpmb_frames(struct udevice *dev, + struct optee_msg_arg *arg) +{ + arg->ret = TEE_ERROR_NOT_IMPLEMENTED; +} +#endif + #ifdef CONFIG_DM_I2C /** * optee_suppl_cmd_i2c_transfer() - route I2C requests to an I2C chip diff --git a/drivers/tee/optee/rpmb_ufs.c b/drivers/tee/optee/rpmb_ufs.c new file mode 100644 index 00000000000..3e54a1a37d7 --- /dev/null +++ b/drivers/tee/optee/rpmb_ufs.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <dm.h> +#include <tee.h> +#include <ufs.h> + +#include "optee_msg.h" +#include "optee_msg_supplicant.h" +#include "optee_private.h" + +static int optee_rpmb_get_dev(struct udevice **scsi_devp) +{ + struct udevice *ufs_dev, *scsi_dev; + int ret; + + ret = uclass_get_device(UCLASS_UFS, CONFIG_UFS_RPMB_CONTROLLER, + &ufs_dev); + if (ret) + return ret; + + ret = device_get_child(ufs_dev, 0, &scsi_dev); + if (ret) + return ret; + + *scsi_devp = scsi_dev; + + return 0; +} + +void optee_suppl_cmd_rpmb_probe_reset(struct udevice *dev, + struct optee_msg_arg *arg) +{ + struct optee_private *priv = dev_get_priv(dev); + + if (arg->num_params != 1 || + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT) { + arg->ret = TEE_ERROR_BAD_PARAMETERS; + return; + } + + priv->rpmb_next_region = 0; + priv->rpmb_cur_region = 0; + + arg->params[0].u.value.a = OPTEE_RPC_SHM_TYPE_APPL; + arg->ret = TEE_SUCCESS; +} + +void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev, + struct optee_msg_arg *arg) +{ + struct optee_private *priv = dev_get_priv(dev); + struct udevice *scsi_dev; + struct tee_shm *cid_shm; + u8 size_mult = 0; + u8 rel_wr = 0; + void *cid_buf; + ulong cid_size; + int ret; + + if (arg->num_params != 2 || + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT || + arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) { + arg->ret = TEE_ERROR_BAD_PARAMETERS; + return; + } + + cid_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref; + cid_buf = (u8 *)cid_shm->addr + arg->params[1].u.rmem.offs; + cid_size = arg->params[1].u.rmem.size; + if (cid_size < UFS_RPMB_CID_SIZE) { + arg->ret = TEE_ERROR_SHORT_BUFFER; + return; + } + + if (optee_rpmb_get_dev(&scsi_dev)) { + arg->ret = TEE_ERROR_ITEM_NOT_FOUND; + return; + } + + while (priv->rpmb_next_region < UFS_RPMB_NUM_REGIONS) { + unsigned int region = priv->rpmb_next_region++; + + ret = ufs_rpmb_get_region_info(scsi_dev, region, &size_mult, + &rel_wr, cid_buf); + if (ret < 0) { + arg->ret = TEE_ERROR_GENERIC; + return; + } + if (!ret) + continue; + + priv->rpmb_cur_region = region; + arg->params[0].u.value.a = OPTEE_RPC_RPMB_UFS; + arg->params[0].u.value.b = size_mult; + arg->params[0].u.value.c = rel_wr; + arg->params[1].u.rmem.size = UFS_RPMB_CID_SIZE; + arg->ret = TEE_SUCCESS; + return; + } + + arg->ret = TEE_ERROR_ITEM_NOT_FOUND; +} + +void optee_suppl_cmd_rpmb_frames(struct udevice *dev, + struct optee_msg_arg *arg) +{ + struct optee_private *priv = dev_get_priv(dev); + struct tee_shm *req_shm; + struct tee_shm *rsp_shm; + struct udevice *scsi_dev; + void *req_buf; + void *rsp_buf; + ulong req_size; + ulong rsp_size; + + if (arg->num_params != 2 || + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_RMEM_INPUT || + arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) { + arg->ret = TEE_ERROR_BAD_PARAMETERS; + return; + } + + if (optee_rpmb_get_dev(&scsi_dev)) { + arg->ret = TEE_ERROR_ITEM_NOT_FOUND; + return; + } + + req_shm = (struct tee_shm *)(ulong)arg->params[0].u.rmem.shm_ref; + req_buf = (u8 *)req_shm->addr + arg->params[0].u.rmem.offs; + req_size = arg->params[0].u.rmem.size; + + rsp_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref; + rsp_buf = (u8 *)rsp_shm->addr + arg->params[1].u.rmem.offs; + rsp_size = arg->params[1].u.rmem.size; + + if (ufs_rpmb_route_frames(scsi_dev, priv->rpmb_cur_region, req_buf, + req_size, rsp_buf, rsp_size)) + arg->ret = TEE_ERROR_BAD_PARAMETERS; + else + arg->ret = TEE_SUCCESS; +} diff --git a/drivers/tee/optee/supplicant.c b/drivers/tee/optee/supplicant.c index 8a426f53ba8..50b780037fb 100644 --- a/drivers/tee/optee/supplicant.c +++ b/drivers/tee/optee/supplicant.c @@ -89,6 +89,15 @@ void optee_suppl_cmd(struct udevice *dev, struct tee_shm *shm_arg, case OPTEE_MSG_RPC_CMD_RPMB: optee_suppl_cmd_rpmb(dev, arg); break; + case OPTEE_MSG_RPC_CMD_RPMB_PROBE_RESET: + optee_suppl_cmd_rpmb_probe_reset(dev, arg); + break; + case OPTEE_MSG_RPC_CMD_RPMB_PROBE_NEXT: + optee_suppl_cmd_rpmb_probe_next(dev, arg); + break; + case OPTEE_MSG_RPC_CMD_RPMB_FRAMES: + optee_suppl_cmd_rpmb_frames(dev, arg); + break; case OPTEE_MSG_RPC_CMD_I2C_TRANSFER: optee_suppl_cmd_i2c_transfer(arg); break; diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index d39fcda42dc..d7fe2486ee2 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -105,4 +105,12 @@ config SUPPORT_UFS_RPMB single RPMB transport, so this is mutually exclusive with the eMMC RPMB supplicant (SUPPORT_EMMC_RPMB). +config UFS_RPMB_CONTROLLER + int "UFS controller index used for RPMB" + depends on SUPPORT_UFS_RPMB + default 0 + help + Index of the RPMB-owning UFS controller in the UCLASS_UFS device + list. Leave at 0 unless the board has more than one UFS controller. + endmenu -- 2.54.0
