diff options
28 files changed, 1095 insertions, 389 deletions
diff --git a/Documentation/tee/index.rst b/Documentation/tee/index.rst index a23bd08847e5..4be6e69d7837 100644 --- a/Documentation/tee/index.rst +++ b/Documentation/tee/index.rst @@ -10,6 +10,7 @@ TEE Subsystem tee op-tee amd-tee + ts-tee .. only:: subproject and html diff --git a/Documentation/tee/ts-tee.rst b/Documentation/tee/ts-tee.rst new file mode 100644 index 000000000000..843e34422648 --- /dev/null +++ b/Documentation/tee/ts-tee.rst @@ -0,0 +1,71 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================= +TS-TEE (Trusted Services project) +================================= + +This driver provides access to secure services implemented by Trusted Services. + +Trusted Services [1] is a TrustedFirmware.org project that provides a framework +for developing and deploying device Root of Trust services in FF-A [2] S-EL0 +Secure Partitions. The project hosts the reference implementation of the Arm +Platform Security Architecture [3] for Arm A-profile devices. + +The FF-A Secure Partitions (SP) are accessible through the FF-A driver [4] which +provides the low level communication for this driver. On top of that the Trusted +Services RPC protocol is used [5]. To use the driver from user space a reference +implementation is provided at [6], which is part of the Trusted Services client +library called libts [7]. + +All Trusted Services (TS) SPs have the same FF-A UUID; it identifies the TS RPC +protocol. A TS SP can host one or more services (e.g. PSA Crypto, PSA ITS, etc). +A service is identified by its service UUID; the same type of service cannot be +present twice in the same SP. During SP boot each service in the SP is assigned +an "interface ID". This is just a short ID to simplify message addressing. + +The generic TEE design is to share memory at once with the Trusted OS, which can +then be reused to communicate with multiple applications running on the Trusted +OS. However, in case of FF-A, memory sharing works on an endpoint level, i.e. +memory is shared with a specific SP. User space has to be able to separately +share memory with each SP based on its endpoint ID; therefore a separate TEE +device is registered for each discovered TS SP. Opening the SP corresponds to +opening the TEE device and creating a TEE context. A TS SP hosts one or more +services. Opening a service corresponds to opening a session in the given +tee_context. + +Overview of a system with Trusted Services components:: + + User space Kernel space Secure world + ~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~ + +--------+ +-------------+ + | Client | | Trusted | + +--------+ | Services SP | + /\ +-------------+ + || /\ + || || + || || + \/ \/ + +-------+ +----------+--------+ +-------------+ + | libts | | TEE | TS-TEE | | FF-A SPMC | + | | | subsys | driver | | + SPMD | + +-------+----------------+----+-----+--------+-----------+-------------+ + | Generic TEE API | | FF-A | TS RPC protocol | + | IOCTL (TEE_IOC_*) | | driver | over FF-A | + +-----------------------------+ +--------+-------------------------+ + +References +========== + +[1] https://www.trustedfirmware.org/projects/trusted-services/ + +[2] https://developer.arm.com/documentation/den0077/ + +[3] https://www.arm.com/architecture/security-features/platform-security + +[4] drivers/firmware/arm_ffa/ + +[5] https://trusted-services.readthedocs.io/en/v1.0.0/developer/service-access-protocols.html#abi + +[6] https://git.trustedfirmware.org/TS/trusted-services.git/tree/components/rpc/ts_rpc/caller/linux/ts_rpc_caller_linux.c?h=v1.0.0 + +[7] https://git.trustedfirmware.org/TS/trusted-services.git/tree/deployments/libts/arm-linux/CMakeLists.txt?h=v1.0.0 diff --git a/MAINTAINERS b/MAINTAINERS index 90da6cc39b6a..b6f2b6e92961 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21753,6 +21753,7 @@ F: Documentation/driver-api/tee.rst F: Documentation/tee/ F: Documentation/userspace-api/tee.rst F: drivers/tee/ +F: include/linux/tee_core.h F: include/linux/tee_drv.h F: include/uapi/linux/tee.h @@ -22546,6 +22547,15 @@ F: Documentation/ABI/testing/configfs-tsm F: drivers/virt/coco/tsm.c F: include/linux/tsm.h +TRUSTED SERVICES TEE DRIVER +M: Balint Dobszay <balint.dobszay@arm.com> +M: Sudeep Holla <sudeep.holla@arm.com> +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: trusted-services@lists.trustedfirmware.org +S: Maintained +F: Documentation/tee/ts-tee.rst +F: drivers/tee/tstee/ + TTY LAYER AND SERIAL DRIVERS M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> M: Jiri Slaby <jirislaby@kernel.org> diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig index 73a147202e88..61b507c18780 100644 --- a/drivers/tee/Kconfig +++ b/drivers/tee/Kconfig @@ -15,5 +15,6 @@ if TEE source "drivers/tee/optee/Kconfig" source "drivers/tee/amdtee/Kconfig" +source "drivers/tee/tstee/Kconfig" endif diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index 68da044afbfa..5488cba30bd2 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_TSTEE) += tstee/ diff --git a/drivers/tee/amdtee/amdtee_private.h b/drivers/tee/amdtee/amdtee_private.h index 6d0f7062bb87..d87050033894 100644 --- a/drivers/tee/amdtee/amdtee_private.h +++ b/drivers/tee/amdtee/amdtee_private.h @@ -9,7 +9,7 @@ #include <linux/mutex.h> #include <linux/spinlock.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/kref.h> #include <linux/types.h> #include "amdtee_if.h" diff --git a/drivers/tee/amdtee/call.c b/drivers/tee/amdtee/call.c index e9b63dcb3194..4c21b02be4af 100644 --- a/drivers/tee/amdtee/call.c +++ b/drivers/tee/amdtee/call.c @@ -5,7 +5,7 @@ #include <linux/device.h> #include <linux/tee.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/psp-tee.h> #include <linux/slab.h> #include <linux/psp.h> diff --git a/drivers/tee/amdtee/core.c b/drivers/tee/amdtee/core.c index 3c15f6a9e91c..e487231d25dc 100644 --- a/drivers/tee/amdtee/core.c +++ b/drivers/tee/amdtee/core.c @@ -9,13 +9,12 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/device.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/types.h> #include <linux/mm.h> #include <linux/uaccess.h> #include <linux/firmware.h> #include "amdtee_private.h" -#include "../tee_private.h" #include <linux/psp-tee.h> static struct amdtee_driver_data *drv_data; diff --git a/drivers/tee/amdtee/shm_pool.c b/drivers/tee/amdtee/shm_pool.c index f0303126f199..6346e0bc8a64 100644 --- a/drivers/tee/amdtee/shm_pool.c +++ b/drivers/tee/amdtee/shm_pool.c @@ -4,7 +4,7 @@ */ #include <linux/slab.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/psp.h> #include "amdtee_private.h" diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index a91e50be11be..16eb953e14bb 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -7,7 +7,7 @@ #include <linux/errno.h> #include <linux/mm.h> #include <linux/slab.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/types.h> #include "optee_private.h" diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 3aed554bc8d8..39e688d4e974 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -9,77 +9,13 @@ #include <linux/crash_dump.h> #include <linux/errno.h> #include <linux/io.h> -#include <linux/mm.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/types.h> #include "optee_private.h" -int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, - size_t size, size_t align, - int (*shm_register)(struct tee_context *ctx, - struct tee_shm *shm, - struct page **pages, - size_t num_pages, - unsigned long start)) -{ - size_t nr_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE; - struct page **pages; - unsigned int i; - int rc = 0; - - /* - * Ignore alignment since this is already going to be page aligned - * and there's no need for any larger alignment. - */ - shm->kaddr = alloc_pages_exact(nr_pages * PAGE_SIZE, - GFP_KERNEL | __GFP_ZERO); - if (!shm->kaddr) - return -ENOMEM; - - shm->paddr = virt_to_phys(shm->kaddr); - shm->size = nr_pages * PAGE_SIZE; - - pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); - if (!pages) { - rc = -ENOMEM; - goto err; - } - - for (i = 0; i < nr_pages; i++) - pages[i] = virt_to_page((u8 *)shm->kaddr + i * PAGE_SIZE); - - shm->pages = pages; - shm->num_pages = nr_pages; - - if (shm_register) { - rc = shm_register(shm->ctx, shm, pages, nr_pages, - (unsigned long)shm->kaddr); - if (rc) - goto err; - } - - return 0; -err: - free_pages_exact(shm->kaddr, shm->size); - shm->kaddr = NULL; - return rc; -} - -void optee_pool_op_free_helper(struct tee_shm_pool *pool, struct tee_shm *shm, - int (*shm_unregister)(struct tee_context *ctx, - struct tee_shm *shm)) -{ - if (shm_unregister) - shm_unregister(shm->ctx, shm); - free_pages_exact(shm->kaddr, shm->size); - shm->kaddr = NULL; - kfree(shm->pages); - shm->pages = NULL; -} - static void optee_bus_scan(struct work_struct *work) { WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP)); diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c index 1892e49a8e6a..d296c70ddfdc 100644 --- a/drivers/tee/optee/device.c +++ b/drivers/tee/optee/device.c @@ -7,7 +7,7 @@ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/uuid.h> #include "optee_private.h" diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c index ecb5eb079408..3235e1c719e8 100644 --- a/drivers/tee/optee/ffa_abi.c +++ b/drivers/tee/optee/ffa_abi.c @@ -11,7 +11,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/types.h> #include "optee_private.h" #include "optee_ffa.h" @@ -374,14 +374,14 @@ static int optee_ffa_shm_unregister_supp(struct tee_context *ctx, static int pool_ffa_op_alloc(struct tee_shm_pool *pool, struct tee_shm *shm, size_t size, size_t align) { - return optee_pool_op_alloc_helper(pool, shm, size, align, - optee_ffa_shm_register); + return tee_dyn_shm_alloc_helper(shm, size, align, + optee_ffa_shm_register); } static void pool_ffa_op_free(struct tee_shm_pool *pool, struct tee_shm *shm) { - optee_pool_op_free_helper(pool, shm, optee_ffa_shm_unregister); + tee_dyn_shm_free_helper(shm, optee_ffa_shm_unregister); } static void pool_ffa_op_destroy_pool(struct tee_shm_pool *pool) diff --git a/drivers/tee/optee/notif.c b/drivers/tee/optee/notif.c index 05212842b0a5..0d7878e770cd 100644 --- a/drivers/tee/optee/notif.c +++ b/drivers/tee/optee/notif.c @@ -9,7 +9,7 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include "optee_private.h" struct notif_entry { diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 7a5243c78b55..429cc20be5cc 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -9,7 +9,7 @@ #include <linux/arm-smccc.h> #include <linux/rhashtable.h> #include <linux/semaphore.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/types.h> #include "optee_msg.h" @@ -283,18 +283,6 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session); int optee_enumerate_devices(u32 func); void optee_unregister_devices(void); -int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm, - size_t size, size_t align, - int (*shm_register)(struct tee_context *ctx, - struct tee_shm *shm, - struct page **pages, - size_t num_pages, - unsigned long start)); -void optee_pool_op_free_helper(struct tee_shm_pool *pool, struct tee_shm *shm, - int (*shm_unregister)(struct tee_context *ctx, - struct tee_shm *shm)); - - void optee_remove_common(struct optee *optee); int optee_open(struct tee_context *ctx, bool cap_memref_null); void optee_release(struct tee_context *ctx); diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c index e69bc6380683..f086812f1179 100644 --- a/drivers/tee/optee/rpc.c +++ b/drivers/tee/optee/rpc.c @@ -8,7 +8,7 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/slab.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include "optee_private.h" #include "optee_rpc_cmd.h" diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index c82b7b88991d..844285d4f03c 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -23,7 +23,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/types.h> #include <linux/workqueue.h> #include "optee_private.h" @@ -592,19 +592,18 @@ static int pool_op_alloc(struct tee_shm_pool *pool, * to be registered with OP-TEE. */ if (shm->flags & TEE_SHM_PRIV) - return optee_pool_op_alloc_helper(pool, shm, size, align, NULL); + return tee_dyn_shm_alloc_helper(shm, size, align, NULL); - return optee_pool_op_alloc_helper(pool, shm, size, align, - optee_shm_register); + return tee_dyn_shm_alloc_helper(shm, size, align, optee_shm_register); } static void pool_op_free(struct tee_shm_pool *pool, struct tee_shm *shm) { if (!(shm->flags & TEE_SHM_PRIV)) - optee_pool_op_free_helper(pool, shm, optee_shm_unregister); + tee_dyn_shm_free_helper(shm, optee_shm_unregister); else - optee_pool_op_free_helper(pool, shm, NULL); + tee_dyn_shm_free_helper(shm, NULL); } static void pool_op_destroy_pool(struct tee_shm_pool *pool) diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index e59c20d74b36..82ad095d2b1c 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -11,7 +11,7 @@ #include <linux/idr.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/uaccess.h> #include <crypto/hash.h> #include <crypto/sha1.h> diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h index 754e11dcb240..9bc50605227c 100644 --- a/drivers/tee/tee_private.h +++ b/drivers/tee/tee_private.h @@ -12,41 +12,6 @@ #include <linux/mutex.h> #include <linux/types.h> -#define TEE_DEVICE_FLAG_REGISTERED 0x1 -#define TEE_MAX_DEV_NAME_LEN 32 - -/** - * struct tee_device - TEE Device representation - * @name: name of device - * @desc: description of device - * @id: unique id of device - * @flags: represented by TEE_DEVICE_FLAG_REGISTERED above - * @dev: embedded basic device structure - * @cdev: embedded cdev - * @num_users: number of active users of this device - * @c_no_user: completion used when unregistering the device - * @mutex: mutex protecting @num_users and @idr - * @idr: register of user space shared memory objects allocated or - * registered on this device - * @pool: shared memory pool - */ -struct tee_device { - char name[TEE_MAX_DEV_NAME_LEN]; - const struct tee_desc *desc; - int id; - unsigned int flags; - - struct device dev; - struct cdev cdev; - - size_t num_users; - struct completion c_no_users; - struct mutex mutex; /* protects num_users and idr */ - - struct idr idr; - struct tee_shm_pool *pool; -}; - int tee_shm_get_fd(struct tee_shm *shm); bool tee_device_get(struct tee_device *teedev); diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index 731d9028b67f..daf6e5cfd59a 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -5,10 +5,11 @@ #include <linux/anon_inodes.h> #include <linux/device.h> #include <linux/idr.h> +#include <linux/io.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/uaccess.h> #include <linux/uio.h> #include <linux/highmem.h> @@ -202,6 +203,70 @@ struct tee_shm *tee_shm_alloc_priv_buf(struct tee_context *ctx, size_t size) } EXPORT_SYMBOL_GPL(tee_shm_alloc_priv_buf); +int tee_dyn_shm_alloc_helper(struct tee_shm *shm, size_t size, size_t align, + int (*shm_register)(struct tee_context *ctx, + struct tee_shm *shm, + struct page **pages, + size_t num_pages, + unsigned long start)) +{ + size_t nr_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE; + struct page **pages; + unsigned int i; + int rc = 0; + + /* + * Ignore alignment since this is already going to be page aligned + * and there's no need for any larger alignment. + */ + shm->kaddr = alloc_pages_exact(nr_pages * PAGE_SIZE, + GFP_KERNEL | __GFP_ZERO); + if (!shm->kaddr) + return -ENOMEM; + + shm->paddr = virt_to_phys(shm->kaddr); + shm->size = nr_pages * PAGE_SIZE; + + pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); + if (!pages) { + rc = -ENOMEM; + goto err; + } + + for (i = 0; i < nr_pages; i++) + pages[i] = virt_to_page((u8 *)shm->kaddr + i * PAGE_SIZE); + + shm->pages = pages; + shm->num_pages = nr_pages; + + if (shm_register) { + rc = shm_register(shm->ctx, shm, pages, nr_pages, + (unsigned long)shm->kaddr); + if (rc) + goto err; + } + + return 0; +err: + free_pages_exact(shm->kaddr, shm->size); + shm->kaddr = NULL; + return rc; +} +EXPORT_SYMBOL_GPL(tee_dyn_shm_alloc_helper); + +void tee_dyn_shm_free_helper(struct tee_shm *shm, + int (*shm_unregister)(struct tee_context *ctx, + struct tee_shm *shm)) +{ + if (shm_unregister) + shm_unregister(shm->ctx, shm); + free_pages_exact(shm->kaddr, shm->size); + shm->kaddr = NULL; + kfree(shm->pages); + shm->pages = NULL; +} +EXPORT_SYMBOL_GPL(tee_dyn_shm_free_helper); + static struct tee_shm * register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags, int id) diff --git a/drivers/tee/tee_shm_pool.c b/drivers/tee/tee_shm_pool.c index 058bfbac657a..80004b55628d 100644 --- a/drivers/tee/tee_shm_pool.c +++ b/drivers/tee/tee_shm_pool.c @@ -6,7 +6,7 @@ #include <linux/dma-buf.h> #include <linux/genalloc.h> #include <linux/slab.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include "tee_private.h" static int pool_op_gen_alloc(struct tee_shm_pool *pool, struct tee_shm *shm, diff --git a/drivers/tee/tstee/Kconfig b/drivers/tee/tstee/Kconfig new file mode 100644 index 000000000000..d32f91d47398 --- /dev/null +++ b/drivers/tee/tstee/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +config ARM_TSTEE + tristate "Arm Trusted Services TEE driver" + depends on ARM_FFA_TRANSPORT + default n + help + The Trusted Services project provides a framework for developing and + deploying device Root of Trust services in FF-A Secure Partitions. + This driver provides an interface to make Trusted Services Secure + Partitions accessible for user space clients, since the FF-A driver + doesn't implement a user space interface directly. diff --git a/drivers/tee/tstee/Makefile b/drivers/tee/tstee/Makefile new file mode 100644 index 000000000000..5227020ebd30 --- /dev/null +++ b/drivers/tee/tstee/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +arm-tstee-objs := core.o +obj-$(CONFIG_ARM_TSTEE) = arm-tstee.o diff --git a/drivers/tee/tstee/core.c b/drivers/tee/tstee/core.c new file mode 100644 index 000000000000..533425e9e9e7 --- /dev/null +++ b/drivers/tee/tstee/core.c @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Arm Limited + */ + +#include <linux/arm_ffa.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/limits.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/tee_core.h> +#include <linux/types.h> +#include <linux/uuid.h> +#include <linux/xarray.h> +#include "tstee_private.h" + +#define FFA_DIRECT_REQ_ARG_NUM 5 +#define FFA_INVALID_MEM_HANDLE U64_MAX + +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); +} + +static void tstee_get_version(struct tee_device *teedev, + struct tee_ioctl_version_data *vers) +{ + struct tstee *tstee = tee_get_drvdata(teedev); + struct tee_ioctl_version_data v = { + .impl_id = TEE_IMPL_ID_TSTEE, + /* FF-A endpoint ID only uses the lower 16 bits */ + .impl_caps = lower_16_bits(tstee->ffa_dev->vm_id), + .gen_caps = 0, + }; + + *vers = v; +} + +static int tstee_open(struct tee_context *ctx) +{ + struct ts_context_data *ctxdata; + + ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL); + if (!ctxdata) + return -ENOMEM; + + xa_init_flags(&ctxdata->sess_list, XA_FLAGS_ALLOC); + + ctx->data = ctxdata; + + return 0; +} + +static void tstee_release(struct tee_context *ctx) +{ + struct ts_context_data *ctxdata = ctx->data; + struct ts_session *sess; + unsigned long idx; + + if (!ctxdata) + return; + + xa_for_each(&ctxdata->sess_list, idx, sess) { + xa_erase(&ctxdata->sess_list, idx); + kfree(sess); + } + + xa_destroy(&ctxdata->sess_list); + + kfree(ctxdata); + ctx->data = NULL; +} + +static int tstee_open_session(struct tee_context *ctx, + struct tee_ioctl_open_session_arg *arg, + struct tee_param *param __always_unused) +{ + struct tstee *tstee = tee_get_drvdata(ctx->teedev); + struct ffa_device *ffa_dev = tstee->ffa_dev; + struct ts_context_data *ctxdata = ctx->data; + struct ffa_send_direct_data ffa_data; + struct ts_session *sess = NULL; + u32 ffa_args[FFA_DIRECT_REQ_ARG_NUM] = {}; + u32 sess_id; + int rc; + + ffa_args[TS_RPC_CTRL_REG] = + TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID, + TS_RPC_OP_SERVICE_INFO); + + memcpy(ffa_args + TS_RPC_SERVICE_INFO_UUID0, arg->uuid, UUID_SIZE); + + arg_list_to_ffa_data(ffa_args, &ffa_data); + rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data); + if (rc) + return rc; + + arg_list_from_ffa_data(&ffa_data, ffa_args); + + if (ffa_args[TS_RPC_SERVICE_INFO_RPC_STATUS] != TS_RPC_OK) + return -ENODEV; + + if (ffa_args[TS_RPC_SERVICE_INFO_IFACE] > U8_MAX) + return -EINVAL; + + sess = kzalloc(sizeof(*sess), GFP_KERNEL); + if (!sess) + return -ENOMEM; + + sess->iface_id = ffa_args[TS_RPC_SERVICE_INFO_IFACE]; + + rc = xa_alloc(&ctxdata->sess_list, &sess_id, sess, xa_limit_32b, + GFP_KERNEL); + if (rc) { + kfree(sess); + return rc; + } + + arg->session = sess_id; + arg->ret = 0; + + return 0; +} + +static int tstee_close_session(struct tee_context *ctx, u32 session) +{ + struct ts_context_data *ctxdata = ctx->data; + struct ts_session *sess; + + /* Calls xa_lock() internally */ + sess = xa_erase(&ctxdata->sess_list, session); + if (!sess) + return -EINVAL; + + kfree(sess); + + return 0; +} + +static int tstee_invoke_func(struct tee_context *ctx, + struct tee_ioctl_invoke_arg *arg, + struct tee_param *param) +{ + struct tstee *tstee = tee_get_drvdata(ctx->teedev); + struct ffa_device *ffa_dev = tstee->ffa_dev; + struct ts_context_data *ctxdata = ctx->data; + struct ffa_send_direct_data ffa_data; + struct tee_shm *shm = NULL; + struct ts_session *sess; + u32 req_len, ffa_args[FFA_DIRECT_REQ_ARG_NUM] = {}; + int shm_id, rc; + u8 iface_id; + u64 handle; + u16 opcode; + + xa_lock(&ctxdata->sess_list); + sess = xa_load(&ctxdata->sess_list, arg->session); + + /* + * Do this while holding the lock to make sure that the session wasn't + * closed meanwhile + */ + if (sess) + iface_id = sess->iface_id; + + xa_unlock(&ctxdata->sess_list); + if (!sess) + return -EINVAL; + + opcode = lower_16_bits(arg->func); + shm_id = lower_32_bits(param[0].u.value.a); + req_len = lower_32_bits(param[0].u.value.b); + + if (shm_id != 0) { + shm = tee_shm_get_from_id(ctx, shm_id); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + if (shm->size < req_len) { + dev_err(&ffa_dev->dev, + "request doesn't fit into shared memory buffer\n"); + rc = -EINVAL; + goto out; + } + + handle = shm->sec_world_id; + } else { + handle = FFA_INVALID_MEM_HANDLE; + } + + ffa_args[TS_RPC_CTRL_REG] = TS_RPC_CTRL_PACK_IFACE_OPCODE(iface_id, + opcode); + ffa_args[TS_RPC_SERVICE_MEM_HANDLE_LSW] = lower_32_bits(handle); + ffa_args[TS_RPC_SERVICE_MEM_HANDLE_MSW] = upper_32_bits(handle); + ffa_args[TS_RPC_SERVICE_REQ_LEN] = req_len; + ffa_args[TS_RPC_SERVICE_CLIENT_ID] = 0; + + arg_list_to_ffa_data(ffa_args, &ffa_data); + rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data); + if (rc) |
