[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAFA6WYNbwqNqK89ZCWWpAT5HCR59A+J873_5Odyjyb9qu00nsg@mail.gmail.com>
Date: Fri, 22 Apr 2022 12:29:26 +0530
From: Sumit Garg <sumit.garg@...aro.org>
To: Sudeep Holla <sudeep.holla@....com>
Cc: linux-kernel@...r.kernel.org, op-tee@...ts.trustedfirmware.org,
Jens Wiklander <jens.wiklander@...aro.org>,
Balint Dobszay <balint.dobszay@....com>
Subject: Re: [PATCH] tee: Add Arm FF-A TEE driver
Hi Sudeep,
On Fri, 8 Apr 2022 at 19:11, Sudeep Holla <sudeep.holla@....com> wrote:
>
> The Arm FF-A provides mechanism for Linux kernel and modules to
> communicate with the secure partitions. This is useful for some
> Trusted-OS driver that are kernel resident or modules.
>
> We would also like to avoid adding kernel drivers to communicate with
> each and every service provided by these secure partitions. In order to
> achieve the same with FF-A, it would be better to provide user-space
> interface to access the FF-A functionalities. TEE subsystem seems to be
> the best suited to meet those requirements without having to create a
> new solution custom to FF-A alone.
Yeah, this interface sounds interesting.
>
> All FF-A partitions that user-space access can be associated with this
> new FF-A TEE driver and represented by a single TEE device. Though the
> various secure services are generally distributed across multiple secure
> partitions, all of these can be made accessible through this single FF-A
> TEE device.
>
> The minimal functionality needed by the user space application is
> implemented, namely:
> - Query all partition IDs for a specific FF-A UUID
> - Sending synchronous message to a partition
> - Share/unshare buffer with the partition
>
Are there any corresponding user-space applications/libraries
available to get hands-on with this interface?
> Cc: Jens Wiklander <jens.wiklander@...aro.org>
> Cc: Sumit Garg <sumit.garg@...aro.org>
> Co-developed-by: Balint Dobszay <balint.dobszay@....com>
> Signed-off-by: Balint Dobszay <balint.dobszay@....com>
> Signed-off-by: Sudeep Holla <sudeep.holla@....com>
> ---
> drivers/tee/Kconfig | 1 +
> drivers/tee/Makefile | 1 +
> drivers/tee/arm_ffa_tee/Kconfig | 15 +
> drivers/tee/arm_ffa_tee/Makefile | 6 +
> drivers/tee/arm_ffa_tee/core.c | 460 ++++++++++++++++++++++
> drivers/tee/arm_ffa_tee/ffa_tee_private.h | 39 ++
> drivers/tee/arm_ffa_tee/shm_pool.c | 94 +++++
> drivers/tee/arm_ffa_tee/ts_msg.c | 133 +++++++
> drivers/tee/arm_ffa_tee/ts_msg.h | 75 ++++
> include/uapi/linux/arm_ffa_tee.h | 116 ++++++
> include/uapi/linux/tee.h | 1 +
> 11 files changed, 941 insertions(+)
> create mode 100644 drivers/tee/arm_ffa_tee/Kconfig
> create mode 100644 drivers/tee/arm_ffa_tee/Makefile
> create mode 100644 drivers/tee/arm_ffa_tee/core.c
> create mode 100644 drivers/tee/arm_ffa_tee/ffa_tee_private.h
> create mode 100644 drivers/tee/arm_ffa_tee/shm_pool.c
> create mode 100644 drivers/tee/arm_ffa_tee/ts_msg.c
> create mode 100644 drivers/tee/arm_ffa_tee/ts_msg.h
> create mode 100644 include/uapi/linux/arm_ffa_tee.h
>
> Hi All,
>
> This is the initial version of FF-A TEE driver to get the feedback on the
> overall design/approach.
>
> Few TODOs I plan to do before we finalise:
> 1. Need to decouple the driver from few Trusted Service protocols currently
> implemented. I have WIP, but couldn't get all the tests working(yet to
> figure out whether the issue is in driver or tests themselves). Just
> posting it as is to get initial feedback on other areas.
Yes I would be in favor of this.
>
> 2. Based on the way FF-A spec changes/discussions, does it make sense to
> make search based on UUID + partitionID instead of just partitionID or
> leave that for userspace.
IIUC, the UUID is the one identifying the trusted service. So what
purpose does partionID solves for user-space program?
>
> 3. While I definitely want to move the protocol specifics from the driver
> (as mentioned in (1)), do we even try to remove adding UUID of each service
> we would like to use this driver.
Yes, we shouldn't hardcode any UUIDs for trusted services within the
driver (it isn't scalable) but rather during open sessions we should
search if a particular UUID is available on FF-A bus to communicate
with?
> I haven't thought through that yet,
> but the idea I have is to just have a blocked UUID list which can
> contain UUID for OPTEE and other in-kernel users.
> That may need changes in FF-A bus match but something to consider ?
>
Currently in the case of OP-TEE we depend on an open session login
method where the particular trusted application decides whether a
particular login method is allowed or not, refer here [1] for more
details. I guess similar access control checks can be implemented by a
particular trusted service during an open session. This will allow us
to not maintain any allowed or blocked list.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/tee.h#n169
-Sumit
> Regards,
> Sudeep
>
> diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig
> index e99d840c2511..385f46b66bd4 100644
> --- a/drivers/tee/Kconfig
> +++ b/drivers/tee/Kconfig
> @@ -17,6 +17,7 @@ menu "TEE drivers"
>
> source "drivers/tee/optee/Kconfig"
> source "drivers/tee/amdtee/Kconfig"
> +source "drivers/tee/arm_ffa_tee/Kconfig"
> endmenu
>
> endif
> diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile
> index 68da044afbfa..fb7a961665cd 100644
> --- a/drivers/tee/Makefile
> +++ b/drivers/tee/Makefile
> @@ -5,3 +5,4 @@ tee-objs += tee_shm.o
> tee-objs += tee_shm_pool.o
> obj-$(CONFIG_OPTEE) += optee/
> obj-$(CONFIG_AMDTEE) += amdtee/
> +obj-$(CONFIG_ARM_FFA_TEE) += arm_ffa_tee/
> diff --git a/drivers/tee/arm_ffa_tee/Kconfig b/drivers/tee/arm_ffa_tee/Kconfig
> new file mode 100644
> index 000000000000..52e3051c48e0
> --- /dev/null
> +++ b/drivers/tee/arm_ffa_tee/Kconfig
> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +# Arm FF-A Trusted Execution Environment Configuration
> +config ARM_FFA_TEE
> + tristate "ARM FFA TEE"
> + depends on MMU
> + depends on ARM_FFA_TRANSPORT
> + default ARM_FFA_TRANSPORT
> + help
> + This implements the Trusted Execution Environment (TEE) driver
> + based on ARM FF-A.
> +
> + This driver provides user space access to Trusted/Secure services.
> + The implementation extends the TEE subsystem using FF-A compliant
> + messaging between the normal/non-secure and trusted/secure worlds.
> +
> diff --git a/drivers/tee/arm_ffa_tee/Makefile b/drivers/tee/arm_ffa_tee/Makefile
> new file mode 100644
> index 000000000000..e49c6a5927fe
> --- /dev/null
> +++ b/drivers/tee/arm_ffa_tee/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +obj-$(CONFIG_ARM_FFA_TEE) += arm-ffa-tee.o
> +arm-ffa-tee-objs += core.o
> +arm-ffa-tee-objs += shm_pool.o
> +arm-ffa-tee-objs += ts_msg.o
> diff --git a/drivers/tee/arm_ffa_tee/core.c b/drivers/tee/arm_ffa_tee/core.c
> new file mode 100644
> index 000000000000..87150d7cd7a7
> --- /dev/null
> +++ b/drivers/tee/arm_ffa_tee/core.c
> @@ -0,0 +1,460 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022, Arm Limited
> + *
> + * This module implements a TEE driver to enable user space applications to
> + * invoke services deployed in FF-A Secure Partitions.
> + */
> +
> +#include <linux/arm_ffa.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/scatterlist.h>
> +#include <linux/slab.h>
> +#include <linux/stat.h>
> +#include <linux/tee_drv.h>
> +#include <linux/types.h>
> +#include <linux/uaccess.h>
> +#include <uapi/linux/arm_ffa_tee.h>
> +
> +#include "ffa_tee_private.h"
> +#include "ts_msg.h"
> +
> +struct ffa_dev_list {
> + struct ffa_device *ffa_dev;
> + const struct ffa_dev_ops *ffa_ops;
> + struct list_head list_node;
> +};
> +
> +static LIST_HEAD(ffa_devs);
> +/* Protection for the entire list */
> +static DEFINE_MUTEX(ffatee_list_mutex);
> +
> +static struct ffa_dev_list *ffa_tee_get_bound_dev(u16 part_id)
> +{
> + struct ffa_dev_list *tdev, *dev = NULL;
> +
> + mutex_lock(&ffatee_list_mutex);
> + list_for_each_entry(tdev, &ffa_devs, list_node) {
> + if (tdev->ffa_dev->vm_id == part_id) {
> + dev = tdev;
> + break;
> + }
> + }
> + mutex_unlock(&ffatee_list_mutex);
> +
> + return dev;
> +}
> +
> +static void ffa_tee_get_version(struct tee_device *teedev __always_unused,
> + struct tee_ioctl_version_data *vers)
> +{
> + struct tee_ioctl_version_data v = {
> + .impl_id = TEE_IMPL_ID_FFATEE,
> + .impl_caps = 0,
> + .gen_caps = 0,
> + };
> +
> + *vers = v;
> +}
> +
> +static int ffa_tee_open(struct tee_context *ctx)
> +{
> + struct ffa_tee_context_data *ctxdata;
> +
> + ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
> + if (!ctxdata)
> + return -ENOMEM;
> + ctx->data = ctxdata;
> +
> + return 0;
> +}
> +
> +static void ffa_tee_release(struct tee_context *ctx)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> +
> + kfree(ctxdata);
> + ctx->data = NULL;
> +}
> +
> +static int ffa_tee_open_session(struct tee_context *ctx,
> + struct tee_ioctl_open_session_arg *arg,
> + struct tee_param *param)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> + struct ffa_dev_list *dev;
> + u16 part_id;
> +
> + /*
> + * If any of these is set, it means a session is already open in this
> + * context. Return an error because only a single session per context is
> + * allowed, see arm_ffa_tee.h for details.
> + */
> + if (ctxdata->ffa_dev || ctxdata->ffa_ops)
> + return -EBUSY;
> +
> + if (arg->num_params != 1)
> + return -EINVAL;
> +
> + part_id = lower_16_bits(param[0].u.value.a);
> +
> + dev = ffa_tee_get_bound_dev(part_id);
> + if (!dev)
> + return -ENODEV;
> +
> + ctxdata->ffa_dev = dev->ffa_dev;
> + ctxdata->ffa_ops = dev->ffa_ops;
> +
> + return 0;
> +}
> +
> +static int ffa_tee_close_session(struct tee_context *ctx,
> + u32 session __always_unused)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> +
> + ctxdata->ffa_dev = NULL;
> + ctxdata->ffa_ops = NULL;
> +
> + return 0;
> +}
> +
> +static int ffa_tee_list_part(struct tee_context *ctx __always_unused,
> + struct tee_ioctl_invoke_arg *arg,
> + struct tee_param *param)
> +{
> + const struct ffa_dev_list *dev = NULL;
> + u8 uuid_buf[UUID_SIZE] = {};
> + uuid_t uuid;
> + u16 __user *ubuf;
> + size_t ubuf_max_cnt, cnt = 0;
> + u16 part_id;
> +
> + if (arg->num_params != 2)
> + return -EINVAL;
> +
> + memcpy(&uuid_buf[0], ¶m[0].u.value.a, 8);
> + memcpy(&uuid_buf[8], ¶m[0].u.value.b, 8);
> + import_uuid(&uuid, uuid_buf);
> +
> + ubuf = u64_to_user_ptr(param[1].u.value.a);
> + ubuf_max_cnt = (size_t)param[1].u.value.b;
> +
> + if (!ubuf || !ubuf_max_cnt || !IS_ALIGNED((uintptr_t)ubuf, sizeof(u16)))
> + return -EINVAL;
> +
> + /*
> + * Copy partition IDs to user space buffer until the buffer is full or
> + * all IDs have been copied.
> + */
> + mutex_lock(&ffatee_list_mutex);
> + list_for_each_entry(dev, &ffa_devs, list_node) {
> + if (uuid_equal(&uuid, &dev->ffa_dev->uuid)) {
> + part_id = lower_16_bits(dev->ffa_dev->vm_id);
> + if (put_user(part_id, ubuf)) {
> + mutex_unlock(&ffatee_list_mutex);
> + return -EFAULT;
> + }
> +
> + ubuf++;
> + cnt++;
> +
> + if (cnt >= ubuf_max_cnt) {
> + /* Buffer too short, there might be more IDs */
> + param[1].u.value.b = 1;
> + goto out;
> + }
> + }
> + }
> + /* No more IDs, buffer was long enough */
> + param[1].u.value.b = 0;
> +
> +out:
> + param[1].u.value.a = cnt;
> + mutex_unlock(&ffatee_list_mutex);
> + return 0;
> +}
> +
> +static int ffa_tee_invoke_func(struct tee_context *ctx,
> + struct tee_ioctl_invoke_arg *arg,
> + struct tee_param *param)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> + int rc;
> +
> + switch (arg->func) {
> + case CMD_GET_PARTITION_LIST:
> + rc = ffa_tee_list_part(ctx, arg, param);
> + break;
> + case CMD_SEND_MSG:
> + /* Check that a session has been opened */
> + if (!ctxdata->ffa_dev || !ctxdata->ffa_ops)
> + return -EINVAL;
> +
> + if (is_ts_protocol(&ctxdata->ffa_dev->uuid)) {
> + rc = ts_msg_sync_send_recv(ctx, arg, param);
> + } else {
> + pr_err("%s protocol not implemented for UUID: %pUb\n",
> + __func__, &ctxdata->ffa_dev->uuid);
> + rc = -EINVAL;
> + }
> + break;
> + default:
> + rc = -EINVAL;
> + break;
> + }
> +
> + return rc;
> +}
> +
> +static int ffa_tee_cancel_req(struct tee_context *ctx __always_unused,
> + u32 cancel_id __always_unused,
> + u32 session __always_unused)
> +{
> + return -EINVAL;
> +}
> +
> +int ffa_tee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
> + struct page **pages, size_t num_pages,
> + unsigned long start __always_unused)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> + struct ffa_mem_region_attributes mem_attr = {
> + .attrs = FFA_MEM_RW,
> + .flag = 0,
> + };
> + struct ffa_mem_ops_args args = {
> + .attrs = &mem_attr,
> + .flags = 0,
> + .nattrs = 1,
> + .use_txbuf = true,
> + };
> + struct sg_table sgt;
> + int rc;
> +
> + /* Check that a session has been opened */
> + if (!ctxdata->ffa_dev || !ctxdata->ffa_ops)
> + return -EINVAL;
> +
> + mem_attr.receiver = ctxdata->ffa_dev->vm_id;
> +
> + rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, 0,
> + num_pages * PAGE_SIZE, GFP_KERNEL);
> + if (rc)
> + return rc;
> +
> + args.sg = sgt.sgl;
> + rc = ctxdata->ffa_ops->memory_share(ctxdata->ffa_dev, &args);
> + sg_free_table(&sgt);
> + if (rc)
> + return rc;
> +
> + shm->sec_world_id = args.g_handle;
> +
> + if (is_ts_protocol(&ctxdata->ffa_dev->uuid)) {
> + rc = ts_msg_shm_share(ctx, shm);
> + } else {
> + pr_err("%s: protocol not implemented for UUID: %pUb\n",
> + __func__, &ctxdata->ffa_dev->uuid);
> + rc = -EINVAL;
> + }
> +
> + if (rc)
> + ctxdata->ffa_ops->memory_reclaim(shm->sec_world_id, 0);
> +
> + return rc;
> +}
> +
> +int ffa_tee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> + int rc;
> +
> + /* Check that a session has been opened */
> + if (!ctxdata->ffa_dev || !ctxdata->ffa_ops)
> + return -EINVAL;
> +
> + if (is_ts_protocol(&ctxdata->ffa_dev->uuid)) {
> + rc = ts_msg_shm_reclaim(ctx, shm);
> + } else {
> + pr_err("%s: protocol not implemented for UUID: %pUb\n",
> + __func__, &ctxdata->ffa_dev->uuid);
> + rc = -EINVAL;
> + }
> +
> + if (rc)
> + return rc;
> +
> + rc = ctxdata->ffa_ops->memory_reclaim(shm->sec_world_id, 0);
> +
> + return rc;
> +}
> +
> +static const struct tee_driver_ops ffa_tee_ops = {
> + .get_version = ffa_tee_get_version,
> + .open = ffa_tee_open,
> + .release = ffa_tee_release,
> + .open_session = ffa_tee_open_session,
> + .close_session = ffa_tee_close_session,
> + .invoke_func = ffa_tee_invoke_func,
> + .cancel_req = ffa_tee_cancel_req,
> + .shm_register = ffa_tee_shm_register,
> + .shm_unregister = ffa_tee_shm_unregister,
> +};
> +
> +static const struct tee_desc ffa_tee_desc = {
> + .name = "ffa-tee-client",
> + .ops = &ffa_tee_ops,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct ffa_tee *ffa_tee;
> +
> +static void ffa_tee_deinit_common(void)
> +{
> + tee_device_unregister(ffa_tee->teedev);
> + if (ffa_tee->pool)
> + tee_shm_pool_free(ffa_tee->pool);
> + kfree(ffa_tee);
> +}
> +
> +static int ffa_tee_init(void)
> +{
> + int rc;
> +
> + ffa_tee = kzalloc(sizeof(*ffa_tee), GFP_KERNEL);
> + if (!ffa_tee)
> + return -ENOMEM;
> +
> + ffa_tee->pool = ffa_tee_create_shm_pool();
> + if (IS_ERR(ffa_tee->pool)) {
> + rc = PTR_ERR(ffa_tee->pool);
> + ffa_tee->pool = NULL;
> + goto err;
> + }
> +
> + ffa_tee->teedev = tee_device_alloc(&ffa_tee_desc, NULL, ffa_tee->pool,
> + ffa_tee);
> + if (IS_ERR(ffa_tee->teedev)) {
> + rc = PTR_ERR(ffa_tee->teedev);
> + ffa_tee->teedev = NULL;
> + goto err;
> + }
> +
> + rc = tee_device_register(ffa_tee->teedev);
> + if (rc)
> + goto err;
> +
> + return 0;
> +
> +err:
> + ffa_tee_deinit_common();
> + return rc;
> +}
> +
> +static void ffa_tee_deinit(void)
> +{
> + if (ffa_tee)
> + ffa_tee_deinit_common();
> +}
> +
> +/* FF-A client driver initialization */
> +static int ffa_tee_probe(struct ffa_device *ffa_dev)
> +{
> + struct ffa_dev_list *dev;
> +
> + dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> + if (!dev)
> + return -ENOMEM;
> +
> + dev->ffa_dev = ffa_dev;
> + dev->ffa_ops = ffa_dev_ops_get(ffa_dev);
> +
> + /* Trusted Services SPs use 32-bit direct messaging */
> + if (is_ts_protocol(&ffa_dev->uuid))
> + dev->ffa_ops->mode_32bit_set(ffa_dev);
> +
> + mutex_lock(&ffatee_list_mutex);
> + list_add(&dev->list_node, &ffa_devs);
> + mutex_unlock(&ffatee_list_mutex);
> +
> + return 0;
> +}
> +
> +static void ffa_tee_remove(struct ffa_device *ffa_dev)
> +{
> + struct ffa_dev_list *dev, *dev_tmp;
> +
> + mutex_lock(&ffatee_list_mutex);
> + list_for_each_entry_safe(dev, dev_tmp, &ffa_devs, list_node) {
> + if (dev->ffa_dev == ffa_dev) {
> + list_del(&dev->list_node);
> + kfree(dev);
> + }
> + }
> + mutex_unlock(&ffatee_list_mutex);
> +}
> +
> +static const struct ffa_device_id ffa_tee_device_ids[] = {
> + /* TS RPC protocol UUID: bdcd76d7-825e-4751-963b-86d4f84943ac */
> + { TS_RPC_UUID },
> + /* PSA Crypto SP UUID: d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0 */
> + { PSA_CRYPTO_SP_UUID },
> + /* PSA ITS SP UUID: dc1eef48-b17a-4ccf-ac8b-dfcff7711b14 */
> + { PSA_ITS_SP_UUID },
> + /* PSA PS SP UUID: 751bf801-3dde-4768-a514-0f10aeed1790 */
> + { PSA_PS_SP_UUID },
> + /* PSA Attestation SP UUID: a1baf155-8876-4695-8f7c-54955e8db974 */
> + { PSA_IAT_SP_UUID },
> + {}
> +};
> +
> +static struct ffa_driver ffa_tee_driver = {
> + .name = "arm_ffa_tee",
> + .probe = ffa_tee_probe,
> + .remove = ffa_tee_remove,
> + .id_table = ffa_tee_device_ids,
> +};
> +
> +static int __init ffa_tee_mod_init(void)
> +{
> + int rc;
> +
> + if (!IS_REACHABLE(CONFIG_TEE) ||
> + !IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT))
> + return -EOPNOTSUPP;
> +
> + rc = ffa_register(&ffa_tee_driver);
> + if (rc)
> + return rc;
> +
> + rc = ffa_tee_init();
> + if (rc)
> + ffa_unregister(&ffa_tee_driver);
> +
> + return rc;
> +}
> +module_init(ffa_tee_mod_init)
> +
> +static void __exit ffa_tee_mod_exit(void)
> +{
> + if (IS_REACHABLE(CONFIG_TEE))
> + ffa_tee_deinit();
> +
> + if (IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT))
> + ffa_unregister(&ffa_tee_driver);
> +}
> +module_exit(ffa_tee_mod_exit)
> +
> +MODULE_ALIAS("arm-ffa-tee");
> +MODULE_AUTHOR("Balint Dobszay <balint.dobszay@....com>");
> +MODULE_AUTHOR("Sudeep Holla <sudeep.holla@....com>");
> +MODULE_DESCRIPTION("Arm FF-A TEE driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("1.0.0");
> diff --git a/drivers/tee/arm_ffa_tee/ffa_tee_private.h b/drivers/tee/arm_ffa_tee/ffa_tee_private.h
> new file mode 100644
> index 000000000000..e37fe51adb8d
> --- /dev/null
> +++ b/drivers/tee/arm_ffa_tee/ffa_tee_private.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2022, Arm Limited
> + */
> +
> +#ifndef FFA_TEE_PRIVATE_H
> +#define FFA_TEE_PRIVATE_H
> +
> +#include <linux/arm_ffa.h>
> +#include <linux/tee_drv.h>
> +
> +/**
> + * struct ffa_tee - Main struct describing this TEE driver
> + * @teedev TEE device allocated and registered by the driver
> + * @pool Dynamic shared memory pool for the TEE device
> + */
> +struct ffa_tee {
> + struct tee_device *teedev;
> + struct tee_shm_pool *pool;
> +};
> +
> +/**
> + * struct ffa_tee_context_data - Context information
> + * @ffa_dev FF-A device selected for this context
> + * @ffa_ops FF-A operations of the device
> + */
> +struct ffa_tee_context_data {
> + struct ffa_device *ffa_dev;
> + const struct ffa_dev_ops *ffa_ops;
> +};
> +
> +int ffa_tee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
> + struct page **pages, size_t num_pages,
> + unsigned long start);
> +int ffa_tee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm);
> +
> +struct tee_shm_pool *ffa_tee_create_shm_pool(void);
> +
> +#endif /* FFA_TEE_PRIVATE_H */
> diff --git a/drivers/tee/arm_ffa_tee/shm_pool.c b/drivers/tee/arm_ffa_tee/shm_pool.c
> new file mode 100644
> index 000000000000..7c3a20ea07d3
> --- /dev/null
> +++ b/drivers/tee/arm_ffa_tee/shm_pool.c
> @@ -0,0 +1,94 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022, Arm Limited
> + */
> +
> +#include <linux/arm_ffa.h>
> +#include <linux/device.h>
> +#include <linux/dma-buf.h>
> +#include <linux/genalloc.h>
> +#include <linux/slab.h>
> +#include <linux/tee_drv.h>
> +
> +#include "ffa_tee_private.h"
> +
> +/*
> + * This file implements a dynamic shared memory pool. It's used by the TEE
> + * subsystem to allocate kernel memory to be shared with the SWd as part of the
> + * TEE_IOC_SHM_ALLOC call.
> + */
> +
> +static int pool_op_alloc(struct tee_shm_pool *pool __always_unused,
> + struct tee_shm *shm, size_t size, size_t align)
> +{
> + unsigned int order, nr_pages, i;
> + struct page *page, **pages;
> + int rc;
> +
> + if (size == 0)
> + return -EINVAL;
> +
> + order = get_order(size);
> + nr_pages = 1 << order;
> +
> + page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
> + if (!page)
> + return -ENOMEM;
> +
> + shm->kaddr = page_address(page);
> + shm->paddr = page_to_phys(page);
> + shm->size = PAGE_SIZE << order;
> +
> + pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL);
> + if (!pages) {
> + rc = -ENOMEM;
> + goto err;
> + }
> +
> + for (i = 0; i < nr_pages; i++)
> + pages[i] = page + i;
> +
> + shm->flags |= TEE_SHM_DYNAMIC;
> + rc = ffa_tee_shm_register(shm->ctx, shm, pages, nr_pages,
> + (unsigned long)shm->kaddr);
> + kfree(pages);
> + if (rc)
> + goto err;
> +
> + return 0;
> +
> +err:
> + __free_pages(page, order);
> + return rc;
> +}
> +
> +static void pool_op_free(struct tee_shm_pool *pool __always_unused,
> + struct tee_shm *shm)
> +{
> + ffa_tee_shm_unregister(shm->ctx, shm);
> + free_pages((unsigned long)shm->kaddr, get_order(shm->size));
> + shm->kaddr = NULL;
> +}
> +
> +static void pool_op_destroy_pool(struct tee_shm_pool *pool)
> +{
> + kfree(pool);
> +}
> +
> +static const struct tee_shm_pool_ops pool_ops = {
> + .alloc = pool_op_alloc,
> + .free = pool_op_free,
> + .destroy_pool = pool_op_destroy_pool,
> +};
> +
> +struct tee_shm_pool *ffa_tee_create_shm_pool(void)
> +{
> + struct tee_shm_pool *pool = kzalloc(sizeof(*pool), GFP_KERNEL);
> +
> + if (!pool)
> + return ERR_PTR(-ENOMEM);
> +
> + pool->ops = &pool_ops;
> +
> + return pool;
> +}
> diff --git a/drivers/tee/arm_ffa_tee/ts_msg.c b/drivers/tee/arm_ffa_tee/ts_msg.c
> new file mode 100644
> index 000000000000..c8f8e6292cd6
> --- /dev/null
> +++ b/drivers/tee/arm_ffa_tee/ts_msg.c
> @@ -0,0 +1,133 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022, Arm Limited
> + */
> +
> +#include <linux/arm_ffa.h>
> +#include <linux/kernel.h>
> +#include <linux/tee_drv.h>
> +#include <linux/types.h>
> +#include <linux/uuid.h>
> +
> +#include "ffa_tee_private.h"
> +#include "ts_msg.h"
> +
> +/*
> + * This file implements the message sending and shared memory handling callbacks
> + * using the Trusted Services RPC protocol.
> + */
> +
> +bool is_ts_protocol(uuid_t *uuid)
> +{
> + return (uuid_equal(uuid, &TS_RPC_UUID) ||
> + uuid_equal(uuid, &PSA_CRYPTO_SP_UUID) ||
> + uuid_equal(uuid, &PSA_ITS_SP_UUID) ||
> + uuid_equal(uuid, &PSA_PS_SP_UUID) ||
> + uuid_equal(uuid, &PSA_IAT_SP_UUID));
> +}
> +
> +static void arg_list_to_ffa_data(const u32 *args,
> + struct ffa_send_direct_data *data)
> +{
> + data->data0 = args[0];
> + data->data1 = args[1];
> + data->data2 = args[2];
> + data->data3 = args[3];
> + data->data4 = args[4];
> +}
> +
> +static void arg_list_from_ffa_data(const struct ffa_send_direct_data *data,
> + u32 *args)
> +{
> + args[0] = lower_32_bits(data->data0);
> + args[1] = lower_32_bits(data->data1);
> + args[2] = lower_32_bits(data->data2);
> + args[3] = lower_32_bits(data->data3);
> + args[4] = lower_32_bits(data->data4);
> +}
> +
> +int ts_msg_sync_send_recv(struct tee_context *ctx,
> + struct tee_ioctl_invoke_arg *arg,
> + struct tee_param *param)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> + struct ffa_send_direct_data data;
> + u16 iface, opcode;
> + u32 args[5] = {};
> + int rc;
> +
> + if (arg->num_params != 1)
> + return -EINVAL;
> +
> + iface = upper_16_bits(param[0].u.value.a);
> + opcode = lower_16_bits(param[0].u.value.a);
> +
> + args[TS_MSG_IFACE_ID_OPCODE] = TS_MSG_ADD_IFACE_OPCODE(iface, opcode);
> + args[TS_MSG_REQ_DATA_LEN] = param[0].u.value.b;
> + args[TS_MSG_ENCODING] = param[0].u.value.c;
> + args[TS_MSG_CALLER_ID] = 0;
> +
> + arg_list_to_ffa_data(args, &data);
> + rc = ctxdata->ffa_ops->sync_send_receive(ctxdata->ffa_dev, &data);
> + if (rc)
> + return rc;
> + arg_list_from_ffa_data(&data, args);
> +
> + param[0].u.value.a = args[TS_MSG_RESP_DATA_LEN];
> + param[0].u.value.b = (u64)args[TS_MSG_RESP_RPC_STATUS] << 32;
> + param[0].u.value.b |= args[TS_MSG_RESP_OP_STATUS];
> + param[0].u.value.c = 0;
> +
> + return 0;
> +}
> +
> +int ts_msg_shm_share(struct tee_context *ctx, struct tee_shm *shm)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> + struct ffa_send_direct_data data;
> + u32 args[5] = {};
> + int rc;
> +
> + args[TS_MSG_IFACE_ID_OPCODE] =
> + TS_MSG_ADD_IFACE_OPCODE(TS_MSG_MGMT_IFACE_ID, TS_MSG_OPCODE_SHARE_MEM);
> + args[TS_MSG_SHARE_MEM_HANDLE_LSW] = lower_32_bits(shm->sec_world_id);
> + args[TS_MSG_SHARE_MEM_HANDLE_MSW] = upper_32_bits(shm->sec_world_id);
> + args[TS_MSG_SHARE_MEM_SIZE] = shm->size;
> +
> + arg_list_to_ffa_data(args, &data);
> + rc = ctxdata->ffa_ops->sync_send_receive(ctxdata->ffa_dev, &data);
> + if (rc)
> + return rc;
> + arg_list_from_ffa_data(&data, args);
> +
> + /* Management call response only sets RPC status field */
> + if (args[TS_MSG_RESP_RPC_STATUS] != 0)
> + return (int)args[TS_MSG_RESP_RPC_STATUS];
> +
> + return 0;
> +}
> +
> +int ts_msg_shm_reclaim(struct tee_context *ctx, struct tee_shm *shm)
> +{
> + struct ffa_tee_context_data *ctxdata = ctx->data;
> + struct ffa_send_direct_data data;
> + u32 args[5] = {};
> + int rc;
> +
> + args[TS_MSG_IFACE_ID_OPCODE] =
> + TS_MSG_ADD_IFACE_OPCODE(TS_MSG_MGMT_IFACE_ID, TS_MSG_OPCODE_UNSHARE_MEM);
> + args[TS_MSG_SHARE_MEM_HANDLE_LSW] = lower_32_bits(shm->sec_world_id);
> + args[TS_MSG_SHARE_MEM_HANDLE_MSW] = upper_32_bits(shm->sec_world_id);
> +
> + arg_list_to_ffa_data(args, &data);
> + rc = ctxdata->ffa_ops->sync_send_receive(ctxdata->ffa_dev, &data);
> + if (rc)
> + return rc;
> + arg_list_from_ffa_data(&data, args);
> +
> + /* Management call response only sets RPC status field */
> + if (args[TS_MSG_RESP_RPC_STATUS] != 0)
> + return (int)args[TS_MSG_RESP_RPC_STATUS];
> +
> + return 0;
> +}
> diff --git a/drivers/tee/arm_ffa_tee/ts_msg.h b/drivers/tee/arm_ffa_tee/ts_msg.h
> new file mode 100644
> index 000000000000..de5c9218a790
> --- /dev/null
> +++ b/drivers/tee/arm_ffa_tee/ts_msg.h
> @@ -0,0 +1,75 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2022, Arm Limited
> + */
> +
> +#ifndef TS_MSG_H
> +#define TS_MSG_H
> +
> +/*
> + * Defines convention for use of FF-A direct call arguments by Trusted Services.
> + */
> +
> +/* UUID of this protocol */
> +#define TS_RPC_UUID UUID_INIT(0xbdcd76d7, 0x825e, 0x4751, \
> + 0x96, 0x3b, 0x86, 0xd4, 0xf8, 0x49, 0x43, 0xac)
> +
> +/* Macros for parameters carried in a single register */
> +#define TS_MSG_ADD_IFACE_OPCODE(i, o) (((i) << 16) | ((o) & 0xffff))
> +#define TS_MSG_EXTRACT_IFACE(reg) ((reg) >> 16)
> +#define TS_MSG_EXTRACT_OPCODE(reg) ((reg) & 0xffff)
> +
> +/*
> + * If SPs are built with FF-A Routing Extension enabled, this should be 1.
> + * Otherwise it should be 0.
> + */
> +#define FFARE_OFFSET (1)
> +
> +/* Common req & resp arg offests */
> +#define TS_MSG_IFACE_ID_OPCODE (0 + FFARE_OFFSET)
> +
> +/* Req arg offsets */
> +#define TS_MSG_REQ_DATA_LEN (1 + FFARE_OFFSET)
> +#define TS_MSG_CALLER_ID (2 + FFARE_OFFSET)
> +#define TS_MSG_ENCODING (3 + FFARE_OFFSET)
> +
> +/* Resp arg offsets */
> +#define TS_MSG_RESP_DATA_LEN (1 + FFARE_OFFSET)
> +#define TS_MSG_RESP_RPC_STATUS (2 + FFARE_OFFSET)
> +#define TS_MSG_RESP_OP_STATUS (3 + FFARE_OFFSET)
> +
> +/* Share/unshare buffer offsets */
> +#define TS_MSG_SHARE_MEM_HANDLE_LSW (1 + FFARE_OFFSET)
> +#define TS_MSG_SHARE_MEM_HANDLE_MSW (2 + FFARE_OFFSET)
> +#define TS_MSG_SHARE_MEM_SIZE (3 + FFARE_OFFSET)
> +
> +/* Interface ID for the FF-A based RPC layer for management operations */
> +#define TS_MSG_MGMT_IFACE_ID (0x1000)
> +
> +/* Common opcodes used by the FF-A based RPC layer for management operations */
> +#define TS_MSG_OPCODE_SHARE_MEM (0)
> +#define TS_MSG_OPCODE_UNSHARE_MEM (1)
> +
> +/*
> + * Currently all PSA SPs use the same protocol, but have dedicated UUIDs instead
> + * of using the common protocol UUID. All UUIDs listed here should be treated as
> + * having the same protocol. These will be removed later when the rest of the
> + * components are updated.
> + */
> +#define PSA_CRYPTO_SP_UUID UUID_INIT(0xd9df52d5, 0x16a2, 0x4bb2, \
> + 0x9a, 0xa4, 0xd2, 0x6d, 0x3b, 0x84, 0xe8, 0xc0)
> +#define PSA_ITS_SP_UUID UUID_INIT(0xdc1eef48, 0xb17a, 0x4ccf, \
> + 0xac, 0x8b, 0xdf, 0xcf, 0xf7, 0x71, 0x1b, 0x14)
> +#define PSA_PS_SP_UUID UUID_INIT(0x751bf801, 0x3dde, 0x4768, \
> + 0xa5, 0x14, 0x0f, 0x10, 0xae, 0xed, 0x17, 0x90)
> +#define PSA_IAT_SP_UUID UUID_INIT(0xa1baf155, 0x8876, 0x4695, \
> + 0x8f, 0x7c, 0x54, 0x95, 0x5e, 0x8d, 0xb9, 0x74)
> +
> +bool is_ts_protocol(uuid_t *uuid);
> +int ts_msg_sync_send_recv(struct tee_context *ctx,
> + struct tee_ioctl_invoke_arg *arg,
> + struct tee_param *param);
> +int ts_msg_shm_share(struct tee_context *ctx, struct tee_shm *shm);
> +int ts_msg_shm_reclaim(struct tee_context *ctx, struct tee_shm *shm);
> +
> +#endif /* TS_MSG_H */
> diff --git a/include/uapi/linux/arm_ffa_tee.h b/include/uapi/linux/arm_ffa_tee.h
> new file mode 100644
> index 000000000000..c2ce1360a190
> --- /dev/null
> +++ b/include/uapi/linux/arm_ffa_tee.h
> @@ -0,0 +1,116 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020-2021, Arm Limited
> + */
> +
> +#ifndef ARM_FFA_TEE_H
> +#define ARM_FFA_TEE_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * Some of the TEE ioctl calls don't have a parameter where the destination
> + * partition ID could be passed. To workaround this, first the partition ID has
> + * to be set in the context. This can be done using the open session ioctl.
> + * Currently this call doesn't invoke the SWd, i.e. there is no "real" session
> + * opened that should be registered in the SWd. It's only used to store the
> + * destination partition ID so subsequent calls can use it.
> + *
> + * Prior to calling open session, only one type of call is allowed:
> + * CMD_GET_PARTITION_LIST, because this doesn't invoke the SWd.
> + *
> + * For TEE_IOC_OPEN_SESSION. In tee_ioctl_open_session_arg:
> + * - num_params is 1,
> + * - rest of the fields is empty.
> + *
> + * Parameter encoding:
> + * param[0]:
> + * - attr: TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT
> + * - a: destination partition ID (u16)
> + * - b: 0
> + * - c: 0
> + */
> +
> +/*
> + * This command is for querying the list of partitions with a matching UUID.
> + *
> + * This is not the same as a generic FF-A discovery call. The PARTITION_INFO_GET
> + * call is done by the FF-A driver and only the devices compatible with this
> + * driver (i.e. listed in this module's .id_table) are bound to this driver.
> + * This command searches the list of these bound devices looking for matching
> + * UUIDs and writes the corresponding partition IDs into the supplied buffer.
> + * It can (should) be called before TEE_IOC_OPEN_SESSION, to find the desired
> + * destination partition ID.
> + *
> + * Use with TEE_IOC_INVOKE. In tee_ioctl_invoke_arg:
> + * - func is CMD_GET_PARTITION_LIST,
> + * - num_params is 2,
> + * - rest of the fields is empty.
> + *
> + * Parameter encoding:
> + * param[0]:
> + * - attr: TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT
> + * - a: first 8 bytes of the FF-A UUID (big-endian)
> + * - b: last 8 bytes of the FF-A UUID (big-endian)
> + * - c: 0
> + *
> + * param[1]:
> + * - attr: TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT
> + * - a: address of partition ID list (array of u16)
> + * - b: max number of partition IDs in list (number of elements in array)
> + * - c: 0
> + *
> + * Return parameter encoding:
> + * param[0]: input only
> + *
> + * param[1]:
> + * - a: number of IDs returned in the list
> + * - b: 0 if all possible IDs are returned
> + * 1 if there might be more (buffer was too short)
> + * - c: 0
> + */
> +#define CMD_GET_PARTITION_LIST (1)
> +
> +/*
> + * This command is for sending a message to a Secure Partition.
> + *
> + * The parameter encoding and implementation of this command depends on the ABI
> + * implemented by the SP (i.e. how it interprets the arguments of an FF-A direct
> + * request message). Currently the only implementation available in the driver
> + * is the Trusted Services RPC protocol, but other protocols can be added in the
> + * future.
> + * The following description is specific to the Trusted Services RPC protocol.
> + *
> + * Use with TEE_IOC_INVOKE. In tee_ioctl_invoke_arg:
> + * - func is CMD_SEND_MSG,
> + * - num_params is 1,
> + * - rest of the fields is empty.
> + *
> + * Parameter encoding:
> + * param[0]:
> + * - attr: TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT
> + * - a: interface ID | opcode
> + * - b: request length
> + * - c: encoding
> + *
> + * Return parameter encoding:
> + * param[0]:
> + * - a: response length
> + * - b: RPC status | operation status
> + * - c: 0
> + */
> +#define CMD_SEND_MSG (2)
> +
> +#define CMD_SEND_MSG_PARAM_A(iface, opcode) ((__u64)( \
> + (((__u32)(iface) & (__u32)0x0000ffffUL) << 16) | \
> + ((__u32)(opcode) & (__u32)0x0000ffffUL)))
> +#define CMD_SEND_MSG_PARAM_B(req_len) ((__u32)(req_len))
> +#define CMD_SEND_MSG_PARAM_C(encoding) ((__u32)(encoding))
> +
> +#define CMD_SEND_MSG_RESP_LEN(param_a) ((__u32)(param_a))
> +#define CMD_SEND_MSG_RPC_STATUS(param_b) \
> + ((__s32)(((param_b) >> 32) & (__u32)0xffffffffUL))
> +#define CMD_SEND_MSG_OP_STATUS(param_b) \
> + ((__s32)((param_b) & (__u32)0xffffffffUL))
> +
> +#endif /* ARM_FFA_TEE_H */
> diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h
> index 25a6c534beb1..4455a5b1a923 100644
> --- a/include/uapi/linux/tee.h
> +++ b/include/uapi/linux/tee.h
> @@ -60,6 +60,7 @@
> */
> #define TEE_IMPL_ID_OPTEE 1
> #define TEE_IMPL_ID_AMDTEE 2
> +#define TEE_IMPL_ID_FFATEE 3
>
> /*
> * OP-TEE specific capabilities
> --
> 2.35.1
>
Powered by blists - more mailing lists