Enable UFS RPMB-backed OP-TEE secure storage on Genio 720
Subsystems (4)
cover Enable UFS RPMB-backed OP-TEE secure storage on Genio 720
This series enables UFS RPMB-backed OP-TEE secure storage on Genio 720. The goal is to support pre-OS services such as EFI variable storage with the same RPMB device identity used under Linux.
The platform also needs the OP-TEE UFS read fixes [1] and MT8391 platform and hardware-key support [2].
[1] https://github.com/OP-TEE/optee_os/pull/8238
[2] https://github.com/OP-TEE/optee_os/pull/8242
---
Carlo Caione (6):
ufs: rpmb: validate requests before issuing commands
ufs: rpmb: stop the model string at its NUL terminator
tee: optee: keep UFS RPMB discovery state consistent
tee: optee: enumerate UFS RPMB services when consumers exist
configs: add a Genio 720 UFS configuration with OP-TEE RPMB
doc: uefi: mention UFS RPMB for OP-TEE variable storage
Macpaul Lin (1):
cmd: allow the OP-TEE RPMB command with UFS storage
cmd/Kconfig | 4 ++-- configs/mt8391_genio_720_evk_ufs_defconfig | 7 +++++++ doc/develop/uefi/uefi.rst | 5 +++-- drivers/tee/optee/core.c | 8 +++++++- drivers/tee/optee/optee_private.h | 9 ++++++++- drivers/tee/optee/rpmb_ufs.c | 18 ++++++++++++++++-- drivers/ufs/ufs-rpmb.c | 22 +++++++++++++++------- 7 files changed, 58 insertions(+), 15 deletions(-)
---
base-commit: 934995f642a21ca7f35fa9aed5f061394fcba243
change-id: 20261111-genio720-ufs-rpmb-minimal-41e476364217
Best regards,
Signature · 1 line
Carlo Caione <[email protected]>
PATCH 1/7 ufs: rpmb: validate requests before issuing commands
Check frame counts and response space before issuing any commands. A malformed request must not program a key or write data and then fail on response validation. Use Linux's request shapes so surplus frames cannot be sent or silently discarded.
--- drivers/ufs/ufs-rpmb.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
drivers/ufs/ufs-rpmb.c +13 -7
@@ -157,16 +157,25 @@ int ufs_rpmb_route_frames(struct udevice *scsi_dev, unsigned int region,int ret;if (!scsi_dev || reqlen %RPMB_FRAME_SIZE || - rsplen %RPMB_FRAME_SIZE || !n_req) + rsplen %RPMB_FRAME_SIZE || !n_req || !n_rsp)return -EINVAL ; request =get_unaligned_be16 ((u8 *)req +RPMB_FRAME_REQ_OFFSET ); +/* +* Enforce Linux's frame counts before any I/O: a key-programming +* request and a write counter read are a single frame answered by a +* single frame, a data write may span several frames but returns one +* result, and a data read is one request returning several frames. +*/ switch (request) {case RPMB_REQ_KEY :case RPMB_REQ_WRITE_DATA : {u8 status_frame[RPMB_FRAME_SIZE ]; +if (n_rsp !=1 || (request ==RPMB_REQ_KEY && n_req !=1 )) +return -EINVAL ; + ret =ufs_rpmb_send (scsi_dev, region, req, n_req);if (ret)return ret;
@@ -178,20 +187,17 @@ int ufs_rpmb_route_frames(struct udevice *scsi_dev, unsigned int region,if (ret)return ret; -if (n_rsp <1 ) -return -EINVAL ; -return ufs_rpmb_recv (scsi_dev, region, rsp,1 ); }case RPMB_REQ_WCOUNTER :case RPMB_REQ_READ_DATA : +if (n_req !=1 || (request ==RPMB_REQ_WCOUNTER && n_rsp !=1 )) +return -EINVAL ; + ret =ufs_rpmb_send (scsi_dev, region, req,1 );if (ret)return ret; -if (n_rsp <1 ) -return -EINVAL ; -return ufs_rpmb_recv (scsi_dev, region, rsp, n_rsp);default :debug ("ufs-rpmb: unsupported request 0x%x\n" , request);
Signature · 1 line
2.56.0
PATCH 2/7 ufs: rpmb: stop the model string at its NUL terminator
In reply to Carlo CaioneSome UFS model descriptors contain trailing UTF-16 NULs. Converting them to spaces changes the RPMB identity, whereas Linux stops at the first NUL. OP-TEE then derives different keys for the same region in the two boot stages. Stop at the terminator to preserve a common identity.
--- drivers/ufs/ufs-rpmb.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/ufs/ufs-rpmb.c +2 -0
@@ -270,6 +270,8 @@ static void ufs_rpmb_string_to_ascii(const u8 *raw, char *out, size_t outsz)for (i =0 ; i < nchars && n < (int )outsz -1 ; i++) {u16 c =get_unaligned_be16 (raw +QUERY_DESC_HDR_SIZE + i *2 ); +if (!c) +break ; out[n++] = (c >=0x20 && c <=0x7e ) ? (char )c :' ' ; } out[n] ='\0' ;
Signature · 1 line
2.56.0
PATCH 3/7 tee: optee: keep UFS RPMB discovery state consistent
In reply to Carlo CaioneReject frame requests until discovery selects a region, and invalidate that selection on every discovery failure. Keep the cursor on a region whose metadata read failed so a retry does not silently skip it.
--- drivers/tee/optee/core.c | 2 ++ drivers/tee/optee/optee_private.h | 9 ++++++++- drivers/tee/optee/rpmb_ufs.c | 18 ++++++++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-)
drivers/tee/optee/core.c +2 -0
@@ -829,6 +829,8 @@ static int optee_probe(struct udevice *dev)u32 sec_caps;int ret; +optee_suppl_rpmb_init (dev); +if (!is_optee_api (pdata->invoke_fn)) {dev_err (dev,"OP-TEE api uid mismatch\n" );return -ENOENT ;
drivers/tee/optee/optee_private.h +8 -1
@@ -34,7 +34,8 @@/** * 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 +* @rpmb_cur_region: UFS RPMB region selected by the last PROBE_NEXT, or +* UFS_RPMB_NUM_REGIONS while no region is selected */ struct optee_private {unsigned int rpmb_next_region;
@@ -97,6 +98,8 @@ static inline void optee_suppl_rpmb_release(struct udevice *dev)#endif #ifdef CONFIG_SUPPORT_UFS_RPMB +void optee_suppl_rpmb_init (struct udevice *dev); +void optee_suppl_cmd_rpmb_probe_reset (struct udevice *dev,struct optee_msg_arg *arg);
@@ -106,6 +109,10 @@ void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev,void optee_suppl_cmd_rpmb_frames (struct udevice *dev,struct optee_msg_arg *arg);#else +static inline void optee_suppl_rpmb_init (struct udevice *dev) +{ +} +static inline void optee_suppl_cmd_rpmb_probe_reset (struct udevice *dev,struct optee_msg_arg *arg) {
drivers/tee/optee/rpmb_ufs.c +16 -2
@@ -8,6 +8,13 @@#include "optee_msg_supplicant.h" #include "optee_private.h" +void optee_suppl_rpmb_init (struct udevice *dev) +{ +struct optee_private *priv =dev_get_priv (dev); + + priv->rpmb_cur_region =UFS_RPMB_NUM_REGIONS ; +} +static int optee_rpmb_get_dev (struct udevice **scsi_devp) {struct udevice *ufs_dev, *scsi_dev;
@@ -32,6 +39,7 @@ void optee_suppl_cmd_rpmb_probe_reset(struct udevice *dev, {struct optee_private *priv =dev_get_priv (dev); + priv->rpmb_cur_region =UFS_RPMB_NUM_REGIONS ;if (arg->num_params !=1 || arg->params[0 ].attr !=OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT ) { arg->ret =TEE_ERROR_BAD_PARAMETERS ;
@@ -39,7 +47,6 @@ void optee_suppl_cmd_rpmb_probe_reset(struct udevice *dev, } priv->rpmb_next_region =0 ; - priv->rpmb_cur_region =0 ; arg->params[0 ].u.value.a =OPTEE_MSG_RPC_SHM_TYPE_APPL ; arg->ret =TEE_SUCCESS ;
@@ -57,6 +64,7 @@ void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev,ulong cid_size;int ret; + priv->rpmb_cur_region =UFS_RPMB_NUM_REGIONS ;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 ) {
@@ -78,7 +86,7 @@ void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev, }while (priv->rpmb_next_region <UFS_RPMB_NUM_REGIONS ) { -unsigned int region = priv->rpmb_next_region++; +unsigned int region = priv->rpmb_next_region; ret =ufs_rpmb_get_region_info (scsi_dev, region, &size_mult, &rel_wr, cid_buf);
@@ -86,6 +94,7 @@ void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev, arg->ret =TEE_ERROR_GENERIC ;return ; } + priv->rpmb_next_region++;if (!ret)continue ;
@@ -120,6 +129,11 @@ void optee_suppl_cmd_rpmb_frames(struct udevice *dev,return ; } +if (priv->rpmb_cur_region >=UFS_RPMB_NUM_REGIONS ) { + arg->ret =TEE_ERROR_ITEM_NOT_FOUND ; +return ; + } +if (optee_rpmb_get_dev (&scsi_dev)) { arg->ret =TEE_ERROR_ITEM_NOT_FOUND ;return ;
Signature · 1 line
2.56.0
Re: [PATCH 3/7] tee: optee: keep UFS RPMB discovery state consistent
Hi Carlo,
Quoted 5 lines · Carlo Caione
Reject frame requests until discovery selects a region, and invalidate that selection on every discovery failure. Keep the cursor on a region whose metadata read failed so a retry does not silently skip it.
The commit message does not explain why any of the above is needed.
Thanks
/Ilias
Quoted 130 lines
Fixes 3b39df3bc540 ("optee: implement the RPMB subsystem interface for UFS")Signed-off-by Carlo Caione <[email protected]>--- drivers/tee/optee/core.c | 2 ++ drivers/tee/optee/optee_private.h | 9 ++++++++- drivers/tee/optee/rpmb_ufs.c | 18 ++++++++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-)drivers/tee/optee/core.c +2
-0@@ -829,6 +829,8 @@ static int optee_probe(struct udevice *dev)u32 sec_caps;int ret; +optee_suppl_rpmb_init (dev); +if (!is_optee_api (pdata->invoke_fn)) {dev_err (dev,"OP-TEE api uid mismatch\n" );return -ENOENT ;drivers/tee/optee/optee_private.h +8
-1@@ -34,7 +34,8 @@/** * 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 +* @rpmb_cur_region: UFS RPMB region selected by the last PROBE_NEXT, or +* UFS_RPMB_NUM_REGIONS while no region is selected */ struct optee_private {unsigned int rpmb_next_region;@@ -97,6 +98,8 @@ static inline void optee_suppl_rpmb_release(struct udevice *dev)#endif #ifdef CONFIG_SUPPORT_UFS_RPMB +void optee_suppl_rpmb_init (struct udevice *dev); +void optee_suppl_cmd_rpmb_probe_reset (struct udevice *dev,struct optee_msg_arg *arg);@@ -106,6 +109,10 @@ void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev,void optee_suppl_cmd_rpmb_frames (struct udevice *dev,struct optee_msg_arg *arg);#else +static inline void optee_suppl_rpmb_init (struct udevice *dev) +{ +} +static inline void optee_suppl_cmd_rpmb_probe_reset (struct udevice *dev,struct optee_msg_arg *arg) {drivers/tee/optee/rpmb_ufs.c +16
-3@@ -8,6 +8,13 @@#include "optee_msg_supplicant.h" #include "optee_private.h" +void optee_suppl_rpmb_init (struct udevice *dev) +{ +struct optee_private *priv =dev_get_priv (dev); + + priv->rpmb_cur_region =UFS_RPMB_NUM_REGIONS ; +} +static int optee_rpmb_get_dev (struct udevice **scsi_devp) {struct udevice *ufs_dev, *scsi_dev;@@ -32,6 +39,7 @@ void optee_suppl_cmd_rpmb_probe_reset(struct udevice *dev, {struct optee_private *priv =dev_get_priv (dev); + priv->rpmb_cur_region =UFS_RPMB_NUM_REGIONS ;if (arg->num_params !=1 || arg->params[0 ].attr !=OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT ) { arg->ret =TEE_ERROR_BAD_PARAMETERS ;@@ -39,7 +47,6 @@ void optee_suppl_cmd_rpmb_probe_reset(struct udevice *dev, } priv->rpmb_next_region =0 ; - priv->rpmb_cur_region =0 ; arg->params[0 ].u.value.a =OPTEE_MSG_RPC_SHM_TYPE_APPL ; arg->ret =TEE_SUCCESS ;@@ -57,6 +64,7 @@ void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev,ulong cid_size;int ret; + priv->rpmb_cur_region =UFS_RPMB_NUM_REGIONS ;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 ) {@@ -78,7 +86,7 @@ void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev, }while (priv->rpmb_next_region <UFS_RPMB_NUM_REGIONS ) { -unsigned int region = priv->rpmb_next_region++; +unsigned int region = priv->rpmb_next_region; ret =ufs_rpmb_get_region_info (scsi_dev, region, &size_mult, &rel_wr, cid_buf);@@ -86,6 +94,7 @@ void optee_suppl_cmd_rpmb_probe_next(struct udevice *dev, arg->ret =TEE_ERROR_GENERIC ;return ; } + priv->rpmb_next_region++;if (!ret)continue ;@@ -120,6 +129,11 @@ void optee_suppl_cmd_rpmb_frames(struct udevice *dev,return ; } +if (priv->rpmb_cur_region >=UFS_RPMB_NUM_REGIONS ) { + arg->ret =TEE_ERROR_ITEM_NOT_FOUND ; +return ; + } +if (optee_rpmb_get_dev (&scsi_dev)) { arg->ret =TEE_ERROR_ITEM_NOT_FOUND ;return ; --2.56.0
PATCH 4/7 tee: optee: enumerate UFS RPMB services when consumers exist
In reply to Carlo CaioneRPMB-backed service discovery currently runs only with eMMC. With UFS enabled, services advertised only by PTA_CMD_GET_DEVICES_RPMB are never bound. Allow the query with either transport.
Skip enumeration when no service drivers are registered, so enabling UFS support alone does not initialize storage unnecessarily.
--- drivers/tee/optee/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/tee/optee/core.c +5 -1
@@ -194,13 +194,17 @@ static int bind_service_drivers(struct udevice *dev)int ret, ret2, ret3 =0 ;u32 tee_sess; + if (!ll_entry_count(struct optee_service, optee_service)) +return 0 ; + ret =optee_open_enum_session (dev, &tee_sess);if (ret)return ret; ret =optee_bind_services (dev, tee_sess,PTA_CMD_GET_DEVICES ); ret2 =optee_bind_services (dev, tee_sess,PTA_CMD_GET_DEVICES_SUPP ); -if (CONFIG_IS_ENABLED (SUPPORT_EMMC_RPMB )) +if (CONFIG_IS_ENABLED (SUPPORT_EMMC_RPMB ) || +CONFIG_IS_ENABLED (SUPPORT_UFS_RPMB )) ret3 =optee_bind_services (dev, tee_sess,PTA_CMD_GET_DEVICES_RPMB );
Signature · 1 line
2.56.0
PATCH 5/7 cmd: allow the OP-TEE RPMB command with UFS storage
In reply to Carlo CaioneFrom: Macpaul Lin <[email protected]>
CMD_OPTEE_RPMB is restricted to the eMMC transport even though the OP- TEE persistent-object interface is independent of the storage medium. Allow it with the UFS RPMB subsystem transport as well, preserving the existing sandbox path and default.
--- cmd/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
cmd/Kconfig +2 -2
@@ -1554,12 +1554,12 @@ config CMD_CLONE config CMD_OPTEE_RPMB bool "Enable read/write support on RPMB via OPTEE" - depends on (SUPPORT_EMMC_RPMB && OPTEE) || SANDBOX_TEE + depends on ((SUPPORT_EMMC_RPMB || SUPPORT_UFS_RPMB) && OPTEE) || SANDBOX_TEE default y if SANDBOX_TEE select OPTEE_TA_AVB if SANDBOX_TEE help Enable the commands for reading, writing persistent named values - in the Replay Protection Memory Block partition in eMMC by + in the Replay Protection Memory Block partition in eMMC or UFS by using Persistent Objects in OPTEE config CMD_OPTEE
Signature · 1 line
2.56.0
PATCH 6/7 configs: add a Genio 720 UFS configuration with OP-TEE RPMB
In reply to Carlo CaioneThe Genio 720 board already provides a merged UFS device tree, but its default configuration selects eMMC. Add a UFS entry point which reuses the common board configuration and selects the existing UFS overlay.
Enable the OP-TEE client and Qualcomm UFS RPMB transport on this UFS variant without changing the default eMMC configuration. The device tree already describes the secure firmware and its reserved memory.
--- configs/mt8391_genio_720_evk_ufs_defconfig | 7 +++++++ 1 file changed, 7 insertions(+)
configs/mt8391_genio_720_evk_ufs_defconfig new file +7 -0
@@ -0,0 +1,7 @@ +#include <configs/mt8391_genio_720_evk_defconfig> + +CONFIG_DEFAULT_DEVICE_TREE="mt8391-genio-720-evk-ufs" +CONFIG_DEFAULT_FDT_FILE="mt8391-genio-720-evk-ufs" +CONFIG_TEE=y +CONFIG_OPTEE=y +CONFIG_SUPPORT_UFS_RPMB=y
Signature · 1 line
2.56.0
PATCH 7/7 doc: uefi: mention UFS RPMB for OP-TEE variable storage
In reply to Carlo CaioneU-Boot's OP-TEE supplicant can relay RPMB requests to a UFS device when CONFIG_SUPPORT_UFS_RPMB is enabled, but the UEFI documentation still names only the eMMC transport for OP-TEE-backed variables. Mention both options.
--- doc/develop/uefi/uefi.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
doc/develop/uefi/uefi.rst +3 -2
@@ -214,10 +214,11 @@ CONFIG_EFI_MM_COMM_TEE=y. Tianocore EDK II's standalone management mode driver for variables can be linked to OP-TEE for this purpose. This module uses the Replay -Protected Memory Block (RPMB) of an eMMC device for persisting +Protected Memory Block (RPMB) of an eMMC or UFS device for persisting non-volatile variables. When calling the variable services via the OP-TEE API U-Boot's OP-TEE supplicant relays calls to the RPMB driver -which has to be enabled via CONFIG_SUPPORT_EMMC_RPMB=y. +which has to be enabled via CONFIG_SUPPORT_EMMC_RPMB=y for eMMC or +CONFIG_SUPPORT_UFS_RPMB=y for UFS. EDK2 Build instructions ***********************
Signature · 1 line
2.56.0
Re: [PATCH 7/7] doc: uefi: mention UFS RPMB for OP-TEE variable storage
Carlo,
When we designed and implemented this with Jens it was in theory the abstraction we aimed for, but has anyone actually tested it?
Quoted 8 lines · Carlo Caione
U-Boot's OP-TEE supplicant can relay RPMB requests to a UFS device when
CONFIG_SUPPORT_UFS_RPMBis enabled, but the UEFI documentation still names only the eMMC transport for OP-TEE-backed variables. Mention both options.Signed-off-by Carlo Caione <[email protected]>---
Quoted 26 lines
doc/develop/uefi/uefi.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)doc/develop/uefi/uefi.rst +3
-3@@ -214,10 +214,11 @@ CONFIG_EFI_MM_COMM_TEE=y. Tianocore EDK II's standalone management mode driver for variables can be linked to OP-TEE for this purpose. This module uses the Replay -Protected Memory Block (RPMB) of an eMMC device for persisting +Protected Memory Block (RPMB) of an eMMC or UFS device for persisting non-volatile variables. When calling the variable services via the OP-TEE API U-Boot's OP-TEE supplicant relays calls to the RPMB driver -which has to be enabled via CONFIG_SUPPORT_EMMC_RPMB=y. +which has to be enabled via CONFIG_SUPPORT_EMMC_RPMB=y for eMMC or +CONFIG_SUPPORT_UFS_RPMB=y for UFS. EDK2 Build instructions *********************** --2.56.0
Re: [PATCH 7/7] doc: uefi: mention UFS RPMB for OP-TEE variable storage
Quoted 1 line · Ilias Apalodimas
Carlo,
Hi Ilias,
Quoted 2 lines
When we designed and implemented this with Jens it was in theory the abstraction we aimed for, but has anyone actually tested it?
It was tested on a G720 platform. We created, updated and deleted a non-volatile EFI variable from U-Boot, backed by the RPMB on UFS.
The stack was this series + the two OP-TEE PRs linked in the cover letter, using EDK II StandaloneMm.
--
Carlo Caione