mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] tee: optee: ffa: support shared memory offsets on large-page kernels
@ 2026-09-04 13:47 Mahantesh Salimath
  2026-09-10 12:28 ` Sumit Garg
  2026-09-10 16:11 ` [PATCH v2] " Mahantesh Salimath
  0 siblings, 2 replies; 5+ messages in thread
From: Mahantesh Salimath @ 2026-09-04 13:47 UTC (permalink / raw)
  To: Jens Wiklander; +Cc: Sumit Garg, op-tee, linux-kernel

OP-TEE FF-A memory objects use 4 KiB pages, while the kernel page
size may be larger. Consequently, tee_shm->offset can be greater than
or equal to FFA_PAGE_SIZE, but OP-TEE rejects such a value in
internal_offs.

Do not encode the excess page offset in offs_low/offs_high. Those
fields describe the logical memref offset and are copied back into
tee_param->shm_offs on return. Folding the page offset into them breaks
parameter round trips when a memref is reused. They are also ignored by
the OPTEE_RPC_CMD_SHM_ALLOC response path, which uses only global_id and
internal_offs to construct the shared-memory mobj.

Instead, start the FF-A descriptor at the 4 KiB page containing the
shared buffer, the same approach as optee_fill_pages_list() in the SMC
ABI. Store the remaining in-page offset in internal_offs and preserve
shm_offs in offs_low/offs_high. This keeps internal_offs within the
FF-A page size, maps RPC allocations at the correct address, and
preserves normal memref offsets across repeated invocations.

Tested on ARMv8-A with 64 KiB PAGE_SIZE. OP-TEE OS ran as a secure
partition under Hafnium (SPMC) over FF-A. Verified registered shared
memory with tee_shm->offset >= 4 KiB, memref reuse on the same
TEEC_Operation, and RPC OPTEE_RPC_CMD_SHM_ALLOC (xtest regression
6007-6009). optee_hello_world, optee_aes, and xtest regression 1005,
1007, 1008, 4001-4003 and 6001-6003 also passed.

Fixes: 4615e5a34b95 ("optee: add FF-A support")
Acked-by: Liming Sun <limings@nvidia.com>
Acked-by: James Hurley <jahurley@nvidia.com>
Acked-by: Dave Thompson <davthompson@nvidia.com>
Signed-off-by: Mahantesh Salimath <mahantesh@nvidia.com>
---
 drivers/tee/optee/ffa_abi.c   | 66 +++++++++++++++++++++++++++++------
 drivers/tee/optee/optee_msg.h |  4 +--
 2 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index 633715b98625..2a37e4899dc6 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -187,6 +187,40 @@ static int optee_ffa_from_msg_param(struct optee *optee,
 	return 0;
 }
 
+/*
+ * OP-TEE FF-A memory objects use 4 KiB pages while the kernel page size may
+ * be larger, for example 64 KiB on arm64. The FF-A descriptor is registered
+ * from the 4 KiB page containing the start of the shared buffer, so
+ * internal_offs is the offset into that page.
+ */
+static void optee_ffa_set_internal_offs(struct optee_msg_param_fmem *fmem,
+					struct tee_shm *shm)
+{
+	size_t page_offs = tee_shm_get_page_offset(shm);
+
+	BUILD_BUG_ON(PAGE_SIZE < FFA_PAGE_SIZE);
+
+	fmem->internal_offs = page_offs & (FFA_PAGE_SIZE - 1);
+}
+
+/*
+ * Keep shm_offs unchanged in offs_low/offs_high: it is returned to callers
+ * and may be reused for a subsequent invocation.
+ */
+static int optee_ffa_set_fmem_offsets(struct optee_msg_param_fmem *fmem,
+				      struct tee_shm *shm, u64 shm_offs)
+{
+	optee_ffa_set_internal_offs(fmem, shm);
+
+	fmem->offs_low = shm_offs;
+	fmem->offs_high = shm_offs >> 32;
+	/* Check that the entire offset could be stored. */
+	if (fmem->offs_high != shm_offs >> 32)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int to_msg_param_ffa_mem(struct optee_msg_param *mp,
 				const struct tee_param *p)
 {
@@ -196,14 +230,8 @@ static int to_msg_param_ffa_mem(struct optee_msg_param *mp,
 		   TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
 
 	if (shm) {
-		u64 shm_offs = p->u.memref.shm_offs;
-
-		mp->u.fmem.internal_offs = shm->offset;
-
-		mp->u.fmem.offs_low = shm_offs;
-		mp->u.fmem.offs_high = shm_offs >> 32;
-		/* Check that the entire offset could be stored. */
-		if (mp->u.fmem.offs_high != shm_offs >> 32)
+		if (optee_ffa_set_fmem_offsets(&mp->u.fmem, shm,
+					       p->u.memref.shm_offs))
 			return -EINVAL;
 
 		mp->u.fmem.global_id = shm->sec_world_id;
@@ -284,14 +312,30 @@ static int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm,
 		.nattrs = 1,
 	};
 	struct sg_table sgt;
+	size_t page_offs;
+	size_t ffa_offs;
+	size_t ffa_size;
 	int rc;
 
+	if (!num_pages)
+		return -EINVAL;
+
 	rc = optee_check_mem_type(start, num_pages);
 	if (rc)
 		return rc;
 
-	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, 0,
-				       num_pages * PAGE_SIZE, GFP_KERNEL);
+	page_offs = tee_shm_get_page_offset(shm);
+	ffa_offs = round_down(page_offs, FFA_PAGE_SIZE);
+	ffa_size = num_pages * PAGE_SIZE - ffa_offs;
+
+	/*
+	 * Start the FF-A descriptor at the 4 KiB page containing the shared
+	 * buffer, skipping unused leading 4 KiB pages when PAGE_SIZE is
+	 * larger. Same approach as optee_fill_pages_list() in the SMC ABI.
+	 * This leaves only page_offs & (FFA_PAGE_SIZE - 1) for internal_offs.
+	 */
+	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, ffa_offs,
+				       ffa_size, GFP_KERNEL);
 	if (rc)
 		return rc;
 	args.sg = sgt.sgl;
@@ -458,8 +502,8 @@ static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
 		.attr = OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT,
 		.u.fmem.size = tee_shm_get_size(shm),
 		.u.fmem.global_id = shm->sec_world_id,
-		.u.fmem.internal_offs = shm->offset,
 	};
+	optee_ffa_set_internal_offs(&arg->params[0].u.fmem, shm);
 
 	arg->ret = TEEC_SUCCESS;
 }
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
index 7d9b12e71c03..6c3043f8da33 100644
--- a/drivers/tee/optee/optee_msg.h
+++ b/drivers/tee/optee/optee_msg.h
@@ -136,8 +136,8 @@ struct optee_msg_param_rmem {
  * struct optee_msg_param_fmem - FF-A memory reference parameter
  * @offs_low:		lower bits of offset into shared memory reference
  * @offs_high:		higher bits of offset into shared memory reference
- * @internal_offs:	internal offset into the first page of shared memory
- *			reference
+ * @internal_offs:	offset into the first 4 KiB page of the FF-A shared
+ *			memory region
  * @size:		size of the buffer
  * @global_id:		global identifier of the shared memory
  */
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] tee: optee: ffa: support shared memory offsets on large-page kernels
  2026-09-04 13:47 [PATCH] tee: optee: ffa: support shared memory offsets on large-page kernels Mahantesh Salimath
@ 2026-09-10 12:28 ` Sumit Garg
  2026-09-10 16:08   ` Mahantesh Salimath
  2026-09-10 16:11 ` [PATCH v2] " Mahantesh Salimath
  1 sibling, 1 reply; 5+ messages in thread
From: Sumit Garg @ 2026-09-10 12:28 UTC (permalink / raw)
  To: Mahantesh Salimath; +Cc: Jens Wiklander, op-tee, linux-kernel

On Fri, 04 Sep 2026 at 13:47:32 +0000, Mahantesh Salimath wrote:
>OP-TEE FF-A memory objects use 4 KiB pages, while the kernel page
>size may be larger. Consequently, tee_shm->offset can be greater than
>or equal to FFA_PAGE_SIZE, but OP-TEE rejects such a value in
>internal_offs.
>
>Do not encode the excess page offset in offs_low/offs_high. Those
>fields describe the logical memref offset and are copied back into
>tee_param->shm_offs on return. Folding the page offset into them breaks
>parameter round trips when a memref is reused. They are also ignored by
>the OPTEE_RPC_CMD_SHM_ALLOC response path, which uses only global_id and
>internal_offs to construct the shared-memory mobj.
>
>Instead, start the FF-A descriptor at the 4 KiB page containing the
>shared buffer, the same approach as optee_fill_pages_list() in the SMC
>ABI. Store the remaining in-page offset in internal_offs and preserve
>shm_offs in offs_low/offs_high. This keeps internal_offs within the
>FF-A page size, maps RPC allocations at the correct address, and
>preserves normal memref offsets across repeated invocations.
>
>Tested on ARMv8-A with 64 KiB PAGE_SIZE. OP-TEE OS ran as a secure
>partition under Hafnium (SPMC) over FF-A. Verified registered shared
>memory with tee_shm->offset >= 4 KiB, memref reuse on the same
>TEEC_Operation, and RPC OPTEE_RPC_CMD_SHM_ALLOC (xtest regression
>6007-6009). optee_hello_world, optee_aes, and xtest regression 1005,
>1007, 1008, 4001-4003 and 6001-6003 also passed.
>
>Fixes: 4615e5a34b95 ("optee: add FF-A support")
>Acked-by: Liming Sun <limings@nvidia.com>
>Acked-by: James Hurley <jahurley@nvidia.com>
>Acked-by: Dave Thompson <davthompson@nvidia.com>
>Signed-off-by: Mahantesh Salimath <mahantesh@nvidia.com>
>---
> drivers/tee/optee/ffa_abi.c   | 66 +++++++++++++++++++++++++++++------
> drivers/tee/optee/optee_msg.h |  4 +--
> 2 files changed, 57 insertions(+), 13 deletions(-)
>
>diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
>index 633715b98625..2a37e4899dc6 100644
>--- a/drivers/tee/optee/ffa_abi.c
>+++ b/drivers/tee/optee/ffa_abi.c
>@@ -187,6 +187,40 @@ static int optee_ffa_from_msg_param(struct optee *optee,
> 	return 0;
> }
>
>+/*
>+ * OP-TEE FF-A memory objects use 4 KiB pages while the kernel page size may
>+ * be larger, for example 64 KiB on arm64. The FF-A descriptor is registered
>+ * from the 4 KiB page containing the start of the shared buffer, so
>+ * internal_offs is the offset into that page.
>+ */
>+static void optee_ffa_set_internal_offs(struct optee_msg_param_fmem *fmem,
>+					struct tee_shm *shm)
>+{
>+	size_t page_offs = tee_shm_get_page_offset(shm);
>+
>+	BUILD_BUG_ON(PAGE_SIZE < FFA_PAGE_SIZE);
>+
>+	fmem->internal_offs = page_offs & (FFA_PAGE_SIZE - 1);
>+}
>+
>+/*
>+ * Keep shm_offs unchanged in offs_low/offs_high: it is returned to callers
>+ * and may be reused for a subsequent invocation.
>+ */
>+static int optee_ffa_set_fmem_offsets(struct optee_msg_param_fmem *fmem,
>+				      struct tee_shm *shm, u64 shm_offs)
>+{
>+	optee_ffa_set_internal_offs(fmem, shm);
>+
>+	fmem->offs_low = shm_offs;
>+	fmem->offs_high = shm_offs >> 32;
>+	/* Check that the entire offset could be stored. */
>+	if (fmem->offs_high != shm_offs >> 32)
>+		return -EINVAL;
>+
>+	return 0;
>+}
>+
> static int to_msg_param_ffa_mem(struct optee_msg_param *mp,
> 				const struct tee_param *p)
> {
>@@ -196,14 +230,8 @@ static int to_msg_param_ffa_mem(struct optee_msg_param *mp,
> 		   TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
>
> 	if (shm) {
>-		u64 shm_offs = p->u.memref.shm_offs;
>-
>-		mp->u.fmem.internal_offs = shm->offset;
>-
>-		mp->u.fmem.offs_low = shm_offs;
>-		mp->u.fmem.offs_high = shm_offs >> 32;
>-		/* Check that the entire offset could be stored. */
>-		if (mp->u.fmem.offs_high != shm_offs >> 32)
>+		if (optee_ffa_set_fmem_offsets(&mp->u.fmem, shm,
>+					       p->u.memref.shm_offs))
> 			return -EINVAL;
>

This all can rather be simplified below, lots of indirection here.

diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index 633715b98625..b9dcd2e2e28b 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -198,8 +198,8 @@ static int to_msg_param_ffa_mem(struct optee_msg_param *mp,
         if (shm) {
                 u64 shm_offs = p->u.memref.shm_offs;
  
-               mp->u.fmem.internal_offs = shm->offset;
-
+               mp->u.fmem.internal_offs = tee_shm_get_page_offset(shm) &
+                                          (FFA_PAGE_SIZE - 1);
                 mp->u.fmem.offs_low = shm_offs;
                 mp->u.fmem.offs_high = shm_offs >> 32;
                 /* Check that the entire offset could be stored. */

> 		mp->u.fmem.global_id = shm->sec_world_id;
>@@ -284,14 +312,30 @@ static int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm,
> 		.nattrs = 1,
> 	};
> 	struct sg_table sgt;
>+	size_t page_offs;
>+	size_t ffa_offs;
>+	size_t ffa_size;
> 	int rc;
>
>+	if (!num_pages)
>+		return -EINVAL;
>+
> 	rc = optee_check_mem_type(start, num_pages);
> 	if (rc)
> 		return rc;
>
>-	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, 0,
>-				       num_pages * PAGE_SIZE, GFP_KERNEL);
>+	page_offs = tee_shm_get_page_offset(shm);
>+	ffa_offs = round_down(page_offs, FFA_PAGE_SIZE);
>+	ffa_size = num_pages * PAGE_SIZE - ffa_offs;

Avoid redundant variables which are used only once.

>+
>+	/*
>+	 * Start the FF-A descriptor at the 4 KiB page containing the shared
>+	 * buffer, skipping unused leading 4 KiB pages when PAGE_SIZE is
>+	 * larger. Same approach as optee_fill_pages_list() in the SMC ABI.
>+	 * This leaves only page_offs & (FFA_PAGE_SIZE - 1) for internal_offs.
>+	 */
>+	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, ffa_offs,
>+				       ffa_size, GFP_KERNEL);
> 	if (rc)
> 		return rc;
> 	args.sg = sgt.sgl;
>@@ -458,8 +502,8 @@ static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
> 		.attr = OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT,
> 		.u.fmem.size = tee_shm_get_size(shm),
> 		.u.fmem.global_id = shm->sec_world_id,
>-		.u.fmem.internal_offs = shm->offset,
> 	};
>+	optee_ffa_set_internal_offs(&arg->params[0].u.fmem, shm);

Ditto, directly inline the masking here.

-Sumit

>
> 	arg->ret = TEEC_SUCCESS;
> }
>diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
>index 7d9b12e71c03..6c3043f8da33 100644
>--- a/drivers/tee/optee/optee_msg.h
>+++ b/drivers/tee/optee/optee_msg.h
>@@ -136,8 +136,8 @@ struct optee_msg_param_rmem {
>  * struct optee_msg_param_fmem - FF-A memory reference parameter
>  * @offs_low:		lower bits of offset into shared memory reference
>  * @offs_high:		higher bits of offset into shared memory reference
>- * @internal_offs:	internal offset into the first page of shared memory
>- *			reference
>+ * @internal_offs:	offset into the first 4 KiB page of the FF-A shared
>+ *			memory region
>  * @size:		size of the buffer
>  * @global_id:		global identifier of the shared memory
>  */
>-- 
>2.43.0
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] tee: optee: ffa: support shared memory offsets on large-page kernels
  2026-09-10 12:28 ` Sumit Garg
@ 2026-09-10 16:08   ` Mahantesh Salimath
  0 siblings, 0 replies; 5+ messages in thread
From: Mahantesh Salimath @ 2026-09-10 16:08 UTC (permalink / raw)
  To: Sumit Garg; +Cc: Jens Wiklander, op-tee, linux-kernel

Thanks for the review. I'll send a v2 shortly with the helpers
inlined and the extra locals dropped, as you suggested.

Thanks,
Mahantesh

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2] tee: optee: ffa: support shared memory offsets on large-page kernels
  2026-09-04 13:47 [PATCH] tee: optee: ffa: support shared memory offsets on large-page kernels Mahantesh Salimath
  2026-09-10 12:28 ` Sumit Garg
@ 2026-09-10 16:11 ` Mahantesh Salimath
  2026-09-21 12:25   ` Sumit Garg
  1 sibling, 1 reply; 5+ messages in thread
From: Mahantesh Salimath @ 2026-09-10 16:11 UTC (permalink / raw)
  To: Jens Wiklander; +Cc: Sumit Garg, op-tee, linux-kernel

OP-TEE FF-A memory objects use 4 KiB pages, while the kernel page
size may be larger. Consequently, tee_shm->offset can be greater than
or equal to FFA_PAGE_SIZE, but OP-TEE rejects such a value in
internal_offs.

Do not encode the excess page offset in offs_low/offs_high. Those
fields describe the logical memref offset and are copied back into
tee_param->shm_offs on return. Folding the page offset into them breaks
parameter round trips when a memref is reused. They are also ignored by
the OPTEE_RPC_CMD_SHM_ALLOC response path, which uses only global_id and
internal_offs to construct the shared-memory mobj.

Instead, start the FF-A descriptor at the 4 KiB page containing the
shared buffer, the same approach as optee_fill_pages_list() in the SMC
ABI. Store the remaining in-page offset in internal_offs and preserve
shm_offs in offs_low/offs_high. This keeps internal_offs within the
FF-A page size, maps RPC allocations at the correct address, and
preserves normal memref offsets across repeated invocations.

Tested on ARMv8-A with 64 KiB PAGE_SIZE. OP-TEE OS ran as a secure
partition under Hafnium (SPMC) over FF-A. Verified registered shared
memory with tee_shm->offset >= 4 KiB, memref reuse on the same
TEEC_Operation, and RPC OPTEE_RPC_CMD_SHM_ALLOC (xtest regression
6007-6009). optee_hello_world, optee_aes, and xtest regression 1005,
1007, 1008, 4001-4003 and 6001-6003 also passed.

Fixes: 4615e5a34b95 ("optee: add FF-A support")
Acked-by: Liming Sun <limings@nvidia.com>
Acked-by: James Hurley <jahurley@nvidia.com>
Acked-by: Dave Thompson <davthompson@nvidia.com>
Signed-off-by: Mahantesh Salimath <mahantesh@nvidia.com>
---
v2:
- Drop helper indirection; mask internal_offs inline (Sumit Garg)
- Keep a single ffa_offs local in optee_ffa_shm_register()

Link: https://lore.kernel.org/lkml/20260904134732.1072541-1-mahantesh@nvidia.com/

 drivers/tee/optee/ffa_abi.c   | 22 ++++++++++++++++++----
 drivers/tee/optee/optee_msg.h |  4 ++--
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index 633715b98625..fdedcab50f23 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -198,7 +198,8 @@ static int to_msg_param_ffa_mem(struct optee_msg_param *mp,
 	if (shm) {
 		u64 shm_offs = p->u.memref.shm_offs;
 
-		mp->u.fmem.internal_offs = shm->offset;
+		mp->u.fmem.internal_offs = tee_shm_get_page_offset(shm) &
+					   (FFA_PAGE_SIZE - 1);
 
 		mp->u.fmem.offs_low = shm_offs;
 		mp->u.fmem.offs_high = shm_offs >> 32;
@@ -284,14 +285,26 @@ static int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm,
 		.nattrs = 1,
 	};
 	struct sg_table sgt;
+	size_t ffa_offs;
 	int rc;
 
+	if (!num_pages)
+		return -EINVAL;
+
 	rc = optee_check_mem_type(start, num_pages);
 	if (rc)
 		return rc;
 
-	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, 0,
-				       num_pages * PAGE_SIZE, GFP_KERNEL);
+	/*
+	 * Start the FF-A descriptor at the 4 KiB page containing the shared
+	 * buffer, skipping unused leading 4 KiB pages when PAGE_SIZE is
+	 * larger. Same approach as optee_fill_pages_list() in the SMC ABI.
+	 * This leaves only the offset into that 4 KiB page for internal_offs.
+	 */
+	ffa_offs = round_down(tee_shm_get_page_offset(shm), FFA_PAGE_SIZE);
+	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, ffa_offs,
+				       num_pages * PAGE_SIZE - ffa_offs,
+				       GFP_KERNEL);
 	if (rc)
 		return rc;
 	args.sg = sgt.sgl;
@@ -458,7 +471,8 @@ static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
 		.attr = OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT,
 		.u.fmem.size = tee_shm_get_size(shm),
 		.u.fmem.global_id = shm->sec_world_id,
-		.u.fmem.internal_offs = shm->offset,
+		.u.fmem.internal_offs = tee_shm_get_page_offset(shm) &
+					(FFA_PAGE_SIZE - 1),
 	};
 
 	arg->ret = TEEC_SUCCESS;
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
index 7d9b12e71c03..6c3043f8da33 100644
--- a/drivers/tee/optee/optee_msg.h
+++ b/drivers/tee/optee/optee_msg.h
@@ -136,8 +136,8 @@ struct optee_msg_param_rmem {
  * struct optee_msg_param_fmem - FF-A memory reference parameter
  * @offs_low:		lower bits of offset into shared memory reference
  * @offs_high:		higher bits of offset into shared memory reference
- * @internal_offs:	internal offset into the first page of shared memory
- *			reference
+ * @internal_offs:	offset into the first 4 KiB page of the FF-A shared
+ *			memory region
  * @size:		size of the buffer
  * @global_id:		global identifier of the shared memory
  */
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] tee: optee: ffa: support shared memory offsets on large-page kernels
  2026-09-10 16:11 ` [PATCH v2] " Mahantesh Salimath
@ 2026-09-21 12:25   ` Sumit Garg
  0 siblings, 0 replies; 5+ messages in thread
From: Sumit Garg @ 2026-09-21 12:25 UTC (permalink / raw)
  To: Mahantesh Salimath; +Cc: Jens Wiklander, op-tee, linux-kernel

On Thu, 10 Sep 2026 at 16:11:24 +0000, Mahantesh Salimath wrote:
>OP-TEE FF-A memory objects use 4 KiB pages, while the kernel page
>size may be larger. Consequently, tee_shm->offset can be greater than
>or equal to FFA_PAGE_SIZE, but OP-TEE rejects such a value in
>internal_offs.
>
>Do not encode the excess page offset in offs_low/offs_high. Those
>fields describe the logical memref offset and are copied back into
>tee_param->shm_offs on return. Folding the page offset into them breaks
>parameter round trips when a memref is reused. They are also ignored by
>the OPTEE_RPC_CMD_SHM_ALLOC response path, which uses only global_id and
>internal_offs to construct the shared-memory mobj.
>
>Instead, start the FF-A descriptor at the 4 KiB page containing the
>shared buffer, the same approach as optee_fill_pages_list() in the SMC
>ABI. Store the remaining in-page offset in internal_offs and preserve
>shm_offs in offs_low/offs_high. This keeps internal_offs within the
>FF-A page size, maps RPC allocations at the correct address, and
>preserves normal memref offsets across repeated invocations.
>
>Tested on ARMv8-A with 64 KiB PAGE_SIZE. OP-TEE OS ran as a secure
>partition under Hafnium (SPMC) over FF-A. Verified registered shared
>memory with tee_shm->offset >= 4 KiB, memref reuse on the same
>TEEC_Operation, and RPC OPTEE_RPC_CMD_SHM_ALLOC (xtest regression
>6007-6009). optee_hello_world, optee_aes, and xtest regression 1005,
>1007, 1008, 4001-4003 and 6001-6003 also passed.
>
>Fixes: 4615e5a34b95 ("optee: add FF-A support")
>Acked-by: Liming Sun <limings@nvidia.com>
>Acked-by: James Hurley <jahurley@nvidia.com>
>Acked-by: Dave Thompson <davthompson@nvidia.com>
>Signed-off-by: Mahantesh Salimath <mahantesh@nvidia.com>
>---
>v2:
>- Drop helper indirection; mask internal_offs inline (Sumit Garg)
>- Keep a single ffa_offs local in optee_ffa_shm_register()
>
>Link: https://lore.kernel.org/lkml/20260904134732.1072541-1-mahantesh@nvidia.com/
>
> drivers/tee/optee/ffa_abi.c   | 22 ++++++++++++++++++----
> drivers/tee/optee/optee_msg.h |  4 ++--
> 2 files changed, 20 insertions(+), 6 deletions(-)

Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com>

-Sumit

>
>diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
>index 633715b98625..fdedcab50f23 100644
>--- a/drivers/tee/optee/ffa_abi.c
>+++ b/drivers/tee/optee/ffa_abi.c
>@@ -198,7 +198,8 @@ static int to_msg_param_ffa_mem(struct optee_msg_param *mp,
> 	if (shm) {
> 		u64 shm_offs = p->u.memref.shm_offs;
>
>-		mp->u.fmem.internal_offs = shm->offset;
>+		mp->u.fmem.internal_offs = tee_shm_get_page_offset(shm) &
>+					   (FFA_PAGE_SIZE - 1);
>
> 		mp->u.fmem.offs_low = shm_offs;
> 		mp->u.fmem.offs_high = shm_offs >> 32;
>@@ -284,14 +285,26 @@ static int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm,
> 		.nattrs = 1,
> 	};
> 	struct sg_table sgt;
>+	size_t ffa_offs;
> 	int rc;
>
>+	if (!num_pages)
>+		return -EINVAL;
>+
> 	rc = optee_check_mem_type(start, num_pages);
> 	if (rc)
> 		return rc;
>
>-	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, 0,
>-				       num_pages * PAGE_SIZE, GFP_KERNEL);
>+	/*
>+	 * Start the FF-A descriptor at the 4 KiB page containing the shared
>+	 * buffer, skipping unused leading 4 KiB pages when PAGE_SIZE is
>+	 * larger. Same approach as optee_fill_pages_list() in the SMC ABI.
>+	 * This leaves only the offset into that 4 KiB page for internal_offs.
>+	 */
>+	ffa_offs = round_down(tee_shm_get_page_offset(shm), FFA_PAGE_SIZE);
>+	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, ffa_offs,
>+				       num_pages * PAGE_SIZE - ffa_offs,
>+				       GFP_KERNEL);
> 	if (rc)
> 		return rc;
> 	args.sg = sgt.sgl;
>@@ -458,7 +471,8 @@ static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
> 		.attr = OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT,
> 		.u.fmem.size = tee_shm_get_size(shm),
> 		.u.fmem.global_id = shm->sec_world_id,
>-		.u.fmem.internal_offs = shm->offset,
>+		.u.fmem.internal_offs = tee_shm_get_page_offset(shm) &
>+					(FFA_PAGE_SIZE - 1),
> 	};
>
> 	arg->ret = TEEC_SUCCESS;
>diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
>index 7d9b12e71c03..6c3043f8da33 100644
>--- a/drivers/tee/optee/optee_msg.h
>+++ b/drivers/tee/optee/optee_msg.h
>@@ -136,8 +136,8 @@ struct optee_msg_param_rmem {
>  * struct optee_msg_param_fmem - FF-A memory reference parameter
>  * @offs_low:		lower bits of offset into shared memory reference
>  * @offs_high:		higher bits of offset into shared memory reference
>- * @internal_offs:	internal offset into the first page of shared memory
>- *			reference
>+ * @internal_offs:	offset into the first 4 KiB page of the FF-A shared
>+ *			memory region
>  * @size:		size of the buffer
>  * @global_id:		global identifier of the shared memory
>  */
>-- 
>2.43.0
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-21 12:25 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-04 13:47 [PATCH] tee: optee: ffa: support shared memory offsets on large-page kernels Mahantesh Salimath
2026-09-10 12:28 ` Sumit Garg
2026-09-10 16:08   ` Mahantesh Salimath
2026-09-10 16:11 ` [PATCH v2] " Mahantesh Salimath
2026-09-21 12:25   ` Sumit Garg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®