[PATCH RFC v3 1/9] tee: optee: share the global shared-memory ID mapping

Amirreza Zarrabi amirreza.zarrabi at oss.qualcomm.com
Mon Oct 12 22:41:28 PDT 2026


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 at 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;
+}

-- 
2.34.1




More information about the linux-riscv mailing list