This series introduces a generic TEE bus driver concept for TEE based
kernel drivers which would like to communicate with TEE based devices/
services.
Patch #1 adds TEE bus concept where devices/services are identified via
Universally Unique Identifier (UUID) and drivers register a table of
device UUIDs which they can support. This concept also allows for device
enumeration to be specific to corresponding TEE implementation like
OP-TEE etc.
Patch #2 adds TEE bus device enumeration support for OP-TEE. OP-TEE
provides a pseudo TA to enumerate TAs which can act as devices/services
for TEE bus.
Patch #3 adds supp_nowait flag for non-blocking requests arising via
TEE internal client interface.
Patch #4 adds OP-TEE based hwrng driver which act as TEE bus driver.
On ARM SoC's with TrustZone enabled, peripherals like entropy sources
might not be accessible to normal world (linux in this case) and rather
accessible to secure world (OP-TEE in this case) only. So this driver
aims to provides a generic interface to OP-TEE based random number
generator service.
Example case is Developerbox based on Socionext's Synquacer SoC [1]
which provides 7 thermal sensors accessible from secure world only which
could be used as entropy sources (thermal/measurement noise).
[1] https://www.96boards.org/product/developerbox/
Changes in v2:
Based on review comments, the scope of this series has increased as
follows:
1. Added TEE bus driver framework.
2. Added OP-TEE based device enumeration.
3. Register optee-rng driver as TEE bus driver.
4. Removed DT dependency for optee-rng device UUID.
5. Added supp_nowait flag.
Sumit Garg (4):
tee: add bus driver framework for TEE based devices
tee: optee: add TEE bus device enumeration support
tee: add supp_nowait flag in tee_context struct
hwrng: add OP-TEE based rng driver
MAINTAINERS | 5 +
drivers/char/hw_random/Kconfig | 15 ++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/optee-rng.c | 272 +++++++++++++++++++++++++++++++++++++
drivers/tee/optee/Makefile | 1 +
drivers/tee/optee/core.c | 4 +
drivers/tee/optee/device.c | 150 ++++++++++++++++++++
drivers/tee/optee/optee_private.h | 3 +
drivers/tee/optee/supp.c | 10 +-
drivers/tee/tee_core.c | 43 +++++-
include/linux/tee_drv.h | 42 ++++++
11 files changed, 542 insertions(+), 4 deletions(-)
create mode 100644 drivers/char/hw_random/optee-rng.c
create mode 100644 drivers/tee/optee/device.c
--
2.7.4
On Thu, Jan 10, 2019 at 05:54:55PM +0530, Sumit Garg wrote:
> OP-TEE provides a pseudo TA to enumerate TAs which can act as devices/
> services for TEE bus. So implement device enumeration using invoke
> function: PTA_CMD_GET_DEVICES provided by pseudo TA to fetch array of
> device UUIDs. Also register these enumerated devices with TEE bus as
> "optee-clntX" device.
>
> Signed-off-by: Sumit Garg <[email protected]>
> ---
> drivers/tee/optee/Makefile | 1 +
> drivers/tee/optee/core.c | 4 +
> drivers/tee/optee/device.c | 150 ++++++++++++++++++++++++++++++++++++++
> drivers/tee/optee/optee_private.h | 3 +
> 4 files changed, 158 insertions(+)
> create mode 100644 drivers/tee/optee/device.c
>
> diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
> index 48d262a..56263ae 100644
> --- a/drivers/tee/optee/Makefile
> +++ b/drivers/tee/optee/Makefile
> @@ -5,3 +5,4 @@ optee-objs += call.o
> optee-objs += rpc.o
> optee-objs += supp.o
> optee-objs += shm_pool.o
> +optee-objs += device.o
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index e5efce3..ac59c77 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -634,6 +634,10 @@ static struct optee *optee_probe(struct device_node *np)
> if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
> pr_info("dynamic shared memory is enabled\n");
>
> + rc = optee_enumerate_devices();
> + if (rc)
> + goto err;
> +
> pr_info("initialized driver\n");
> return optee;
> err:
> diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c
> new file mode 100644
> index 0000000..b38d24b
> --- /dev/null
> +++ b/drivers/tee/optee/device.c
> @@ -0,0 +1,150 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 Linaro Ltd.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.h>
> +#include <linux/uuid.h>
> +#include "optee_private.h"
> +
> +/*
> + * Get device UUIDs
> + *
> + * [out] memref[0] Array of device UUIDs
> + *
> + * Return codes:
> + * TEE_SUCCESS - Invoke command success
> + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> + * TEE_ERROR_SHORT_BUFFER - Output buffer size less than required
> + */
> +#define PTA_CMD_GET_DEVICES 0x0
> +
> +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> +{
> + if (ver->impl_id == TEE_IMPL_ID_OPTEE)
> + return 1;
> + else
> + return 0;
> +}
> +
> +static int get_devices(struct tee_context *ctx, u32 session,
> + struct tee_shm *device_uuid, u32 *shm_size)
Missing const on device_uuid?
> +{
> + u32 ret = 0;
> + struct tee_ioctl_invoke_arg inv_arg = {0};
> + struct tee_param param[4] = {0};
> +
> + /* Invoke PTA_CMD_GET_DEVICES function */
> + inv_arg.func = PTA_CMD_GET_DEVICES;
> + inv_arg.session = session;
> + inv_arg.num_params = 4;
> +
> + /* Fill invoke cmd params */
> + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
> + param[0].u.memref.shm = device_uuid;
> + param[0].u.memref.size = *shm_size;
> + param[0].u.memref.shm_offs = 0;
> +
> + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> + if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) &&
> + (inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) {
> + pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n",
> + inv_arg.ret);
> + return -EINVAL;
> + }
> +
> + *shm_size = param[0].u.memref.size;
> +
> + return 0;
> +}
> +
> +static int optee_register_device(uuid_t *device_uuid, u32 device_id)
const?
> +{
> + struct tee_client_device *optee_device = NULL;
> + int rc;
> +
> + optee_device = kzalloc(sizeof(*optee_device), GFP_KERNEL);
> + if (!optee_device)
> + return -ENOMEM;
> +
> + optee_device->dev.bus = &tee_bus_type;
> + dev_set_name(&optee_device->dev, "optee-clnt%u", device_id);
> + uuid_copy(&optee_device->id.uuid, device_uuid);
> +
> + rc = device_register(&optee_device->dev);
> + if (rc)
> + pr_err("device registration failed, err: %d\n", rc);
Leak optee_device?
> +
> + return rc;
> +}
> +
> +int optee_enumerate_devices(void)
> +{
> + uuid_t pta_uuid =
> + UUID_INIT(0x7011a688, 0xddde, 0x4053,
> + 0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8);
I think this could/should be const too.
> + struct tee_ioctl_open_session_arg sess_arg = {0};
> + struct tee_shm *device_shm = NULL;
> + uuid_t *device_uuid = NULL;
> + struct tee_context *ctx = NULL;
> + u32 shm_size = 0, idx = 0;
> + int rc;
> +
> + /* Open context with OP-TEE driver */
> + ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
> + if (IS_ERR(ctx))
> + return -ENODEV;
> +
> + /* Open session with device enumeration pseudo TA */
> + memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN);
> + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
> + sess_arg.num_params = 0;
> +
> + rc = tee_client_open_session(ctx, &sess_arg, NULL);
> + if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) {
> + /* Device enumeration pseudo TA not found */
> + rc = 0;
> + goto out_ctx;
> + }
> +
> + rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
Use NULL and 0 directly here instead of relying on initialized values.
This makes it clear we are fetching the size of a buffer and are doing
something different to the next call to get_devices().
> + if (rc < 0)
> + goto out_sess;
> +
> + device_shm = tee_shm_alloc(ctx, shm_size,
> + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
> + if (IS_ERR(device_shm)) {
> + pr_err("tee_shm_alloc failed\n");
> + rc = PTR_ERR(device_shm);
> + goto out_sess;
> + }
> +
> + rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
> + if (rc < 0)
> + goto out_shm;
> +
> + device_uuid = tee_shm_get_va(device_shm, 0);
> + if (IS_ERR(device_uuid)) {
> + pr_err("tee_shm_get_va failed\n");
> + rc = PTR_ERR(device_uuid);
> + goto out_shm;
> + }
> +
> + while (idx < shm_size / sizeof(uuid_t)) {
This is a very uncommon way to write a for loop ;-).
> + rc = optee_register_device(&device_uuid[idx], idx);
> + if (rc)
> + goto out_shm;
> + idx++;
> + }
> +
> +out_shm:
> + tee_shm_free(device_shm);
> +out_sess:
> + tee_client_close_session(ctx, sess_arg.session);
> +out_ctx:
> + tee_client_close_context(ctx);
> +
> + return rc;
> +}
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index 35e7938..a5e84af 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -28,6 +28,7 @@
> #define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
> #define TEEC_ERROR_COMMUNICATION 0xFFFF000E
> #define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
> +#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
>
> #define TEEC_ORIGIN_COMMS 0x00000002
>
> @@ -181,6 +182,8 @@ void optee_free_pages_list(void *array, size_t num_entries);
> void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
> size_t page_offset);
>
> +int optee_enumerate_devices(void);
> +
> /*
> * Small helpers
> */
> --
> 2.7.4
>
On Thu, 10 Jan 2019 at 19:36, Daniel Thompson
<[email protected]> wrote:
>
> On Thu, Jan 10, 2019 at 05:54:54PM +0530, Sumit Garg wrote:
> > Introduce a generic TEE bus driver concept for TEE based kernel drivers
> > which would like to communicate with TEE based devices/services.
> >
> > In this TEE bus concept, devices/services are identified via Universally
> > Unique Identifier (UUID) and drivers register a table of device UUIDs
> > which they can support.
> >
> > So this TEE bus framework registers a match() callback function which
> > iterates over the driver UUID table to find a corresponding match for
> > device UUID. If a match is found, then this particular device is probed
> > via corresponding probe api registered by the driver. This process
> > happens whenever a device or a driver is registered with TEE bus.
> >
> > Also this framework allows for device enumeration to be specific to
> > corresponding TEE implementation like OP-TEE etc.
> >
> > Signed-off-by: Sumit Garg <[email protected]>
> > ---
> > drivers/tee/tee_core.c | 41 ++++++++++++++++++++++++++++++++++++++---
> > include/linux/tee_drv.h | 36 ++++++++++++++++++++++++++++++++++++
> > 2 files changed, 74 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> > index 7b2bb4c..9ddb89e 100644
> > --- a/drivers/tee/tee_core.c
> > +++ b/drivers/tee/tee_core.c
> > @@ -15,7 +15,6 @@
> > #define pr_fmt(fmt) "%s: " fmt, __func__
> >
> > #include <linux/cdev.h>
> > -#include <linux/device.h>
> > #include <linux/fs.h>
> > #include <linux/idr.h>
> > #include <linux/module.h>
> > @@ -1027,6 +1026,30 @@ int tee_client_invoke_func(struct tee_context *ctx,
> > }
> > EXPORT_SYMBOL_GPL(tee_client_invoke_func);
> >
> > +static int tee_client_device_match(struct device *dev,
> > + struct device_driver *drv)
> > +{
> > + struct tee_client_device *tee_device;
> > + const struct tee_client_device_id *id_table;
> > +
> > + tee_device = to_tee_client_device(dev);
> > + id_table = to_tee_client_driver(drv)->id_table;
> > +
> > + while (!uuid_is_null(&id_table->uuid)) {
> > + if (uuid_equal(&tee_device->id.uuid, &id_table->uuid))
> > + return 1;
> > + id_table++;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +struct bus_type tee_bus_type = {
> > + .name = "tee",
> > + .match = tee_client_device_match,
> > +};
> > +EXPORT_SYMBOL_GPL(tee_bus_type);
> > +
> > static int __init tee_init(void)
> > {
> > int rc;
> > @@ -1040,10 +1063,21 @@ static int __init tee_init(void)
> > rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee");
> > if (rc) {
> > pr_err("failed to allocate char dev region\n");
> > - class_destroy(tee_class);
> > - tee_class = NULL;
> > + goto class_err;
> > }
> >
> > + rc = bus_register(&tee_bus_type);
> > + if (rc) {
> > + pr_err("failed to register tee bus\n");
> > + goto class_err;
>
> There is an unregister_chrdev_region() in tee_exit(). Why isn't it
> needed on this error path?
>
Will add "unregister_chrdev_region()" on this error path.
-Sumit
>
> > + }
> > +
> > + return 0;
> > +
> > +class_err:
> > + class_destroy(tee_class);
> > + tee_class = NULL;
> > +
> > return rc;
> > }
> >
> > @@ -1052,6 +1086,7 @@ static void __exit tee_exit(void)
> > class_destroy(tee_class);
> > tee_class = NULL;
> > unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
> > + bus_unregister(&tee_bus_type);
> > }
> >
> > subsys_initcall(tee_init);
> > diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
> > index 6cfe058..ed16bf1 100644
> > --- a/include/linux/tee_drv.h
> > +++ b/include/linux/tee_drv.h
> > @@ -20,6 +20,8 @@
> > #include <linux/kref.h>
> > #include <linux/list.h>
> > #include <linux/tee.h>
> > +#include <linux/device.h>
> > +#include <linux/uuid.h>
> >
> > /*
> > * The file describes the API provided by the generic TEE driver to the
> > @@ -538,4 +540,38 @@ static inline bool tee_param_is_memref(struct tee_param *param)
> > }
> > }
> >
> > +extern struct bus_type tee_bus_type;
> > +
> > +/**
> > + * struct tee_client_device_id - tee based device identifier
> > + * @uuid: For TEE based client devices we use the device uuid
> > + * as the identifier.
> > + */
> > +struct tee_client_device_id {
> > + uuid_t uuid;
> > +};
> > +
> > +/**
> > + * struct tee_client_device - tee based device
> > + * @id: device identifier
> > + * @dev: device structure
> > + */
> > +struct tee_client_device {
> > + struct tee_client_device_id id;
> > + struct device dev;
> > +};
> > +#define to_tee_client_device(d) container_of(d, struct tee_client_device, dev)
> > +
> > +/**
> > + * struct tee_client_driver - tee client driver
> > + * @id_table: device id table supported by this driver
> > + * @driver: driver structure
> > + */
> > +struct tee_client_driver {
> > + const struct tee_client_device_id *id_table;
> > + struct device_driver driver;
> > +};
> > +#define to_tee_client_driver(d) \
> > + container_of(d, struct tee_client_driver, driver)
> > +
> > #endif /*__TEE_DRV_H*/
> > --
> > 2.7.4
> >
On Thu, 10 Jan 2019 at 19:57, Daniel Thompson
<[email protected]> wrote:
>
> On Thu, Jan 10, 2019 at 05:54:57PM +0530, Sumit Garg wrote:
> > On ARM SoC's with TrustZone enabled, peripherals like entropy sources
> > might not be accessible to normal world (linux in this case) and rather
> > accessible to secure world (OP-TEE in this case) only. So this driver
> > aims to provides a generic interface to OP-TEE based random number
> > generator service.
> >
> > This driver registers on TEE bus to interact with OP-TEE based rng
> > device/service.
> >
> > Signed-off-by: Sumit Garg <[email protected]>
> > ---
> > MAINTAINERS | 5 +
> > drivers/char/hw_random/Kconfig | 15 ++
> > drivers/char/hw_random/Makefile | 1 +
> > drivers/char/hw_random/optee-rng.c | 272 +++++++++++++++++++++++++++++++++++++
> > 4 files changed, 293 insertions(+)
> > create mode 100644 drivers/char/hw_random/optee-rng.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 32d44447..502733c 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -11260,6 +11260,11 @@ M: Jens Wiklander <[email protected]>
> > S: Maintained
> > F: drivers/tee/optee/
> >
> > +OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
> > +M: Sumit Garg <[email protected]>
> > +S: Maintained
> > +F: drivers/char/hw_random/optee-rng.c
> > +
> > OPA-VNIC DRIVER
> > M: Dennis Dalessandro <[email protected]>
> > M: Niranjana Vishwanathapura <[email protected]>
> > diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> > index dac895d..25a7d8f 100644
> > --- a/drivers/char/hw_random/Kconfig
> > +++ b/drivers/char/hw_random/Kconfig
> > @@ -424,6 +424,21 @@ config HW_RANDOM_EXYNOS
> > will be called exynos-trng.
> >
> > If unsure, say Y.
> > +
> > +config HW_RANDOM_OPTEE
> > + tristate "OP-TEE based Random Number Generator support"
> > + depends on OPTEE
> > + default HW_RANDOM
> > + help
> > + This driver provides support for OP-TEE based Random Number
> > + Generator on ARM SoCs where hardware entropy sources are not
> > + accessible to normal world (Linux).
> > +
> > + To compile this driver as a module, choose M here: the module
> > + will be called optee-rng.
> > +
> > + If unsure, say Y.
> > +
> > endif # HW_RANDOM
> >
> > config UML_RANDOM
> > diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
> > index e35ec3c..7c9ef4a 100644
> > --- a/drivers/char/hw_random/Makefile
> > +++ b/drivers/char/hw_random/Makefile
> > @@ -38,3 +38,4 @@ obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
> > obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
> > obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
> > obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
> > +obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
> > diff --git a/drivers/char/hw_random/optee-rng.c b/drivers/char/hw_random/optee-rng.c
> > new file mode 100644
> > index 0000000..ebfe1f2c
> > --- /dev/null
> > +++ b/drivers/char/hw_random/optee-rng.c
> > @@ -0,0 +1,272 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2018-2019 Linaro Ltd.
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/of.h>
> > +#include <linux/hw_random.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <linux/tee_drv.h>
> > +#include <linux/uuid.h>
> > +
> > +#define DRIVER_NAME "optee-rng"
> > +
> > +#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
> > +
> > +/*
> > + * TA_CMD_GET_ENTROPY - Get Entropy from RNG
> > + *
> > + * param[0] (inout memref) - Entropy buffer memory reference
> > + * param[1] unused
> > + * param[2] unused
> > + * param[3] unused
> > + *
> > + * Result:
> > + * TEE_SUCCESS - Invoke command success
> > + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> > + * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
> > + * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
> > + */
> > +#define TA_CMD_GET_ENTROPY 0x0
> > +
> > +/*
> > + * TA_CMD_GET_RNG_INFO - Get RNG information
> > + *
> > + * param[0] (out value) - value.a: RNG data-rate in bytes per second
> > + * value.b: Quality/Entropy per 1024 bit of data
> > + * param[1] unused
> > + * param[2] unused
> > + * param[3] unused
> > + *
> > + * Result:
> > + * TEE_SUCCESS - Invoke command success
> > + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> > + */
> > +#define TA_CMD_GET_RNG_INFO 0x1
> > +
> > +#define MAX_ENTROPY_REQ_SZ (4 * 1024)
> > +
> > +static struct tee_context *ctx;
> > +static struct tee_shm *entropy_shm_pool;
> > +static u32 ta_rng_data_rate;
> > +static u32 ta_rng_session_id;
> > +
> > +static size_t get_optee_rng_data(void *buf, size_t req_size)
> > +{
> > + u32 ret = 0;
> > + u8 *rng_data = NULL;
> > + size_t rng_size = 0;
> > + struct tee_ioctl_invoke_arg inv_arg = {0};
> > + struct tee_param param[4] = {0};
> > +
> > + /* Invoke TA_CMD_GET_RNG function of Trusted App */
> > + inv_arg.func = TA_CMD_GET_ENTROPY;
> > + inv_arg.session = ta_rng_session_id;
> > + inv_arg.num_params = 4;
> > +
> > + /* Fill invoke cmd params */
> > + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
> > + param[0].u.memref.shm = entropy_shm_pool;
> > + param[0].u.memref.size = req_size;
> > + param[0].u.memref.shm_offs = 0;
> > +
> > + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> > + if ((ret < 0) || (inv_arg.ret != 0)) {
> > + pr_err("TA_CMD_GET_ENTROPY invoke function error: %x\n",
> > + inv_arg.ret);
>
> You have a real device now! Almost all of the pr_xxx functions can become
> dev_xxx instead.
>
Ok will change to dev_xxx function calls.
>
> > + return 0;
> > + }
> > +
> > + rng_data = tee_shm_get_va(entropy_shm_pool, 0);
> > + if (IS_ERR(rng_data)) {
> > + pr_err("tee_shm_get_va failed\n");
> > + return 0;
> > + }
> > +
> > + rng_size = param[0].u.memref.size;
> > + memcpy(buf, rng_data, rng_size);
> > +
> > + return rng_size;
> > +}
> > +
> > +static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
> > +{
> > + u8 *data = buf;
> > + size_t read = 0, rng_size = 0;
> > + int timeout = 1;
> > +
> > + if (max > MAX_ENTROPY_REQ_SZ)
> > + max = MAX_ENTROPY_REQ_SZ;
> > +
> > + while (read == 0) {
> > + rng_size = get_optee_rng_data(data, (max - read));
> > +
> > + data += rng_size;
> > + read += rng_size;
> > +
> > + if (wait) {
> > + if (timeout-- == 0)
> > + return read;
> > + msleep((1000 * (max - read)) / ta_rng_data_rate);
> > + } else {
> > + return read;
> > + }
> > + }
> > +
> > + return read;
> > +}
> > +
> > +static int optee_rng_init(struct hwrng *rng)
> > +{
> > + entropy_shm_pool = tee_shm_alloc(ctx, MAX_ENTROPY_REQ_SZ,
> > + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
> > + if (IS_ERR(entropy_shm_pool)) {
> > + pr_err("tee_shm_alloc failed\n");
> > + return PTR_ERR(entropy_shm_pool);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static void optee_rng_cleanup(struct hwrng *rng)
> > +{
> > + tee_shm_free(entropy_shm_pool);
> > +}
> > +
> > +static struct hwrng optee_rng = {
> > + .name = DRIVER_NAME,
> > + .init = optee_rng_init,
> > + .cleanup = optee_rng_cleanup,
> > + .read = optee_rng_read,
> > +};
> > +
> > +static int get_optee_rng_info(void)
> > +{
> > + u32 ret = 0;
> > + struct tee_ioctl_invoke_arg inv_arg = {0};
> > + struct tee_param param[4] = {0};
> > +
> > + /* Invoke TA_CMD_GET_RNG function of Trusted App */
> > + inv_arg.func = TA_CMD_GET_RNG_INFO;
> > + inv_arg.session = ta_rng_session_id;
> > + inv_arg.num_params = 4;
> > +
> > + /* Fill invoke cmd params */
> > + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> > +
> > + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> > + if ((ret < 0) || (inv_arg.ret != 0)) {
> > + pr_err("TA_CMD_GET_RNG_INFO invoke function error: %x\n",
> > + inv_arg.ret);
> > + return -EINVAL;
> > + }
> > +
> > + ta_rng_data_rate = param[0].u.value.a;
> > + optee_rng.quality = param[0].u.value.b;
> > +
> > + return 0;
> > +}
> > +
> > +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> > +{
> > + if (ver->impl_id == TEE_IMPL_ID_OPTEE)
> > + return 1;
> > + else
> > + return 0;
> > +}
> > +
> > +static int optee_rng_probe(struct device *dev)
> > +{
> > + struct tee_client_device *rng_device = to_tee_client_device(dev);
> > + int ret = 0, err = -ENODEV;
> > + struct tee_ioctl_open_session_arg sess_arg = {0};
> > +
> > + /* Open context with TEE driver */
> > + ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
> > + if (IS_ERR(ctx))
> > + return -ENODEV;
> > +
> > + /* Open session with hwrng Trusted App */
> > + memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> > + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
> > + sess_arg.num_params = 0;
> > +
> > + ret = tee_client_open_session(ctx, &sess_arg, NULL);
> > + if ((ret < 0) || (sess_arg.ret != 0)) {
> > + pr_err("tee_client_open_session failed, error: %x\n",
> > + sess_arg.ret);
> > + err = -EINVAL;
> > + goto out_ctx;
> > + }
> > + ta_rng_session_id = sess_arg.session;
> > +
> > + err = get_optee_rng_info();
> > + if (err)
> > + goto out_sess;
> > +
> > + err = hwrng_register(&optee_rng);
> > + if (err) {
> > + pr_err("registering failed (%d)\n", err);
> > + goto out_sess;
> > + }
> > +
> > + return 0;
> > +
> > +out_sess:
> > + tee_client_close_session(ctx, ta_rng_session_id);
> > +out_ctx:
> > + tee_client_close_context(ctx);
> > +
> > + return err;
> > +}
> > +
> > +static int optee_rng_remove(struct device *dev)
> > +{
> > + tee_client_close_session(ctx, ta_rng_session_id);
> > + tee_client_close_context(ctx);
> > + hwrng_unregister(&optee_rng);
> > +
> > + return 0;
> > +}
> > +
> > +const struct tee_client_device_id optee_rng_id_table[] = {
> > + {UUID_INIT(0xab7a617c, 0xb8e7, 0x4d8f,
> > + 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64)},
> > + {}
> > +};
> > +
> > +static struct tee_client_driver optee_rng_driver = {
> > + .id_table = optee_rng_id_table,
> > + .driver = {
> > + .name = DRIVER_NAME,
> > + .bus = &tee_bus_type,
> > + .probe = optee_rng_probe,
> > + .remove = optee_rng_remove,
> > + },
> > +};
> > +
> > +static int __init mod_init(void)
>
> Not required for correctness but for grepability I'd prefer optee_rng_init .
>
Ok, will rename mod_init -> optee_rng_init and mod_exit -> optee_rng_exit.
-Sumit
>
> Daniel.
>
> > +{
> > + int rc;
> > +
> > + rc = driver_register(&optee_rng_driver.driver);
> > + if (rc)
> > + pr_warn("driver registration failed, err: %d", rc);
> > +
> > + return rc;
> > +}
> > +
> > +static void __exit mod_exit(void)
> > +{
> > + driver_unregister(&optee_rng_driver.driver);
> > +}
> > +
> > +module_init(mod_init);
> > +module_exit(mod_exit);
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_AUTHOR("Sumit Garg <[email protected]>");
> > +MODULE_DESCRIPTION("OP-TEE based random number generator driver");
> > --
> > 2.7.4
> >
On Fri, 11 Jan 2019 at 15:24, Daniel Thompson
<[email protected]> wrote:
>
> On Fri, Jan 11, 2019 at 01:00:49PM +0530, Sumit Garg wrote:
> > On Thu, 10 Jan 2019 at 19:53, Daniel Thompson
> > <[email protected]> wrote:
> > > > diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> > > > index 9ddb89e..5d6c317 100644
> > > > --- a/drivers/tee/tee_core.c
> > > > +++ b/drivers/tee/tee_core.c
> > > > @@ -105,6 +105,7 @@ static int tee_open(struct inode *inode, struct file *filp)
> > > > if (IS_ERR(ctx))
> > > > return PTR_ERR(ctx);
> > > >
> > > > + ctx->supp_nowait = false;
> > > > filp->private_data = ctx;
> > > > return 0;
> > > > }
> > > > @@ -981,6 +982,7 @@ tee_client_open_context(struct tee_context *start,
> > > > } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
> > > >
> > > > put_device(put_dev);
> > > > + ctx->supp_nowait = true;
> > >
> > > Why automatically set supp_nowait inside open_context() ?
> > >
> >
> > I think this is the default behaviour (non-blocking request) that any
> > in kernel client would expect. Also this flag could be configured
> > again before call to open_session() if any in kernel client requires
> > different behaviour.
>
> Makes sense. I think this is a deep enough behaviour to warrant proper
> commenting though.
>
Sure, will add comments.
-Sumit
>
> Daniel.
On Thu, Jan 10, 2019 at 05:54:57PM +0530, Sumit Garg wrote:
> On ARM SoC's with TrustZone enabled, peripherals like entropy sources
> might not be accessible to normal world (linux in this case) and rather
> accessible to secure world (OP-TEE in this case) only. So this driver
> aims to provides a generic interface to OP-TEE based random number
> generator service.
>
> This driver registers on TEE bus to interact with OP-TEE based rng
> device/service.
>
> Signed-off-by: Sumit Garg <[email protected]>
> ---
> MAINTAINERS | 5 +
> drivers/char/hw_random/Kconfig | 15 ++
> drivers/char/hw_random/Makefile | 1 +
> drivers/char/hw_random/optee-rng.c | 272 +++++++++++++++++++++++++++++++++++++
> 4 files changed, 293 insertions(+)
> create mode 100644 drivers/char/hw_random/optee-rng.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 32d44447..502733c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11260,6 +11260,11 @@ M: Jens Wiklander <[email protected]>
> S: Maintained
> F: drivers/tee/optee/
>
> +OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
> +M: Sumit Garg <[email protected]>
> +S: Maintained
> +F: drivers/char/hw_random/optee-rng.c
> +
> OPA-VNIC DRIVER
> M: Dennis Dalessandro <[email protected]>
> M: Niranjana Vishwanathapura <[email protected]>
> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> index dac895d..25a7d8f 100644
> --- a/drivers/char/hw_random/Kconfig
> +++ b/drivers/char/hw_random/Kconfig
> @@ -424,6 +424,21 @@ config HW_RANDOM_EXYNOS
> will be called exynos-trng.
>
> If unsure, say Y.
> +
> +config HW_RANDOM_OPTEE
> + tristate "OP-TEE based Random Number Generator support"
> + depends on OPTEE
> + default HW_RANDOM
> + help
> + This driver provides support for OP-TEE based Random Number
> + Generator on ARM SoCs where hardware entropy sources are not
> + accessible to normal world (Linux).
> +
> + To compile this driver as a module, choose M here: the module
> + will be called optee-rng.
> +
> + If unsure, say Y.
> +
> endif # HW_RANDOM
>
> config UML_RANDOM
> diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
> index e35ec3c..7c9ef4a 100644
> --- a/drivers/char/hw_random/Makefile
> +++ b/drivers/char/hw_random/Makefile
> @@ -38,3 +38,4 @@ obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
> obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
> obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
> obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
> +obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
> diff --git a/drivers/char/hw_random/optee-rng.c b/drivers/char/hw_random/optee-rng.c
> new file mode 100644
> index 0000000..ebfe1f2c
> --- /dev/null
> +++ b/drivers/char/hw_random/optee-rng.c
> @@ -0,0 +1,272 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2018-2019 Linaro Ltd.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/of.h>
> +#include <linux/hw_random.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.h>
> +#include <linux/uuid.h>
> +
> +#define DRIVER_NAME "optee-rng"
> +
> +#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
> +
> +/*
> + * TA_CMD_GET_ENTROPY - Get Entropy from RNG
> + *
> + * param[0] (inout memref) - Entropy buffer memory reference
> + * param[1] unused
> + * param[2] unused
> + * param[3] unused
> + *
> + * Result:
> + * TEE_SUCCESS - Invoke command success
> + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> + * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
> + * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
> + */
> +#define TA_CMD_GET_ENTROPY 0x0
> +
> +/*
> + * TA_CMD_GET_RNG_INFO - Get RNG information
> + *
> + * param[0] (out value) - value.a: RNG data-rate in bytes per second
> + * value.b: Quality/Entropy per 1024 bit of data
> + * param[1] unused
> + * param[2] unused
> + * param[3] unused
> + *
> + * Result:
> + * TEE_SUCCESS - Invoke command success
> + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> + */
> +#define TA_CMD_GET_RNG_INFO 0x1
> +
> +#define MAX_ENTROPY_REQ_SZ (4 * 1024)
> +
> +static struct tee_context *ctx;
> +static struct tee_shm *entropy_shm_pool;
> +static u32 ta_rng_data_rate;
> +static u32 ta_rng_session_id;
> +
> +static size_t get_optee_rng_data(void *buf, size_t req_size)
> +{
> + u32 ret = 0;
> + u8 *rng_data = NULL;
> + size_t rng_size = 0;
> + struct tee_ioctl_invoke_arg inv_arg = {0};
> + struct tee_param param[4] = {0};
> +
> + /* Invoke TA_CMD_GET_RNG function of Trusted App */
> + inv_arg.func = TA_CMD_GET_ENTROPY;
> + inv_arg.session = ta_rng_session_id;
> + inv_arg.num_params = 4;
> +
> + /* Fill invoke cmd params */
> + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
> + param[0].u.memref.shm = entropy_shm_pool;
> + param[0].u.memref.size = req_size;
> + param[0].u.memref.shm_offs = 0;
> +
> + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> + if ((ret < 0) || (inv_arg.ret != 0)) {
> + pr_err("TA_CMD_GET_ENTROPY invoke function error: %x\n",
> + inv_arg.ret);
You have a real device now! Almost all of the pr_xxx functions can become
dev_xxx instead.
> + return 0;
> + }
> +
> + rng_data = tee_shm_get_va(entropy_shm_pool, 0);
> + if (IS_ERR(rng_data)) {
> + pr_err("tee_shm_get_va failed\n");
> + return 0;
> + }
> +
> + rng_size = param[0].u.memref.size;
> + memcpy(buf, rng_data, rng_size);
> +
> + return rng_size;
> +}
> +
> +static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
> +{
> + u8 *data = buf;
> + size_t read = 0, rng_size = 0;
> + int timeout = 1;
> +
> + if (max > MAX_ENTROPY_REQ_SZ)
> + max = MAX_ENTROPY_REQ_SZ;
> +
> + while (read == 0) {
> + rng_size = get_optee_rng_data(data, (max - read));
> +
> + data += rng_size;
> + read += rng_size;
> +
> + if (wait) {
> + if (timeout-- == 0)
> + return read;
> + msleep((1000 * (max - read)) / ta_rng_data_rate);
> + } else {
> + return read;
> + }
> + }
> +
> + return read;
> +}
> +
> +static int optee_rng_init(struct hwrng *rng)
> +{
> + entropy_shm_pool = tee_shm_alloc(ctx, MAX_ENTROPY_REQ_SZ,
> + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
> + if (IS_ERR(entropy_shm_pool)) {
> + pr_err("tee_shm_alloc failed\n");
> + return PTR_ERR(entropy_shm_pool);
> + }
> +
> + return 0;
> +}
> +
> +static void optee_rng_cleanup(struct hwrng *rng)
> +{
> + tee_shm_free(entropy_shm_pool);
> +}
> +
> +static struct hwrng optee_rng = {
> + .name = DRIVER_NAME,
> + .init = optee_rng_init,
> + .cleanup = optee_rng_cleanup,
> + .read = optee_rng_read,
> +};
> +
> +static int get_optee_rng_info(void)
> +{
> + u32 ret = 0;
> + struct tee_ioctl_invoke_arg inv_arg = {0};
> + struct tee_param param[4] = {0};
> +
> + /* Invoke TA_CMD_GET_RNG function of Trusted App */
> + inv_arg.func = TA_CMD_GET_RNG_INFO;
> + inv_arg.session = ta_rng_session_id;
> + inv_arg.num_params = 4;
> +
> + /* Fill invoke cmd params */
> + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> +
> + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> + if ((ret < 0) || (inv_arg.ret != 0)) {
> + pr_err("TA_CMD_GET_RNG_INFO invoke function error: %x\n",
> + inv_arg.ret);
> + return -EINVAL;
> + }
> +
> + ta_rng_data_rate = param[0].u.value.a;
> + optee_rng.quality = param[0].u.value.b;
> +
> + return 0;
> +}
> +
> +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> +{
> + if (ver->impl_id == TEE_IMPL_ID_OPTEE)
> + return 1;
> + else
> + return 0;
> +}
> +
> +static int optee_rng_probe(struct device *dev)
> +{
> + struct tee_client_device *rng_device = to_tee_client_device(dev);
> + int ret = 0, err = -ENODEV;
> + struct tee_ioctl_open_session_arg sess_arg = {0};
> +
> + /* Open context with TEE driver */
> + ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
> + if (IS_ERR(ctx))
> + return -ENODEV;
> +
> + /* Open session with hwrng Trusted App */
> + memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
> + sess_arg.num_params = 0;
> +
> + ret = tee_client_open_session(ctx, &sess_arg, NULL);
> + if ((ret < 0) || (sess_arg.ret != 0)) {
> + pr_err("tee_client_open_session failed, error: %x\n",
> + sess_arg.ret);
> + err = -EINVAL;
> + goto out_ctx;
> + }
> + ta_rng_session_id = sess_arg.session;
> +
> + err = get_optee_rng_info();
> + if (err)
> + goto out_sess;
> +
> + err = hwrng_register(&optee_rng);
> + if (err) {
> + pr_err("registering failed (%d)\n", err);
> + goto out_sess;
> + }
> +
> + return 0;
> +
> +out_sess:
> + tee_client_close_session(ctx, ta_rng_session_id);
> +out_ctx:
> + tee_client_close_context(ctx);
> +
> + return err;
> +}
> +
> +static int optee_rng_remove(struct device *dev)
> +{
> + tee_client_close_session(ctx, ta_rng_session_id);
> + tee_client_close_context(ctx);
> + hwrng_unregister(&optee_rng);
> +
> + return 0;
> +}
> +
> +const struct tee_client_device_id optee_rng_id_table[] = {
> + {UUID_INIT(0xab7a617c, 0xb8e7, 0x4d8f,
> + 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64)},
> + {}
> +};
> +
> +static struct tee_client_driver optee_rng_driver = {
> + .id_table = optee_rng_id_table,
> + .driver = {
> + .name = DRIVER_NAME,
> + .bus = &tee_bus_type,
> + .probe = optee_rng_probe,
> + .remove = optee_rng_remove,
> + },
> +};
> +
> +static int __init mod_init(void)
Not required for correctness but for grepability I'd prefer optee_rng_init .
Daniel.
> +{
> + int rc;
> +
> + rc = driver_register(&optee_rng_driver.driver);
> + if (rc)
> + pr_warn("driver registration failed, err: %d", rc);
> +
> + return rc;
> +}
> +
> +static void __exit mod_exit(void)
> +{
> + driver_unregister(&optee_rng_driver.driver);
> +}
> +
> +module_init(mod_init);
> +module_exit(mod_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Sumit Garg <[email protected]>");
> +MODULE_DESCRIPTION("OP-TEE based random number generator driver");
> --
> 2.7.4
>
This flag indicates that requests in this context should not wait for
tee-supplicant daemon to be started if not present and just return
with an error code. It is needed for requests which should be
non-blocking in nature like ones arising from TEE based kernel drivers
or any in kernel api that uses TEE internal client interface.
Signed-off-by: Sumit Garg <[email protected]>
---
drivers/tee/optee/supp.c | 10 +++++++++-
drivers/tee/tee_core.c | 2 ++
include/linux/tee_drv.h | 6 ++++++
3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c
index 43626e1..92f56b8 100644
--- a/drivers/tee/optee/supp.c
+++ b/drivers/tee/optee/supp.c
@@ -88,10 +88,18 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
{
struct optee *optee = tee_get_drvdata(ctx->teedev);
struct optee_supp *supp = &optee->supp;
- struct optee_supp_req *req = kzalloc(sizeof(*req), GFP_KERNEL);
+ struct optee_supp_req *req;
bool interruptable;
u32 ret;
+ /*
+ * Return in case there is no supplicant available and
+ * non-blocking request.
+ */
+ if (!supp->ctx && ctx->supp_nowait)
+ return TEEC_ERROR_COMMUNICATION;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req)
return TEEC_ERROR_OUT_OF_MEMORY;
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 9ddb89e..5d6c317 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -105,6 +105,7 @@ static int tee_open(struct inode *inode, struct file *filp)
if (IS_ERR(ctx))
return PTR_ERR(ctx);
+ ctx->supp_nowait = false;
filp->private_data = ctx;
return 0;
}
@@ -981,6 +982,7 @@ tee_client_open_context(struct tee_context *start,
} while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
put_device(put_dev);
+ ctx->supp_nowait = true;
return ctx;
}
EXPORT_SYMBOL_GPL(tee_client_open_context);
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index ed16bf1..fe1a920 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -49,6 +49,11 @@ struct tee_shm_pool;
* @releasing: flag that indicates if context is being released right now.
* It is needed to break circular dependency on context during
* shared memory release.
+ * @supp_nowait: flag that indicates that requests in this context should not
+ * wait for tee-supplicant daemon to be started if not present
+ * 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.
*/
struct tee_context {
struct tee_device *teedev;
@@ -56,6 +61,7 @@ struct tee_context {
void *data;
struct kref refcount;
bool releasing;
+ bool supp_nowait;
};
struct tee_param_memref {
--
2.7.4
On Thu, 10 Jan 2019 at 19:53, Daniel Thompson
<[email protected]> wrote:
>
> On Thu, Jan 10, 2019 at 05:54:56PM +0530, Sumit Garg wrote:
> > This flag indicates that requests in this context should not wait for
> > tee-supplicant daemon to be started if not present and just return
> > with an error code. It is needed for requests which should be
> > non-blocking in nature like ones arising from TEE based kernel drivers
> > or any in kernel api that uses TEE internal client interface.
>
> This patch seems out of order in the patch set: Doesn't
> optee_enumarate_devices() require this feature if it is to
> work correctly with a TEE that does not implement the enumeate pTA.
>
> If so better to implement the feature first so that
> optee_emumerate_devices() works correctly when it first appears.
>
Agree, will make this patch as #2 in next version.
> >
> > Signed-off-by: Sumit Garg <[email protected]>
> > ---
> > drivers/tee/optee/supp.c | 10 +++++++++-
> > drivers/tee/tee_core.c | 2 ++
> > include/linux/tee_drv.h | 6 ++++++
> > 3 files changed, 17 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c
> > index 43626e1..92f56b8 100644
> > --- a/drivers/tee/optee/supp.c
> > +++ b/drivers/tee/optee/supp.c
> > @@ -88,10 +88,18 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
> > {
> > struct optee *optee = tee_get_drvdata(ctx->teedev);
> > struct optee_supp *supp = &optee->supp;
> > - struct optee_supp_req *req = kzalloc(sizeof(*req), GFP_KERNEL);
> > + struct optee_supp_req *req;
> > bool interruptable;
> > u32 ret;
> >
> > + /*
> > + * Return in case there is no supplicant available and
> > + * non-blocking request.
> > + */
> > + if (!supp->ctx && ctx->supp_nowait)
> > + return TEEC_ERROR_COMMUNICATION;
> > +
> > + req = kzalloc(sizeof(*req), GFP_KERNEL);
> > if (!req)
> > return TEEC_ERROR_OUT_OF_MEMORY;
> >
> > diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> > index 9ddb89e..5d6c317 100644
> > --- a/drivers/tee/tee_core.c
> > +++ b/drivers/tee/tee_core.c
> > @@ -105,6 +105,7 @@ static int tee_open(struct inode *inode, struct file *filp)
> > if (IS_ERR(ctx))
> > return PTR_ERR(ctx);
> >
> > + ctx->supp_nowait = false;
> > filp->private_data = ctx;
> > return 0;
> > }
> > @@ -981,6 +982,7 @@ tee_client_open_context(struct tee_context *start,
> > } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
> >
> > put_device(put_dev);
> > + ctx->supp_nowait = true;
>
> Why automatically set supp_nowait inside open_context() ?
>
I think this is the default behaviour (non-blocking request) that any
in kernel client would expect. Also this flag could be configured
again before call to open_session() if any in kernel client requires
different behaviour.
-Sumit
>
> > return ctx;
> > }
> > EXPORT_SYMBOL_GPL(tee_client_open_context);
> > diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
> > index ed16bf1..fe1a920 100644
> > --- a/include/linux/tee_drv.h
> > +++ b/include/linux/tee_drv.h
> > @@ -49,6 +49,11 @@ struct tee_shm_pool;
> > * @releasing: flag that indicates if context is being released right now.
> > * It is needed to break circular dependency on context during
> > * shared memory release.
> > + * @supp_nowait: flag that indicates that requests in this context should not
> > + * wait for tee-supplicant daemon to be started if not present
> > + * 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.
> > */
> > struct tee_context {
> > struct tee_device *teedev;
> > @@ -56,6 +61,7 @@ struct tee_context {
> > void *data;
> > struct kref refcount;
> > bool releasing;
> > + bool supp_nowait;
> > };
> >
> > struct tee_param_memref {
> > --
> > 2.7.4
> >
On Thu, 10 Jan 2019 at 19:49, Daniel Thompson
<[email protected]> wrote:
>
> On Thu, Jan 10, 2019 at 05:54:55PM +0530, Sumit Garg wrote:
> > OP-TEE provides a pseudo TA to enumerate TAs which can act as devices/
> > services for TEE bus. So implement device enumeration using invoke
> > function: PTA_CMD_GET_DEVICES provided by pseudo TA to fetch array of
> > device UUIDs. Also register these enumerated devices with TEE bus as
> > "optee-clntX" device.
> >
> > Signed-off-by: Sumit Garg <[email protected]>
> > ---
> > drivers/tee/optee/Makefile | 1 +
> > drivers/tee/optee/core.c | 4 +
> > drivers/tee/optee/device.c | 150 ++++++++++++++++++++++++++++++++++++++
> > drivers/tee/optee/optee_private.h | 3 +
> > 4 files changed, 158 insertions(+)
> > create mode 100644 drivers/tee/optee/device.c
> >
> > diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
> > index 48d262a..56263ae 100644
> > --- a/drivers/tee/optee/Makefile
> > +++ b/drivers/tee/optee/Makefile
> > @@ -5,3 +5,4 @@ optee-objs += call.o
> > optee-objs += rpc.o
> > optee-objs += supp.o
> > optee-objs += shm_pool.o
> > +optee-objs += device.o
> > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > index e5efce3..ac59c77 100644
> > --- a/drivers/tee/optee/core.c
> > +++ b/drivers/tee/optee/core.c
> > @@ -634,6 +634,10 @@ static struct optee *optee_probe(struct device_node *np)
> > if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
> > pr_info("dynamic shared memory is enabled\n");
> >
> > + rc = optee_enumerate_devices();
> > + if (rc)
> > + goto err;
> > +
> > pr_info("initialized driver\n");
> > return optee;
> > err:
> > diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c
> > new file mode 100644
> > index 0000000..b38d24b
> > --- /dev/null
> > +++ b/drivers/tee/optee/device.c
> > @@ -0,0 +1,150 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2019 Linaro Ltd.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/slab.h>
> > +#include <linux/tee_drv.h>
> > +#include <linux/uuid.h>
> > +#include "optee_private.h"
> > +
> > +/*
> > + * Get device UUIDs
> > + *
> > + * [out] memref[0] Array of device UUIDs
> > + *
> > + * Return codes:
> > + * TEE_SUCCESS - Invoke command success
> > + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> > + * TEE_ERROR_SHORT_BUFFER - Output buffer size less than required
> > + */
> > +#define PTA_CMD_GET_DEVICES 0x0
> > +
> > +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> > +{
> > + if (ver->impl_id == TEE_IMPL_ID_OPTEE)
> > + return 1;
> > + else
> > + return 0;
> > +}
> > +
> > +static int get_devices(struct tee_context *ctx, u32 session,
> > + struct tee_shm *device_uuid, u32 *shm_size)
>
> Missing const on device_uuid?
>
I don't think we should have a const for device_uuid here as this is
shared memory struct pointer which is dynamically allocated and used
to fetch device UUIDs.
>
> > +{
> > + u32 ret = 0;
> > + struct tee_ioctl_invoke_arg inv_arg = {0};
> > + struct tee_param param[4] = {0};
> > +
> > + /* Invoke PTA_CMD_GET_DEVICES function */
> > + inv_arg.func = PTA_CMD_GET_DEVICES;
> > + inv_arg.session = session;
> > + inv_arg.num_params = 4;
> > +
> > + /* Fill invoke cmd params */
> > + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
> > + param[0].u.memref.shm = device_uuid;
> > + param[0].u.memref.size = *shm_size;
> > + param[0].u.memref.shm_offs = 0;
> > +
> > + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> > + if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) &&
> > + (inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) {
> > + pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n",
> > + inv_arg.ret);
> > + return -EINVAL;
> > + }
> > +
> > + *shm_size = param[0].u.memref.size;
> > +
> > + return 0;
> > +}
> > +
> > +static int optee_register_device(uuid_t *device_uuid, u32 device_id)
>
> const?
>
Will add const here.
>
> > +{
> > + struct tee_client_device *optee_device = NULL;
> > + int rc;
> > +
> > + optee_device = kzalloc(sizeof(*optee_device), GFP_KERNEL);
> > + if (!optee_device)
> > + return -ENOMEM;
> > +
> > + optee_device->dev.bus = &tee_bus_type;
> > + dev_set_name(&optee_device->dev, "optee-clnt%u", device_id);
> > + uuid_copy(&optee_device->id.uuid, device_uuid);
> > +
> > + rc = device_register(&optee_device->dev);
> > + if (rc)
> > + pr_err("device registration failed, err: %d\n", rc);
>
> Leak optee_device?
>
Will fix.
>
> > +
> > + return rc;
> > +}
> > +
> > +int optee_enumerate_devices(void)
> > +{
> > + uuid_t pta_uuid =
> > + UUID_INIT(0x7011a688, 0xddde, 0x4053,
> > + 0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8);
>
> I think this could/should be const too.
>
Agree, will add const here too.
>
> > + struct tee_ioctl_open_session_arg sess_arg = {0};
> > + struct tee_shm *device_shm = NULL;
> > + uuid_t *device_uuid = NULL;
> > + struct tee_context *ctx = NULL;
> > + u32 shm_size = 0, idx = 0;
> > + int rc;
> > +
> > + /* Open context with OP-TEE driver */
> > + ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
> > + if (IS_ERR(ctx))
> > + return -ENODEV;
> > +
> > + /* Open session with device enumeration pseudo TA */
> > + memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN);
> > + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
> > + sess_arg.num_params = 0;
> > +
> > + rc = tee_client_open_session(ctx, &sess_arg, NULL);
> > + if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) {
> > + /* Device enumeration pseudo TA not found */
> > + rc = 0;
> > + goto out_ctx;
> > + }
> > +
> > + rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
>
> Use NULL and 0 directly here instead of relying on initialized values.
> This makes it clear we are fetching the size of a buffer and are doing
> something different to the next call to get_devices().
>
Ok, will directly pass NULL here.
>
> > + if (rc < 0)
> > + goto out_sess;
> > +
> > + device_shm = tee_shm_alloc(ctx, shm_size,
> > + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
> > + if (IS_ERR(device_shm)) {
> > + pr_err("tee_shm_alloc failed\n");
> > + rc = PTR_ERR(device_shm);
> > + goto out_sess;
> > + }
> > +
> > + rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
> > + if (rc < 0)
> > + goto out_shm;
> > +
> > + device_uuid = tee_shm_get_va(device_shm, 0);
> > + if (IS_ERR(device_uuid)) {
> > + pr_err("tee_shm_get_va failed\n");
> > + rc = PTR_ERR(device_uuid);
> > + goto out_shm;
> > + }
> > +
> > + while (idx < shm_size / sizeof(uuid_t)) {
>
> This is a very uncommon way to write a for loop ;-).
>
Ok, will add "num_devices" variable.
-Sumit
>
> > + rc = optee_register_device(&device_uuid[idx], idx);
> > + if (rc)
> > + goto out_shm;
> > + idx++;
> > + }
> > +
> > +out_shm:
> > + tee_shm_free(device_shm);
> > +out_sess:
> > + tee_client_close_session(ctx, sess_arg.session);
> > +out_ctx:
> > + tee_client_close_context(ctx);
> > +
> > + return rc;
> > +}
> > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > index 35e7938..a5e84af 100644
> > --- a/drivers/tee/optee/optee_private.h
> > +++ b/drivers/tee/optee/optee_private.h
> > @@ -28,6 +28,7 @@
> > #define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
> > #define TEEC_ERROR_COMMUNICATION 0xFFFF000E
> > #define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
> > +#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
> >
> > #define TEEC_ORIGIN_COMMS 0x00000002
> >
> > @@ -181,6 +182,8 @@ void optee_free_pages_list(void *array, size_t num_entries);
> > void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
> > size_t page_offset);
> >
> > +int optee_enumerate_devices(void);
> > +
> > /*
> > * Small helpers
> > */
> > --
> > 2.7.4
> >
OP-TEE provides a pseudo TA to enumerate TAs which can act as devices/
services for TEE bus. So implement device enumeration using invoke
function: PTA_CMD_GET_DEVICES provided by pseudo TA to fetch array of
device UUIDs. Also register these enumerated devices with TEE bus as
"optee-clntX" device.
Signed-off-by: Sumit Garg <[email protected]>
---
drivers/tee/optee/Makefile | 1 +
drivers/tee/optee/core.c | 4 +
drivers/tee/optee/device.c | 150 ++++++++++++++++++++++++++++++++++++++
drivers/tee/optee/optee_private.h | 3 +
4 files changed, 158 insertions(+)
create mode 100644 drivers/tee/optee/device.c
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
index 48d262a..56263ae 100644
--- a/drivers/tee/optee/Makefile
+++ b/drivers/tee/optee/Makefile
@@ -5,3 +5,4 @@ optee-objs += call.o
optee-objs += rpc.o
optee-objs += supp.o
optee-objs += shm_pool.o
+optee-objs += device.o
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index e5efce3..ac59c77 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -634,6 +634,10 @@ static struct optee *optee_probe(struct device_node *np)
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
pr_info("dynamic shared memory is enabled\n");
+ rc = optee_enumerate_devices();
+ if (rc)
+ goto err;
+
pr_info("initialized driver\n");
return optee;
err:
diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c
new file mode 100644
index 0000000..b38d24b
--- /dev/null
+++ b/drivers/tee/optee/device.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Linaro Ltd.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/uuid.h>
+#include "optee_private.h"
+
+/*
+ * Get device UUIDs
+ *
+ * [out] memref[0] Array of device UUIDs
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ * TEE_ERROR_SHORT_BUFFER - Output buffer size less than required
+ */
+#define PTA_CMD_GET_DEVICES 0x0
+
+static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+ if (ver->impl_id == TEE_IMPL_ID_OPTEE)
+ return 1;
+ else
+ return 0;
+}
+
+static int get_devices(struct tee_context *ctx, u32 session,
+ struct tee_shm *device_uuid, u32 *shm_size)
+{
+ u32 ret = 0;
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[4] = {0};
+
+ /* Invoke PTA_CMD_GET_DEVICES function */
+ inv_arg.func = PTA_CMD_GET_DEVICES;
+ inv_arg.session = session;
+ inv_arg.num_params = 4;
+
+ /* Fill invoke cmd params */
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+ param[0].u.memref.shm = device_uuid;
+ param[0].u.memref.size = *shm_size;
+ param[0].u.memref.shm_offs = 0;
+
+ ret = tee_client_invoke_func(ctx, &inv_arg, param);
+ if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) &&
+ (inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) {
+ pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n",
+ inv_arg.ret);
+ return -EINVAL;
+ }
+
+ *shm_size = param[0].u.memref.size;
+
+ return 0;
+}
+
+static int optee_register_device(uuid_t *device_uuid, u32 device_id)
+{
+ struct tee_client_device *optee_device = NULL;
+ int rc;
+
+ optee_device = kzalloc(sizeof(*optee_device), GFP_KERNEL);
+ if (!optee_device)
+ return -ENOMEM;
+
+ optee_device->dev.bus = &tee_bus_type;
+ dev_set_name(&optee_device->dev, "optee-clnt%u", device_id);
+ uuid_copy(&optee_device->id.uuid, device_uuid);
+
+ rc = device_register(&optee_device->dev);
+ if (rc)
+ pr_err("device registration failed, err: %d\n", rc);
+
+ return rc;
+}
+
+int optee_enumerate_devices(void)
+{
+ uuid_t pta_uuid =
+ UUID_INIT(0x7011a688, 0xddde, 0x4053,
+ 0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8);
+ struct tee_ioctl_open_session_arg sess_arg = {0};
+ struct tee_shm *device_shm = NULL;
+ uuid_t *device_uuid = NULL;
+ struct tee_context *ctx = NULL;
+ u32 shm_size = 0, idx = 0;
+ int rc;
+
+ /* Open context with OP-TEE driver */
+ ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+ if (IS_ERR(ctx))
+ return -ENODEV;
+
+ /* Open session with device enumeration pseudo TA */
+ memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN);
+ sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+ sess_arg.num_params = 0;
+
+ rc = tee_client_open_session(ctx, &sess_arg, NULL);
+ if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) {
+ /* Device enumeration pseudo TA not found */
+ rc = 0;
+ goto out_ctx;
+ }
+
+ rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
+ if (rc < 0)
+ goto out_sess;
+
+ device_shm = tee_shm_alloc(ctx, shm_size,
+ TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+ if (IS_ERR(device_shm)) {
+ pr_err("tee_shm_alloc failed\n");
+ rc = PTR_ERR(device_shm);
+ goto out_sess;
+ }
+
+ rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
+ if (rc < 0)
+ goto out_shm;
+
+ device_uuid = tee_shm_get_va(device_shm, 0);
+ if (IS_ERR(device_uuid)) {
+ pr_err("tee_shm_get_va failed\n");
+ rc = PTR_ERR(device_uuid);
+ goto out_shm;
+ }
+
+ while (idx < shm_size / sizeof(uuid_t)) {
+ rc = optee_register_device(&device_uuid[idx], idx);
+ if (rc)
+ goto out_shm;
+ idx++;
+ }
+
+out_shm:
+ tee_shm_free(device_shm);
+out_sess:
+ tee_client_close_session(ctx, sess_arg.session);
+out_ctx:
+ tee_client_close_context(ctx);
+
+ return rc;
+}
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index 35e7938..a5e84af 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -28,6 +28,7 @@
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
+#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
#define TEEC_ORIGIN_COMMS 0x00000002
@@ -181,6 +182,8 @@ void optee_free_pages_list(void *array, size_t num_entries);
void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
size_t page_offset);
+int optee_enumerate_devices(void);
+
/*
* Small helpers
*/
--
2.7.4
On Fri, Jan 11, 2019 at 01:00:49PM +0530, Sumit Garg wrote:
> On Thu, 10 Jan 2019 at 19:53, Daniel Thompson
> <[email protected]> wrote:
> > > diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> > > index 9ddb89e..5d6c317 100644
> > > --- a/drivers/tee/tee_core.c
> > > +++ b/drivers/tee/tee_core.c
> > > @@ -105,6 +105,7 @@ static int tee_open(struct inode *inode, struct file *filp)
> > > if (IS_ERR(ctx))
> > > return PTR_ERR(ctx);
> > >
> > > + ctx->supp_nowait = false;
> > > filp->private_data = ctx;
> > > return 0;
> > > }
> > > @@ -981,6 +982,7 @@ tee_client_open_context(struct tee_context *start,
> > > } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
> > >
> > > put_device(put_dev);
> > > + ctx->supp_nowait = true;
> >
> > Why automatically set supp_nowait inside open_context() ?
> >
>
> I think this is the default behaviour (non-blocking request) that any
> in kernel client would expect. Also this flag could be configured
> again before call to open_session() if any in kernel client requires
> different behaviour.
Makes sense. I think this is a deep enough behaviour to warrant proper
commenting though.
Daniel.
On Fri, 11 Jan 2019 at 15:09, Daniel Thompson
<[email protected]> wrote:
>
> On Fri, Jan 11, 2019 at 12:52:19PM +0530, Sumit Garg wrote:
> > On Thu, 10 Jan 2019 at 19:49, Daniel Thompson
> > <[email protected]> wrote:
> > > > +static int get_devices(struct tee_context *ctx, u32 session,
> > > > + struct tee_shm *device_uuid, u32 *shm_size)
> > >
> > > Missing const on device_uuid?
> > >
> >
> > I don't think we should have a const for device_uuid here as this is
> > shared memory struct pointer which is dynamically allocated and used
> > to fetch device UUIDs.
>
> Agree. Perhaps device_uuid is misnamed though (part of the reason I
> misread this is that it is singular so I though it was a single UUID
> travelling into the TZ).
>
Will rename it to device_shm instead.
> > > > + rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
> > > > + if (rc < 0)
> > > > + goto out_shm;
> > > > +
> > > > + device_uuid = tee_shm_get_va(device_shm, 0);
> > > > + if (IS_ERR(device_uuid)) {
> > > > + pr_err("tee_shm_get_va failed\n");
> > > > + rc = PTR_ERR(device_uuid);
> > > > + goto out_shm;
> > > > + }
> > > > +
> > > > + while (idx < shm_size / sizeof(uuid_t)) {
> > >
> > > This is a very uncommon way to write a for loop ;-).
> > >
> >
> > Ok, will add "num_devices" variable.
>
> num_devices might add readability but that is not what I meant.
>
> The most idiomatic way to write somthing that loops for every valid index
> value is:
>
> for (i=0; i < limit; i++)
>
> You wrote it like this:
>
> int idx=0;
>
> /* lots of code between initializer and first use */
>
> while (idx < limit) {
> /* more code */
> idx++;
> }
>
> Sure, they are equivalent but the idiomatic form is easier to read.
>
Oh okay, will use "for" loop instead.
-Sumit
>
> Daniel.
Introduce a generic TEE bus driver concept for TEE based kernel drivers
which would like to communicate with TEE based devices/services.
In this TEE bus concept, devices/services are identified via Universally
Unique Identifier (UUID) and drivers register a table of device UUIDs
which they can support.
So this TEE bus framework registers a match() callback function which
iterates over the driver UUID table to find a corresponding match for
device UUID. If a match is found, then this particular device is probed
via corresponding probe api registered by the driver. This process
happens whenever a device or a driver is registered with TEE bus.
Also this framework allows for device enumeration to be specific to
corresponding TEE implementation like OP-TEE etc.
Signed-off-by: Sumit Garg <[email protected]>
---
drivers/tee/tee_core.c | 41 ++++++++++++++++++++++++++++++++++++++---
include/linux/tee_drv.h | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 74 insertions(+), 3 deletions(-)
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 7b2bb4c..9ddb89e 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -15,7 +15,6 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/cdev.h>
-#include <linux/device.h>
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/module.h>
@@ -1027,6 +1026,30 @@ int tee_client_invoke_func(struct tee_context *ctx,
}
EXPORT_SYMBOL_GPL(tee_client_invoke_func);
+static int tee_client_device_match(struct device *dev,
+ struct device_driver *drv)
+{
+ struct tee_client_device *tee_device;
+ const struct tee_client_device_id *id_table;
+
+ tee_device = to_tee_client_device(dev);
+ id_table = to_tee_client_driver(drv)->id_table;
+
+ while (!uuid_is_null(&id_table->uuid)) {
+ if (uuid_equal(&tee_device->id.uuid, &id_table->uuid))
+ return 1;
+ id_table++;
+ }
+
+ return 0;
+}
+
+struct bus_type tee_bus_type = {
+ .name = "tee",
+ .match = tee_client_device_match,
+};
+EXPORT_SYMBOL_GPL(tee_bus_type);
+
static int __init tee_init(void)
{
int rc;
@@ -1040,10 +1063,21 @@ static int __init tee_init(void)
rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee");
if (rc) {
pr_err("failed to allocate char dev region\n");
- class_destroy(tee_class);
- tee_class = NULL;
+ goto class_err;
}
+ rc = bus_register(&tee_bus_type);
+ if (rc) {
+ pr_err("failed to register tee bus\n");
+ goto class_err;
+ }
+
+ return 0;
+
+class_err:
+ class_destroy(tee_class);
+ tee_class = NULL;
+
return rc;
}
@@ -1052,6 +1086,7 @@ static void __exit tee_exit(void)
class_destroy(tee_class);
tee_class = NULL;
unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
+ bus_unregister(&tee_bus_type);
}
subsys_initcall(tee_init);
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 6cfe058..ed16bf1 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -20,6 +20,8 @@
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/tee.h>
+#include <linux/device.h>
+#include <linux/uuid.h>
/*
* The file describes the API provided by the generic TEE driver to the
@@ -538,4 +540,38 @@ static inline bool tee_param_is_memref(struct tee_param *param)
}
}
+extern struct bus_type tee_bus_type;
+
+/**
+ * struct tee_client_device_id - tee based device identifier
+ * @uuid: For TEE based client devices we use the device uuid
+ * as the identifier.
+ */
+struct tee_client_device_id {
+ uuid_t uuid;
+};
+
+/**
+ * struct tee_client_device - tee based device
+ * @id: device identifier
+ * @dev: device structure
+ */
+struct tee_client_device {
+ struct tee_client_device_id id;
+ struct device dev;
+};
+#define to_tee_client_device(d) container_of(d, struct tee_client_device, dev)
+
+/**
+ * struct tee_client_driver - tee client driver
+ * @id_table: device id table supported by this driver
+ * @driver: driver structure
+ */
+struct tee_client_driver {
+ const struct tee_client_device_id *id_table;
+ struct device_driver driver;
+};
+#define to_tee_client_driver(d) \
+ container_of(d, struct tee_client_driver, driver)
+
#endif /*__TEE_DRV_H*/
--
2.7.4
On Thu, 10 Jan 2019 at 19:26, Joakim Bech <[email protected]> wrote:
>
> On Thu, Jan 10, 2019 at 05:54:57PM +0530, Sumit Garg wrote:
> > On ARM SoC's with TrustZone enabled, peripherals like entropy sources
> > might not be accessible to normal world (linux in this case) and rather
> > accessible to secure world (OP-TEE in this case) only. So this driver
> > aims to provides a generic interface to OP-TEE based random number
> > generator service.
> >
> > This driver registers on TEE bus to interact with OP-TEE based rng
> >
> > device/service.
> >
> > Signed-off-by: Sumit Garg <[email protected]>
> > ---
> > MAINTAINERS | 5 +
> > drivers/char/hw_random/Kconfig | 15 ++
> > drivers/char/hw_random/Makefile | 1 +
> > drivers/char/hw_random/optee-rng.c | 272 +++++++++++++++++++++++++++++++++++++
> > 4 files changed, 293 insertions(+)
> > create mode 100644 drivers/char/hw_random/optee-rng.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 32d44447..502733c 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -11260,6 +11260,11 @@ M: Jens Wiklander <[email protected]>
> > S: Maintained
> > F: drivers/tee/optee/
> >
> > +OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
> > +M: Sumit Garg <[email protected]>
> > +S: Maintained
> > +F: drivers/char/hw_random/optee-rng.c
> > +
> > OPA-VNIC DRIVER
> > M: Dennis Dalessandro <[email protected]>
> > M: Niranjana Vishwanathapura <[email protected]>
> > diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> > index dac895d..25a7d8f 100644
> > --- a/drivers/char/hw_random/Kconfig
> > +++ b/drivers/char/hw_random/Kconfig
> > @@ -424,6 +424,21 @@ config HW_RANDOM_EXYNOS
> > will be called exynos-trng.
> >
> > If unsure, say Y.
> > +
> > +config HW_RANDOM_OPTEE
> > + tristate "OP-TEE based Random Number Generator support"
> > + depends on OPTEE
> > + default HW_RANDOM
> > + help
> > + This driver provides support for OP-TEE based Random Number
> > + Generator on ARM SoCs where hardware entropy sources are not
> > + accessible to normal world (Linux).
> > +
> > + To compile this driver as a module, choose M here: the module
> > + will be called optee-rng.
> > +
> > + If unsure, say Y.
> > +
> > endif # HW_RANDOM
> >
> > config UML_RANDOM
> > diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
> > index e35ec3c..7c9ef4a 100644
> > --- a/drivers/char/hw_random/Makefile
> > +++ b/drivers/char/hw_random/Makefile
> > @@ -38,3 +38,4 @@ obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
> > obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
> > obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
> > obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
> > +obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
> > diff --git a/drivers/char/hw_random/optee-rng.c b/drivers/char/hw_random/optee-rng.c
> > new file mode 100644
> > index 0000000..ebfe1f2c
> > --- /dev/null
> > +++ b/drivers/char/hw_random/optee-rng.c
> > @@ -0,0 +1,272 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2018-2019 Linaro Ltd.
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/of.h>
> > +#include <linux/hw_random.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <linux/tee_drv.h>
> > +#include <linux/uuid.h>
> > +
> > +#define DRIVER_NAME "optee-rng"
> > +
> > +#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
> > +
> > +/*
> > + * TA_CMD_GET_ENTROPY - Get Entropy from RNG
> > + *
> > + * param[0] (inout memref) - Entropy buffer memory reference
> > + * param[1] unused
> > + * param[2] unused
> > + * param[3] unused
> > + *
> > + * Result:
> > + * TEE_SUCCESS - Invoke command success
> > + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> > + * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
> > + * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
> > + */
> > +#define TA_CMD_GET_ENTROPY 0x0
> > +
> > +/*
> > + * TA_CMD_GET_RNG_INFO - Get RNG information
> > + *
> > + * param[0] (out value) - value.a: RNG data-rate in bytes per second
> > + * value.b: Quality/Entropy per 1024 bit of data
> > + * param[1] unused
> > + * param[2] unused
> > + * param[3] unused
> > + *
> > + * Result:
> > + * TEE_SUCCESS - Invoke command success
> > + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> > + */
> > +#define TA_CMD_GET_RNG_INFO 0x1
> > +
> > +#define MAX_ENTROPY_REQ_SZ (4 * 1024)
> > +
> > +static struct tee_context *ctx;
> > +static struct tee_shm *entropy_shm_pool;
> > +static u32 ta_rng_data_rate;
> > +static u32 ta_rng_session_id;
> > +
> > +static size_t get_optee_rng_data(void *buf, size_t req_size)
> > +{
> > + u32 ret = 0;
> > + u8 *rng_data = NULL;
> > + size_t rng_size = 0;
> > + struct tee_ioctl_invoke_arg inv_arg = {0};
> > + struct tee_param param[4] = {0};
> > +
> > + /* Invoke TA_CMD_GET_RNG function of Trusted App */
> >
> TA_CMD_GET_ENTROPY?
>
Will correct.
> > + inv_arg.func = TA_CMD_GET_ENTROPY;
> > + inv_arg.session = ta_rng_session_id;
> > + inv_arg.num_params = 4;
> > +
> > + /* Fill invoke cmd params */
> > + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
> >
> > + param[0].u.memref.shm = entropy_shm_pool;
> > + param[0].u.memref.size = req_size;
> > + param[0].u.memref.shm_offs = 0;
> > +
> > + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> > + if ((ret < 0) || (inv_arg.ret != 0)) {
> > + pr_err("TA_CMD_GET_ENTROPY invoke function error: %x\n",
> > + inv_arg.ret);
> > + return 0;
> > + }
> > +
> > + rng_data = tee_shm_get_va(entropy_shm_pool, 0);
> > + if (IS_ERR(rng_data)) {
> > + pr_err("tee_shm_get_va failed\n");
> > + return 0;
> > + }
> > +
> > + rng_size = param[0].u.memref.size;
> > + memcpy(buf, rng_data, rng_size);
> > +
> > + return rng_size;
> > +}
> > +
> > +static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
> > +{
> > + u8 *data = buf;
> > + size_t read = 0, rng_size = 0;
> > + int timeout = 1;
> > +
> > + if (max > MAX_ENTROPY_REQ_SZ)
> > + max = MAX_ENTROPY_REQ_SZ;
> > +
> > + while (read == 0) {
> > + rng_size = get_optee_rng_data(data, (max - read));
> > +
> > + data += rng_size;
> > + read += rng_size;
> > +
> > + if (wait) {
> > + if (timeout-- == 0)
> > + return read;
> > + msleep((1000 * (max - read)) / ta_rng_data_rate);
> > + } else {
> > + return read;
> > + }
> > + }
> > +
> > + return read;
> > +}
> > +
> > +static int optee_rng_init(struct hwrng *rng)
> > +{
> > + entropy_shm_pool = tee_shm_alloc(ctx, MAX_ENTROPY_REQ_SZ,
> > + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
> > + if (IS_ERR(entropy_shm_pool)) {
> > + pr_err("tee_shm_alloc failed\n");
> > + return PTR_ERR(entropy_shm_pool);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static void optee_rng_cleanup(struct hwrng *rng)
> > +{
> > + tee_shm_free(entropy_shm_pool);
> > +}
> > +
> > +static struct hwrng optee_rng = {
> > + .name = DRIVER_NAME,
> > + .init = optee_rng_init,
> > + .cleanup = optee_rng_cleanup,
> > + .read = optee_rng_read,
> > +};
> > +
> > +static int get_optee_rng_info(void)
> > +{
> > + u32 ret = 0;
> > + struct tee_ioctl_invoke_arg inv_arg = {0};
> > + struct tee_param param[4] = {0};
> > +
> > + /* Invoke TA_CMD_GET_RNG function of Trusted App */
> >
> TA_CMD_GET_RNG_INFO?
>
Will correct.
> > + inv_arg.func = TA_CMD_GET_RNG_INFO;
> > + inv_arg.session = ta_rng_session_id;
> > + inv_arg.num_params = 4;
> > +
> > + /* Fill invoke cmd params */
> > + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> > +
> > + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> > + if ((ret < 0) || (inv_arg.ret != 0)) {
> > + pr_err("TA_CMD_GET_RNG_INFO invoke function error: %x\n",
> > + inv_arg.ret);
> > + return -EINVAL;
> > + }
> > +
> > + ta_rng_data_rate = param[0].u.value.a;
> > + optee_rng.quality = param[0].u.value.b;
> > +
> > + return 0;
> > +}
> > +
> > +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> > +{
> > + if (ver->impl_id == TEE_IMPL_ID_OPTEE)
> > + return 1;
> > + else
> > + return 0;
> > +}
> > +
> > +static int optee_rng_probe(struct device *dev)
> > +{
> > + struct tee_client_device *rng_device = to_tee_client_device(dev);
> > + int ret = 0, err = -ENODEV;
> > + struct tee_ioctl_open_session_arg sess_arg = {0};
> > +
> > + /* Open context with TEE driver */
> > + ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
> > + if (IS_ERR(ctx))
> > + return -ENODEV;
> > +
> > + /* Open session with hwrng Trusted App */
> > + memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> > + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
> > + sess_arg.num_params = 0;
> > +
> > + ret = tee_client_open_session(ctx, &sess_arg, NULL);
> > + if ((ret < 0) || (sess_arg.ret != 0)) {
> > + pr_err("tee_client_open_session failed, error: %x\n",
> > + sess_arg.ret);
> > + err = -EINVAL;
> > + goto out_ctx;
> > + }
> > + ta_rng_session_id = sess_arg.session;
> > +
> > + err = get_optee_rng_info();
> > + if (err)
> > + goto out_sess;
> > +
> > + err = hwrng_register(&optee_rng);
> > + if (err) {
> > + pr_err("registering failed (%d)\n", err);
> > + goto out_sess;
> > + }
> > +
> > + return 0;
> > +
> > +out_sess:
> > + tee_client_close_session(ctx, ta_rng_session_id);
> > +out_ctx:
> > + tee_client_close_context(ctx);
> > +
> > + return err;
> > +}
> > +
> > +static int optee_rng_remove(struct device *dev)
> > +{
> > + tee_client_close_session(ctx, ta_rng_session_id);
> > + tee_client_close_context(ctx);
> > + hwrng_unregister(&optee_rng);
> > +
> > + return 0;
> > +}
> > +
> > +const struct tee_client_device_id optee_rng_id_table[] = {
> > + {UUID_INIT(0xab7a617c, 0xb8e7, 0x4d8f,
> > + 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64)},
> > + {}
> > +};
> >
> Just so I'm with you here, in the v1 patch set you said, that this could be
> populated with other platform specific RNG UUID/GUID later. So if I implement
> another RNG TA for another device in OP-TEE, then I only need to update this
> array with another corresponding ID? To me it looks like the ta_rng_session_id
> just stores an id for a single TEE RNG source, correct? I.e., this patch set is
> not really written to fully support more than a single source in OP-TEE at this
> point? I.e., my assumption about just adding another UUID to the array is wrong?
>
But do you think multiple OP-TEE RNG devices/TAs for a particular
platform would be a feasible use-case? I would expect a particular
platform would expose only a single OP-TEE RNG device even if it has
multiple hardware entropy sources accessible to secure world only.
So my intention of having this id_table populated with other RNG
UUID/GUID was that if another platform chooses to implement RNG TA
with different UUID (not having global RNG TA UUID) rather than this
driver trying to support multiple devices running concurrently. Having
said that, this may be true for other TEE based drivers which would
like to support multiple devices running concurrently.
-Sumit
> > +
> > +static struct tee_client_driver optee_rng_driver = {
> > + .id_table = optee_rng_id_table,
> > + .driver = {
> > + .name = DRIVER_NAME,
> > + .bus = &tee_bus_type,
> > + .probe = optee_rng_probe,
> > + .remove = optee_rng_remove,
> > + },
> > +};
> > +
> > +static int __init mod_init(void)
> > +{
> > + int rc;
> > +
> > + rc = driver_register(&optee_rng_driver.driver);
> > + if (rc)
> > + pr_warn("driver registration failed, err: %d", rc);
> > +
> > + return rc;
> > +}
> > +
> > +static void __exit mod_exit(void)
> > +{
> > + driver_unregister(&optee_rng_driver.driver);
> > +}
> > +
> > +module_init(mod_init);
> > +module_exit(mod_exit);
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_AUTHOR("Sumit Garg <[email protected]>");
> > +MODULE_DESCRIPTION("OP-TEE based random number generator driver");
> > --
> > 2.7.4
> >
> > _______________________________________________
> > Tee-dev mailing list
> > [email protected]
> > https://lists.linaro.org/mailman/listinfo/tee-dev
>
> --
> Regards,
> Joakim
On Thu, Jan 10, 2019 at 05:54:56PM +0530, Sumit Garg wrote:
> This flag indicates that requests in this context should not wait for
> tee-supplicant daemon to be started if not present and just return
> with an error code. It is needed for requests which should be
> non-blocking in nature like ones arising from TEE based kernel drivers
> or any in kernel api that uses TEE internal client interface.
This patch seems out of order in the patch set: Doesn't
optee_enumarate_devices() require this feature if it is to
work correctly with a TEE that does not implement the enumeate pTA.
If so better to implement the feature first so that
optee_emumerate_devices() works correctly when it first appears.
>
> Signed-off-by: Sumit Garg <[email protected]>
> ---
> drivers/tee/optee/supp.c | 10 +++++++++-
> drivers/tee/tee_core.c | 2 ++
> include/linux/tee_drv.h | 6 ++++++
> 3 files changed, 17 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c
> index 43626e1..92f56b8 100644
> --- a/drivers/tee/optee/supp.c
> +++ b/drivers/tee/optee/supp.c
> @@ -88,10 +88,18 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
> {
> struct optee *optee = tee_get_drvdata(ctx->teedev);
> struct optee_supp *supp = &optee->supp;
> - struct optee_supp_req *req = kzalloc(sizeof(*req), GFP_KERNEL);
> + struct optee_supp_req *req;
> bool interruptable;
> u32 ret;
>
> + /*
> + * Return in case there is no supplicant available and
> + * non-blocking request.
> + */
> + if (!supp->ctx && ctx->supp_nowait)
> + return TEEC_ERROR_COMMUNICATION;
> +
> + req = kzalloc(sizeof(*req), GFP_KERNEL);
> if (!req)
> return TEEC_ERROR_OUT_OF_MEMORY;
>
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index 9ddb89e..5d6c317 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -105,6 +105,7 @@ static int tee_open(struct inode *inode, struct file *filp)
> if (IS_ERR(ctx))
> return PTR_ERR(ctx);
>
> + ctx->supp_nowait = false;
> filp->private_data = ctx;
> return 0;
> }
> @@ -981,6 +982,7 @@ tee_client_open_context(struct tee_context *start,
> } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
>
> put_device(put_dev);
> + ctx->supp_nowait = true;
Why automatically set supp_nowait inside open_context() ?
> return ctx;
> }
> EXPORT_SYMBOL_GPL(tee_client_open_context);
> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
> index ed16bf1..fe1a920 100644
> --- a/include/linux/tee_drv.h
> +++ b/include/linux/tee_drv.h
> @@ -49,6 +49,11 @@ struct tee_shm_pool;
> * @releasing: flag that indicates if context is being released right now.
> * It is needed to break circular dependency on context during
> * shared memory release.
> + * @supp_nowait: flag that indicates that requests in this context should not
> + * wait for tee-supplicant daemon to be started if not present
> + * 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.
> */
> struct tee_context {
> struct tee_device *teedev;
> @@ -56,6 +61,7 @@ struct tee_context {
> void *data;
> struct kref refcount;
> bool releasing;
> + bool supp_nowait;
> };
>
> struct tee_param_memref {
> --
> 2.7.4
>
On Thu, Jan 10, 2019 at 05:54:57PM +0530, Sumit Garg wrote:
> On ARM SoC's with TrustZone enabled, peripherals like entropy sources
> might not be accessible to normal world (linux in this case) and rather
> accessible to secure world (OP-TEE in this case) only. So this driver
> aims to provides a generic interface to OP-TEE based random number
> generator service.
>
> This driver registers on TEE bus to interact with OP-TEE based rng
>
> device/service.
>
> Signed-off-by: Sumit Garg <[email protected]>
> ---
> MAINTAINERS | 5 +
> drivers/char/hw_random/Kconfig | 15 ++
> drivers/char/hw_random/Makefile | 1 +
> drivers/char/hw_random/optee-rng.c | 272 +++++++++++++++++++++++++++++++++++++
> 4 files changed, 293 insertions(+)
> create mode 100644 drivers/char/hw_random/optee-rng.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 32d44447..502733c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11260,6 +11260,11 @@ M: Jens Wiklander <[email protected]>
> S: Maintained
> F: drivers/tee/optee/
>
> +OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
> +M: Sumit Garg <[email protected]>
> +S: Maintained
> +F: drivers/char/hw_random/optee-rng.c
> +
> OPA-VNIC DRIVER
> M: Dennis Dalessandro <[email protected]>
> M: Niranjana Vishwanathapura <[email protected]>
> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> index dac895d..25a7d8f 100644
> --- a/drivers/char/hw_random/Kconfig
> +++ b/drivers/char/hw_random/Kconfig
> @@ -424,6 +424,21 @@ config HW_RANDOM_EXYNOS
> will be called exynos-trng.
>
> If unsure, say Y.
> +
> +config HW_RANDOM_OPTEE
> + tristate "OP-TEE based Random Number Generator support"
> + depends on OPTEE
> + default HW_RANDOM
> + help
> + This driver provides support for OP-TEE based Random Number
> + Generator on ARM SoCs where hardware entropy sources are not
> + accessible to normal world (Linux).
> +
> + To compile this driver as a module, choose M here: the module
> + will be called optee-rng.
> +
> + If unsure, say Y.
> +
> endif # HW_RANDOM
>
> config UML_RANDOM
> diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
> index e35ec3c..7c9ef4a 100644
> --- a/drivers/char/hw_random/Makefile
> +++ b/drivers/char/hw_random/Makefile
> @@ -38,3 +38,4 @@ obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
> obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
> obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
> obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
> +obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
> diff --git a/drivers/char/hw_random/optee-rng.c b/drivers/char/hw_random/optee-rng.c
> new file mode 100644
> index 0000000..ebfe1f2c
> --- /dev/null
> +++ b/drivers/char/hw_random/optee-rng.c
> @@ -0,0 +1,272 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2018-2019 Linaro Ltd.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/of.h>
> +#include <linux/hw_random.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.h>
> +#include <linux/uuid.h>
> +
> +#define DRIVER_NAME "optee-rng"
> +
> +#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
> +
> +/*
> + * TA_CMD_GET_ENTROPY - Get Entropy from RNG
> + *
> + * param[0] (inout memref) - Entropy buffer memory reference
> + * param[1] unused
> + * param[2] unused
> + * param[3] unused
> + *
> + * Result:
> + * TEE_SUCCESS - Invoke command success
> + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> + * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
> + * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
> + */
> +#define TA_CMD_GET_ENTROPY 0x0
> +
> +/*
> + * TA_CMD_GET_RNG_INFO - Get RNG information
> + *
> + * param[0] (out value) - value.a: RNG data-rate in bytes per second
> + * value.b: Quality/Entropy per 1024 bit of data
> + * param[1] unused
> + * param[2] unused
> + * param[3] unused
> + *
> + * Result:
> + * TEE_SUCCESS - Invoke command success
> + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
> + */
> +#define TA_CMD_GET_RNG_INFO 0x1
> +
> +#define MAX_ENTROPY_REQ_SZ (4 * 1024)
> +
> +static struct tee_context *ctx;
> +static struct tee_shm *entropy_shm_pool;
> +static u32 ta_rng_data_rate;
> +static u32 ta_rng_session_id;
> +
> +static size_t get_optee_rng_data(void *buf, size_t req_size)
> +{
> + u32 ret = 0;
> + u8 *rng_data = NULL;
> + size_t rng_size = 0;
> + struct tee_ioctl_invoke_arg inv_arg = {0};
> + struct tee_param param[4] = {0};
> +
> + /* Invoke TA_CMD_GET_RNG function of Trusted App */
>
TA_CMD_GET_ENTROPY?
> + inv_arg.func = TA_CMD_GET_ENTROPY;
> + inv_arg.session = ta_rng_session_id;
> + inv_arg.num_params = 4;
> +
> + /* Fill invoke cmd params */
> + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
>
> + param[0].u.memref.shm = entropy_shm_pool;
> + param[0].u.memref.size = req_size;
> + param[0].u.memref.shm_offs = 0;
> +
> + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> + if ((ret < 0) || (inv_arg.ret != 0)) {
> + pr_err("TA_CMD_GET_ENTROPY invoke function error: %x\n",
> + inv_arg.ret);
> + return 0;
> + }
> +
> + rng_data = tee_shm_get_va(entropy_shm_pool, 0);
> + if (IS_ERR(rng_data)) {
> + pr_err("tee_shm_get_va failed\n");
> + return 0;
> + }
> +
> + rng_size = param[0].u.memref.size;
> + memcpy(buf, rng_data, rng_size);
> +
> + return rng_size;
> +}
> +
> +static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
> +{
> + u8 *data = buf;
> + size_t read = 0, rng_size = 0;
> + int timeout = 1;
> +
> + if (max > MAX_ENTROPY_REQ_SZ)
> + max = MAX_ENTROPY_REQ_SZ;
> +
> + while (read == 0) {
> + rng_size = get_optee_rng_data(data, (max - read));
> +
> + data += rng_size;
> + read += rng_size;
> +
> + if (wait) {
> + if (timeout-- == 0)
> + return read;
> + msleep((1000 * (max - read)) / ta_rng_data_rate);
> + } else {
> + return read;
> + }
> + }
> +
> + return read;
> +}
> +
> +static int optee_rng_init(struct hwrng *rng)
> +{
> + entropy_shm_pool = tee_shm_alloc(ctx, MAX_ENTROPY_REQ_SZ,
> + TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
> + if (IS_ERR(entropy_shm_pool)) {
> + pr_err("tee_shm_alloc failed\n");
> + return PTR_ERR(entropy_shm_pool);
> + }
> +
> + return 0;
> +}
> +
> +static void optee_rng_cleanup(struct hwrng *rng)
> +{
> + tee_shm_free(entropy_shm_pool);
> +}
> +
> +static struct hwrng optee_rng = {
> + .name = DRIVER_NAME,
> + .init = optee_rng_init,
> + .cleanup = optee_rng_cleanup,
> + .read = optee_rng_read,
> +};
> +
> +static int get_optee_rng_info(void)
> +{
> + u32 ret = 0;
> + struct tee_ioctl_invoke_arg inv_arg = {0};
> + struct tee_param param[4] = {0};
> +
> + /* Invoke TA_CMD_GET_RNG function of Trusted App */
>
TA_CMD_GET_RNG_INFO?
> + inv_arg.func = TA_CMD_GET_RNG_INFO;
> + inv_arg.session = ta_rng_session_id;
> + inv_arg.num_params = 4;
> +
> + /* Fill invoke cmd params */
> + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
> +
> + ret = tee_client_invoke_func(ctx, &inv_arg, param);
> + if ((ret < 0) || (inv_arg.ret != 0)) {
> + pr_err("TA_CMD_GET_RNG_INFO invoke function error: %x\n",
> + inv_arg.ret);
> + return -EINVAL;
> + }
> +
> + ta_rng_data_rate = param[0].u.value.a;
> + optee_rng.quality = param[0].u.value.b;
> +
> + return 0;
> +}
> +
> +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> +{
> + if (ver->impl_id == TEE_IMPL_ID_OPTEE)
> + return 1;
> + else
> + return 0;
> +}
> +
> +static int optee_rng_probe(struct device *dev)
> +{
> + struct tee_client_device *rng_device = to_tee_client_device(dev);
> + int ret = 0, err = -ENODEV;
> + struct tee_ioctl_open_session_arg sess_arg = {0};
> +
> + /* Open context with TEE driver */
> + ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
> + if (IS_ERR(ctx))
> + return -ENODEV;
> +
> + /* Open session with hwrng Trusted App */
> + memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
> + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
> + sess_arg.num_params = 0;
> +
> + ret = tee_client_open_session(ctx, &sess_arg, NULL);
> + if ((ret < 0) || (sess_arg.ret != 0)) {
> + pr_err("tee_client_open_session failed, error: %x\n",
> + sess_arg.ret);
> + err = -EINVAL;
> + goto out_ctx;
> + }
> + ta_rng_session_id = sess_arg.session;
> +
> + err = get_optee_rng_info();
> + if (err)
> + goto out_sess;
> +
> + err = hwrng_register(&optee_rng);
> + if (err) {
> + pr_err("registering failed (%d)\n", err);
> + goto out_sess;
> + }
> +
> + return 0;
> +
> +out_sess:
> + tee_client_close_session(ctx, ta_rng_session_id);
> +out_ctx:
> + tee_client_close_context(ctx);
> +
> + return err;
> +}
> +
> +static int optee_rng_remove(struct device *dev)
> +{
> + tee_client_close_session(ctx, ta_rng_session_id);
> + tee_client_close_context(ctx);
> + hwrng_unregister(&optee_rng);
> +
> + return 0;
> +}
> +
> +const struct tee_client_device_id optee_rng_id_table[] = {
> + {UUID_INIT(0xab7a617c, 0xb8e7, 0x4d8f,
> + 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64)},
> + {}
> +};
>
Just so I'm with you here, in the v1 patch set you said, that this could be
populated with other platform specific RNG UUID/GUID later. So if I implement
another RNG TA for another device in OP-TEE, then I only need to update this
array with another corresponding ID? To me it looks like the ta_rng_session_id
just stores an id for a single TEE RNG source, correct? I.e., this patch set is
not really written to fully support more than a single source in OP-TEE at this
point? I.e., my assumption about just adding another UUID to the array is wrong?
> +
> +static struct tee_client_driver optee_rng_driver = {
> + .id_table = optee_rng_id_table,
> + .driver = {
> + .name = DRIVER_NAME,
> + .bus = &tee_bus_type,
> + .probe = optee_rng_probe,
> + .remove = optee_rng_remove,
> + },
> +};
> +
> +static int __init mod_init(void)
> +{
> + int rc;
> +
> + rc = driver_register(&optee_rng_driver.driver);
> + if (rc)
> + pr_warn("driver registration failed, err: %d", rc);
> +
> + return rc;
> +}
> +
> +static void __exit mod_exit(void)
> +{
> + driver_unregister(&optee_rng_driver.driver);
> +}
> +
> +module_init(mod_init);
> +module_exit(mod_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Sumit Garg <[email protected]>");
> +MODULE_DESCRIPTION("OP-TEE based random number generator driver");
> --
> 2.7.4
>
> _______________________________________________
> Tee-dev mailing list
> [email protected]
> https://lists.linaro.org/mailman/listinfo/tee-dev
--
Regards,
Joakim
On ARM SoC's with TrustZone enabled, peripherals like entropy sources
might not be accessible to normal world (linux in this case) and rather
accessible to secure world (OP-TEE in this case) only. So this driver
aims to provides a generic interface to OP-TEE based random number
generator service.
This driver registers on TEE bus to interact with OP-TEE based rng
device/service.
Signed-off-by: Sumit Garg <[email protected]>
---
MAINTAINERS | 5 +
drivers/char/hw_random/Kconfig | 15 ++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/optee-rng.c | 272 +++++++++++++++++++++++++++++++++++++
4 files changed, 293 insertions(+)
create mode 100644 drivers/char/hw_random/optee-rng.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 32d44447..502733c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11260,6 +11260,11 @@ M: Jens Wiklander <[email protected]>
S: Maintained
F: drivers/tee/optee/
+OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
+M: Sumit Garg <[email protected]>
+S: Maintained
+F: drivers/char/hw_random/optee-rng.c
+
OPA-VNIC DRIVER
M: Dennis Dalessandro <[email protected]>
M: Niranjana Vishwanathapura <[email protected]>
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index dac895d..25a7d8f 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -424,6 +424,21 @@ config HW_RANDOM_EXYNOS
will be called exynos-trng.
If unsure, say Y.
+
+config HW_RANDOM_OPTEE
+ tristate "OP-TEE based Random Number Generator support"
+ depends on OPTEE
+ default HW_RANDOM
+ help
+ This driver provides support for OP-TEE based Random Number
+ Generator on ARM SoCs where hardware entropy sources are not
+ accessible to normal world (Linux).
+
+ To compile this driver as a module, choose M here: the module
+ will be called optee-rng.
+
+ If unsure, say Y.
+
endif # HW_RANDOM
config UML_RANDOM
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index e35ec3c..7c9ef4a 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
+obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
diff --git a/drivers/char/hw_random/optee-rng.c b/drivers/char/hw_random/optee-rng.c
new file mode 100644
index 0000000..ebfe1f2c
--- /dev/null
+++ b/drivers/char/hw_random/optee-rng.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2019 Linaro Ltd.
+ */
+
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/hw_random.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/uuid.h>
+
+#define DRIVER_NAME "optee-rng"
+
+#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
+
+/*
+ * TA_CMD_GET_ENTROPY - Get Entropy from RNG
+ *
+ * param[0] (inout memref) - Entropy buffer memory reference
+ * param[1] unused
+ * param[2] unused
+ * param[3] unused
+ *
+ * Result:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
+ * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
+ */
+#define TA_CMD_GET_ENTROPY 0x0
+
+/*
+ * TA_CMD_GET_RNG_INFO - Get RNG information
+ *
+ * param[0] (out value) - value.a: RNG data-rate in bytes per second
+ * value.b: Quality/Entropy per 1024 bit of data
+ * param[1] unused
+ * param[2] unused
+ * param[3] unused
+ *
+ * Result:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ */
+#define TA_CMD_GET_RNG_INFO 0x1
+
+#define MAX_ENTROPY_REQ_SZ (4 * 1024)
+
+static struct tee_context *ctx;
+static struct tee_shm *entropy_shm_pool;
+static u32 ta_rng_data_rate;
+static u32 ta_rng_session_id;
+
+static size_t get_optee_rng_data(void *buf, size_t req_size)
+{
+ u32 ret = 0;
+ u8 *rng_data = NULL;
+ size_t rng_size = 0;
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[4] = {0};
+
+ /* Invoke TA_CMD_GET_RNG function of Trusted App */
+ inv_arg.func = TA_CMD_GET_ENTROPY;
+ inv_arg.session = ta_rng_session_id;
+ inv_arg.num_params = 4;
+
+ /* Fill invoke cmd params */
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
+ param[0].u.memref.shm = entropy_shm_pool;
+ param[0].u.memref.size = req_size;
+ param[0].u.memref.shm_offs = 0;
+
+ ret = tee_client_invoke_func(ctx, &inv_arg, param);
+ if ((ret < 0) || (inv_arg.ret != 0)) {
+ pr_err("TA_CMD_GET_ENTROPY invoke function error: %x\n",
+ inv_arg.ret);
+ return 0;
+ }
+
+ rng_data = tee_shm_get_va(entropy_shm_pool, 0);
+ if (IS_ERR(rng_data)) {
+ pr_err("tee_shm_get_va failed\n");
+ return 0;
+ }
+
+ rng_size = param[0].u.memref.size;
+ memcpy(buf, rng_data, rng_size);
+
+ return rng_size;
+}
+
+static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+{
+ u8 *data = buf;
+ size_t read = 0, rng_size = 0;
+ int timeout = 1;
+
+ if (max > MAX_ENTROPY_REQ_SZ)
+ max = MAX_ENTROPY_REQ_SZ;
+
+ while (read == 0) {
+ rng_size = get_optee_rng_data(data, (max - read));
+
+ data += rng_size;
+ read += rng_size;
+
+ if (wait) {
+ if (timeout-- == 0)
+ return read;
+ msleep((1000 * (max - read)) / ta_rng_data_rate);
+ } else {
+ return read;
+ }
+ }
+
+ return read;
+}
+
+static int optee_rng_init(struct hwrng *rng)
+{
+ entropy_shm_pool = tee_shm_alloc(ctx, MAX_ENTROPY_REQ_SZ,
+ TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+ if (IS_ERR(entropy_shm_pool)) {
+ pr_err("tee_shm_alloc failed\n");
+ return PTR_ERR(entropy_shm_pool);
+ }
+
+ return 0;
+}
+
+static void optee_rng_cleanup(struct hwrng *rng)
+{
+ tee_shm_free(entropy_shm_pool);
+}
+
+static struct hwrng optee_rng = {
+ .name = DRIVER_NAME,
+ .init = optee_rng_init,
+ .cleanup = optee_rng_cleanup,
+ .read = optee_rng_read,
+};
+
+static int get_optee_rng_info(void)
+{
+ u32 ret = 0;
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[4] = {0};
+
+ /* Invoke TA_CMD_GET_RNG function of Trusted App */
+ inv_arg.func = TA_CMD_GET_RNG_INFO;
+ inv_arg.session = ta_rng_session_id;
+ inv_arg.num_params = 4;
+
+ /* Fill invoke cmd params */
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+
+ ret = tee_client_invoke_func(ctx, &inv_arg, param);
+ if ((ret < 0) || (inv_arg.ret != 0)) {
+ pr_err("TA_CMD_GET_RNG_INFO invoke function error: %x\n",
+ inv_arg.ret);
+ return -EINVAL;
+ }
+
+ ta_rng_data_rate = param[0].u.value.a;
+ optee_rng.quality = param[0].u.value.b;
+
+ return 0;
+}
+
+static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+ if (ver->impl_id == TEE_IMPL_ID_OPTEE)
+ return 1;
+ else
+ return 0;
+}
+
+static int optee_rng_probe(struct device *dev)
+{
+ struct tee_client_device *rng_device = to_tee_client_device(dev);
+ int ret = 0, err = -ENODEV;
+ struct tee_ioctl_open_session_arg sess_arg = {0};
+
+ /* Open context with TEE driver */
+ ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+ if (IS_ERR(ctx))
+ return -ENODEV;
+
+ /* Open session with hwrng Trusted App */
+ memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
+ sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+ sess_arg.num_params = 0;
+
+ ret = tee_client_open_session(ctx, &sess_arg, NULL);
+ if ((ret < 0) || (sess_arg.ret != 0)) {
+ pr_err("tee_client_open_session failed, error: %x\n",
+ sess_arg.ret);
+ err = -EINVAL;
+ goto out_ctx;
+ }
+ ta_rng_session_id = sess_arg.session;
+
+ err = get_optee_rng_info();
+ if (err)
+ goto out_sess;
+
+ err = hwrng_register(&optee_rng);
+ if (err) {
+ pr_err("registering failed (%d)\n", err);
+ goto out_sess;
+ }
+
+ return 0;
+
+out_sess:
+ tee_client_close_session(ctx, ta_rng_session_id);
+out_ctx:
+ tee_client_close_context(ctx);
+
+ return err;
+}
+
+static int optee_rng_remove(struct device *dev)
+{
+ tee_client_close_session(ctx, ta_rng_session_id);
+ tee_client_close_context(ctx);
+ hwrng_unregister(&optee_rng);
+
+ return 0;
+}
+
+const struct tee_client_device_id optee_rng_id_table[] = {
+ {UUID_INIT(0xab7a617c, 0xb8e7, 0x4d8f,
+ 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64)},
+ {}
+};
+
+static struct tee_client_driver optee_rng_driver = {
+ .id_table = optee_rng_id_table,
+ .driver = {
+ .name = DRIVER_NAME,
+ .bus = &tee_bus_type,
+ .probe = optee_rng_probe,
+ .remove = optee_rng_remove,
+ },
+};
+
+static int __init mod_init(void)
+{
+ int rc;
+
+ rc = driver_register(&optee_rng_driver.driver);
+ if (rc)
+ pr_warn("driver registration failed, err: %d", rc);
+
+ return rc;
+}
+
+static void __exit mod_exit(void)
+{
+ driver_unregister(&optee_rng_driver.driver);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sumit Garg <[email protected]>");
+MODULE_DESCRIPTION("OP-TEE based random number generator driver");
--
2.7.4
On Fri, Jan 11, 2019 at 12:52:19PM +0530, Sumit Garg wrote:
> On Thu, 10 Jan 2019 at 19:49, Daniel Thompson
> <[email protected]> wrote:
> > > +static int get_devices(struct tee_context *ctx, u32 session,
> > > + struct tee_shm *device_uuid, u32 *shm_size)
> >
> > Missing const on device_uuid?
> >
>
> I don't think we should have a const for device_uuid here as this is
> shared memory struct pointer which is dynamically allocated and used
> to fetch device UUIDs.
Agree. Perhaps device_uuid is misnamed though (part of the reason I
misread this is that it is singular so I though it was a single UUID
travelling into the TZ).
> > > + rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
> > > + if (rc < 0)
> > > + goto out_shm;
> > > +
> > > + device_uuid = tee_shm_get_va(device_shm, 0);
> > > + if (IS_ERR(device_uuid)) {
> > > + pr_err("tee_shm_get_va failed\n");
> > > + rc = PTR_ERR(device_uuid);
> > > + goto out_shm;
> > > + }
> > > +
> > > + while (idx < shm_size / sizeof(uuid_t)) {
> >
> > This is a very uncommon way to write a for loop ;-).
> >
>
> Ok, will add "num_devices" variable.
num_devices might add readability but that is not what I meant.
The most idiomatic way to write somthing that loops for every valid index
value is:
for (i=0; i < limit; i++)
You wrote it like this:
int idx=0;
/* lots of code between initializer and first use */
while (idx < limit) {
/* more code */
idx++;
}
Sure, they are equivalent but the idiomatic form is easier to read.
Daniel.
On Thu, Jan 10, 2019 at 05:54:54PM +0530, Sumit Garg wrote:
> Introduce a generic TEE bus driver concept for TEE based kernel drivers
> which would like to communicate with TEE based devices/services.
>
> In this TEE bus concept, devices/services are identified via Universally
> Unique Identifier (UUID) and drivers register a table of device UUIDs
> which they can support.
>
> So this TEE bus framework registers a match() callback function which
> iterates over the driver UUID table to find a corresponding match for
> device UUID. If a match is found, then this particular device is probed
> via corresponding probe api registered by the driver. This process
> happens whenever a device or a driver is registered with TEE bus.
>
> Also this framework allows for device enumeration to be specific to
> corresponding TEE implementation like OP-TEE etc.
>
> Signed-off-by: Sumit Garg <[email protected]>
> ---
> drivers/tee/tee_core.c | 41 ++++++++++++++++++++++++++++++++++++++---
> include/linux/tee_drv.h | 36 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 74 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index 7b2bb4c..9ddb89e 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -15,7 +15,6 @@
> #define pr_fmt(fmt) "%s: " fmt, __func__
>
> #include <linux/cdev.h>
> -#include <linux/device.h>
> #include <linux/fs.h>
> #include <linux/idr.h>
> #include <linux/module.h>
> @@ -1027,6 +1026,30 @@ int tee_client_invoke_func(struct tee_context *ctx,
> }
> EXPORT_SYMBOL_GPL(tee_client_invoke_func);
>
> +static int tee_client_device_match(struct device *dev,
> + struct device_driver *drv)
> +{
> + struct tee_client_device *tee_device;
> + const struct tee_client_device_id *id_table;
> +
> + tee_device = to_tee_client_device(dev);
> + id_table = to_tee_client_driver(drv)->id_table;
> +
> + while (!uuid_is_null(&id_table->uuid)) {
> + if (uuid_equal(&tee_device->id.uuid, &id_table->uuid))
> + return 1;
> + id_table++;
> + }
> +
> + return 0;
> +}
> +
> +struct bus_type tee_bus_type = {
> + .name = "tee",
> + .match = tee_client_device_match,
> +};
> +EXPORT_SYMBOL_GPL(tee_bus_type);
> +
> static int __init tee_init(void)
> {
> int rc;
> @@ -1040,10 +1063,21 @@ static int __init tee_init(void)
> rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee");
> if (rc) {
> pr_err("failed to allocate char dev region\n");
> - class_destroy(tee_class);
> - tee_class = NULL;
> + goto class_err;
> }
>
> + rc = bus_register(&tee_bus_type);
> + if (rc) {
> + pr_err("failed to register tee bus\n");
> + goto class_err;
There is an unregister_chrdev_region() in tee_exit(). Why isn't it
needed on this error path?
> + }
> +
> + return 0;
> +
> +class_err:
> + class_destroy(tee_class);
> + tee_class = NULL;
> +
> return rc;
> }
>
> @@ -1052,6 +1086,7 @@ static void __exit tee_exit(void)
> class_destroy(tee_class);
> tee_class = NULL;
> unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
> + bus_unregister(&tee_bus_type);
> }
>
> subsys_initcall(tee_init);
> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
> index 6cfe058..ed16bf1 100644
> --- a/include/linux/tee_drv.h
> +++ b/include/linux/tee_drv.h
> @@ -20,6 +20,8 @@
> #include <linux/kref.h>
> #include <linux/list.h>
> #include <linux/tee.h>
> +#include <linux/device.h>
> +#include <linux/uuid.h>
>
> /*
> * The file describes the API provided by the generic TEE driver to the
> @@ -538,4 +540,38 @@ static inline bool tee_param_is_memref(struct tee_param *param)
> }
> }
>
> +extern struct bus_type tee_bus_type;
> +
> +/**
> + * struct tee_client_device_id - tee based device identifier
> + * @uuid: For TEE based client devices we use the device uuid
> + * as the identifier.
> + */
> +struct tee_client_device_id {
> + uuid_t uuid;
> +};
> +
> +/**
> + * struct tee_client_device - tee based device
> + * @id: device identifier
> + * @dev: device structure
> + */
> +struct tee_client_device {
> + struct tee_client_device_id id;
> + struct device dev;
> +};
> +#define to_tee_client_device(d) container_of(d, struct tee_client_device, dev)
> +
> +/**
> + * struct tee_client_driver - tee client driver
> + * @id_table: device id table supported by this driver
> + * @driver: driver structure
> + */
> +struct tee_client_driver {
> + const struct tee_client_device_id *id_table;
> + struct device_driver driver;
> +};
> +#define to_tee_client_driver(d) \
> + container_of(d, struct tee_client_driver, driver)
> +
> #endif /*__TEE_DRV_H*/
> --
> 2.7.4
>