The FF-A backend maintains a hash table translating secure-world memory handles to TEE shared-memory objects. This bookkeeping does not depend on FF-A and is also needed by the RPMI backend.
Move the mapping and its locking into common helpers and convert the FF-A backend to use them.
This prepares the OP-TEE driver for RPMI transport support on RISC-V.
Signed-off-by: Amirreza Zarrabi amirreza.zarrabi@oss.qualcomm.com --- drivers/tee/optee/Makefile | 1 + drivers/tee/optee/ffa_abi.c | 133 +++++++---------------------------- drivers/tee/optee/optee_private.h | 30 ++++++-- drivers/tee/optee/shm_handle_map.c | 138 +++++++++++++++++++++++++++++++++++++ 4 files changed, 188 insertions(+), 114 deletions(-)
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile index 183cdde1ac04..ec2efc27ef05 100644 --- a/drivers/tee/optee/Makefile +++ b/drivers/tee/optee/Makefile @@ -7,6 +7,7 @@ optee-objs += rpc.o optee-objs += protmem.o optee-objs += supp.o optee-objs += device.o +optee-objs += shm_handle_map.o optee-$(CONFIG_HAVE_ARM_SMCCC) += smc_abi.o optee-$(CONFIG_ARM_FFA_TRANSPORT) += ffa_abi.o
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c index 702da7d98fbc..5a926353c653 100644 --- a/drivers/tee/optee/ffa_abi.c +++ b/drivers/tee/optee/ffa_abi.c @@ -22,100 +22,15 @@ * This file implement the FF-A ABI used when communicating with secure world * OP-TEE OS via FF-A. * This file is divided into the following sections: - * 1. Maintain a hash table for lookup of a global FF-A memory handle - * 2. Convert between struct tee_param and struct optee_msg_param - * 3. Low level support functions to register shared memory in secure world - * 4. Dynamic shared memory pool based on alloc_pages() - * 5. Do a normal scheduled call into secure world - * 6. Driver initialization. + * 1. Convert between struct tee_param and struct optee_msg_param + * 2. Low level support functions to register shared memory in secure world + * 3. Dynamic shared memory pool based on alloc_pages() + * 4. Do a normal scheduled call into secure world + * 5. Driver initialization. */
/* - * 1. Maintain a hash table for lookup of a global FF-A memory handle - * - * FF-A assigns a global memory handle for each piece shared memory. - * This handle is then used when communicating with secure world. - * - * Main functions are optee_shm_add_ffa_handle() and optee_shm_rem_ffa_handle() - */ -struct shm_rhash { - struct tee_shm *shm; - u64 global_id; - struct rhash_head linkage; -}; - -static void rh_free_fn(void *ptr, void *arg) -{ - kfree(ptr); -} - -static const struct rhashtable_params shm_rhash_params = { - .head_offset = offsetof(struct shm_rhash, linkage), - .key_len = sizeof(u64), - .key_offset = offsetof(struct shm_rhash, global_id), - .automatic_shrinking = true, -}; - -static struct tee_shm *optee_shm_from_ffa_handle(struct optee *optee, - u64 global_id) -{ - struct tee_shm *shm = NULL; - struct shm_rhash *r; - - mutex_lock(&optee->ffa.mutex); - r = rhashtable_lookup_fast(&optee->ffa.global_ids, &global_id, - shm_rhash_params); - if (r) - shm = r->shm; - mutex_unlock(&optee->ffa.mutex); - - return shm; -} - -static int optee_shm_add_ffa_handle(struct optee *optee, struct tee_shm *shm, - u64 global_id) -{ - struct shm_rhash *r; - int rc; - - r = kmalloc_obj(*r); - if (!r) - return -ENOMEM; - r->shm = shm; - r->global_id = global_id; - - mutex_lock(&optee->ffa.mutex); - rc = rhashtable_lookup_insert_fast(&optee->ffa.global_ids, &r->linkage, - shm_rhash_params); - mutex_unlock(&optee->ffa.mutex); - - if (rc) - kfree(r); - - return rc; -} - -static int optee_shm_rem_ffa_handle(struct optee *optee, u64 global_id) -{ - struct shm_rhash *r; - int rc = -ENOENT; - - mutex_lock(&optee->ffa.mutex); - r = rhashtable_lookup_fast(&optee->ffa.global_ids, &global_id, - shm_rhash_params); - if (r) - rc = rhashtable_remove_fast(&optee->ffa.global_ids, - &r->linkage, shm_rhash_params); - mutex_unlock(&optee->ffa.mutex); - - if (!rc) - kfree(r); - - return rc; -} - -/* - * 2. Convert between struct tee_param and struct optee_msg_param + * 1. Convert between struct tee_param and struct optee_msg_param * * optee_ffa_from_msg_param() and optee_ffa_to_msg_param() are the main * functions. @@ -133,7 +48,8 @@ static void from_msg_param_ffa_mem(struct optee *optee, struct tee_param *p, p->u.memref.size = mp->u.fmem.size;
if (mp->u.fmem.global_id != OPTEE_MSG_FMEM_INVALID_GLOBAL_ID) - shm = optee_shm_from_ffa_handle(optee, mp->u.fmem.global_id); + shm = optee_shm_handle_map_lookup(&optee->ffa.shm_map, + mp->u.fmem.global_id); p->u.memref.shm = shm;
if (shm) { @@ -262,7 +178,7 @@ static int optee_ffa_to_msg_param(struct optee *optee, }
/* - * 3. Low level support functions to register shared memory in secure world + * 2. Low level support functions to register shared memory in secure world * * Functions to register and unregister shared memory both for normal * clients and for tee-supplicant. @@ -313,7 +229,7 @@ static int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm, if (rc) return rc;
- rc = optee_shm_add_ffa_handle(optee, shm, args.g_handle); + rc = optee_shm_handle_map_add(&optee->ffa.shm_map, shm, args.g_handle); if (rc) { mem_ops->memory_reclaim(args.g_handle, 0); return rc; @@ -339,7 +255,7 @@ static int optee_ffa_shm_unregister(struct tee_context *ctx, }; int rc;
- optee_shm_rem_ffa_handle(optee, global_handle); + optee_shm_handle_map_remove(&optee->ffa.shm_map, global_handle); shm->sec_world_id = 0;
rc = msg_ops->sync_send_receive(ffa_dev, &data); @@ -367,7 +283,7 @@ static int optee_ffa_shm_unregister_supp(struct tee_context *ctx, * this ID. */
- optee_shm_rem_ffa_handle(optee, global_handle); + optee_shm_handle_map_remove(&optee->ffa.shm_map, global_handle); mem_ops = optee->ffa.ffa_dev->ops->mem_ops; rc = mem_ops->memory_reclaim(global_handle, 0); if (rc) @@ -379,7 +295,7 @@ static int optee_ffa_shm_unregister_supp(struct tee_context *ctx, }
/* - * 4. Dynamic shared memory pool based on alloc_pages() + * 3. Dynamic shared memory pool based on alloc_pages() * * Implements an OP-TEE specific shared memory pool. * The main function is optee_ffa_shm_pool_alloc_pages(). @@ -428,7 +344,7 @@ static struct tee_shm_pool *optee_ffa_shm_pool_alloc_pages(void) }
/* - * 5. Do a normal scheduled call into secure world + * 4. Do a normal scheduled call into secure world * * The function optee_ffa_do_call_with_arg() performs a normal scheduled * call into secure world. During this call may normal world request help @@ -488,7 +404,8 @@ static void handle_ffa_rpc_func_cmd_shm_free(struct tee_context *ctx, arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) goto err_bad_param;
- shm = optee_shm_from_ffa_handle(optee, arg->params[0].u.value.b); + shm = optee_shm_handle_map_lookup(&optee->ffa.shm_map, + arg->params[0].u.value.b); if (!shm) goto err_bad_param; switch (arg->params[0].u.value.a) { @@ -736,7 +653,8 @@ static int optee_ffa_lend_protmem(struct optee *optee, struct tee_shm *protmem, if (rc) goto err_reclaim;
- rc = optee_shm_add_ffa_handle(optee, protmem, args.g_handle); + rc = optee_shm_handle_map_add(&optee->ffa.shm_map, protmem, + args.g_handle); if (rc) goto err_unreg;
@@ -770,7 +688,7 @@ static int optee_ffa_reclaim_protmem(struct optee *optee, }; int rc;
- optee_shm_rem_ffa_handle(optee, global_handle); + optee_shm_handle_map_remove(&optee->ffa.shm_map, global_handle); protmem->sec_world_id = 0;
rc = msg_ops->sync_send_receive(ffa_dev, &data); @@ -785,9 +703,9 @@ static int optee_ffa_reclaim_protmem(struct optee *optee, }
/* - * 6. Driver initialization + * 5. Driver initialization * - * During driver inititialization is the OP-TEE Secure Partition is probed + * During driver initialization is the OP-TEE Secure Partition is probed * to find out which features it supports so the driver can be initialized * with a matching configuration. */ @@ -991,8 +909,7 @@ static void optee_ffa_remove(struct ffa_device *ffa_dev) } optee_remove_common(optee);
- mutex_destroy(&optee->ffa.mutex); - rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL); + optee_shm_handle_map_uninit(&optee->ffa.shm_map);
kfree(optee); } @@ -1137,10 +1054,9 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
optee_set_dev_group(optee);
- rc = rhashtable_init(&optee->ffa.global_ids, &shm_rhash_params); + rc = optee_shm_handle_map_init(&optee->ffa.shm_map); if (rc) goto err_unreg_supp_teedev; - mutex_init(&optee->ffa.mutex); optee_cq_init(&optee->call_queue, 0); optee_supp_init(&optee->supp); optee_shm_arg_cache_init(optee, arg_cache_flags); @@ -1193,12 +1109,11 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev) err_close_ctx: teedev_close_context(ctx); err_rhashtable_free: - rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL); + optee_shm_handle_map_uninit(&optee->ffa.shm_map); rpmb_dev_put(optee->rpmb_dev); mutex_destroy(&optee->rpmb_dev_mutex); optee_supp_uninit(&optee->supp); mutex_destroy(&optee->call_queue.mutex); - mutex_destroy(&optee->ffa.mutex); err_unreg_supp_teedev: tee_device_unregister(optee->supp_teedev); err_unreg_teedev: diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 02d6f79df407..92428945ee33 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -157,6 +157,29 @@ struct optee_smc { }; #endif
+/** + * struct optee_shm_handle_map - Shared-memory lookup by secure-world identity + * @mutex: Serializes lookup, insertion and removal + * @rht: Maps opaque 64-bit identities to shared-memory objects + * + * Owners keep SHM objects alive while their registrations are in use. + * Never hold @mutex across transport calls, RPC or thread-availability waits. + */ +struct optee_shm_handle_map { + /* Protects lookup, insertion and removal. */ + struct mutex mutex; + struct rhashtable rht; +}; + +int optee_shm_handle_map_init(struct optee_shm_handle_map *map); +void optee_shm_handle_map_uninit(struct optee_shm_handle_map *map); +int optee_shm_handle_map_add(struct optee_shm_handle_map *map, + struct tee_shm *shm, u64 global_id); +int optee_shm_handle_map_remove(struct optee_shm_handle_map *map, + u64 global_id); +struct tee_shm * +optee_shm_handle_map_lookup(struct optee_shm_handle_map *map, u64 global_id); + #if IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT) /** * struct optee_ffa - FFA communication struct @@ -164,17 +187,14 @@ struct optee_smc { * OP-TEE in secure world * @bottom_half_value: notification ID used for bottom half signalling or * U32_MAX if unused - * @mutex: serializes access to @global_ids - * @global_ids: FF-A shared memory global handle translation + * @shm_map: FF-A shared memory global handle translation * @notif_wq: workqueue for FF-A asynchronous notification * @notif_work: work for FF-A asynchronous notification */ struct optee_ffa { struct ffa_device *ffa_dev; u32 bottom_half_value; - /* Serializes access to @global_ids */ - struct mutex mutex; - struct rhashtable global_ids; + struct optee_shm_handle_map shm_map; struct workqueue_struct *notif_wq; struct work_struct notif_work; }; diff --git a/drivers/tee/optee/shm_handle_map.c b/drivers/tee/optee/shm_handle_map.c new file mode 100644 index 000000000000..54324c9c3644 --- /dev/null +++ b/drivers/tee/optee/shm_handle_map.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, 2023 Linaro Limited + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/errno.h> +#include <linux/slab.h> +#include "optee_private.h" + +struct optee_shm_handle_map_entry { + struct tee_shm *shm; + u64 global_id; + struct rhash_head node; +}; + +static const struct rhashtable_params shm_handle_map_params = { + .head_offset = offsetof(struct optee_shm_handle_map_entry, node), + .key_offset = offsetof(struct optee_shm_handle_map_entry, global_id), + .key_len = sizeof(u64), + .automatic_shrinking = true, +}; + +static void shm_handle_map_free(void *ptr, void *arg) +{ + kfree(ptr); +} + +/** + * optee_shm_handle_map_init() - Initialize a shared-memory identity map + * @map: Map to initialize + * + * Return: 0 on success or a negative error. + */ +int optee_shm_handle_map_init(struct optee_shm_handle_map *map) +{ + int rc; + + mutex_init(&map->mutex); + rc = rhashtable_init(&map->rht, &shm_handle_map_params); + if (rc) + mutex_destroy(&map->mutex); + + return rc; +} + +/** + * optee_shm_handle_map_uninit() - Free a shared-memory identity map + * @map: Initialized map with no concurrent users + * + * Free tracking entries, not SHM objects or their secure-world registrations. + */ +void optee_shm_handle_map_uninit(struct optee_shm_handle_map *map) +{ + rhashtable_free_and_destroy(&map->rht, shm_handle_map_free, NULL); + mutex_destroy(&map->mutex); +} + +/** + * optee_shm_handle_map_add() - Track a registered shared-memory object + * @map: Initialized map + * @shm: Shared-memory object kept alive by its owner + * @global_id: Opaque secure-world identity + * + * Return: 0 on success or a negative error. + */ +int optee_shm_handle_map_add(struct optee_shm_handle_map *map, + struct tee_shm *shm, u64 global_id) +{ + struct optee_shm_handle_map_entry *entry; + int rc; + + entry = kmalloc_obj(*entry); + if (!entry) + return -ENOMEM; + + entry->shm = shm; + entry->global_id = global_id; + + mutex_lock(&map->mutex); + rc = rhashtable_lookup_insert_fast(&map->rht, &entry->node, + shm_handle_map_params); + mutex_unlock(&map->mutex); + if (rc) + kfree(entry); + + return rc; +} + +/** + * optee_shm_handle_map_remove() - Remove a shared-memory tracking entry + * @map: Initialized map + * @global_id: Opaque secure-world identity + * + * Return: 0 on success, -ENOENT if absent, or a negative removal error. + */ +int optee_shm_handle_map_remove(struct optee_shm_handle_map *map, u64 global_id) +{ + struct optee_shm_handle_map_entry *entry; + int rc = -ENOENT; + + mutex_lock(&map->mutex); + entry = rhashtable_lookup_fast(&map->rht, &global_id, + shm_handle_map_params); + if (entry) + rc = rhashtable_remove_fast(&map->rht, &entry->node, + shm_handle_map_params); + mutex_unlock(&map->mutex); + if (!rc) + kfree(entry); + + return rc; +} + +/** + * optee_shm_handle_map_lookup() - Look up a registered shared-memory object + * @map: Initialized map + * @global_id: Opaque secure-world identity + * + * The caller must keep the SHM object alive; no reference is acquired here. + * + * Return: The shared-memory object or NULL if the identity is absent. + */ +struct tee_shm * +optee_shm_handle_map_lookup(struct optee_shm_handle_map *map, u64 global_id) +{ + struct optee_shm_handle_map_entry *entry; + struct tee_shm *shm = NULL; + + mutex_lock(&map->mutex); + entry = rhashtable_lookup_fast(&map->rht, &global_id, + shm_handle_map_params); + if (entry) + shm = entry->shm; + mutex_unlock(&map->mutex); + + return shm; +}