[PATCH v5 0/4] OP-TEE I2C trampoline and associated tests

From: Igor Opaniuk igor.opaniuk@foundries.io
This patchset allows OP-TEE to communicate with I2C devices; a typical use case would be servicing U-Boot requests that require underlying cryptographic operations implemented by an I2C chip.
On a board fitted with the NXP SE050 I2C secure element, OP-TEE can route some of the cryptographic operations it needs to that device (ie RSA, ECC, CTR..).
Before the REE executes, OP-TEE would use its own I2C drivers to communicate with the device on the bus; later on, once the REE is up, accesses to the I2C bus should be coordinated with the REE to avoid collisions. However instead of implementing such a synchronization mechanism, this trampoline service permits OP-TEE to route those I2C requests back to U-boot without then having to worry about collisions.
Lets suppose that U-Boot executes the trusted application Android Verified Boot; when OP-TEE receives the request - and before executing the application - it uses RSA to verify it. So on the back of the TA function invocation, OP-TEE returns to U-boot with a sequence of RPC calls requesting I2C transfers (check carefully the implementation in do_call_with_arg(...) implemented in drivers/tee/optee/core.c and notice the while loop)
When using sandbox testing, RPC is called directly to validate its actual implementation; however as succintly described above, these calls will always be originated in OP-TEE.
Changes v5: * [Jens Wiklander] Addressed comment about optee_alloc_and_init_page_list(): drop inline, proper return value and comment
Changes v4: * [Simon Glass] Reduced amount ifdefs warnings and move to if (IS_ENABLED(CONFIG_*)) where possible * Fixed pointer-sign warnings
Changes v3: * [Simon Glass] Added RPC I2C test coverage
Changes v2: * [Simon Glass] Adjusted the usage of DM internal api (dev_get_parent_platdata) * [Simon Glass] Added additional comments to functions * [Jens Wiklander] s/tmem/rmem/g
Igor Opaniuk (3): test: py: add pygit2 and pyelftools to requirements.txt drivers: tee: sandbox: add rpc test ta emulation test: dm: tee: extend with RPC test
Jorge Ramirez-Ortiz (1): drivers: tee: i2c trampoline driver
drivers/tee/Makefile | 2 + drivers/tee/optee/Kconfig | 9 ++ drivers/tee/optee/Makefile | 1 + drivers/tee/optee/i2c.c | 90 ++++++++++++++ drivers/tee/optee/optee_msg.h | 21 ++++ drivers/tee/optee/optee_msg_supplicant.h | 5 + drivers/tee/optee/optee_private.h | 17 +++ drivers/tee/optee/supplicant.c | 3 + drivers/tee/sandbox.c | 143 ++++++++++++++++++++++- include/tee/optee_ta_rpc_test.h | 28 +++++ test/dm/tee.c | 107 ++++++++++++++++- test/py/requirements.txt | 2 + 12 files changed, 419 insertions(+), 9 deletions(-) create mode 100644 drivers/tee/optee/i2c.c create mode 100644 include/tee/optee_ta_rpc_test.h

From: Jorge Ramirez-Ortiz jorge@foundries.io
This commit gives the secure world access to the I2C bus so it can communicate with I2C slaves (typically those would be secure elements like the NXP SE050).
A similar service implementation has been merged in linux: c05210ab ("drivers: optee: allow op-tee to access devices on the i2c bus")
Signed-off-by: Jorge Ramirez-Ortiz jorge@foundries.io Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
drivers/tee/optee/Makefile | 1 + drivers/tee/optee/i2c.c | 90 ++++++++++++++++++++++++ drivers/tee/optee/optee_msg.h | 21 ++++++ drivers/tee/optee/optee_msg_supplicant.h | 5 ++ drivers/tee/optee/optee_private.h | 17 +++++ drivers/tee/optee/supplicant.c | 3 + 6 files changed, 137 insertions(+) create mode 100644 drivers/tee/optee/i2c.c
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile index 928d3f8002..068c6e7aa1 100644 --- a/drivers/tee/optee/Makefile +++ b/drivers/tee/optee/Makefile @@ -2,4 +2,5 @@
obj-y += core.o obj-y += supplicant.o +obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o diff --git a/drivers/tee/optee/i2c.c b/drivers/tee/optee/i2c.c new file mode 100644 index 0000000000..ef4e10f991 --- /dev/null +++ b/drivers/tee/optee/i2c.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2020 Foundries.io Ltd + */ + +#include <common.h> +#include <dm.h> +#include <i2c.h> +#include <tee.h> +#include "optee_msg.h" +#include "optee_private.h" + +static int check_xfer_flags(struct udevice *chip, uint tee_flags) +{ + uint flags; + int ret; + + ret = i2c_get_chip_flags(chip, &flags); + if (ret) + return ret; + + if (tee_flags & OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT) { + if (!(flags & DM_I2C_CHIP_10BIT)) + return -EINVAL; + } else { + if (flags & DM_I2C_CHIP_10BIT) + return -EINVAL; + } + + return 0; +} + +void optee_suppl_cmd_i2c_transfer(struct optee_msg_arg *arg) +{ + const u8 attr[] = { + OPTEE_MSG_ATTR_TYPE_VALUE_INPUT, + OPTEE_MSG_ATTR_TYPE_VALUE_INPUT, + OPTEE_MSG_ATTR_TYPE_RMEM_INOUT, + OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT, + }; + struct udevice *chip_dev; + struct tee_shm *shm; + u8 *buf; + int ret; + + if (arg->num_params != ARRAY_SIZE(attr) || + arg->params[0].attr != attr[0] || + arg->params[1].attr != attr[1] || + arg->params[2].attr != attr[2] || + arg->params[3].attr != attr[3]) { + goto bad; + } + + shm = (struct tee_shm *)(unsigned long)arg->params[2].u.rmem.shm_ref; + buf = shm->addr; + if (!buf) + goto bad; + + if (i2c_get_chip_for_busnum((int)arg->params[0].u.value.b, + (int)arg->params[0].u.value.c, + 0, &chip_dev)) + goto bad; + + if (check_xfer_flags(chip_dev, arg->params[1].u.value.a)) + goto bad; + + switch (arg->params[0].u.value.a) { + case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD: + ret = dm_i2c_read(chip_dev, 0, buf, + (size_t)arg->params[2].u.rmem.size); + break; + case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR: + ret = dm_i2c_write(chip_dev, 0, buf, + (size_t)arg->params[2].u.rmem.size); + break; + default: + goto bad; + } + + if (ret) { + arg->ret = TEE_ERROR_COMMUNICATION; + } else { + arg->params[3].u.value.a = arg->params[2].u.rmem.size; + arg->ret = TEE_SUCCESS; + } + + return; +bad: + arg->ret = TEE_ERROR_BAD_PARAMETERS; +} diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h index 24c60960fc..8d40ce60c2 100644 --- a/drivers/tee/optee/optee_msg.h +++ b/drivers/tee/optee/optee_msg.h @@ -422,4 +422,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_msg_supplicant.h b/drivers/tee/optee/optee_msg_supplicant.h index a0fb8063c8..963cfd4782 100644 --- a/drivers/tee/optee/optee_msg_supplicant.h +++ b/drivers/tee/optee/optee_msg_supplicant.h @@ -147,6 +147,11 @@ #define OPTEE_MSG_RPC_CMD_SHM_ALLOC 6 #define OPTEE_MSG_RPC_CMD_SHM_FREE 7
+/* + * I2C bus access + */ +#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21 + /* * 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 9442d1c176..1f07a27ee4 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -60,6 +60,23 @@ static inline void optee_suppl_rpmb_release(struct udevice *dev) } #endif
+#ifdef CONFIG_DM_I2C +/** + * optee_suppl_cmd_i2c_transfer() - route I2C requests to an I2C chip + * @arg: OP-TEE message (layout specified in optee_msg.h) defining the + * transfer mode (read/write), adapter, chip and control flags. + * + * Handles OP-TEE requests to transfer data to the I2C chip on the I2C adapter. + */ +void optee_suppl_cmd_i2c_transfer(struct optee_msg_arg *arg); +#else +static inline void optee_suppl_cmd_i2c_transfer(struct optee_msg_arg *arg) +{ + debug("OPTEE_MSG_RPC_CMD_I2C_TRANSFER not implemented\n"); + arg->ret = TEE_ERROR_NOT_IMPLEMENTED; +} +#endif + void *optee_alloc_and_init_page_list(void *buf, ulong len, u64 *phys_buf_ptr);
#endif /* __OPTEE_PRIVATE_H */ diff --git a/drivers/tee/optee/supplicant.c b/drivers/tee/optee/supplicant.c index ae042b9a20..f9dd874b59 100644 --- a/drivers/tee/optee/supplicant.c +++ b/drivers/tee/optee/supplicant.c @@ -89,6 +89,9 @@ 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_I2C_TRANSFER: + optee_suppl_cmd_i2c_transfer(arg); + break; default: arg->ret = TEE_ERROR_NOT_IMPLEMENTED; }

From: Igor Opaniuk igor.opaniuk@foundries.io
Add pygit2 and pyelftools to the list of packages for virtualenv needed to run all sets of pytests.This fixes warnings like:
binman.elf_test.TestElf.testDecodeElf (subunit.RemotedTestCase): Python elftools not available
Signed-off-by: Igor Opaniuk igor.opaniuk@foundries.io Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
test/py/requirements.txt | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/test/py/requirements.txt b/test/py/requirements.txt index cf251186f4..926bccad69 100644 --- a/test/py/requirements.txt +++ b/test/py/requirements.txt @@ -10,6 +10,8 @@ packaging==19.2 pbr==5.4.3 pluggy==0.13.0 py==1.8.0 +pyelftools==0.27 +pygit2==1.4.0 pyparsing==2.4.2 pytest==5.2.1 python-mimeparse==1.6.0

From: Igor Opaniuk igor.opaniuk@foundries.io
This adds support for RPC test trusted application emulation, which permits to test reverse RPC calls to TEE supplicant. Currently it covers requests to the I2C bus from TEE.
Signed-off-by: Igor Opaniuk igor.opaniuk@foundries.io Reviewed-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
drivers/tee/Makefile | 2 + drivers/tee/optee/Kconfig | 9 ++ drivers/tee/sandbox.c | 143 +++++++++++++++++++++++++++++++- include/tee/optee_ta_rpc_test.h | 28 +++++++ 4 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 include/tee/optee_ta_rpc_test.h
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index 5c8ffdbce8..ff844195ae 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -2,5 +2,7 @@
obj-y += tee-uclass.o obj-$(CONFIG_SANDBOX) += sandbox.o +obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/supplicant.o +obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/i2c.o obj-$(CONFIG_OPTEE) += optee/ obj-y += broadcom/ diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index d489834df9..65622f30b1 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -22,6 +22,15 @@ config OPTEE_TA_AVB The TA can support the "avb" subcommands "read_rb", "write"rb" and "is_unlocked".
+config OPTEE_TA_RPC_TEST + bool "Support RPC TEST TA" + depends on SANDBOX_TEE + default y + help + Enables support for RPC test trusted application emulation, which + permits to test reverse RPC calls to TEE supplicant. Should + be used only in sandbox env. + endmenu
endif diff --git a/drivers/tee/sandbox.c b/drivers/tee/sandbox.c index e1ba027fd6..d075701b4e 100644 --- a/drivers/tee/sandbox.c +++ b/drivers/tee/sandbox.c @@ -7,11 +7,15 @@ #include <sandboxtee.h> #include <tee.h> #include <tee/optee_ta_avb.h> +#include <tee/optee_ta_rpc_test.h> + +#include "optee/optee_msg.h" +#include "optee/optee_private.h"
/* * The sandbox tee driver tries to emulate a generic Trusted Exectution - * Environment (TEE) with the Trusted Application (TA) OPTEE_TA_AVB - * available. + * Environment (TEE) with the Trusted Applications (TA) OPTEE_TA_AVB and + * OPTEE_TA_RPC_TEST available. */
static const u32 pstorage_max = 16; @@ -32,7 +36,38 @@ struct ta_entry { struct tee_param *params); };
-#ifdef CONFIG_OPTEE_TA_AVB +static int get_msg_arg(struct udevice *dev, uint num_params, + struct tee_shm **shmp, struct optee_msg_arg **msg_arg) +{ + int rc; + struct optee_msg_arg *ma; + + rc = __tee_shm_add(dev, OPTEE_MSG_NONCONTIG_PAGE_SIZE, NULL, + OPTEE_MSG_GET_ARG_SIZE(num_params), TEE_SHM_ALLOC, + shmp); + if (rc) + return rc; + + ma = (*shmp)->addr; + memset(ma, 0, OPTEE_MSG_GET_ARG_SIZE(num_params)); + ma->num_params = num_params; + *msg_arg = ma; + + return 0; +} + +void *optee_alloc_and_init_page_list(void *buf, ulong len, + u64 *phys_buf_ptr) +{ + /* + * An empty stub is added just to fix linking issues. + * This function isn't supposed to be called in sandbox + * setup, otherwise replace this with a proper + * implementation from optee/core.c + */ + return NULL; +} + static u32 get_attr(uint n, uint num_params, struct tee_param *params) { if (n >= num_params) @@ -63,6 +98,7 @@ bad_params: return TEE_ERROR_BAD_PARAMETERS; }
+#ifdef CONFIG_OPTEE_TA_AVB static u32 ta_avb_open_session(struct udevice *dev, uint num_params, struct tee_param *params) { @@ -214,7 +250,100 @@ static u32 ta_avb_invoke_func(struct udevice *dev, u32 func, uint num_params, return TEE_ERROR_NOT_SUPPORTED; } } -#endif /*OPTEE_TA_AVB*/ +#endif /* OPTEE_TA_AVB */ + +#ifdef CONFIG_OPTEE_TA_RPC_TEST +static u32 ta_rpc_test_open_session(struct udevice *dev, uint num_params, + struct tee_param *params) +{ + /* + * We don't expect additional parameters when opening a session to + * this TA. + */ + return check_params(TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE, + TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE, + num_params, params); +} + +static void fill_i2c_rpc_params(struct optee_msg_arg *msg_arg, u64 bus_num, + u64 chip_addr, u64 op, + struct tee_param_memref memref) +{ + msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; + msg_arg->params[2].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT; + msg_arg->params[3].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT; + + /* trigger I2C services of TEE supplicant */ + msg_arg->cmd = OPTEE_MSG_RPC_CMD_I2C_TRANSFER; + + msg_arg->params[0].u.value.a = op; + msg_arg->params[0].u.value.b = bus_num; + msg_arg->params[0].u.value.c = chip_addr; + + /* buffer to read/write data */ + msg_arg->params[2].u.rmem.shm_ref = (ulong)memref.shm; + msg_arg->params[2].u.rmem.size = memref.size; + msg_arg->params[2].u.rmem.offs = memref.shm_offs; + + msg_arg->num_params = 4; +} + +static u32 ta_rpc_test_invoke_func(struct udevice *dev, u32 func, + uint num_params, + struct tee_param *params) +{ + struct tee_shm *shm; + struct tee_param_memref memref_data; + struct optee_msg_arg *msg_arg; + int chip_addr, bus_num, op; + int res; + + res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT, + TEE_PARAM_ATTR_TYPE_MEMREF_INOUT, + TEE_PARAM_ATTR_TYPE_NONE, + TEE_PARAM_ATTR_TYPE_NONE, + num_params, params); + if (res) + return TEE_ERROR_BAD_PARAMETERS; + + bus_num = params[0].u.value.a; + chip_addr = params[0].u.value.b; + memref_data = params[1].u.memref; + + switch (func) { + case TA_RPC_TEST_CMD_I2C_READ: + op = OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD; + break; + case TA_RPC_TEST_CMD_I2C_WRITE: + op = OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR; + break; + default: + return TEE_ERROR_NOT_SUPPORTED; + } + + /* + * Fill params for an RPC call to tee supplicant + */ + res = get_msg_arg(dev, 4, &shm, &msg_arg); + if (res) + goto bad; + + fill_i2c_rpc_params(msg_arg, bus_num, chip_addr, op, memref_data); + + /* Make an RPC call to tee supplicant */ + optee_suppl_cmd(dev, shm, 0); + res = msg_arg->ret; + +bad: + tee_shm_free(shm); + + if (res) + return res; + + return TEE_SUCCESS; +} +#endif /* CONFIG_OPTEE_TA_RPC_TEST */
static const struct ta_entry ta_entries[] = { #ifdef CONFIG_OPTEE_TA_AVB @@ -223,6 +352,12 @@ static const struct ta_entry ta_entries[] = { .invoke_func = ta_avb_invoke_func, }, #endif +#ifdef CONFIG_OPTEE_TA_RPC_TEST + { .uuid = TA_RPC_TEST_UUID, + .open_session = ta_rpc_test_open_session, + .invoke_func = ta_rpc_test_invoke_func, + }, +#endif };
static void sandbox_tee_get_version(struct udevice *dev, diff --git a/include/tee/optee_ta_rpc_test.h b/include/tee/optee_ta_rpc_test.h new file mode 100644 index 0000000000..cae2fb04b4 --- /dev/null +++ b/include/tee/optee_ta_rpc_test.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* Copyright (c) 2020 Foundries Ltd */ + +#ifndef __TA_RPC_TEST_H +#define __TA_RPC_TEST_H + +#define TA_RPC_TEST_UUID { 0x48420575, 0x96ca, 0x401a, \ + { 0x89, 0x91, 0x1e, 0xfd, 0xce, 0xbd, 0x7d, 0x04 } } + +/* + * Does a reverse RPC call for I2C read + * + * in params[0].value.a: bus number + * in params[0].value.b: chip address + * inout params[1].u.memref: buffer to read data + */ +#define TA_RPC_TEST_CMD_I2C_READ 0 + +/* + * Does a reverse RPC call for I2C write + * + * in params[0].value.a: bus number + * in params[0].value.b: chip address + * inout params[1].u.memref: buffer with data to write + */ +#define TA_RPC_TEST_CMD_I2C_WRITE 1 + +#endif /* __TA_RPC_TEST_H */

Hi Igor,
On Wed, 20 Jan 2021 at 18:56, Igor Opaniuk igor.opaniuk@gmail.com wrote:
From: Igor Opaniuk igor.opaniuk@foundries.io
This adds support for RPC test trusted application emulation, which permits to test reverse RPC calls to TEE supplicant. Currently it covers requests to the I2C bus from TEE.
Signed-off-by: Igor Opaniuk igor.opaniuk@foundries.io Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
drivers/tee/Makefile | 2 + drivers/tee/optee/Kconfig | 9 ++ drivers/tee/sandbox.c | 143 +++++++++++++++++++++++++++++++- include/tee/optee_ta_rpc_test.h | 28 +++++++ 4 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 include/tee/optee_ta_rpc_test.h
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index 5c8ffdbce8..ff844195ae 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -2,5 +2,7 @@
obj-y += tee-uclass.o obj-$(CONFIG_SANDBOX) += sandbox.o +obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/supplicant.o +obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/i2c.o
I think this line should move to drivers/tee/optee/Makefile for consistency.
obj-$(CONFIG_OPTEE) += optee/ obj-y += broadcom/ diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index d489834df9..65622f30b1 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -22,6 +22,15 @@ config OPTEE_TA_AVB The TA can support the "avb" subcommands "read_rb", "write"rb" and "is_unlocked".
+config OPTEE_TA_RPC_TEST
bool "Support RPC TEST TA"
depends on SANDBOX_TEE
default y
help
Enables support for RPC test trusted application emulation, which
permits to test reverse RPC calls to TEE supplicant. Should
be used only in sandbox env.
endmenu
endif diff --git a/drivers/tee/sandbox.c b/drivers/tee/sandbox.c index e1ba027fd6..d075701b4e 100644 --- a/drivers/tee/sandbox.c +++ b/drivers/tee/sandbox.c @@ -7,11 +7,15 @@ #include <sandboxtee.h> #include <tee.h> #include <tee/optee_ta_avb.h> +#include <tee/optee_ta_rpc_test.h>
+#include "optee/optee_msg.h" +#include "optee/optee_private.h"
/*
- The sandbox tee driver tries to emulate a generic Trusted Exectution
- Environment (TEE) with the Trusted Application (TA) OPTEE_TA_AVB
- available.
- Environment (TEE) with the Trusted Applications (TA) OPTEE_TA_AVB and
*/
- OPTEE_TA_RPC_TEST available.
static const u32 pstorage_max = 16; @@ -32,7 +36,38 @@ struct ta_entry { struct tee_param *params); };
-#ifdef CONFIG_OPTEE_TA_AVB +static int get_msg_arg(struct udevice *dev, uint num_params,
struct tee_shm **shmp, struct optee_msg_arg **msg_arg)
+{
int rc;
struct optee_msg_arg *ma;
rc = __tee_shm_add(dev, OPTEE_MSG_NONCONTIG_PAGE_SIZE, NULL,
OPTEE_MSG_GET_ARG_SIZE(num_params), TEE_SHM_ALLOC,
shmp);
if (rc)
return rc;
ma = (*shmp)->addr;
memset(ma, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
ma->num_params = num_params;
*msg_arg = ma;
return 0;
+}
+void *optee_alloc_and_init_page_list(void *buf, ulong len,
u64 *phys_buf_ptr)
+{
/*
* An empty stub is added just to fix linking issues.
* This function isn't supposed to be called in sandbox
* setup, otherwise replace this with a proper
* implementation from optee/core.c
*/
return NULL;
+}
static u32 get_attr(uint n, uint num_params, struct tee_param *params) { if (n >= num_params) @@ -63,6 +98,7 @@ bad_params: return TEE_ERROR_BAD_PARAMETERS; }
+#ifdef CONFIG_OPTEE_TA_AVB static u32 ta_avb_open_session(struct udevice *dev, uint num_params, struct tee_param *params) { @@ -214,7 +250,100 @@ static u32 ta_avb_invoke_func(struct udevice *dev, u32 func, uint num_params, return TEE_ERROR_NOT_SUPPORTED; } } -#endif /*OPTEE_TA_AVB*/ +#endif /* OPTEE_TA_AVB */
+#ifdef CONFIG_OPTEE_TA_RPC_TEST +static u32 ta_rpc_test_open_session(struct udevice *dev, uint num_params,
struct tee_param *params)
+{
/*
* We don't expect additional parameters when opening a session to
* this TA.
*/
return check_params(TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
num_params, params);
+}
+static void fill_i2c_rpc_params(struct optee_msg_arg *msg_arg, u64 bus_num,
u64 chip_addr, u64 op,
struct tee_param_memref memref)
+{
msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
msg_arg->params[2].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT;
msg_arg->params[3].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT;
/* trigger I2C services of TEE supplicant */
msg_arg->cmd = OPTEE_MSG_RPC_CMD_I2C_TRANSFER;
msg_arg->params[0].u.value.a = op;
msg_arg->params[0].u.value.b = bus_num;
msg_arg->params[0].u.value.c = chip_addr;
/* buffer to read/write data */
msg_arg->params[2].u.rmem.shm_ref = (ulong)memref.shm;
msg_arg->params[2].u.rmem.size = memref.size;
msg_arg->params[2].u.rmem.offs = memref.shm_offs;
msg_arg->num_params = 4;
+}
+static u32 ta_rpc_test_invoke_func(struct udevice *dev, u32 func,
uint num_params,
struct tee_param *params)
+{
struct tee_shm *shm;
struct tee_param_memref memref_data;
struct optee_msg_arg *msg_arg;
int chip_addr, bus_num, op;
int res;
res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
TEE_PARAM_ATTR_TYPE_MEMREF_INOUT,
TEE_PARAM_ATTR_TYPE_NONE,
TEE_PARAM_ATTR_TYPE_NONE,
num_params, params);
if (res)
return TEE_ERROR_BAD_PARAMETERS;
bus_num = params[0].u.value.a;
chip_addr = params[0].u.value.b;
memref_data = params[1].u.memref;
switch (func) {
case TA_RPC_TEST_CMD_I2C_READ:
op = OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD;
break;
case TA_RPC_TEST_CMD_I2C_WRITE:
op = OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR;
break;
default:
return TEE_ERROR_NOT_SUPPORTED;
}
/*
* Fill params for an RPC call to tee supplicant
*/
res = get_msg_arg(dev, 4, &shm, &msg_arg);
if (res)
goto bad;
fill_i2c_rpc_params(msg_arg, bus_num, chip_addr, op, memref_data);
/* Make an RPC call to tee supplicant */
optee_suppl_cmd(dev, shm, 0);
res = msg_arg->ret;
+bad:
maye rename to out since not a error only path.
tee_shm_free(shm);
if (res)
return res;
return TEE_SUCCESS;
'return res;' will do the job.
+} +#endif /* CONFIG_OPTEE_TA_RPC_TEST */
static const struct ta_entry ta_entries[] = { #ifdef CONFIG_OPTEE_TA_AVB @@ -223,6 +352,12 @@ static const struct ta_entry ta_entries[] = { .invoke_func = ta_avb_invoke_func, }, #endif +#ifdef CONFIG_OPTEE_TA_RPC_TEST
{ .uuid = TA_RPC_TEST_UUID,
.open_session = ta_rpc_test_open_session,
.invoke_func = ta_rpc_test_invoke_func,
},
+#endif };
static void sandbox_tee_get_version(struct udevice *dev, diff --git a/include/tee/optee_ta_rpc_test.h b/include/tee/optee_ta_rpc_test.h new file mode 100644 index 0000000000..cae2fb04b4 --- /dev/null +++ b/include/tee/optee_ta_rpc_test.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* Copyright (c) 2020 Foundries Ltd */
+#ifndef __TA_RPC_TEST_H +#define __TA_RPC_TEST_H
+#define TA_RPC_TEST_UUID { 0x48420575, 0x96ca, 0x401a, \
{ 0x89, 0x91, 0x1e, 0xfd, 0xce, 0xbd, 0x7d, 0x04 } }
+/*
- Does a reverse RPC call for I2C read
- in params[0].value.a: bus number
- in params[0].value.b: chip address
Should maybe consider the so-called 'i2c control flags' in the test (i.é. 7 or 10 bit i2c address) since these flags are checked in the RPC implementation.
- inout params[1].u.memref: buffer to read data
- */
+#define TA_RPC_TEST_CMD_I2C_READ 0
+/*
- Does a reverse RPC call for I2C write
- in params[0].value.a: bus number
- in params[0].value.b: chip address
- inout params[1].u.memref: buffer with data to write
- */
+#define TA_RPC_TEST_CMD_I2C_WRITE 1
+#endif /* __TA_RPC_TEST_H */
2.25.1

HI Etienne,
On Thu, Jan 21, 2021 at 9:39 AM Etienne Carriere etienne.carriere@linaro.org wrote:
Hi Igor,
On Wed, 20 Jan 2021 at 18:56, Igor Opaniuk igor.opaniuk@gmail.com wrote:
From: Igor Opaniuk igor.opaniuk@foundries.io
This adds support for RPC test trusted application emulation, which permits to test reverse RPC calls to TEE supplicant. Currently it covers requests to the I2C bus from TEE.
Signed-off-by: Igor Opaniuk igor.opaniuk@foundries.io Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
drivers/tee/Makefile | 2 + drivers/tee/optee/Kconfig | 9 ++ drivers/tee/sandbox.c | 143 +++++++++++++++++++++++++++++++- include/tee/optee_ta_rpc_test.h | 28 +++++++ 4 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 include/tee/optee_ta_rpc_test.h
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index 5c8ffdbce8..ff844195ae 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -2,5 +2,7 @@
obj-y += tee-uclass.o obj-$(CONFIG_SANDBOX) += sandbox.o +obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/supplicant.o +obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/i2c.o
I think this line should move to drivers/tee/optee/Makefile for consistency.
Well, what we do here is testing TEE supplicant from TEE sandbox driver. So this is why I pull that bits and pieces from OP-TEE driver, however OP-TEE driver itself isn't compiled (CONFIG_OPTEE=n when CONFIG_SANDBOX=y). I don't either like this idea, but currently that's the only way to add some RPC test coverage that was requested in v1.
CONFIG_OPTEE_TA_RPC_TEST is currently supposed to be used only in sandbox setups (for testing RPC call paths with DM tests).
obj-$(CONFIG_OPTEE) += optee/ obj-y += broadcom/ diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index d489834df9..65622f30b1 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -22,6 +22,15 @@ config OPTEE_TA_AVB The TA can support the "avb" subcommands "read_rb", "write"rb" and "is_unlocked".
+config OPTEE_TA_RPC_TEST
bool "Support RPC TEST TA"
depends on SANDBOX_TEE
default y
help
Enables support for RPC test trusted application emulation, which
permits to test reverse RPC calls to TEE supplicant. Should
be used only in sandbox env.
endmenu
endif diff --git a/drivers/tee/sandbox.c b/drivers/tee/sandbox.c index e1ba027fd6..d075701b4e 100644 --- a/drivers/tee/sandbox.c +++ b/drivers/tee/sandbox.c @@ -7,11 +7,15 @@ #include <sandboxtee.h> #include <tee.h> #include <tee/optee_ta_avb.h> +#include <tee/optee_ta_rpc_test.h>
+#include "optee/optee_msg.h" +#include "optee/optee_private.h"
/*
- The sandbox tee driver tries to emulate a generic Trusted Exectution
- Environment (TEE) with the Trusted Application (TA) OPTEE_TA_AVB
- available.
- Environment (TEE) with the Trusted Applications (TA) OPTEE_TA_AVB and
*/
- OPTEE_TA_RPC_TEST available.
static const u32 pstorage_max = 16; @@ -32,7 +36,38 @@ struct ta_entry { struct tee_param *params); };
-#ifdef CONFIG_OPTEE_TA_AVB +static int get_msg_arg(struct udevice *dev, uint num_params,
struct tee_shm **shmp, struct optee_msg_arg **msg_arg)
+{
int rc;
struct optee_msg_arg *ma;
rc = __tee_shm_add(dev, OPTEE_MSG_NONCONTIG_PAGE_SIZE, NULL,
OPTEE_MSG_GET_ARG_SIZE(num_params), TEE_SHM_ALLOC,
shmp);
if (rc)
return rc;
ma = (*shmp)->addr;
memset(ma, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
ma->num_params = num_params;
*msg_arg = ma;
return 0;
+}
+void *optee_alloc_and_init_page_list(void *buf, ulong len,
u64 *phys_buf_ptr)
+{
/*
* An empty stub is added just to fix linking issues.
* This function isn't supposed to be called in sandbox
* setup, otherwise replace this with a proper
* implementation from optee/core.c
*/
return NULL;
+}
static u32 get_attr(uint n, uint num_params, struct tee_param *params) { if (n >= num_params) @@ -63,6 +98,7 @@ bad_params: return TEE_ERROR_BAD_PARAMETERS; }
+#ifdef CONFIG_OPTEE_TA_AVB static u32 ta_avb_open_session(struct udevice *dev, uint num_params, struct tee_param *params) { @@ -214,7 +250,100 @@ static u32 ta_avb_invoke_func(struct udevice *dev, u32 func, uint num_params, return TEE_ERROR_NOT_SUPPORTED; } } -#endif /*OPTEE_TA_AVB*/ +#endif /* OPTEE_TA_AVB */
+#ifdef CONFIG_OPTEE_TA_RPC_TEST +static u32 ta_rpc_test_open_session(struct udevice *dev, uint num_params,
struct tee_param *params)
+{
/*
* We don't expect additional parameters when opening a session to
* this TA.
*/
return check_params(TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
num_params, params);
+}
+static void fill_i2c_rpc_params(struct optee_msg_arg *msg_arg, u64 bus_num,
u64 chip_addr, u64 op,
struct tee_param_memref memref)
+{
msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
msg_arg->params[2].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT;
msg_arg->params[3].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT;
/* trigger I2C services of TEE supplicant */
msg_arg->cmd = OPTEE_MSG_RPC_CMD_I2C_TRANSFER;
msg_arg->params[0].u.value.a = op;
msg_arg->params[0].u.value.b = bus_num;
msg_arg->params[0].u.value.c = chip_addr;
/* buffer to read/write data */
msg_arg->params[2].u.rmem.shm_ref = (ulong)memref.shm;
msg_arg->params[2].u.rmem.size = memref.size;
msg_arg->params[2].u.rmem.offs = memref.shm_offs;
msg_arg->num_params = 4;
+}
+static u32 ta_rpc_test_invoke_func(struct udevice *dev, u32 func,
uint num_params,
struct tee_param *params)
+{
struct tee_shm *shm;
struct tee_param_memref memref_data;
struct optee_msg_arg *msg_arg;
int chip_addr, bus_num, op;
int res;
res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
TEE_PARAM_ATTR_TYPE_MEMREF_INOUT,
TEE_PARAM_ATTR_TYPE_NONE,
TEE_PARAM_ATTR_TYPE_NONE,
num_params, params);
if (res)
return TEE_ERROR_BAD_PARAMETERS;
bus_num = params[0].u.value.a;
chip_addr = params[0].u.value.b;
memref_data = params[1].u.memref;
switch (func) {
case TA_RPC_TEST_CMD_I2C_READ:
op = OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD;
break;
case TA_RPC_TEST_CMD_I2C_WRITE:
op = OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR;
break;
default:
return TEE_ERROR_NOT_SUPPORTED;
}
/*
* Fill params for an RPC call to tee supplicant
*/
res = get_msg_arg(dev, 4, &shm, &msg_arg);
if (res)
goto bad;
fill_i2c_rpc_params(msg_arg, bus_num, chip_addr, op, memref_data);
/* Make an RPC call to tee supplicant */
optee_suppl_cmd(dev, shm, 0);
res = msg_arg->ret;
+bad:
maye rename to out since not a error only path.
ok, will do
tee_shm_free(shm);
if (res)
return res;
return TEE_SUCCESS;
'return res;' will do the job.
sure, will fix
+} +#endif /* CONFIG_OPTEE_TA_RPC_TEST */
static const struct ta_entry ta_entries[] = { #ifdef CONFIG_OPTEE_TA_AVB @@ -223,6 +352,12 @@ static const struct ta_entry ta_entries[] = { .invoke_func = ta_avb_invoke_func, }, #endif +#ifdef CONFIG_OPTEE_TA_RPC_TEST
{ .uuid = TA_RPC_TEST_UUID,
.open_session = ta_rpc_test_open_session,
.invoke_func = ta_rpc_test_invoke_func,
},
+#endif };
static void sandbox_tee_get_version(struct udevice *dev, diff --git a/include/tee/optee_ta_rpc_test.h b/include/tee/optee_ta_rpc_test.h new file mode 100644 index 0000000000..cae2fb04b4 --- /dev/null +++ b/include/tee/optee_ta_rpc_test.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* Copyright (c) 2020 Foundries Ltd */
+#ifndef __TA_RPC_TEST_H +#define __TA_RPC_TEST_H
+#define TA_RPC_TEST_UUID { 0x48420575, 0x96ca, 0x401a, \
{ 0x89, 0x91, 0x1e, 0xfd, 0xce, 0xbd, 0x7d, 0x04 } }
+/*
- Does a reverse RPC call for I2C read
- in params[0].value.a: bus number
- in params[0].value.b: chip address
Should maybe consider the so-called 'i2c control flags' in the test (i.é. 7 or 10 bit i2c address) since these flags are checked in the RPC implementation.
Yes, makes sense.
- inout params[1].u.memref: buffer to read data
- */
+#define TA_RPC_TEST_CMD_I2C_READ 0
+/*
- Does a reverse RPC call for I2C write
- in params[0].value.a: bus number
- in params[0].value.b: chip address
- inout params[1].u.memref: buffer with data to write
- */
+#define TA_RPC_TEST_CMD_I2C_WRITE 1
+#endif /* __TA_RPC_TEST_H */
2.25.1

Hi Igor
HI Etienne,
On Thu, Jan 21, 2021 at 9:39 AM Etienne Carriere etienne.carriere@linaro.org wrote:
Hi Igor,
On Wed, 20 Jan 2021 at 18:56, Igor Opaniuk igor.opaniuk@gmail.com wrote:
From: Igor Opaniuk igor.opaniuk@foundries.io
This adds support for RPC test trusted application emulation, which permits to test reverse RPC calls to TEE supplicant. Currently it covers requests to the I2C bus from TEE.
Signed-off-by: Igor Opaniuk igor.opaniuk@foundries.io Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
drivers/tee/Makefile | 2 + drivers/tee/optee/Kconfig | 9 ++ drivers/tee/sandbox.c | 143 +++++++++++++++++++++++++++++++- include/tee/optee_ta_rpc_test.h | 28 +++++++ 4 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 include/tee/optee_ta_rpc_test.h
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index 5c8ffdbce8..ff844195ae 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -2,5 +2,7 @@
obj-y += tee-uclass.o obj-$(CONFIG_SANDBOX) += sandbox.o +obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/supplicant.o +obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/i2c.o
I think this line should move to drivers/tee/optee/Makefile for consistency.
Well, what we do here is testing TEE supplicant from TEE sandbox driver. So this is why I pull that bits and pieces from OP-TEE driver, however OP-TEE driver itself isn't compiled (CONFIG_OPTEE=n when CONFIG_SANDBOX=y). I don't either like this idea, but currently that's the only way to add some RPC test coverage that was requested in v1.
CONFIG_OPTEE_TA_RPC_TEST is currently supposed to be used only in sandbox setups (for testing RPC call paths with DM tests).
Ok, i catch it. These paths make sense.
br, etienne
obj-$(CONFIG_OPTEE) += optee/ obj-y += broadcom/ diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index d489834df9..65622f30b1 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -22,6 +22,15 @@ config OPTEE_TA_AVB The TA can support the "avb" subcommands "read_rb", "write"rb" and "is_unlocked".
+config OPTEE_TA_RPC_TEST
bool "Support RPC TEST TA"
depends on SANDBOX_TEE
default y
help
Enables support for RPC test trusted application emulation, which
permits to test reverse RPC calls to TEE supplicant. Should
be used only in sandbox env.
endmenu
endif (snip)

From: Igor Opaniuk igor.opaniuk@foundries.io
Extend existing DM tee tests adding test coverage for reverse RPC calls. Currently this commit only adds tests for I2C requests from TEE driver to TEE supplicant, for instance reading/writing data to emulated i2c eeprom defines in standard sandbox test device tree (arch/sandbox/dts/test.dtb):
=> i2c bus Bus 0: i2c@0 (active 0) 2c: eeprom@2c, offset len 1, flags 0 ...
Running TEE tests: => ut dm tee Test: dm_test_tee: tee.c Test: dm_test_tee: tee.c (flat tree) Failures: 0
Signed-off-by: Igor Opaniuk igor.opaniuk@foundries.io Reviewed-by: Simon Glass sjg@chromium.org
---
(no changes since v1)
test/dm/tee.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 5 deletions(-)
diff --git a/test/dm/tee.c b/test/dm/tee.c index ddbdcfb0cf..51ffb4e4a9 100644 --- a/test/dm/tee.c +++ b/test/dm/tee.c @@ -13,11 +13,12 @@ #include <test/test.h> #include <test/ut.h> #include <tee/optee_ta_avb.h> +#include <tee/optee_ta_rpc_test.h>
-static int open_session(struct udevice *dev, u32 *session) +static int open_session(struct udevice *dev, u32 *session, + struct tee_optee_ta_uuid uuid) { struct tee_open_session_arg arg; - const struct tee_optee_ta_uuid uuid = TA_AVB_UUID; int rc;
memset(&arg, 0, sizeof(arg)); @@ -32,7 +33,7 @@ static int open_session(struct udevice *dev, u32 *session) return 0; }
-static int invoke_func(struct udevice *dev, u32 session) +static int invoke_func_avb(struct udevice *dev, u32 session) { struct tee_param param = { .attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT }; struct tee_invoke_arg arg; @@ -47,6 +48,47 @@ static int invoke_func(struct udevice *dev, u32 session) return 0; }
+static int invoke_func_rpc_test(struct udevice *dev, u32 session, + u64 op, u64 busnum, u64 chip_addr, + u8 *buf, size_t buf_size) +{ + struct tee_param param[2]; + struct tee_invoke_arg arg; + struct tee_shm *shm_buf; + int rc; + + memset(&arg, 0, sizeof(arg)); + arg.session = session; + arg.func = op; + + rc = tee_shm_alloc(dev, buf_size, + TEE_SHM_ALLOC, &shm_buf); + if (rc) + return rc; + + if (op == TA_RPC_TEST_CMD_I2C_WRITE) + memcpy(shm_buf->addr, buf, buf_size); + + memset(param, 0, sizeof(param)); + param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT; + param[0].u.value.a = busnum; + param[0].u.value.b = chip_addr; + param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT; + param[1].u.memref.shm = shm_buf; + param[1].u.memref.size = buf_size; + + if (tee_invoke_func(dev, &arg, 2, param) || arg.ret) { + goto out; + rc = -1; + } + + if (op == TA_RPC_TEST_CMD_I2C_READ) + memcpy(buf, shm_buf->addr, buf_size); +out: + tee_shm_free(shm_buf); + return rc; +} + static int match(struct tee_version_data *vers, const void *data) { return vers->gen_caps & TEE_GEN_CAP_GP; @@ -62,6 +104,7 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) struct tee_version_data vers; struct udevice *dev; struct sandbox_tee_state *state; + struct tee_optee_ta_uuid avb_uuid = TA_AVB_UUID; u32 session = 0; int rc; u8 data[128]; @@ -71,11 +114,11 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) state = dev_get_priv(dev); ut_assert(!state->session);
- rc = open_session(dev, &session); + rc = open_session(dev, &session, avb_uuid); ut_assert(!rc); ut_assert(session == state->session);
- rc = invoke_func(dev, session); + rc = invoke_func_avb(dev, session); ut_assert(!rc);
rc = tee_close_session(dev, session); @@ -103,11 +146,65 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) return 0; }
+#define I2C_BUF_SIZE 64 + +static int test_tee_rpc(struct unit_test_state *uts) +{ + struct tee_version_data vers; + struct udevice *dev; + struct sandbox_tee_state *state; + struct tee_optee_ta_uuid rpc_test_uuid = TA_RPC_TEST_UUID; + u32 session = 0; + int rc; + + char *test_str = "Test string"; + u8 data[I2C_BUF_SIZE] = {0}; + u8 data_from_eeprom[I2C_BUF_SIZE] = {0}; + + /* Use sandbox I2C EEPROM emulation; bus: 0, chip: 0x2c */ + u64 bus = 0; + u64 chip = 0x2c; + + dev = tee_find_device(NULL, match, NULL, &vers); + ut_assert(dev); + state = dev_get_priv(dev); + ut_assert(!state->session); + + /* Test RPC call asking for I2C sevice */ + rc = open_session(dev, &session, rpc_test_uuid); + ut_assert(!rc); + ut_assert(session == state->session); + + /* Write buffer */ + strncpy((char *)data, test_str, strlen(test_str)); + rc = invoke_func_rpc_test(dev, session, TA_RPC_TEST_CMD_I2C_WRITE, + bus, chip, data, sizeof(data)); + ut_assert(!rc); + + /* Read buffer */ + rc = invoke_func_rpc_test(dev, session, TA_RPC_TEST_CMD_I2C_READ, + bus, chip, data_from_eeprom, + sizeof(data_from_eeprom)); + ut_assert(!rc); + + /* Compare */ + ut_assert(!memcmp(data, data_from_eeprom, sizeof(data))); + + rc = tee_close_session(dev, session); + ut_assert(!rc); + ut_assert(!state->session); + + return 0; +} + static int dm_test_tee(struct unit_test_state *uts) { struct test_tee_vars vars = { NULL, NULL }; int rc = test_tee(uts, &vars);
+ if (IS_ENABLED(CONFIG_OPTEE_TA_RPC_TEST)) + rc = test_tee_rpc(uts); + /* In case test_tee() asserts these may still remain allocated */ tee_shm_free(vars.reg_shm); tee_shm_free(vars.alloc_shm);

Hello Igor,
On Wed, 20 Jan 2021 at 18:56, Igor Opaniuk igor.opaniuk@gmail.com wrote:
From: Igor Opaniuk igor.opaniuk@foundries.io
Extend existing DM tee tests adding test coverage for reverse RPC calls. Currently this commit only adds tests for I2C requests from TEE driver to TEE supplicant, for instance reading/writing data to emulated i2c eeprom defines in standard sandbox test device tree (arch/sandbox/dts/test.dtb):
=> i2c bus Bus 0: i2c@0 (active 0) 2c: eeprom@2c, offset len 1, flags 0 ...
Running TEE tests: => ut dm tee Test: dm_test_tee: tee.c Test: dm_test_tee: tee.c (flat tree) Failures: 0
Signed-off-by: Igor Opaniuk igor.opaniuk@foundries.io Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
test/dm/tee.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 5 deletions(-)
diff --git a/test/dm/tee.c b/test/dm/tee.c index ddbdcfb0cf..51ffb4e4a9 100644 --- a/test/dm/tee.c +++ b/test/dm/tee.c @@ -13,11 +13,12 @@ #include <test/test.h> #include <test/ut.h> #include <tee/optee_ta_avb.h> +#include <tee/optee_ta_rpc_test.h>
-static int open_session(struct udevice *dev, u32 *session) +static int open_session(struct udevice *dev, u32 *session,
struct tee_optee_ta_uuid uuid)
maybe pass a pointer to the uuid. or maybe not, uuid is only 16 bytes....
{ struct tee_open_session_arg arg;
const struct tee_optee_ta_uuid uuid = TA_AVB_UUID; int rc; memset(&arg, 0, sizeof(arg));
@@ -32,7 +33,7 @@ static int open_session(struct udevice *dev, u32 *session) return 0; }
-static int invoke_func(struct udevice *dev, u32 session) +static int invoke_func_avb(struct udevice *dev, u32 session) { struct tee_param param = { .attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT }; struct tee_invoke_arg arg; @@ -47,6 +48,47 @@ static int invoke_func(struct udevice *dev, u32 session) return 0; }
+static int invoke_func_rpc_test(struct udevice *dev, u32 session,
u64 op, u64 busnum, u64 chip_addr,
u8 *buf, size_t buf_size)
+{
struct tee_param param[2];
struct tee_invoke_arg arg;
struct tee_shm *shm_buf;
int rc;
memset(&arg, 0, sizeof(arg));
arg.session = session;
arg.func = op;
rc = tee_shm_alloc(dev, buf_size,
TEE_SHM_ALLOC, &shm_buf);
if (rc)
return rc;
if (op == TA_RPC_TEST_CMD_I2C_WRITE)
memcpy(shm_buf->addr, buf, buf_size);
memset(param, 0, sizeof(param));
param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
param[0].u.value.a = busnum;
param[0].u.value.b = chip_addr;
param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
param[1].u.memref.shm = shm_buf;
param[1].u.memref.size = buf_size;
if (tee_invoke_func(dev, &arg, 2, param) || arg.ret) {
goto out;
rc = -1;
Looks like those lines shall be swapped!
}
if (op == TA_RPC_TEST_CMD_I2C_READ)
memcpy(buf, shm_buf->addr, buf_size);
+out:
tee_shm_free(shm_buf);
return rc;
+}
static int match(struct tee_version_data *vers, const void *data) { return vers->gen_caps & TEE_GEN_CAP_GP; @@ -62,6 +104,7 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) struct tee_version_data vers; struct udevice *dev; struct sandbox_tee_state *state;
struct tee_optee_ta_uuid avb_uuid = TA_AVB_UUID; u32 session = 0; int rc; u8 data[128];
@@ -71,11 +114,11 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) state = dev_get_priv(dev); ut_assert(!state->session);
rc = open_session(dev, &session);
rc = open_session(dev, &session, avb_uuid); ut_assert(!rc); ut_assert(session == state->session);
rc = invoke_func(dev, session);
rc = invoke_func_avb(dev, session); ut_assert(!rc); rc = tee_close_session(dev, session);
@@ -103,11 +146,65 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) return 0; }
+#define I2C_BUF_SIZE 64
+static int test_tee_rpc(struct unit_test_state *uts) +{
struct tee_version_data vers;
struct udevice *dev;
struct sandbox_tee_state *state;
struct tee_optee_ta_uuid rpc_test_uuid = TA_RPC_TEST_UUID;
u32 session = 0;
int rc;
char *test_str = "Test string";
u8 data[I2C_BUF_SIZE] = {0};
u8 data_from_eeprom[I2C_BUF_SIZE] = {0};
/* Use sandbox I2C EEPROM emulation; bus: 0, chip: 0x2c */
u64 bus = 0;
u64 chip = 0x2c;
dev = tee_find_device(NULL, match, NULL, &vers);
ut_assert(dev);
state = dev_get_priv(dev);
ut_assert(!state->session);
/* Test RPC call asking for I2C sevice */
rc = open_session(dev, &session, rpc_test_uuid);
ut_assert(!rc);
ut_assert(session == state->session);
/* Write buffer */
strncpy((char *)data, test_str, strlen(test_str));
rc = invoke_func_rpc_test(dev, session, TA_RPC_TEST_CMD_I2C_WRITE,
bus, chip, data, sizeof(data));
ut_assert(!rc);
/* Read buffer */
rc = invoke_func_rpc_test(dev, session, TA_RPC_TEST_CMD_I2C_READ,
bus, chip, data_from_eeprom,
sizeof(data_from_eeprom));
ut_assert(!rc);
/* Compare */
ut_assert(!memcmp(data, data_from_eeprom, sizeof(data)));
rc = tee_close_session(dev, session);
ut_assert(!rc);
ut_assert(!state->session);
return 0;
+}
static int dm_test_tee(struct unit_test_state *uts) { struct test_tee_vars vars = { NULL, NULL }; int rc = test_tee(uts, &vars);
if (IS_ENABLED(CONFIG_OPTEE_TA_RPC_TEST))
rc = test_tee_rpc(uts);
This scratches return code from test_tee().
Best regards, Etienne
/* In case test_tee() asserts these may still remain allocated */ tee_shm_free(vars.reg_shm); tee_shm_free(vars.alloc_shm);
-- 2.25.1

Hi Etienne,
On Thu, Jan 21, 2021 at 10:00 AM Etienne Carriere etienne.carriere@linaro.org wrote:
Hello Igor,
On Wed, 20 Jan 2021 at 18:56, Igor Opaniuk igor.opaniuk@gmail.com wrote:
From: Igor Opaniuk igor.opaniuk@foundries.io
Extend existing DM tee tests adding test coverage for reverse RPC calls. Currently this commit only adds tests for I2C requests from TEE driver to TEE supplicant, for instance reading/writing data to emulated i2c eeprom defines in standard sandbox test device tree (arch/sandbox/dts/test.dtb):
=> i2c bus Bus 0: i2c@0 (active 0) 2c: eeprom@2c, offset len 1, flags 0 ...
Running TEE tests: => ut dm tee Test: dm_test_tee: tee.c Test: dm_test_tee: tee.c (flat tree) Failures: 0
Signed-off-by: Igor Opaniuk igor.opaniuk@foundries.io Reviewed-by: Simon Glass sjg@chromium.org
(no changes since v1)
test/dm/tee.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 5 deletions(-)
diff --git a/test/dm/tee.c b/test/dm/tee.c index ddbdcfb0cf..51ffb4e4a9 100644 --- a/test/dm/tee.c +++ b/test/dm/tee.c @@ -13,11 +13,12 @@ #include <test/test.h> #include <test/ut.h> #include <tee/optee_ta_avb.h> +#include <tee/optee_ta_rpc_test.h>
-static int open_session(struct udevice *dev, u32 *session) +static int open_session(struct udevice *dev, u32 *session,
struct tee_optee_ta_uuid uuid)
maybe pass a pointer to the uuid. or maybe not, uuid is only 16 bytes....
{ struct tee_open_session_arg arg;
const struct tee_optee_ta_uuid uuid = TA_AVB_UUID; int rc; memset(&arg, 0, sizeof(arg));
@@ -32,7 +33,7 @@ static int open_session(struct udevice *dev, u32 *session) return 0; }
-static int invoke_func(struct udevice *dev, u32 session) +static int invoke_func_avb(struct udevice *dev, u32 session) { struct tee_param param = { .attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT }; struct tee_invoke_arg arg; @@ -47,6 +48,47 @@ static int invoke_func(struct udevice *dev, u32 session) return 0; }
+static int invoke_func_rpc_test(struct udevice *dev, u32 session,
u64 op, u64 busnum, u64 chip_addr,
u8 *buf, size_t buf_size)
+{
struct tee_param param[2];
struct tee_invoke_arg arg;
struct tee_shm *shm_buf;
int rc;
memset(&arg, 0, sizeof(arg));
arg.session = session;
arg.func = op;
rc = tee_shm_alloc(dev, buf_size,
TEE_SHM_ALLOC, &shm_buf);
if (rc)
return rc;
if (op == TA_RPC_TEST_CMD_I2C_WRITE)
memcpy(shm_buf->addr, buf, buf_size);
memset(param, 0, sizeof(param));
param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
param[0].u.value.a = busnum;
param[0].u.value.b = chip_addr;
param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
param[1].u.memref.shm = shm_buf;
param[1].u.memref.size = buf_size;
if (tee_invoke_func(dev, &arg, 2, param) || arg.ret) {
goto out;
rc = -1;
Looks like those lines shall be swapped!
yep, nice catch, thanks!
}
if (op == TA_RPC_TEST_CMD_I2C_READ)
memcpy(buf, shm_buf->addr, buf_size);
+out:
tee_shm_free(shm_buf);
return rc;
+}
static int match(struct tee_version_data *vers, const void *data) { return vers->gen_caps & TEE_GEN_CAP_GP; @@ -62,6 +104,7 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) struct tee_version_data vers; struct udevice *dev; struct sandbox_tee_state *state;
struct tee_optee_ta_uuid avb_uuid = TA_AVB_UUID; u32 session = 0; int rc; u8 data[128];
@@ -71,11 +114,11 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) state = dev_get_priv(dev); ut_assert(!state->session);
rc = open_session(dev, &session);
rc = open_session(dev, &session, avb_uuid); ut_assert(!rc); ut_assert(session == state->session);
rc = invoke_func(dev, session);
rc = invoke_func_avb(dev, session); ut_assert(!rc); rc = tee_close_session(dev, session);
@@ -103,11 +146,65 @@ static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars) return 0; }
+#define I2C_BUF_SIZE 64
+static int test_tee_rpc(struct unit_test_state *uts) +{
struct tee_version_data vers;
struct udevice *dev;
struct sandbox_tee_state *state;
struct tee_optee_ta_uuid rpc_test_uuid = TA_RPC_TEST_UUID;
u32 session = 0;
int rc;
char *test_str = "Test string";
u8 data[I2C_BUF_SIZE] = {0};
u8 data_from_eeprom[I2C_BUF_SIZE] = {0};
/* Use sandbox I2C EEPROM emulation; bus: 0, chip: 0x2c */
u64 bus = 0;
u64 chip = 0x2c;
dev = tee_find_device(NULL, match, NULL, &vers);
ut_assert(dev);
state = dev_get_priv(dev);
ut_assert(!state->session);
/* Test RPC call asking for I2C sevice */
rc = open_session(dev, &session, rpc_test_uuid);
ut_assert(!rc);
ut_assert(session == state->session);
/* Write buffer */
strncpy((char *)data, test_str, strlen(test_str));
rc = invoke_func_rpc_test(dev, session, TA_RPC_TEST_CMD_I2C_WRITE,
bus, chip, data, sizeof(data));
ut_assert(!rc);
/* Read buffer */
rc = invoke_func_rpc_test(dev, session, TA_RPC_TEST_CMD_I2C_READ,
bus, chip, data_from_eeprom,
sizeof(data_from_eeprom));
ut_assert(!rc);
/* Compare */
ut_assert(!memcmp(data, data_from_eeprom, sizeof(data)));
rc = tee_close_session(dev, session);
ut_assert(!rc);
ut_assert(!state->session);
return 0;
+}
static int dm_test_tee(struct unit_test_state *uts) { struct test_tee_vars vars = { NULL, NULL }; int rc = test_tee(uts, &vars);
if (IS_ENABLED(CONFIG_OPTEE_TA_RPC_TEST))
rc = test_tee_rpc(uts);
This scratches return code from test_tee().
Will fix that, thanks!
Best regards, Etienne
/* In case test_tee() asserts these may still remain allocated */ tee_shm_free(vars.reg_shm); tee_shm_free(vars.alloc_shm);
-- 2.25.1
participants (3)
-
Etienne Carriere
-
Igor Opaniuk
-
Igor Opaniuk