mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
@ 2026-07-22  6:59 Harshal Dev
  2026-07-22  6:59 ` [PATCH v2 1/6] tee: qcomtee: Track the object invocation context Harshal Dev
                   ` (6 more replies)
  0 siblings, 7 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-22  6:59 UTC (permalink / raw)
  To: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Harshal Dev

On Qualcomm SoC based platforms, UEFI stores EFI variables within the
Replay Protected Memory Block (RPMB) which is only accessible by the
Qualcomm Trusted Execution Environment (QTEE).

For Qualcomm platforms without emulated RPMB support, specifically
platforms where RPMB is not located within SPI-NOR storage and instead
located on UFS/EMMC storage, non-volatile EFI variables can only be set via
a callback request from the UEFI Secure Application to the RPMB service
running in user-space (within the QTEE supplicant [1]).

Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
QSEECOM based uefisecapp) does not support callback requests. And on
certain Qualcomm platforms such as the RB3Gen2, attempts to access the
QSEECOM interface fail due to lack of support within Qualcomm TEE.
On these platforms, a TEE based uefisecapp client driver is required to:
1. Access cached & volatile EFI variables stored in uefisecapp's memory.
2. Ensure persistence of non-volatile EFI variables via writes through
the RPMB service hosted in the QTEE supplicant.

This series introduces such a uefisecapp TEE client driver for the
aforementioned Qualcomm platforms which installs efi-var operations _if_
the QCOMTEE driver registers support for an object-IPC based uefisecapp
service on the TEE bus during its probe. Only new QTEE firmware versions
available at [2] provide this support.

Thus, QCOMTEE now maintains a static list of always-available object-IPC
based secure services exposed by QTEE. These services are implemented either
within the QTEE kernel or within a pre-loaded Trusted Application (TA)
usually loaded by the bootloader. The uefisecapp TA is an example of a
preloaded TA loaded by UEFI. A static list is required since QTEE does not
yet expose any way to dynamically query and enumerate the services exposed by
it.

To facilitate object-IPC interactions from the kernel-space, this
series also introduces a tee_client_object_invoke_func() to allow
invocation of TEE objects similar to the existing tee_client_invoke_func()
API exported by the TEE subsystem which allows invocation of TEE functions.
Some suporting changes are also introduced to track and handle operations
for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
driver.

Finally and as previously mentioned, access to the object-IPC based uefisecapp
service is restricted on older QTEE firmware versions. A new QTEE firmware
release must be picked up from QArtifactory [2] for all upstream supported
Qualcomm SoCs to enable access to uefisecapp service via the TEE client
driver.

This patch series has been validated on Kodiak RB3Gen2 platform with UFS
storage by attempting to read/write EFI variables via the efivar tool [3]
after mounting the efivarfs filesystem. See [4] for an example.

Merge Strategy:

This patch series could either be taken from the OP-TEE tree or the
QCOM soc tree. I would prefer it to be picked by the OP-TEE tree since
all except the uefisecapp TEE client driver patch in this series make
changes relevant to the TEE subsystem. It would be great if the QCOM soc
tree maintainers can Ack the uefisecapp driver patch.

[1] https://github.com/qualcomm/minkipc
[2] https://shorturl.at/zQU07
[3] https://github.com/rhboot/efivar
[4] https://docs.qualcomm.com/doc/80-70020-27/topic/manage_uefi_environment_variables_using_efivar_tool.html

Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
---
Changes in v2:
- Drop using MSB of the object_id to distingush kernel and user object invoke contexts.
- Introduce enum tee_object_invoke_origin to check the context of object invocation.
- Link to v1: https://lore.kernel.org/r/20260707-qcom_uefisecapp_migrate_qcomtee-v1-0-f659cbd5d04c@oss.qualcomm.com

---
Amirreza Zarrabi (2):
      tee: Add kernel client object invoke helper
      tee: qcomtee: Allow object invokes from kernel clients

Harshal Dev (4):
      tee: qcomtee: Track the object invocation context
      tee: Export uuidv5 generation for TEE backends
      tee: qcomtee: Add support for registering QTEE services on TEE bus
      firmware: qcom: Add support for TEE based EFI-var client driver

 MAINTAINERS                                 |   7 +
 drivers/firmware/qcom/Kconfig               |  24 ++
 drivers/firmware/qcom/Makefile              |   1 +
 drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
 drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++
 drivers/tee/qcomtee/call.c                  | 205 ++++++++++-
 drivers/tee/qcomtee/core.c                  |   9 +-
 drivers/tee/qcomtee/qcomtee.h               |  12 +
 drivers/tee/qcomtee/qcomtee_msg.h           |   1 +
 drivers/tee/qcomtee/qcomtee_object.h        |  16 +-
 drivers/tee/tee_core.c                      |  24 +-
 include/linux/tee_core.h                    |  23 +-
 include/linux/tee_drv.h                     |  18 +-
 13 files changed, 952 insertions(+), 33 deletions(-)
---
base-commit: f3e6330d7fe42b204af05a2dbc68b379e0ad179e
change-id: 20260408-qcom_uefisecapp_migrate_qcomtee-13869d45e014

Best regards,
-- 
Harshal Dev <harshal.dev@oss.qualcomm.com>


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

* [PATCH v2 1/6] tee: qcomtee: Track the object invocation context
  2026-07-22  6:59 [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Harshal Dev
@ 2026-07-22  6:59 ` Harshal Dev
  2026-07-22  6:59 ` [PATCH v2 2/6] tee: Add kernel client object invoke helper Harshal Dev
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-22  6:59 UTC (permalink / raw)
  To: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Harshal Dev

QCOMTEE needs to distinguish between object invocations arriving from
kernel clients and user-space clients in order to correctly marshal
UBUF parameters and decide whether certain operations should be permitted.

Introduce an enum tee_object_invoke_origin to allow clients to indicate
the context of the TEE object invocation, and add a kernel_ctx flag to the
QCOMTEE context so the TEE back-end can track it.

Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
---
 drivers/tee/qcomtee/call.c           | 11 ++++++++---
 drivers/tee/qcomtee/qcomtee_object.h |  8 ++++++--
 drivers/tee/tee_core.c               |  3 ++-
 include/linux/tee_core.h             |  8 +++++++-
 4 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c
index 0efc5646242a..03d33b118f6d 100644
--- a/drivers/tee/qcomtee/call.c
+++ b/drivers/tee/qcomtee/call.c
@@ -393,15 +393,20 @@ static int qcomtee_root_object_check(u32 op, struct tee_param *params,
  */
 static int qcomtee_object_invoke(struct tee_context *ctx,
 				 struct tee_ioctl_object_invoke_arg *arg,
-				 struct tee_param *params)
+				 struct tee_param *params,
+				 enum tee_object_invoke_origin origin)
 {
 	struct qcomtee_context_data *ctxdata = ctx->data;
 	struct qcomtee_object *object;
+	bool kernel_ctx = false;
 	int i, ret, result;
 
 	if (qcomtee_params_check(params, arg->num_params))
 		return -EINVAL;
 
+	if (origin == TEE_OBJECT_INVOKE_KERNEL)
+		kernel_ctx = true;
+
 	/* First, handle reserved operations: */
 	if (arg->op == QCOMTEE_MSG_OBJECT_OP_RELEASE) {
 		del_qtee_object(arg->id, ctxdata);
@@ -411,7 +416,7 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
 
 	/* Otherwise, invoke a QTEE object: */
 	struct qcomtee_object_invoke_ctx *oic __free(kfree) =
-		qcomtee_object_invoke_ctx_alloc(ctx);
+		qcomtee_object_invoke_ctx_alloc(ctx, kernel_ctx);
 	if (!oic)
 		return -ENOMEM;
 
@@ -648,7 +653,7 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
 	int result;
 
 	struct qcomtee_object_invoke_ctx *oic __free(kfree) =
-		qcomtee_object_invoke_ctx_alloc(ctx);
+		qcomtee_object_invoke_ctx_alloc(ctx, true);
 	if (!oic)
 		return;
 
diff --git a/drivers/tee/qcomtee/qcomtee_object.h b/drivers/tee/qcomtee/qcomtee_object.h
index 8b4401ecad48..2528d07e4576 100644
--- a/drivers/tee/qcomtee/qcomtee_object.h
+++ b/drivers/tee/qcomtee/qcomtee_object.h
@@ -146,6 +146,7 @@ static inline int qcomtee_args_len(struct qcomtee_arg *args)
  * struct qcomtee_object_invoke_ctx - QTEE context for object invocation.
  * @ctx: TEE context for this invocation.
  * @flags: flags for the invocation context.
+ * @kernel_ctx: flag that indicates this context is owned by a kernel client.
  * @errno: error code for the invocation.
  * @object: current object invoked in this callback context.
  * @u: array of arguments for the current invocation (+1 for ending arg).
@@ -158,6 +159,7 @@ static inline int qcomtee_args_len(struct qcomtee_arg *args)
 struct qcomtee_object_invoke_ctx {
 	struct tee_context *ctx;
 	unsigned long flags;
+	bool kernel_ctx;
 	int errno;
 
 	struct qcomtee_object *object;
@@ -172,13 +174,15 @@ struct qcomtee_object_invoke_ctx {
 };
 
 static inline struct qcomtee_object_invoke_ctx *
-qcomtee_object_invoke_ctx_alloc(struct tee_context *ctx)
+qcomtee_object_invoke_ctx_alloc(struct tee_context *ctx, bool kernel_ctx)
 {
 	struct qcomtee_object_invoke_ctx *oic;
 
 	oic = kzalloc_obj(*oic);
-	if (oic)
+	if (oic) {
 		oic->ctx = ctx;
+		oic->kernel_ctx = kernel_ctx;
+	}
 	return oic;
 }
 
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index ef9642d72672..dba5d4d2d47e 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -706,7 +706,8 @@ static int tee_ioctl_object_invoke(struct tee_context *ctx,
 			goto out;
 	}
 
-	rc = ctx->teedev->desc->ops->object_invoke_func(ctx, &arg, params);
+	rc = ctx->teedev->desc->ops->object_invoke_func(ctx, &arg, params,
+							TEE_OBJECT_INVOKE_USERSPACE);
 	if (rc)
 		goto out;
 
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
index f993d5118edd..bcb5418d6fdc 100644
--- a/include/linux/tee_core.h
+++ b/include/linux/tee_core.h
@@ -73,6 +73,11 @@ struct tee_device {
 	struct tee_shm_pool *pool;
 };
 
+enum tee_object_invoke_origin {
+	TEE_OBJECT_INVOKE_USERSPACE,
+	TEE_OBJECT_INVOKE_KERNEL,
+};
+
 /**
  * struct tee_driver_ops - driver operations vtable
  * @get_version:	returns version of driver
@@ -117,7 +122,8 @@ struct tee_driver_ops {
 			   struct tee_param *param);
 	int (*object_invoke_func)(struct tee_context *ctx,
 				  struct tee_ioctl_object_invoke_arg *arg,
-				  struct tee_param *param);
+				  struct tee_param *param,
+				  enum tee_object_invoke_origin origin);
 	int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session);
 	int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params,
 			 struct tee_param *param);

-- 
2.34.1


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

* [PATCH v2 2/6] tee: Add kernel client object invoke helper
  2026-07-22  6:59 [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Harshal Dev
  2026-07-22  6:59 ` [PATCH v2 1/6] tee: qcomtee: Track the object invocation context Harshal Dev
@ 2026-07-22  6:59 ` Harshal Dev
  2026-07-22  6:59 ` [PATCH v2 3/6] tee: qcomtee: Allow object invokes from kernel clients Harshal Dev
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-22  6:59 UTC (permalink / raw)
  To: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Harshal Dev

From: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>

Kernel clients can open a TEE context and invoke regular TA commands
through tee_client_invoke_func(). However, there is currently no
equivalent helper for invoking TEE objects.

Add tee_client_object_invoke_func() as a kernel client API for issuing
object invocation requests. The helper checks that the backend provides
object_invoke_func() before forwarding the request by setting the origin
as TEE_OBJECT_INVOKE_KERNEL. This allows TEE backends to support
privileged object-based calls from the kernel-space.

Co-developed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
---
 drivers/tee/tee_core.c  | 12 ++++++++++++
 include/linux/tee_drv.h | 13 +++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index dba5d4d2d47e..bb418490f3af 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -1410,6 +1410,18 @@ int tee_client_invoke_func(struct tee_context *ctx,
 }
 EXPORT_SYMBOL_GPL(tee_client_invoke_func);
 
+int tee_client_object_invoke_func(struct tee_context *ctx,
+				  struct tee_ioctl_object_invoke_arg *arg,
+				  struct tee_param *param)
+{
+	if (!ctx->teedev->desc->ops->object_invoke_func)
+		return -EINVAL;
+
+	return ctx->teedev->desc->ops->object_invoke_func(ctx, arg, param,
+							  TEE_OBJECT_INVOKE_KERNEL);
+}
+EXPORT_SYMBOL_GPL(tee_client_object_invoke_func);
+
 int tee_client_cancel_req(struct tee_context *ctx,
 			  struct tee_ioctl_cancel_arg *arg)
 {
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index e561a26f537a..ca99c6b747a8 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -283,6 +283,19 @@ int tee_client_invoke_func(struct tee_context *ctx,
 			   struct tee_ioctl_invoke_arg *arg,
 			   struct tee_param *param);
 
+/**
+ * tee_client_object_invoke_func() - Invoke a TEE object from kernel space
+ * @ctx:    TEE Context
+ * @arg:    Invoke arguments, see description of
+ *          struct tee_ioctl_object_invoke_arg
+ * @param:  Parameters for the object invocation
+ *
+ * Return: On success, returns 0; on failure, returns < 0.
+ */
+int tee_client_object_invoke_func(struct tee_context *ctx,
+				  struct tee_ioctl_object_invoke_arg *arg,
+				  struct tee_param *param);
+
 /**
  * tee_client_cancel_req() - Request cancellation of the previous open-session
  * or invoke-command operations in a Trusted Application

-- 
2.34.1


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

* [PATCH v2 3/6] tee: qcomtee: Allow object invokes from kernel clients
  2026-07-22  6:59 [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Harshal Dev
  2026-07-22  6:59 ` [PATCH v2 1/6] tee: qcomtee: Track the object invocation context Harshal Dev
  2026-07-22  6:59 ` [PATCH v2 2/6] tee: Add kernel client object invoke helper Harshal Dev
@ 2026-07-22  6:59 ` Harshal Dev
  2026-07-29  7:06   ` Amirreza Zarrabi
  2026-07-22  6:59 ` [PATCH v2 4/6] tee: Export uuidv5 generation for TEE backends Harshal Dev
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 24+ messages in thread
From: Harshal Dev @ 2026-07-22  6:59 UTC (permalink / raw)
  To: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Harshal Dev

From: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>

QCOMTEE currently treats UBUF parameters as userspace addresses and
applies userspace restrictions when invoking the root object. This is
not suitable for object invocation requests issued by kernel clients.

Use the kernel_ctx flag to distinguish kernel client requests from
userspace requests. For kernel contexts, do not mark UBUF parameters as
user addresses, and allow permitted root-object operations to proceed
without applying the userspace-only checks.

This allows in-kernel users of tee_client_object_invoke_func() to issue
object invocation requests through the qcomtee backend.

Co-developed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
---
 drivers/tee/qcomtee/call.c           | 34 +++++++++++++++++++++++-----------
 drivers/tee/qcomtee/qcomtee_object.h |  5 +++--
 include/linux/tee_drv.h              |  5 ++++-
 3 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c
index 03d33b118f6d..c1bba5fbfa3e 100644
--- a/drivers/tee/qcomtee/call.c
+++ b/drivers/tee/qcomtee/call.c
@@ -202,7 +202,7 @@ int qcomtee_objref_from_arg(struct tee_param *param, struct qcomtee_arg *arg,
  */
 static int qcomtee_params_to_args(struct qcomtee_arg *u,
 				  struct tee_param *params, int num_params,
-				  struct tee_context *ctx)
+				  struct qcomtee_object_invoke_ctx *oic)
 {
 	int i;
 
@@ -210,8 +210,14 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
 		switch (params[i].attr) {
 		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT:
 		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:
-			u[i].flags = QCOMTEE_ARG_FLAGS_UADDR;
-			u[i].b.uaddr = params[i].u.ubuf.uaddr;
+			u[i].flags = oic->kernel_ctx ? 0 :
+				QCOMTEE_ARG_FLAGS_UADDR;
+
+			if (u[i].flags && QCOMTEE_ARG_FLAGS_UADDR)
+				u[i].b.uaddr = params[i].u.ubuf.uaddr;
+			else
+				u[i].b.addr = params[i].u.ubuf.addr;
+
 			u[i].b.size = params[i].u.ubuf.size;
 
 			if (params[i].attr ==
@@ -223,7 +229,7 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
 			break;
 		case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT:
 			u[i].type = QCOMTEE_ARG_TYPE_IO;
-			if (qcomtee_objref_to_arg(&u[i], &params[i], ctx))
+			if (qcomtee_objref_to_arg(&u[i], &params[i], oic->ctx))
 				goto out_failed;
 
 			break;
@@ -270,7 +276,7 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
  */
 static int qcomtee_params_from_args(struct tee_param *params,
 				    struct qcomtee_arg *u, int num_params,
-				    struct tee_context *ctx)
+				    struct qcomtee_object_invoke_ctx *oic)
 {
 	int i, np;
 
@@ -288,7 +294,8 @@ static int qcomtee_params_from_args(struct tee_param *params,
 			break;
 		case QCOMTEE_ARG_TYPE_OO:
 			/* TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT */
-			if (qcomtee_objref_from_arg(&params[np], &u[np], ctx))
+			if (qcomtee_objref_from_arg(&params[np], &u[np],
+						    oic->ctx))
 				goto out_failed;
 
 			break;
@@ -304,7 +311,7 @@ static int qcomtee_params_from_args(struct tee_param *params,
 	/* Undo qcomtee_objref_from_arg(). */
 	for (i = 0; i < np; i++) {
 		if (params[i].attr == TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT)
-			qcomtee_context_del_qtee_object(&params[i], ctx);
+			qcomtee_context_del_qtee_object(&params[i], oic->ctx);
 	}
 
 	/* Release any IO and OO objects not processed. */
@@ -357,7 +364,8 @@ static int qcomtee_params_check(struct tee_param *params, int num_params)
 }
 
 /* Check if an operation on ROOT_QCOMTEE_OBJECT from userspace is permitted. */
-static int qcomtee_root_object_check(u32 op, struct tee_param *params,
+static int qcomtee_root_object_check(struct qcomtee_object_invoke_ctx *oic,
+				     u32 op, struct tee_param *params,
 				     int num_params)
 {
 	/* Some privileged operations recognized by QTEE. */
@@ -366,6 +374,9 @@ static int qcomtee_root_object_check(u32 op, struct tee_param *params,
 	    op == QCOMTEE_ROOT_OP_ADCI_SHUTDOWN)
 		return -EINVAL;
 
+	if (oic->kernel_ctx)
+		return 0;
+
 	/*
 	 * QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS is to register with QTEE
 	 * by passing a credential object as input OBJREF. TEE_OBJREF_NULL as a
@@ -429,7 +440,8 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
 	/* Get an object to invoke. */
 	if (arg->id == TEE_OBJREF_NULL) {
 		/* Use ROOT if TEE_OBJREF_NULL is invoked. */
-		if (qcomtee_root_object_check(arg->op, params, arg->num_params))
+		if (qcomtee_root_object_check(oic, arg->op, params,
+					      arg->num_params))
 			return -EINVAL;
 
 		object = ROOT_QCOMTEE_OBJECT;
@@ -437,7 +449,7 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
 		return -EINVAL;
 	}
 
-	ret = qcomtee_params_to_args(u, params, arg->num_params, ctx);
+	ret = qcomtee_params_to_args(u, params, arg->num_params, oic);
 	if (ret)
 		goto out;
 
@@ -455,7 +467,7 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
 
 	if (!result) {
 		/* Assume service is UNAVAIL if unable to process the result. */
-		if (qcomtee_params_from_args(params, u, arg->num_params, ctx))
+		if (qcomtee_params_from_args(params, u, arg->num_params, oic))
 			result = QCOMTEE_MSG_ERROR_UNAVAIL;
 	} else {
 		/*
diff --git a/drivers/tee/qcomtee/qcomtee_object.h b/drivers/tee/qcomtee/qcomtee_object.h
index 2528d07e4576..7bd6e23b038c 100644
--- a/drivers/tee/qcomtee/qcomtee_object.h
+++ b/drivers/tee/qcomtee/qcomtee_object.h
@@ -112,8 +112,9 @@ struct qcomtee_buffer {
  * @b: address and size if the type of argument is a buffer.
  * @o: object instance if the type of argument is an object.
  *
- * &qcomtee_arg.flags only accepts %QCOMTEE_ARG_FLAGS_UADDR for now, which
- * states that &qcomtee_arg.b contains a userspace address in uaddr.
++ * If %QCOMTEE_ARG_FLAGS_UADDR is set in &qcomtee_arg.flags then it implies
++ * that &qcomtee_arg.b contains a userspace address in uaddr.
++ * Otherwise, &qcomtee_arg.b contains a kernel address in addr.
  */
 struct qcomtee_arg {
 	enum qcomtee_arg_type type;
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index ca99c6b747a8..71d0536db60e 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -83,7 +83,10 @@ struct tee_param_memref {
 };
 
 struct tee_param_ubuf {
-	void __user *uaddr;
+	union {
+		void *addr;
+		void __user *uaddr;
+	};
 	size_t size;
 };
 

-- 
2.34.1


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

* [PATCH v2 4/6] tee: Export uuidv5 generation for TEE backends
  2026-07-22  6:59 [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Harshal Dev
                   ` (2 preceding siblings ...)
  2026-07-22  6:59 ` [PATCH v2 3/6] tee: qcomtee: Allow object invokes from kernel clients Harshal Dev
@ 2026-07-22  6:59 ` Harshal Dev
  2026-07-22  6:59 ` [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus Harshal Dev
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-22  6:59 UTC (permalink / raw)
  To: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Harshal Dev

Export the uuidv5() function defined in the TEE core to all TEE backends.
This enables the TEE backend drivers to generate a UUID for identifying
and registering their secure services on the TEE bus.

Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
---
 drivers/tee/tee_core.c   |  9 +++++----
 include/linux/tee_core.h | 15 +++++++++++++++
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index bb418490f3af..df88727b3680 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -135,7 +135,7 @@ static int tee_release(struct inode *inode, struct file *filp)
 }
 
 /**
- * uuid_v5() - Calculate UUIDv5
+ * tee_generate_uuid_v5() - Calculate UUIDv5
  * @uuid: Resulting UUID
  * @ns: Name space ID for UUIDv5 function
  * @name: Name for UUIDv5 function
@@ -146,8 +146,8 @@ static int tee_release(struct inode *inode, struct file *filp)
  * This implements section (for SHA-1):
  * 4.3.  Algorithm for Creating a Name-Based UUID
  */
-static void uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name,
-		    size_t size)
+void tee_generate_uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name,
+			  size_t size)
 {
 	unsigned char hash[SHA1_DIGEST_SIZE];
 	struct sha1_ctx ctx;
@@ -163,6 +163,7 @@ static void uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name,
 	uuid->b[6] = (hash[6] & 0x0F) | 0x50;
 	uuid->b[8] = (hash[8] & 0x3F) | 0x80;
 }
+EXPORT_SYMBOL_GPL(tee_generate_uuid_v5);
 
 int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
 				 const u8 connection_data[TEE_IOCTL_UUID_LEN])
@@ -228,7 +229,7 @@ int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
 		goto out_free_name;
 	}
 
-	uuid_v5(uuid, &tee_client_uuid_ns, name, name_len);
+	tee_generate_uuid_v5(uuid, &tee_client_uuid_ns, name, name_len);
 out_free_name:
 	kfree(name);
 
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
index bcb5418d6fdc..a3f4f88b8423 100644
--- a/include/linux/tee_core.h
+++ b/include/linux/tee_core.h
@@ -272,6 +272,21 @@ void tee_device_set_dev_groups(struct tee_device *teedev,
 int tee_session_calc_client_uuid(uuid_t *uuid, u32 connection_method,
 				 const u8 connection_data[TEE_IOCTL_UUID_LEN]);
 
+/**
+ * tee_generate_uuid_v5() - Calculate UUIDv5
+ * @uuid: Resulting UUID
+ * @ns: Name space ID for UUIDv5 function
+ * @name: Name for UUIDv5 function
+ * @size: Size of name
+ *
+ * UUIDv5 is specific in RFC 4122.
+ *
+ * This implements section (for SHA-1):
+ * 4.3.  Algorithm for Creating a Name-Based UUID
+ */
+void tee_generate_uuid_v5(uuid_t *uuid, const uuid_t *ns, const void *name,
+			  size_t size);
+
 /**
  * struct tee_shm_pool - shared memory pool
  * @ops:		operations

-- 
2.34.1


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

* [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus
  2026-07-22  6:59 [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Harshal Dev
                   ` (3 preceding siblings ...)
  2026-07-22  6:59 ` [PATCH v2 4/6] tee: Export uuidv5 generation for TEE backends Harshal Dev
@ 2026-07-22  6:59 ` Harshal Dev
  2026-07-22  8:29   ` Dmitry Baryshkov
  2026-07-29  7:05   ` Amirreza Zarrabi
  2026-07-22  6:59 ` [PATCH v2 6/6] firmware: qcom: Add support for TEE based EFI-var client driver Harshal Dev
  2026-07-22  8:26 ` [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Dmitry Baryshkov
  6 siblings, 2 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-22  6:59 UTC (permalink / raw)
  To: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Harshal Dev

QTEE exposes certain secure services implemented either within the QTEE
kernel or via pre-loaded Trusted Applications (TAs). Such always-available
services can be readily accessed by TEE client drivers via QTEE's
object-IPC protocol if the service is registered as a device on the TEE
bus.

One such service is the EFI-variables service, implemented by the
uefisecapp TA which enables kernel clients to access EFI variables at
runtime.

Maintain a static list of such always-available secure services and add
support for the QCOMTEE driver to register these services as devices on
the TEE bus during probe.

Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
---
 drivers/tee/qcomtee/call.c           | 160 ++++++++++++++++++++++++++++++++++-
 drivers/tee/qcomtee/core.c           |   9 +-
 drivers/tee/qcomtee/qcomtee.h        |  12 +++
 drivers/tee/qcomtee/qcomtee_msg.h    |   1 +
 drivers/tee/qcomtee/qcomtee_object.h |   3 +-
 5 files changed, 177 insertions(+), 8 deletions(-)

diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c
index c1bba5fbfa3e..e909955e6b21 100644
--- a/drivers/tee/qcomtee/call.c
+++ b/drivers/tee/qcomtee/call.c
@@ -662,7 +662,7 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
 {
 	struct qcomtee_object *client_env, *service;
 	struct qcomtee_arg u[3] = { 0 };
-	int result;
+	int result, error = 0;
 
 	struct qcomtee_object_invoke_ctx *oic __free(kfree) =
 		qcomtee_object_invoke_ctx_alloc(ctx, true);
@@ -675,9 +675,13 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
 
 	/* Get ''FeatureVersions Service'' object. */
 	service = qcomtee_object_get_service(oic, client_env,
-					     QCOMTEE_FEATURE_VER_UID);
-	if (service == NULL_QCOMTEE_OBJECT)
+					     QCOMTEE_FEATURE_VER_UID,
+					     &error);
+	if (service == NULL_QCOMTEE_OBJECT) {
+		if (error)
+			pr_err("Failed to get service! error: %d\n", error);
 		goto out_failed;
+	}
 
 	/* IB: Feature to query. */
 	u[0].b.addr = &id;
@@ -697,6 +701,153 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
 	qcomtee_object_put(client_env);
 }
 
+/**
+ * is_qcomtee_service_available() - Check if the QTEE service identified by the UID
+ * is available
+ * @ctx: TEE context.
+ * @uid: 32-bit UID of the service.
+ *
+ * Returns true if the service exists and is available.
+ * Returns false if a service is not exposed by QTEE.
+ */
+static bool is_qcomtee_service_available(struct tee_context *ctx, u32 uid)
+{
+	struct qcomtee_object *client_env;
+	struct qcomtee_object *service;
+	int error = 0;
+	bool ret = false;
+
+	struct qcomtee_object_invoke_ctx *oic __free(kfree) =
+		qcomtee_object_invoke_ctx_alloc(ctx, true);
+	if (!oic)
+		return ret;
+
+	client_env = qcomtee_object_get_client_env(oic);
+	if (client_env == NULL_QCOMTEE_OBJECT)
+		return ret;
+
+	/* Get service object corresponding to the uid. */
+	service = qcomtee_object_get_service(oic, client_env, uid, &error);
+	if (service != NULL_QCOMTEE_OBJECT) {
+		qcomtee_object_put(service);
+		ret = true;
+	}
+
+	/* When we fail to get the service, QTEE provides the reason. */
+	if (error)
+		pr_err("Failed to get service! error: %d\n", error);
+
+	qcomtee_object_put(client_env);
+	return ret;
+}
+
+/*
+ * QTEE Service UUID name space identifier
+ *
+ * A random UUID that is allocated as a name space identifier for forming UUID's
+ * representing secure services exposed by QTEE.
+ */
+static const uuid_t qtee_service_uuid_ns = UUID_INIT(0xe1b48857, 0x6154, 0x49f9,
+						     0x93, 0x4e, 0xa2, 0xf2,
+						     0x0a, 0xba, 0x98, 0x42);
+
+static const struct qtee_service qtee_services[] = {
+	{ "qcom.tz.uefisecapp",
+	   QCOMTEE_UEFI_SEC_UID }
+};
+
+static void qtee_release_service(struct device *dev)
+{
+	struct tee_client_device *qtee_service = to_tee_client_device(dev);
+
+	kfree(qtee_service);
+}
+
+/**
+ * qtee_enumerate_service() - Enumerate a given QTEE service and register
+ * it on the TEE bus as a TEE client device
+ * @ctx: TEE context.
+ * @service_uuid: UUID of the service to be registered on the TEE bus.
+ * @uid: 32-bit UID used by QTEE to identify the service.
+ *
+ * Returns 0 on success and < 0 on failure.
+ */
+static int qtee_enumerate_service(struct tee_context *ctx, const char *service_name,
+				  const u32 uid)
+{
+	struct tee_client_device *qtee_service;
+	uuid_t service_uuid;
+	int rc;
+
+	if (!is_qcomtee_service_available(ctx, uid))
+		return -ENXIO;
+
+	tee_generate_uuid_v5(&service_uuid, &qtee_service_uuid_ns, service_name,
+			     strlen(service_name));
+
+	qtee_service = kzalloc_obj(*qtee_service);
+	if (!qtee_service)
+		return -ENOMEM;
+
+	qtee_service->dev.bus = &tee_bus_type;
+	qtee_service->dev.release = qtee_release_service;
+	if (dev_set_name(&qtee_service->dev, "qtee-svc-%pUb", &service_uuid)) {
+		kfree(qtee_service);
+		return -ENOMEM;
+	}
+	uuid_copy(&qtee_service->id.uuid, &service_uuid);
+
+	rc = device_register(&qtee_service->dev);
+	if (rc) {
+		pr_err("QTEE service registration failed, err: %d\n", rc);
+		put_device(&qtee_service->dev);
+		kfree(qtee_service);
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * qtee_enumerate_services() - Enumerate all the secure services exposed by QTEE
+ * from the static 'qtee_services' list and register them on the TEE bus as
+ * TEE client devices.
+ *
+ * Not all versions of QTEE support a given service. Hence, we try to
+ * enumerate as many services from the 'qtee_services' list as possible.
+ * Not being able to enumerate a service shouldn't cause the driver probe
+ * to fail since none of the services in the list are mandatory for
+ * establishing communication with QTEE.
+ * @ctx: TEE context.
+ */
+static void qtee_enumerate_services(struct tee_context *ctx)
+{
+	int rc;
+	u32 idx;
+
+	for (idx = 0; idx < ARRAY_SIZE(qtee_services); idx++) {
+		rc = qtee_enumerate_service(ctx, qtee_services[idx].name,
+					    qtee_services[idx].uid);
+		if (rc == -ENXIO)
+			pr_err("QTEE does not implement service %d.\n",
+			       qtee_services[idx].uid);
+	}
+}
+
+static int qtee_unregister_service(struct device *dev, void *data)
+{
+	if (!strncmp(dev_name(dev), "qtee-svc", strlen("qtee-svc")))
+		device_unregister(dev);
+
+	return 0;
+}
+
+static void qtee_unregister_services(void)
+{
+	bus_for_each_dev(&tee_bus_type, NULL, NULL,
+			 qtee_unregister_service);
+}
+
 static const struct tee_driver_ops qcomtee_ops = {
 	.get_version = qcomtee_get_version,
 	.open = qcomtee_open,
@@ -778,6 +929,8 @@ static int qcomtee_probe(struct platform_device *pdev)
 		QTEE_VERSION_GET_MINOR(qcomtee->qtee_version),
 		QTEE_VERSION_GET_PATCH(qcomtee->qtee_version));
 
+	qtee_enumerate_services(qcomtee->ctx);
+
 	return 0;
 
 err_dest_wq:
@@ -807,6 +960,7 @@ static void qcomtee_remove(struct platform_device *pdev)
 {
 	struct qcomtee *qcomtee = platform_get_drvdata(pdev);
 
+	qtee_unregister_services();
 	teedev_close_context(qcomtee->ctx);
 	/* Wait for RELEASE operations to be processed for QTEE objects. */
 	tee_device_unregister(qcomtee->teedev);
diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c
index b1cb50e434f0..4e39e867c3e9 100644
--- a/drivers/tee/qcomtee/core.c
+++ b/drivers/tee/qcomtee/core.c
@@ -896,19 +896,20 @@ qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic)
 
 struct qcomtee_object *
 qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic,
-			   struct qcomtee_object *client_env, u32 uid)
+			   struct qcomtee_object *client_env, u32 uid,
+			   int *result)
 {
 	struct qcomtee_arg u[3] = { 0 };
-	int ret, result;
+	int ret;
 
 	u[0].b.addr = &uid;
 	u[0].b.size = sizeof(uid);
 	u[0].type = QCOMTEE_ARG_TYPE_IB;
 	u[1].type = QCOMTEE_ARG_TYPE_OO;
 	ret = qcomtee_object_do_invoke(oic, client_env, QCOMTEE_CLIENT_ENV_OPEN,
-				       u, &result);
+				       u, result);
 
-	if (ret || result)
+	if (ret || *result)
 		return NULL_QCOMTEE_OBJECT;
 
 	return u[1].o;
diff --git a/drivers/tee/qcomtee/qcomtee.h b/drivers/tee/qcomtee/qcomtee.h
index f39bf63fd1c2..66d305a46c0a 100644
--- a/drivers/tee/qcomtee/qcomtee.h
+++ b/drivers/tee/qcomtee/qcomtee.h
@@ -17,6 +17,8 @@
 #define QCOMTEE_OBJREF_FLAG_USER	BIT(1)
 #define QCOMTEE_OBJREF_FLAG_MEM		BIT(2)
 
+#define QTEE_UUID_NS_NAME_SIZE	        128
+
 /**
  * struct qcomtee - Main service struct.
  * @teedev: client device.
@@ -39,6 +41,16 @@ struct qcomtee {
 	u32 qtee_version;
 };
 
+/**
+ * struct qtee_service - A secure service exposed by QTEE identified by a 32-bit UID.
+ * @name: Name of the QTEE service.
+ * @uid: 32-bit UID used by QTEE to identify the service.
+ */
+struct qtee_service {
+	const char *name;
+	const u32 uid;
+};
+
 void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic);
 struct qcomtee_object *qcomtee_idx_erase(struct qcomtee_object_invoke_ctx *oic,
 					 u32 idx);
diff --git a/drivers/tee/qcomtee/qcomtee_msg.h b/drivers/tee/qcomtee/qcomtee_msg.h
index 878f70178a5b..ecaf8db67d45 100644
--- a/drivers/tee/qcomtee/qcomtee_msg.h
+++ b/drivers/tee/qcomtee/qcomtee_msg.h
@@ -105,6 +105,7 @@ union qcomtee_msg_arg {
 #define QTEE_VERSION_GET_MINOR(x) (((x) >> 12) & 0xffU)
 #define QTEE_VERSION_GET_PATCH(x) ((x) >> 0 & 0xfffU)
 
+#define QCOMTEE_UEFI_SEC_UID            413
 /* Response types as returned from qcomtee_object_invoke_ctx_invoke(). */
 
 /* The message contains a callback request. */
diff --git a/drivers/tee/qcomtee/qcomtee_object.h b/drivers/tee/qcomtee/qcomtee_object.h
index 7bd6e23b038c..f4cb9b8fcbd4 100644
--- a/drivers/tee/qcomtee/qcomtee_object.h
+++ b/drivers/tee/qcomtee/qcomtee_object.h
@@ -316,6 +316,7 @@ qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic);
 
 struct qcomtee_object *
 qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic,
-			   struct qcomtee_object *client_env, u32 uid);
+			   struct qcomtee_object *client_env, u32 uid,
+			   int *result);
 
 #endif /* QCOMTEE_OBJECT_H */

-- 
2.34.1


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

* [PATCH v2 6/6] firmware: qcom: Add support for TEE based EFI-var client driver
  2026-07-22  6:59 [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Harshal Dev
                   ` (4 preceding siblings ...)
  2026-07-22  6:59 ` [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus Harshal Dev
@ 2026-07-22  6:59 ` Harshal Dev
  2026-07-22  8:37   ` Dmitry Baryshkov
  2026-07-22  8:26 ` [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Dmitry Baryshkov
  6 siblings, 1 reply; 24+ messages in thread
From: Harshal Dev @ 2026-07-22  6:59 UTC (permalink / raw)
  To: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Harshal Dev

On Qualcomm SoC based platforms, UEFI stores EFI variables within the
Replay Protected Memory Block (RPMB) which is only accessible by the
Qualcomm Trusted Execution Environment (QTEE).

For Qualcomm platforms without emulated RPMB support, specifically
platforms where RPMB is not located within SPI-NOR storage and instead
located on UFS/EMMC storage, non-volatile EFI variables can only be set via
a callback request from the UEFI Trusted Application (TA) to the RPMB
service running in user-space (within the QTEE supplicant).

Unlike the QCOMTEE driver, the QSEECOM driver (used by the current
uefisecapp client driver) does not support callback requests. And on
certain Qualcomm platforms such as the RB3Gen2, attempts to access the
QSEECOM interface fail due to lack of support within QTEE.
On all such platforms, a TEE based uefisecapp client driver must be used to
access cached/volatile EFI variables within the uefisecapp TA and ensure
persistence of writes to non-volatile EFI variables through the RPMB
service hosted in the QTEE supplicant.

Add support for a TEE based uefisecapp client driver which installs efivar
operations after obtaining an object reference to the uefisecapp service.
This enables the kernel/user-space to access/modify both volatile EFI vars
stored by the Secure Application (in-memory) and non-volatile ones stored
within RPMB.

Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
---
 MAINTAINERS                                 |   7 +
 drivers/firmware/qcom/Kconfig               |  24 ++
 drivers/firmware/qcom/Makefile              |   1 +
 drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
 drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++
 5 files changed, 677 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 10d12b51b1f6..e8316007370f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22018,6 +22018,13 @@ L:	linux-arm-msm@vger.kernel.org
 S:	Maintained
 F:	drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
 
+QUALCOMM TEE UEFISECAPP DRIVER
+M:	Harshal Dev <harshal.dev@oss.qualcomm.com>
+L:	linux-arm-msm@vger.kernel.org
+S:	Maintained
+F:	drivers/firmware/qcom/qcom_tee_uefisecapp.c
+F:	drivers/firmware/qcom/qcom_tee_uefisecapp.h
+
 QUALCOMM RMNET DRIVER
 M:	Subash Abhinov Kasiviswanathan <subash.a.kasiviswanathan@oss.qualcomm.com>
 M:	Sean Tranchetti <sean.tranchetti@oss.qualcomm.com>
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index b477d54b495a..20ce8b58e490 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -74,4 +74,28 @@ config QCOM_QSEECOM_UEFISECAPP
 	  Select Y here to provide access to EFI variables on the aforementioned
 	  platforms.
 
+config QCOM_TEE_UEFISECAPP
+	tristate "Qualcomm TEE UEFI Secure App client driver"
+	depends on QCOMTEE
+	depends on EFI
+	depends on !QCOM_QSEECOM_UEFISECAPP
+	help
+	  On Qualcomm SoC based platforms without emulated RPMB support,
+	  specifically platforms where RPMB is not present within SPI-NOR storage
+	  and instead located on UFS/EMMC storage, non-volatile EFI variables can
+	  only be set via a callback request from the UEFI Secure Application to
+	  the RPMB service running in user-space (within the QTEE supplicant:
+	  github.com/qualcomm/minkipc). Unlike the QCOMTEE driver, the QSEECOM
+	  driver used by the QSEECOM based uefisecapp does not support callback
+	  requests. And so on these platforms, the TEE based uefisecapp client
+	  driver must be used to ensure persistence of non-volatile EFI variables
+	  via writes through the RPMB service hosted in the QTEE supplicant.
+
+	  This module provides a TEE client driver for uefisecapp, installing efivar
+	  operations to allow the kernel and user-space access to EFI variables.
+
+	  Select m here to provide access to EFI variables on the aforementioned
+	  platforms if your Linux distribution has QTEE supplicant installed and
+	  running.
+
 endmenu
diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
index 0be40a1abc13..d780490b2865 100644
--- a/drivers/firmware/qcom/Makefile
+++ b/drivers/firmware/qcom/Makefile
@@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
 obj-$(CONFIG_QCOM_TZMEM)	+= qcom_tzmem.o
 obj-$(CONFIG_QCOM_QSEECOM)	+= qcom_qseecom.o
 obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
+obj-$(CONFIG_QCOM_TEE_UEFISECAPP) += qcom_tee_uefisecapp.o
diff --git a/drivers/firmware/qcom/qcom_tee_uefisecapp.c b/drivers/firmware/qcom/qcom_tee_uefisecapp.c
new file mode 100644
index 000000000000..9a5a6f145a9f
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_tee_uefisecapp.c
@@ -0,0 +1,525 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/efi.h>
+#include <linux/tee.h>
+#include <linux/tee_drv.h>
+#include <linux/ucs2_string.h>
+#include "qcom_tee_uefisecapp.h"
+
+static struct qcomtee_uefisec_app uefisec_app;
+
+static int qcuefi_get_variable(struct tee_param_ubuf in_variable, efi_guid_t *guid,
+			       struct tee_param_ubuf in_attributes,
+			       struct tee_param_ubuf *data,
+			       u32 *out_attributes, u32 *out_errno)
+{
+	int ret;
+	struct tee_ioctl_object_invoke_arg inv_arg;
+	u64 obj_id = uefisec_app.uefisec_svc_obj.id;
+	u32 nparams = 5;
+	struct tee_param param[nparams];
+
+	struct {
+		efi_guid_t guid;
+		u32 in_data_size;
+	} in_cong = { 0 };
+
+	struct {
+		u32 out_data_size;
+		u32 attributes;
+		u32 errno;
+	} out_cong = { 0 };
+
+	in_cong.guid = *guid;
+	in_cong.in_data_size = data->size;
+
+	memset(&inv_arg, 0, sizeof(inv_arg));
+	memset(&param, 0, sizeof(param));
+
+	SET_INVOKE_ARG(inv_arg, obj_id, QCOMTEE_UEFI_SEC_OP_GET_VAR, nparams);
+	SET_TEE_PARAM_UBUF(param[0], UBUF_INPUT, TEE_PARAM_UBUF(in_cong));
+	SET_TEE_PARAM_UBUF(param[1], UBUF_INPUT, in_variable);
+	SET_TEE_PARAM_UBUF(param[2], UBUF_INPUT, in_attributes);
+	SET_TEE_PARAM_UBUF(param[3], UBUF_OUTPUT, TEE_PARAM_UBUF(out_cong));
+	SET_TEE_PARAM_UBUF(param[4], UBUF_OUTPUT, *data);
+
+	ret = tee_client_object_invoke_func(uefisec_app.ctx, &inv_arg, param);
+	if (ret < 0 || inv_arg.ret != 0) {
+		dev_err(uefisec_app.dev, "QCOMTEE_UEFI_SEC_OP_GET_VAR invoke ret: %d, err: 0x%x\n",
+			ret, inv_arg.ret);
+		return ret ?: inv_arg.ret;
+	}
+
+	data->size = out_cong.out_data_size;
+	*out_attributes = out_cong.attributes;
+	*out_errno = out_cong.errno;
+
+	return ret;
+}
+
+static efi_status_t qcomtee_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid,
+					      u32 *attr, unsigned long *data_size,
+					      void *data)
+{
+	int ret;
+	u32 in_attr, out_attributes, out_errno;
+	struct tee_param_ubuf in_data, in_var, in_attributes;
+
+	if (!name || !guid)
+		return EFI_INVALID_PARAMETER;
+
+	/* 'attr' can be NULL, however an input attribute is always expected
+	 * by UefiSecApp TA
+	 */
+	in_attr = 0;
+	if (attr)
+		in_attr = *attr;
+
+	in_data = (struct tee_param_ubuf){ .addr = data, *data_size };
+	in_var = (struct tee_param_ubuf){ .addr = name,
+					  (ucs2_strlen(name) + 1) * sizeof(*name) };
+	in_attributes = (struct tee_param_ubuf){ .addr = &in_attr, sizeof(u32) };
+
+	/* On SUCCESS, 'data' member of 'in_data' has already been updated. */
+	ret = qcuefi_get_variable(in_var, guid, in_attributes, &in_data,
+				  &out_attributes, &out_errno);
+
+	if (ret)
+		return EFI_DEVICE_ERROR;
+
+	if (!out_errno || out_errno == QCOMTEE_UEFI_SEC_ERROR_SIZE_OUT) {
+		/* If 'attr' is NULL 'out_attributes' is not updated. */
+		if (attr)
+			*attr = out_attributes;
+
+		*data_size = in_data.size;
+	}
+
+	return uefisecapp_err_to_efi_status(out_errno);
+}
+
+static int qcuefi_set_variable(struct tee_param_ubuf in_variable, efi_guid_t *guid,
+			       u32 attributes, struct tee_param_ubuf data,
+			       u32 *out_errno)
+{
+	int ret;
+	struct tee_ioctl_object_invoke_arg inv_arg;
+	u64 obj_id = uefisec_app.uefisec_svc_obj.id;
+	u32 nparams = 4;
+	struct tee_param param[nparams];
+
+	struct {
+		efi_guid_t guid;
+		u32 attributes;
+		u32 in_data_size;
+	} in_cong = { 0 };
+
+	in_cong.guid = *guid;
+	in_cong.attributes = attributes;
+	in_cong.in_data_size = data.size;
+
+	memset(&inv_arg, 0, sizeof(inv_arg));
+	memset(&param, 0, sizeof(param));
+
+	SET_INVOKE_ARG(inv_arg, obj_id, QCOMTEE_UEFI_SEC_OP_SET_VAR, nparams);
+	SET_TEE_PARAM_UBUF(param[0], UBUF_INPUT, TEE_PARAM_UBUF(in_cong));
+	SET_TEE_PARAM_UBUF(param[1], UBUF_INPUT, in_variable);
+	SET_TEE_PARAM_UBUF(param[2], UBUF_INPUT, data);
+	SET_TEE_PARAM_UBUF(param[3], UBUF_OUTPUT, TEE_PARAM_UBUF(*out_errno));
+
+	ret = tee_client_object_invoke_func(uefisec_app.ctx, &inv_arg, param);
+	if (ret < 0 || inv_arg.ret != 0) {
+		dev_err(uefisec_app.dev, "QCOMTEE_UEFI_SEC_OP_SET_VAR invoke ret: %d, err: 0x%x\n",
+			ret, inv_arg.ret);
+		return ret ?: inv_arg.ret;
+	}
+
+	return ret;
+}
+
+static efi_status_t qcomtee_uefi_set_variable(efi_char16_t *name, efi_guid_t *guid,
+					      u32 attr, unsigned long data_size,
+					      void *data)
+{
+	int ret;
+	u32 out_errno;
+	struct tee_param_ubuf in_data, in_var;
+
+	if (!name || !guid)
+		return EFI_INVALID_PARAMETER;
+
+	in_data = (struct tee_param_ubuf){ .addr = data, data_size };
+	in_var = (struct tee_param_ubuf){ .addr = name,
+					  (ucs2_strlen(name) + 1) * sizeof(*name) };
+
+	ret = qcuefi_set_variable(in_var, guid, attr, in_data, &out_errno);
+	if (ret)
+		return EFI_DEVICE_ERROR;
+
+	return uefisecapp_err_to_efi_status(out_errno);
+}
+
+static int qcuefi_get_next_variable(struct tee_param_ubuf in_variable, efi_guid_t *guid,
+				    struct tee_param_ubuf *out_variable,
+				    efi_guid_t *out_vendor_guid, u32 *out_errno)
+{
+	int ret;
+	struct tee_ioctl_object_invoke_arg inv_arg;
+	u64 obj_id = uefisec_app.uefisec_svc_obj.id;
+	u32 nparams = 4;
+	struct tee_param param[nparams];
+
+	struct {
+		efi_guid_t guid;
+		u32 in_data_size;
+	} in_cong = { 0 };
+
+	struct {
+		efi_guid_t guid;
+		u32 out_data_size;
+		u32 errno;
+	} out_cong = { 0 };
+
+	/* Pass size of available buffer */
+	in_cong.in_data_size = out_variable->size;
+	in_cong.guid = *guid;
+
+	memset(&inv_arg, 0, sizeof(inv_arg));
+	memset(&param, 0, sizeof(param));
+
+	SET_INVOKE_ARG(inv_arg, obj_id, QCOMTEE_UEFI_SEC_OP_GET_NEXT_VAR_NAME, nparams);
+	SET_TEE_PARAM_UBUF(param[0], UBUF_INPUT, TEE_PARAM_UBUF(in_cong));
+	SET_TEE_PARAM_UBUF(param[1], UBUF_INPUT, in_variable);
+	SET_TEE_PARAM_UBUF(param[2], UBUF_OUTPUT, TEE_PARAM_UBUF(out_cong));
+	SET_TEE_PARAM_UBUF(param[3], UBUF_OUTPUT, *out_variable);
+
+	ret = tee_client_object_invoke_func(uefisec_app.ctx, &inv_arg, param);
+	if (ret < 0 || inv_arg.ret != 0) {
+		dev_err(uefisec_app.dev, "QCOMTEE_UEFI_SEC_OP_GET_NEXT_VAR_NAME invoke ret: %d, err: 0x%x\n",
+			ret, inv_arg.ret);
+		return ret ?: inv_arg.ret;
+	}
+
+	/* UefiSecApp TA does not touch 'out_variable.size'. Update it here.
+	 * On SUCCESS (!out_errno), 'out_data_size' is length of name in 'out_variable.addr'.
+	 * On failure (out_errno == QCOMTEE_UEFI_SEC_ERROR_SIZE_OUT), 'out_data_size' is
+	 * actual name length.
+	 * Otherwise, it's undefined.
+	 */
+	out_variable->size = out_cong.out_data_size;
+	*out_vendor_guid = out_cong.guid;
+	*out_errno = out_cong.errno;
+
+	return ret;
+}
+
+static efi_status_t qcomtee_uefi_get_next_variable(unsigned long *name_size,
+						   efi_char16_t *name,
+						   efi_guid_t *guid)
+{
+	int ret;
+	u32 out_errno;
+	efi_guid_t out_guid;
+	struct tee_param_ubuf in_var, out_var;
+
+	if (!name_size || !name || !guid)
+		return EFI_INVALID_PARAMETER;
+
+	if (*name_size == 0)
+		return EFI_INVALID_PARAMETER;
+
+	/* For 'in_var', 'name_size' is not necessarily size of 'name';
+	 * could be size of buffer where 'name' has been stored. TA expects a
+	 * NULL-terminated string in 'name' and ignores the size.
+	 * For 'out_var', 'name_size' is size of buffer pointed by 'name'.
+	 */
+	in_var = (struct tee_param_ubuf){ .addr = name, *name_size };
+	out_var = (struct tee_param_ubuf){ .addr = name, *name_size };
+
+	ret = qcuefi_get_next_variable(in_var, guid, &out_var, &out_guid,
+				       &out_errno);
+	if (ret)
+		return EFI_DEVICE_ERROR;
+
+	if (!out_errno)
+		*guid = out_guid;
+
+	if (!out_errno || out_errno == QCOMTEE_UEFI_SEC_ERROR_SIZE_OUT)
+		*name_size = out_var.size;
+
+	/* On SUCCESS, 'name' stores the next variable name. */
+	return uefisecapp_err_to_efi_status(out_errno);
+}
+
+static int qcuefi_query_variable_info(u32 attributes,
+				      u64 *maximum_variable_storage_size,
+				      u64 *remaining_variable_storage_size,
+				      u64 *maximum_variable_size, u32 *out_errno)
+{
+	int ret;
+	struct tee_ioctl_object_invoke_arg inv_arg;
+	u64 obj_id = uefisec_app.uefisec_svc_obj.id;
+	u32 nparams = 2;
+	struct tee_param param[nparams];
+
+	struct {
+		u64 max_var_storage_size;
+		u64 remaining_var_storage_size;
+		u64 maximum_var_size;
+		u32 errno;
+	} out_cong = { 0 };
+
+	memset(&inv_arg, 0, sizeof(inv_arg));
+	memset(&param, 0, sizeof(param));
+
+	SET_INVOKE_ARG(inv_arg, obj_id, QCOMTEE_UEFI_SEC_OP_QUERY_VAR_INFO, nparams);
+	SET_TEE_PARAM_UBUF(param[0], UBUF_INPUT, TEE_PARAM_UBUF(attributes));
+	SET_TEE_PARAM_UBUF(param[1], UBUF_OUTPUT, TEE_PARAM_UBUF(out_cong));
+
+	ret = tee_client_object_invoke_func(uefisec_app.ctx, &inv_arg, param);
+	if (ret < 0 || inv_arg.ret != 0) {
+		dev_err(uefisec_app.dev, "QCOMTEE_UEFI_SEC_OP_QUERY_VAR_INFO invoke ret: %d, err: 0x%x\n",
+			ret, inv_arg.ret);
+		return ret ?: inv_arg.ret;
+	}
+
+	*maximum_variable_storage_size = out_cong.max_var_storage_size;
+	*remaining_variable_storage_size = out_cong.remaining_var_storage_size;
+	*maximum_variable_size = out_cong.maximum_var_size;
+	*out_errno = out_cong.errno;
+
+	return ret;
+}
+
+static efi_status_t qcomtee_uefi_query_variable_info(u32 attr, u64 *storage_space,
+						     u64 *remaining_space,
+						     u64 *max_variable_size)
+{
+	int ret;
+	u32 out_errno;
+	u64 maximum_variable_storage_size;
+	u64 remaining_variable_storage_size;
+	u64 maximum_variable_size;
+
+	if (!storage_space || !remaining_space || !max_variable_size)
+		return EFI_INVALID_PARAMETER;
+
+	ret = qcuefi_query_variable_info(attr,
+					 &maximum_variable_storage_size,
+					 &remaining_variable_storage_size,
+					 &maximum_variable_size,
+					 &out_errno);
+
+	if (ret)
+		return EFI_DEVICE_ERROR;
+
+	if (!out_errno) {
+		*storage_space = maximum_variable_storage_size;
+		*remaining_space = remaining_variable_storage_size;
+		*max_variable_size = maximum_variable_size;
+	}
+
+	return uefisecapp_err_to_efi_status(out_errno);
+}
+
+/**
+ * qcomtee_release_object() - Release an object returned by QTEE.
+ *
+ * Each object returned by QTEE repesents a secure service exposed to the
+ * client. Whenever an secure service is opened, QTEE may allocate resources
+ * on the client's behalf. Therefore, once the client is done accessing the
+ * secure service, the object representing it should be explicitly released
+ * so that QTEE can release the associated resources as well.
+ *
+ * @ctx: TEE context.
+ * @object: The object to release.
+ */
+static void qcomtee_release_object(struct tee_context *ctx,
+				   struct tee_param_objref object)
+{
+	struct tee_ioctl_object_invoke_arg inv_arg;
+
+	memset(&inv_arg, 0, sizeof(inv_arg));
+	SET_INVOKE_ARG(inv_arg, object.id, QCOMTEE_MSG_OBJECT_OP_RELEASE, 0);
+	tee_client_object_invoke_func(ctx, &inv_arg, NULL);
+}
+
+/**
+ * qcomtee_get_uefisec_svc_obj() - Get a UEFI Secure App service object to
+ * begin communication with the service.
+ * @ctx: TEE context.
+ * @client_env_obj: The client environment object returned earlier by QTEE.
+ * @uefisec_svc_obj: The UEFI Secure App service object.
+ *
+ * Returns 0 on success.
+ * Returns < 0 if client environment object invocation failed.
+ * Returns > 0 if client environment invocation was success but UEFI Secure App
+ * service object could not be returned for some other reason (represented by the
+ * returned value)
+ */
+static int qcomtee_get_uefisec_svc_obj(struct tee_context *ctx,
+				       struct tee_param_objref client_env_obj,
+				       struct tee_param_objref *uefisec_svc_obj)
+{
+	int ret;
+	struct tee_ioctl_object_invoke_arg inv_arg;
+	u64 obj_id = client_env_obj.id;
+	u32 nparams = 2;
+	struct tee_param param[nparams];
+	u32 uefisec_uid = QCOMTEE_UEFI_SEC_UID;
+
+	memset(&inv_arg, 0, sizeof(inv_arg));
+	memset(&param, 0, sizeof(param));
+
+	SET_INVOKE_ARG(inv_arg, obj_id, QCOMTEE_OP_CLIENT_ENV_OPEN, nparams);
+	SET_TEE_PARAM_UBUF(param[0], UBUF_INPUT, TEE_PARAM_UBUF(uefisec_uid));
+	SET_TEE_PARAM_OBJREF(param[1], OBJREF_OUTPUT, 0, 0);
+
+	ret = tee_client_object_invoke_func(ctx, &inv_arg, param);
+	if (ret < 0 || inv_arg.ret != 0) {
+		dev_err(uefisec_app.dev, "QCOMTEE_CLIENT_ENV_OPEN invoke ret: %d, err: 0x%x\n",
+			ret, inv_arg.ret);
+		return ret ?: inv_arg.ret;
+	}
+
+	*uefisec_svc_obj = param[1].u.objref;
+	return ret;
+}
+
+/**
+ * qcomtee_get_client_env_obj() - Get a client environment object to begin
+ * object exchange with QTEE.
+ * @ctx: TEE context.
+ * @client_env_obj: The client environment object returned by QTEE.
+ *
+ * Returns 0 on success.
+ * Returns < 0 if root object invocation failed.
+ * Returns > 0 if root object invocation was success but client environment
+ * object could not be returned for some other reason (represented by the
+ * returned value)
+ */
+static int qcomtee_get_client_env_obj(struct tee_context *ctx,
+				      struct tee_param_objref *client_env_obj)
+{
+	int ret;
+	struct tee_ioctl_object_invoke_arg inv_arg;
+	u32 nparams = 2;
+	struct tee_param param[nparams];
+
+	memset(&inv_arg, 0, sizeof(inv_arg));
+	memset(&param, 0, sizeof(param));
+
+	SET_INVOKE_ARG(inv_arg, TEE_OBJREF_NULL,
+		       QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS, nparams);
+	SET_TEE_PARAM_OBJREF(param[0], OBJREF_INPUT, TEE_OBJREF_NULL, 0);
+	SET_TEE_PARAM_OBJREF(param[1], OBJREF_OUTPUT, 0, 0);
+
+	ret = tee_client_object_invoke_func(ctx, &inv_arg, param);
+	if (ret < 0 || inv_arg.ret != 0) {
+		dev_err(uefisec_app.dev, "QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS invoke ret: %d, err: 0x%x\n",
+			ret, inv_arg.ret);
+		return ret ?: inv_arg.ret;
+	}
+
+	*client_env_obj = param[1].u.objref;
+	return ret;
+}
+
+static const struct efivar_operations qcom_efivar_ops = {
+	.get_variable = qcomtee_uefi_get_variable,
+	.set_variable = qcomtee_uefi_set_variable,
+	.get_next_variable = qcomtee_uefi_get_next_variable,
+	.query_variable_info = qcomtee_uefi_query_variable_info,
+};
+
+static int qcomtee_ctx_match(struct tee_ioctl_version_data *ver,
+			     const void *data)
+{
+	return (ver->impl_id == TEE_IMPL_ID_QTEE);
+}
+
+static int qcomtee_uefisecapp_probe(struct tee_client_device *tee_dev)
+{
+	int ret, err;
+	struct tee_param_objref client_env_obj;
+	struct tee_param_objref uefisec_svc_obj;
+
+	uefisec_app.dev = &tee_dev->dev;
+	/* Open context with QCOMTEE driver */
+	uefisec_app.ctx = tee_client_open_context(NULL, qcomtee_ctx_match, NULL,
+						  NULL);
+	if (IS_ERR(uefisec_app.ctx))
+		return -ENODEV;
+
+	/* Obtain a reference to client_env object to begin object exchange
+	 * with QTEE
+	 */
+	ret = qcomtee_get_client_env_obj(uefisec_app.ctx, &client_env_obj);
+	if (ret) {
+		err = -EINVAL;
+		goto err_get_client_env;
+	}
+
+	/* Obtain a reference to the uefisec_svc object which provides access to
+	 * the EFI var storage.
+	 */
+	ret = qcomtee_get_uefisec_svc_obj(uefisec_app.ctx, client_env_obj,
+					  &uefisec_svc_obj);
+	if (ret) {
+		err = -EINVAL;
+		goto err_get_uefisec_svc;
+	}
+	uefisec_app.uefisec_svc_obj = uefisec_svc_obj;
+
+	ret = efivars_register(&uefisec_app.efivars, &qcom_efivar_ops);
+	if (ret) {
+		err = ret;
+		goto err_efi_vars_reg;
+	}
+
+	/* We don't need to keep a reference to this object anymore, we only
+	 * needed it to obtain the uefisec_svc object.
+	 */
+	qcomtee_release_object(uefisec_app.ctx, client_env_obj);
+	return 0;
+
+err_efi_vars_reg:
+	qcomtee_release_object(uefisec_app.ctx, uefisec_svc_obj);
+err_get_uefisec_svc:
+	qcomtee_release_object(uefisec_app.ctx, client_env_obj);
+err_get_client_env:
+	tee_client_close_context(uefisec_app.ctx);
+
+	return err;
+}
+
+static void qcomtee_uefisecapp_remove(struct tee_client_device *tee_dev)
+{
+	efivars_unregister(&uefisec_app.efivars);
+	qcomtee_release_object(uefisec_app.ctx, uefisec_app.uefisec_svc_obj);
+	tee_client_close_context(uefisec_app.ctx);
+}
+
+static const struct tee_client_device_id qcomtee_uefisecapp_id_table[] = {
+	{UEFISECAPP_UUID},
+	{}
+};
+MODULE_DEVICE_TABLE(tee, qcomtee_uefisecapp_id_table);
+
+static struct tee_client_driver qcomtee_uefisecapp_driver = {
+	.id_table	= qcomtee_uefisecapp_id_table,
+	.probe		= qcomtee_uefisecapp_probe,
+	.remove		= qcomtee_uefisecapp_remove,
+	.driver		= {
+		.name		= "qcom-tee-uefisecapp",
+	},
+};
+
+module_tee_client_driver(qcomtee_uefisecapp_driver);
+
+MODULE_AUTHOR("Qualcomm");
+MODULE_DESCRIPTION("TEE client driver for Qualcomm TEE UEFI Secure App");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/qcom/qcom_tee_uefisecapp.h b/drivers/firmware/qcom/qcom_tee_uefisecapp.h
new file mode 100644
index 000000000000..a014c18cfed0
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_tee_uefisecapp.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef QCOM_TEE_UEFISECAPP_H
+#define QCOM_TEE_UEFISECAPP_H
+
+#define QCOMTEE_OP_CLIENT_ENV_OPEN 0
+#define QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS 5
+
+/* Each service exposed by QTEE is identified by a 32-bit UID */
+#define QCOMTEE_UEFI_SEC_UID                 413
+
+/* Operations supported by the UEFI Sec App service */
+#define QCOMTEE_UEFI_SEC_OP_GET_VAR 0
+#define QCOMTEE_UEFI_SEC_OP_SET_VAR 1
+#define QCOMTEE_UEFI_SEC_OP_QUERY_VAR_INFO 2
+#define QCOMTEE_UEFI_SEC_OP_GET_NEXT_VAR_NAME 3
+
+/* Error codes returned by the UEFI Sec App service */
+#define QCOMTEE_UEFI_SEC_SUCCESS 0
+#define QCOMTEE_UEFI_SEC_ERROR_INVALID_PARAMETER 10
+#define QCOMTEE_UEFI_SEC_ERROR_UNSUPPORTED 11
+#define QCOMTEE_UEFI_SEC_ERROR_WRITE_PROTECTED 12
+#define QCOMTEE_UEFI_SEC_ERROR_SECURITY_VIOLATION 13
+#define QCOMTEE_UEFI_SEC_ERROR_DEVICE_ERROR 14
+#define QCOMTEE_UEFI_SEC_ERROR_OUT_OF_RESOURCES 15
+#define QCOMTEE_UEFI_SEC_ERROR_VOLUME_CORRUPTED 16
+#define QCOMTEE_UEFI_SEC_ERROR_SIZE_OUT 17
+#define QCOMTEE_UEFI_SEC_ERROR_NOT_FOUND 18
+#define QCOMTEE_UEFI_SEC_ERROR_ALREADY_STARTED 19
+
+/* Operations for objects are 32-bit. QCOMTEE transport uses the upper 16 bits. */
+#define QCOMTEE_MSG_OBJECT_OP_MASK GENMASK(15, 0)
+#define QCOMTEE_MSG_OBJECT_OP_RELEASE (QCOMTEE_MSG_OBJECT_OP_MASK - 0)
+
+/**
+ * struct qcomtee_uefisec_app - An instance of UEFI Secure Application.
+ * @dev: TEE client device on the TEE bus which represents uefisecapp.
+ * @ctx: The context opened with the TEE subsystem by the uefisecapp client.
+ * @uefisec_svc_obj: A TEE object representing the uefisecapp service.
+ * @efivars: EFI variables registered with the EFI subsystem.
+ */
+struct qcomtee_uefisec_app {
+	struct device *dev;
+	struct tee_context *ctx;
+	struct tee_param_objref uefisec_svc_obj;
+	struct efivars efivars;
+};
+
+#define UEFISECAPP_UUID \
+	UUID_INIT(0x01f95dcd, 0x2d7e, 0x58be, \
+		  0xa1, 0x43, 0x81, 0x32, 0xa1, 0x72, 0xdb, 0x7d)
+
+/* Short-hands for these long attribute names */
+#define UBUF_INPUT     TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT
+#define UBUF_OUTPUT    TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT
+#define OBJREF_INPUT   TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT
+#define OBJREF_OUTPUT  TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT
+
+/* Init instance of 'struct tee_param_objref'. */
+#define SET_TEE_PARAM_OBJREF(param, attri, obj_id, obj_flag) do { \
+		(param).attr = (attri); \
+		(param).u.objref.id = (obj_id); \
+		(param).u.objref.flags = (obj_flag); \
+	} while (0)
+
+/* Init instance of 'struct tee_param_ubuf'. */
+#define SET_TEE_PARAM_UBUF(param, attri, ubuff) do { \
+		(param).attr = (attri); \
+		(param).u.ubuf = (ubuff);  \
+	} while (0)
+
+#define TEE_PARAM_UBUF(x) ((struct tee_param_ubuf){ .addr = &(x), sizeof(x) })
+
+#define SET_INVOKE_ARG(arg, object_id, opp, nparam) do { \
+		(arg).id = (object_id); \
+		(arg).op = (opp); \
+		(arg).num_params = (nparam); \
+	} while (0)
+
+static inline efi_status_t uefisecapp_err_to_efi_status(u32 err)
+{
+	switch (err) {
+	case QCOMTEE_UEFI_SEC_SUCCESS:
+		return EFI_SUCCESS;
+
+	case QCOMTEE_UEFI_SEC_ERROR_INVALID_PARAMETER:
+		return EFI_INVALID_PARAMETER;
+
+	case QCOMTEE_UEFI_SEC_ERROR_UNSUPPORTED:
+		return EFI_UNSUPPORTED;
+
+	case QCOMTEE_UEFI_SEC_ERROR_WRITE_PROTECTED:
+		return EFI_WRITE_PROTECTED;
+
+	case QCOMTEE_UEFI_SEC_ERROR_SECURITY_VIOLATION:
+		return EFI_SECURITY_VIOLATION;
+
+	case QCOMTEE_UEFI_SEC_ERROR_DEVICE_ERROR:
+		return EFI_DEVICE_ERROR;
+
+	case QCOMTEE_UEFI_SEC_ERROR_OUT_OF_RESOURCES:
+		return EFI_OUT_OF_RESOURCES;
+
+	case QCOMTEE_UEFI_SEC_ERROR_SIZE_OUT:
+		return EFI_BUFFER_TOO_SMALL;
+
+	case QCOMTEE_UEFI_SEC_ERROR_NOT_FOUND:
+		return EFI_NOT_FOUND;
+
+	/* No matching on EFI_* list. */
+	case QCOMTEE_UEFI_SEC_ERROR_ALREADY_STARTED: /* EFI_ALREADY_STARTED.  */
+	case QCOMTEE_UEFI_SEC_ERROR_VOLUME_CORRUPTED: /* EFI_VOLUME_CORRUPTED. */
+	default:
+		return EFI_DEVICE_ERROR;
+	}
+}
+#endif /* QCOM_TEE_UEFISECAPP_H */

-- 
2.34.1


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

* Re: [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
  2026-07-22  6:59 [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Harshal Dev
                   ` (5 preceding siblings ...)
  2026-07-22  6:59 ` [PATCH v2 6/6] firmware: qcom: Add support for TEE based EFI-var client driver Harshal Dev
@ 2026-07-22  8:26 ` Dmitry Baryshkov
  2026-07-24  9:13   ` Harshal Dev
  6 siblings, 1 reply; 24+ messages in thread
From: Dmitry Baryshkov @ 2026-07-22  8:26 UTC (permalink / raw)
  To: Harshal Dev
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

On Wed, Jul 22, 2026 at 12:29:11PM +0530, Harshal Dev wrote:
> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
> Replay Protected Memory Block (RPMB) which is only accessible by the
> Qualcomm Trusted Execution Environment (QTEE).

Is it so? I think RPMB is accessible to Linux...

> For Qualcomm platforms without emulated RPMB support, specifically

What is emulated RPMB support? Why is it mentioned here? Which platforms
use emulated RPMB?

> platforms where RPMB is not located within SPI-NOR storage and instead
> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
> a callback request from the UEFI Secure Application to the RPMB service
> running in user-space (within the QTEE supplicant [1]).

Can it be moved to the kernel?

> 
> Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
> QSEECOM based uefisecapp) does not support callback requests.

How did it work then? I think Windows has been perfectly using QSEECOM
rather than QTEE.

> And on
> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
> QSEECOM interface fail due to lack of support within Qualcomm TEE.

So, I assume, on RB3 Gen2 the QSEECOM doesn't report uefisecapp as
supported. Does it?

> On these platforms, a TEE based uefisecapp client driver is required to:
> 1. Access cached & volatile EFI variables stored in uefisecapp's memory.
> 2. Ensure persistence of non-volatile EFI variables via writes through
> the RPMB service hosted in the QTEE supplicant.
> 
> This series introduces such a uefisecapp TEE client driver for the
> aforementioned Qualcomm platforms which installs efi-var operations _if_
> the QCOMTEE driver registers support for an object-IPC based uefisecapp
> service on the TEE bus during its probe. Only new QTEE firmware versions
> available at [2] provide this support.

What about existing WoA devices?

> 
> Thus, QCOMTEE now maintains a static list of always-available object-IPC
> based secure services exposed by QTEE. These services are implemented either
> within the QTEE kernel or within a pre-loaded Trusted Application (TA)
> usually loaded by the bootloader. The uefisecapp TA is an example of a
> preloaded TA loaded by UEFI. A static list is required since QTEE does not
> yet expose any way to dynamically query and enumerate the services exposed by
> it.

Can it be fixed instead of having static lists? In the end, we can't
guarantee that users update the firmware.

> 
> To facilitate object-IPC interactions from the kernel-space, this
> series also introduces a tee_client_object_invoke_func() to allow
> invocation of TEE objects similar to the existing tee_client_invoke_func()
> API exported by the TEE subsystem which allows invocation of TEE functions.
> Some suporting changes are also introduced to track and handle operations
> for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
> driver.
> 
> Finally and as previously mentioned, access to the object-IPC based uefisecapp
> service is restricted on older QTEE firmware versions. A new QTEE firmware
> release must be picked up from QArtifactory [2] for all upstream supported
> Qualcomm SoCs to enable access to uefisecapp service via the TEE client
> driver.

What about fused devices?

> 
> This patch series has been validated on Kodiak RB3Gen2 platform with UFS
> storage by attempting to read/write EFI variables via the efivar tool [3]
> after mounting the efivarfs filesystem. See [4] for an example.
> 
> Merge Strategy:
> 
> This patch series could either be taken from the OP-TEE tree or the
> QCOM soc tree. I would prefer it to be picked by the OP-TEE tree since
> all except the uefisecapp TEE client driver patch in this series make
> changes relevant to the TEE subsystem. It would be great if the QCOM soc
> tree maintainers can Ack the uefisecapp driver patch.
> 
> [1] https://github.com/qualcomm/minkipc
> [2] https://shorturl.at/zQU07
> [3] https://github.com/rhboot/efivar
> [4] https://docs.qualcomm.com/doc/80-70020-27/topic/manage_uefi_environment_variables_using_efivar_tool.html
> 
> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
> ---
> Changes in v2:
> - Drop using MSB of the object_id to distingush kernel and user object invoke contexts.
> - Introduce enum tee_object_invoke_origin to check the context of object invocation.
> - Link to v1: https://lore.kernel.org/r/20260707-qcom_uefisecapp_migrate_qcomtee-v1-0-f659cbd5d04c@oss.qualcomm.com
> 
> ---
> Amirreza Zarrabi (2):
>       tee: Add kernel client object invoke helper
>       tee: qcomtee: Allow object invokes from kernel clients
> 
> Harshal Dev (4):
>       tee: qcomtee: Track the object invocation context
>       tee: Export uuidv5 generation for TEE backends
>       tee: qcomtee: Add support for registering QTEE services on TEE bus
>       firmware: qcom: Add support for TEE based EFI-var client driver
> 
>  MAINTAINERS                                 |   7 +
>  drivers/firmware/qcom/Kconfig               |  24 ++
>  drivers/firmware/qcom/Makefile              |   1 +
>  drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
>  drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++

I don't see any changes to the QSEECOM drivers. Is it allowed to use
QSEECOM and QTEE access to uefisecapp at the same time?

>  drivers/tee/qcomtee/call.c                  | 205 ++++++++++-
>  drivers/tee/qcomtee/core.c                  |   9 +-
>  drivers/tee/qcomtee/qcomtee.h               |  12 +
>  drivers/tee/qcomtee/qcomtee_msg.h           |   1 +
>  drivers/tee/qcomtee/qcomtee_object.h        |  16 +-
>  drivers/tee/tee_core.c                      |  24 +-
>  include/linux/tee_core.h                    |  23 +-
>  include/linux/tee_drv.h                     |  18 +-
>  13 files changed, 952 insertions(+), 33 deletions(-)
> ---
> base-commit: f3e6330d7fe42b204af05a2dbc68b379e0ad179e
> change-id: 20260408-qcom_uefisecapp_migrate_qcomtee-13869d45e014
> 
> Best regards,
> -- 
> Harshal Dev <harshal.dev@oss.qualcomm.com>
> 

-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus
  2026-07-22  6:59 ` [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus Harshal Dev
@ 2026-07-22  8:29   ` Dmitry Baryshkov
  2026-07-24  9:13     ` Harshal Dev
  2026-07-29  7:05   ` Amirreza Zarrabi
  1 sibling, 1 reply; 24+ messages in thread
From: Dmitry Baryshkov @ 2026-07-22  8:29 UTC (permalink / raw)
  To: Harshal Dev
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

On Wed, Jul 22, 2026 at 12:29:16PM +0530, Harshal Dev wrote:
> QTEE exposes certain secure services implemented either within the QTEE
> kernel or via pre-loaded Trusted Applications (TAs). Such always-available
> services can be readily accessed by TEE client drivers via QTEE's
> object-IPC protocol if the service is registered as a device on the TEE
> bus.
> 
> One such service is the EFI-variables service, implemented by the
> uefisecapp TA which enables kernel clients to access EFI variables at
> runtime.
> 
> Maintain a static list of such always-available secure services and add
> support for the QCOMTEE driver to register these services as devices on
> the TEE bus during probe.

Is it always available on all platforms supporting QTEE?

> 
> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
> ---
>  drivers/tee/qcomtee/call.c           | 160 ++++++++++++++++++++++++++++++++++-
>  drivers/tee/qcomtee/core.c           |   9 +-
>  drivers/tee/qcomtee/qcomtee.h        |  12 +++
>  drivers/tee/qcomtee/qcomtee_msg.h    |   1 +
>  drivers/tee/qcomtee/qcomtee_object.h |   3 +-
>  5 files changed, 177 insertions(+), 8 deletions(-)
> 

-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 6/6] firmware: qcom: Add support for TEE based EFI-var client driver
  2026-07-22  6:59 ` [PATCH v2 6/6] firmware: qcom: Add support for TEE based EFI-var client driver Harshal Dev
@ 2026-07-22  8:37   ` Dmitry Baryshkov
  2026-07-24  9:14     ` Harshal Dev
  0 siblings, 1 reply; 24+ messages in thread
From: Dmitry Baryshkov @ 2026-07-22  8:37 UTC (permalink / raw)
  To: Harshal Dev
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

On Wed, Jul 22, 2026 at 12:29:17PM +0530, Harshal Dev wrote:
> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
> Replay Protected Memory Block (RPMB) which is only accessible by the
> Qualcomm Trusted Execution Environment (QTEE).
> 
> For Qualcomm platforms without emulated RPMB support, specifically
> platforms where RPMB is not located within SPI-NOR storage and instead
> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
> a callback request from the UEFI Trusted Application (TA) to the RPMB
> service running in user-space (within the QTEE supplicant).
> 
> Unlike the QCOMTEE driver, the QSEECOM driver (used by the current
> uefisecapp client driver) does not support callback requests. And on
> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
> QSEECOM interface fail due to lack of support within QTEE.
> On all such platforms, a TEE based uefisecapp client driver must be used to
> access cached/volatile EFI variables within the uefisecapp TA and ensure
> persistence of writes to non-volatile EFI variables through the RPMB
> service hosted in the QTEE supplicant.
> 
> Add support for a TEE based uefisecapp client driver which installs efivar
> operations after obtaining an object reference to the uefisecapp service.
> This enables the kernel/user-space to access/modify both volatile EFI vars
> stored by the Secure Application (in-memory) and non-volatile ones stored
> within RPMB.
> 
> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
> ---
>  MAINTAINERS                                 |   7 +
>  drivers/firmware/qcom/Kconfig               |  24 ++
>  drivers/firmware/qcom/Makefile              |   1 +
>  drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
>  drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++
>  5 files changed, 677 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 10d12b51b1f6..e8316007370f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22018,6 +22018,13 @@ L:	linux-arm-msm@vger.kernel.org
>  S:	Maintained
>  F:	drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
>  
> +QUALCOMM TEE UEFISECAPP DRIVER
> +M:	Harshal Dev <harshal.dev@oss.qualcomm.com>
> +L:	linux-arm-msm@vger.kernel.org
> +S:	Maintained
> +F:	drivers/firmware/qcom/qcom_tee_uefisecapp.c
> +F:	drivers/firmware/qcom/qcom_tee_uefisecapp.h
> +
>  QUALCOMM RMNET DRIVER
>  M:	Subash Abhinov Kasiviswanathan <subash.a.kasiviswanathan@oss.qualcomm.com>
>  M:	Sean Tranchetti <sean.tranchetti@oss.qualcomm.com>
> diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
> index b477d54b495a..20ce8b58e490 100644
> --- a/drivers/firmware/qcom/Kconfig
> +++ b/drivers/firmware/qcom/Kconfig
> @@ -74,4 +74,28 @@ config QCOM_QSEECOM_UEFISECAPP
>  	  Select Y here to provide access to EFI variables on the aforementioned
>  	  platforms.
>  
> +config QCOM_TEE_UEFISECAPP
> +	tristate "Qualcomm TEE UEFI Secure App client driver"
> +	depends on QCOMTEE
> +	depends on EFI
> +	depends on !QCOM_QSEECOM_UEFISECAPP

Nope. The kernels can be built for multiple platforms. Implement a
runtime selection, which uefisecapp client is to be used.

> +	help
> +	  On Qualcomm SoC based platforms without emulated RPMB support,

What is emulated RPMB support? How does a user (or a distro maintainer)
understand if this needs to be enabled or not?

> +	  specifically platforms where RPMB is not present within SPI-NOR storage
> +	  and instead located on UFS/EMMC storage, non-volatile EFI variables can
> +	  only be set via a callback request from the UEFI Secure Application to
> +	  the RPMB service running in user-space (within the QTEE supplicant:
> +	  github.com/qualcomm/minkipc). Unlike the QCOMTEE driver, the QSEECOM
> +	  driver used by the QSEECOM based uefisecapp does not support callback
> +	  requests. And so on these platforms, the TEE based uefisecapp client
> +	  driver must be used to ensure persistence of non-volatile EFI variables
> +	  via writes through the RPMB service hosted in the QTEE supplicant.
> +
> +	  This module provides a TEE client driver for uefisecapp, installing efivar
> +	  operations to allow the kernel and user-space access to EFI variables.
> +
> +	  Select m here to provide access to EFI variables on the aforementioned
> +	  platforms if your Linux distribution has QTEE supplicant installed and
> +	  running.
> +
>  endmenu
> diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
> index 0be40a1abc13..d780490b2865 100644
> --- a/drivers/firmware/qcom/Makefile
> +++ b/drivers/firmware/qcom/Makefile
> @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
>  obj-$(CONFIG_QCOM_TZMEM)	+= qcom_tzmem.o
>  obj-$(CONFIG_QCOM_QSEECOM)	+= qcom_qseecom.o
>  obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
> +obj-$(CONFIG_QCOM_TEE_UEFISECAPP) += qcom_tee_uefisecapp.o
> diff --git a/drivers/firmware/qcom/qcom_tee_uefisecapp.c b/drivers/firmware/qcom/qcom_tee_uefisecapp.c
> new file mode 100644
> index 000000000000..9a5a6f145a9f
> --- /dev/null
> +++ b/drivers/firmware/qcom/qcom_tee_uefisecapp.c
> @@ -0,0 +1,525 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#include <linux/efi.h>
> +#include <linux/tee.h>
> +#include <linux/tee_drv.h>
> +#include <linux/ucs2_string.h>
> +#include "qcom_tee_uefisecapp.h"

You are the only user, inline the header here.

> +
> +static struct qcomtee_uefisec_app uefisec_app;

Do you need global data? Can it be obtained from other context variables
using container_of()?


-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
  2026-07-22  8:26 ` [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Dmitry Baryshkov
@ 2026-07-24  9:13   ` Harshal Dev
  2026-08-03 14:52     ` Harshal Dev
  2026-08-10  7:07     ` Dmitry Baryshkov
  0 siblings, 2 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-24  9:13 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

Hi Dmitry,

On 22-07-2026 01:56 pm, Dmitry Baryshkov wrote:
> On Wed, Jul 22, 2026 at 12:29:11PM +0530, Harshal Dev wrote:
>> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
>> Replay Protected Memory Block (RPMB) which is only accessible by the
>> Qualcomm Trusted Execution Environment (QTEE).
> 
> Is it so? I think RPMB is accessible to Linux...

I should have been more descriptive here, RPMB is accessible by Linux but
its frames can only be prepared by QTEE.

The RPMB key which is one-time programmed into the storage controller to allow
authentication of the RPMB frames is generated by and only available to a TEE.
So on Qualcomm platforms (and many others platforms with a TEE) Linux can only
route the RPMB frames generated by QTEE to the storage, it cannot create and
write the RPMB frames itself (it doesn't have access to the key).

While it is possible for Linux to generate/program/store this key, on Qualcomm
platforms we do not want Linux to do so because we do not trust it. We trust
QTEE.

I will re-phrase this and make it a bit more clear everywhere.

> 
>> For Qualcomm platforms without emulated RPMB support, specifically
> 
> What is emulated RPMB support? Why is it mentioned here? Which platforms
> use emulated RPMB?

Emulated RPMB refers to RPMB on a storage which doesn't have its own firmware.
Primarily, NAND/NOR storage. Unlike UFS/eMMC storage, NAND/NOR storage does not
have a storage controller where we can program the RPMB key to be used by the
firmware. So we must 'emulate' RPMB by moving the storage driver within QTEE
and making the driver hold/use the key.

Qualcomm compute SoCs (Glymur, Hamoa) have RPMB available on SPI-*NOR* storage,
and a driver for communicating with it is also available in QTEE. And so, these
have 'emulated' RPMB.

I will add this detail in an updated cover letter.
> 
>> platforms where RPMB is not located within SPI-NOR storage and instead
>> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
>> a callback request from the UEFI Secure Application to the RPMB service
>> running in user-space (within the QTEE supplicant [1]).
> 
> Can it be moved to the kernel?

We have a plan to move the RPMB service to the kernel similar to OPTEE:
https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/tee/optee/rpc.c#L449

It is a work in progress. Once this happens, we don't need QTEE supplicant available
on the Linux distribution.

> 
>>
>> Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
>> QSEECOM based uefisecapp) does not support callback requests.
> 
> How did it work then? I think Windows has been perfectly using QSEECOM
> rather than QTEE.

It works because Windows on Arm on Qualcomm has SPI-NOR storage. A driver for which
is available within QTEE, and so QTEE does not need to make a callback request
to Linux to request RPMB frame routing. However, in case of UFS/eMMC storage the
driver only exists in the Linux kernel and so QTEE must make a callback request.

And so, if you try to use the QSEECOM driver to write EFI-variables to RPMB
on a device with UFS/eMMC storage, it won't work.

> 
>> And on
>> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
>> QSEECOM interface fail due to lack of support within Qualcomm TEE.
> 
> So, I assume, on RB3 Gen2 the QSEECOM doesn't report uefisecapp as
> supported. Does it?

It doesn't, this API returns -2 if I add RB3 Gen2 in the allow-list for QSEECOM:
https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/qcom/qcom_qseecom.c#L46

> 
>> On these platforms, a TEE based uefisecapp client driver is required to:
>> 1. Access cached & volatile EFI variables stored in uefisecapp's memory.
>> 2. Ensure persistence of non-volatile EFI variables via writes through
>> the RPMB service hosted in the QTEE supplicant.
>>
>> This series introduces such a uefisecapp TEE client driver for the
>> aforementioned Qualcomm platforms which installs efi-var operations _if_
>> the QCOMTEE driver registers support for an object-IPC based uefisecapp
>> service on the TEE bus during its probe. Only new QTEE firmware versions
>> available at [2] provide this support.
> 
> What about existing WoA devices?

New Windows on Arm devices like Hamoa/Glymur work perfectly fine with existing
QSEECOM based uefisecapp. But they will also work with this new QCOMTEE based
uefisecapp once they upgrade their firmware.

I need to double-check but this firmware release for Glymur on Qualcomm Linux
is probably carrying the support for QCOMTEE based uefisecapp access:
https://github.com/qualcomm-linux/meta-qcom/commit/728251fcbe5113980805ea6c571e33235062ee71
If not, the next release will definitely have it since I have merged support for
this in QTEE and talked to the boot firmware release team about this.

The next planned firmware upgrade for Hamoa will also provide this support for
Qualcomm Linux. And similarly, for all other targets being supported upstream.

> 
>>
>> Thus, QCOMTEE now maintains a static list of always-available object-IPC
>> based secure services exposed by QTEE. These services are implemented either
>> within the QTEE kernel or within a pre-loaded Trusted Application (TA)
>> usually loaded by the bootloader. The uefisecapp TA is an example of a
>> preloaded TA loaded by UEFI. A static list is required since QTEE does not
>> yet expose any way to dynamically query and enumerate the services exposed by
>> it.
> 
> Can it be fixed instead of having static lists? In the end, we can't
> guarantee that users update the firmware.
>

Unfortunately, no existing QTEE release out there currently has this support.
But support for this is currently being added by QTEE team last I checked with them.
Once it is available, and a new QTEE firmware release is out there, we will add
support for dynamically querying QTEE services in the QCOMTEE driver. 
>>
>> To facilitate object-IPC interactions from the kernel-space, this
>> series also introduces a tee_client_object_invoke_func() to allow
>> invocation of TEE objects similar to the existing tee_client_invoke_func()
>> API exported by the TEE subsystem which allows invocation of TEE functions.
>> Some suporting changes are also introduced to track and handle operations
>> for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
>> driver.
>>
>> Finally and as previously mentioned, access to the object-IPC based uefisecapp
>> service is restricted on older QTEE firmware versions. A new QTEE firmware
>> release must be picked up from QArtifactory [2] for all upstream supported
>> Qualcomm SoCs to enable access to uefisecapp service via the TEE client
>> driver.
> 
> What about fused devices?

The procedure for updating the firmware on fused devices is slightly different.
The firmware images need to be signed by the OEM using the security profile
of the chipset before flashing/upgrading them. Security profiles are now public:
https://github.com/qualcomm/security-profiles

Regards,
Harshal

> 
>>
>> This patch series has been validated on Kodiak RB3Gen2 platform with UFS
>> storage by attempting to read/write EFI variables via the efivar tool [3]
>> after mounting the efivarfs filesystem. See [4] for an example.
>>
>> Merge Strategy:
>>
>> This patch series could either be taken from the OP-TEE tree or the
>> QCOM soc tree. I would prefer it to be picked by the OP-TEE tree since
>> all except the uefisecapp TEE client driver patch in this series make
>> changes relevant to the TEE subsystem. It would be great if the QCOM soc
>> tree maintainers can Ack the uefisecapp driver patch.
>>
>> [1] https://github.com/qualcomm/minkipc
>> [2] https://shorturl.at/zQU07
>> [3] https://github.com/rhboot/efivar
>> [4] https://docs.qualcomm.com/doc/80-70020-27/topic/manage_uefi_environment_variables_using_efivar_tool.html
>>
>> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>> ---
>> Changes in v2:
>> - Drop using MSB of the object_id to distingush kernel and user object invoke contexts.
>> - Introduce enum tee_object_invoke_origin to check the context of object invocation.
>> - Link to v1: https://lore.kernel.org/r/20260707-qcom_uefisecapp_migrate_qcomtee-v1-0-f659cbd5d04c@oss.qualcomm.com
>>
>> ---
>> Amirreza Zarrabi (2):
>>       tee: Add kernel client object invoke helper
>>       tee: qcomtee: Allow object invokes from kernel clients
>>
>> Harshal Dev (4):
>>       tee: qcomtee: Track the object invocation context
>>       tee: Export uuidv5 generation for TEE backends
>>       tee: qcomtee: Add support for registering QTEE services on TEE bus
>>       firmware: qcom: Add support for TEE based EFI-var client driver
>>
>>  MAINTAINERS                                 |   7 +
>>  drivers/firmware/qcom/Kconfig               |  24 ++
>>  drivers/firmware/qcom/Makefile              |   1 +
>>  drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
>>  drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++
> 
> I don't see any changes to the QSEECOM drivers. Is it allowed to use
> QSEECOM and QTEE access to uefisecapp at the same time?
> 
>>  drivers/tee/qcomtee/call.c                  | 205 ++++++++++-
>>  drivers/tee/qcomtee/core.c                  |   9 +-
>>  drivers/tee/qcomtee/qcomtee.h               |  12 +
>>  drivers/tee/qcomtee/qcomtee_msg.h           |   1 +
>>  drivers/tee/qcomtee/qcomtee_object.h        |  16 +-
>>  drivers/tee/tee_core.c                      |  24 +-
>>  include/linux/tee_core.h                    |  23 +-
>>  include/linux/tee_drv.h                     |  18 +-
>>  13 files changed, 952 insertions(+), 33 deletions(-)
>> ---
>> base-commit: f3e6330d7fe42b204af05a2dbc68b379e0ad179e
>> change-id: 20260408-qcom_uefisecapp_migrate_qcomtee-13869d45e014
>>
>> Best regards,
>> -- 
>> Harshal Dev <harshal.dev@oss.qualcomm.com>
>>
> 


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

* Re: [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus
  2026-07-22  8:29   ` Dmitry Baryshkov
@ 2026-07-24  9:13     ` Harshal Dev
  0 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-24  9:13 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

Hi Dmitry,

On 22-07-2026 01:59 pm, Dmitry Baryshkov wrote:
> On Wed, Jul 22, 2026 at 12:29:16PM +0530, Harshal Dev wrote:
>> QTEE exposes certain secure services implemented either within the QTEE
>> kernel or via pre-loaded Trusted Applications (TAs). Such always-available
>> services can be readily accessed by TEE client drivers via QTEE's
>> object-IPC protocol if the service is registered as a device on the TEE
>> bus.
>>
>> One such service is the EFI-variables service, implemented by the
>> uefisecapp TA which enables kernel clients to access EFI variables at
>> runtime.
>>
>> Maintain a static list of such always-available secure services and add
>> support for the QCOMTEE driver to register these services as devices on
>> the TEE bus during probe.
> 
> Is it always available on all platforms supporting QTEE?

The uefisecapp service is very old. I know that it has existed since the oldest
SM8x50 chipset. Every upstream supported target currently has support for it, since
they all have UEFI somewhere in the boot chain to load the uefisecapp TA from
the storage partition.

But as we expand this list, it's possible that certain services might not be available
on older QTEE versions, in that case the service will never be registered on the
TEE bus and so the TEE client driver will not probe.

Regards,
Harshal

> 
>>
>> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>> ---
>>  drivers/tee/qcomtee/call.c           | 160 ++++++++++++++++++++++++++++++++++-
>>  drivers/tee/qcomtee/core.c           |   9 +-
>>  drivers/tee/qcomtee/qcomtee.h        |  12 +++
>>  drivers/tee/qcomtee/qcomtee_msg.h    |   1 +
>>  drivers/tee/qcomtee/qcomtee_object.h |   3 +-
>>  5 files changed, 177 insertions(+), 8 deletions(-)
>>
> 


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

* Re: [PATCH v2 6/6] firmware: qcom: Add support for TEE based EFI-var client driver
  2026-07-22  8:37   ` Dmitry Baryshkov
@ 2026-07-24  9:14     ` Harshal Dev
  2026-07-24 10:09       ` Harshal Dev
  0 siblings, 1 reply; 24+ messages in thread
From: Harshal Dev @ 2026-07-24  9:14 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

Hi Dmitry,

On 22-07-2026 02:07 pm, Dmitry Baryshkov wrote:
> On Wed, Jul 22, 2026 at 12:29:17PM +0530, Harshal Dev wrote:
>> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
>> Replay Protected Memory Block (RPMB) which is only accessible by the
>> Qualcomm Trusted Execution Environment (QTEE).
>>
>> For Qualcomm platforms without emulated RPMB support, specifically
>> platforms where RPMB is not located within SPI-NOR storage and instead
>> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
>> a callback request from the UEFI Trusted Application (TA) to the RPMB
>> service running in user-space (within the QTEE supplicant).
>>
>> Unlike the QCOMTEE driver, the QSEECOM driver (used by the current
>> uefisecapp client driver) does not support callback requests. And on
>> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
>> QSEECOM interface fail due to lack of support within QTEE.
>> On all such platforms, a TEE based uefisecapp client driver must be used to
>> access cached/volatile EFI variables within the uefisecapp TA and ensure
>> persistence of writes to non-volatile EFI variables through the RPMB
>> service hosted in the QTEE supplicant.
>>
>> Add support for a TEE based uefisecapp client driver which installs efivar
>> operations after obtaining an object reference to the uefisecapp service.
>> This enables the kernel/user-space to access/modify both volatile EFI vars
>> stored by the Secure Application (in-memory) and non-volatile ones stored
>> within RPMB.
>>
>> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>> ---
>>  MAINTAINERS                                 |   7 +
>>  drivers/firmware/qcom/Kconfig               |  24 ++
>>  drivers/firmware/qcom/Makefile              |   1 +
>>  drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
>>  drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++
>>  5 files changed, 677 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 10d12b51b1f6..e8316007370f 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -22018,6 +22018,13 @@ L:	linux-arm-msm@vger.kernel.org
>>  S:	Maintained
>>  F:	drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
>>  
>> +QUALCOMM TEE UEFISECAPP DRIVER
>> +M:	Harshal Dev <harshal.dev@oss.qualcomm.com>
>> +L:	linux-arm-msm@vger.kernel.org
>> +S:	Maintained
>> +F:	drivers/firmware/qcom/qcom_tee_uefisecapp.c
>> +F:	drivers/firmware/qcom/qcom_tee_uefisecapp.h
>> +
>>  QUALCOMM RMNET DRIVER
>>  M:	Subash Abhinov Kasiviswanathan <subash.a.kasiviswanathan@oss.qualcomm.com>
>>  M:	Sean Tranchetti <sean.tranchetti@oss.qualcomm.com>
>> diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
>> index b477d54b495a..20ce8b58e490 100644
>> --- a/drivers/firmware/qcom/Kconfig
>> +++ b/drivers/firmware/qcom/Kconfig
>> @@ -74,4 +74,28 @@ config QCOM_QSEECOM_UEFISECAPP
>>  	  Select Y here to provide access to EFI variables on the aforementioned
>>  	  platforms.
>>  
>> +config QCOM_TEE_UEFISECAPP
>> +	tristate "Qualcomm TEE UEFI Secure App client driver"
>> +	depends on QCOMTEE
>> +	depends on EFI
>> +	depends on !QCOM_QSEECOM_UEFISECAPP
> 
> Nope. The kernels can be built for multiple platforms. Implement a
> runtime selection, which uefisecapp client is to be used.
>

I agree. I reflected on this yesterday, and in hindsight it feels we do not
really need to add a !QCOM_QSEECOM_UEFISECAPP. Both of these drivers can co-exist.

Both drivers attempt to register to the efivar interface via efivar_register(),
but only one will ever succeed. Since both QCOM_QSEECOM_UEFISECAPP and QCOM_QSEECOM
are built into the kernel with 'y' the default path will be QSEECOM based when
both are supported.

I can drop this 'depends' in v3, and instead add a commit which enables this by
default with CONFIG_QCOM_TEE_UEFISECAPP=m. Let me know your thoughts. 
>> +	help
>> +	  On Qualcomm SoC based platforms without emulated RPMB support,
> 
> What is emulated RPMB support? How does a user (or a distro maintainer)
> understand if this needs to be enabled or not?

Ack. I will try to use simpler terms here to help distro maintainers. If device has
UFS/eMMC storage, this driver is the only way to access EFI variables within
RPMB. So it should be set to 'm'.

If device is SPI-NOR based, this driver will still work. User can decide
if they want to use this or continue with the old QSEECOM path.

Regards,
Harshal

> 
>> +	  specifically platforms where RPMB is not present within SPI-NOR storage
>> +	  and instead located on UFS/EMMC storage, non-volatile EFI variables can
>> +	  only be set via a callback request from the UEFI Secure Application to
>> +	  the RPMB service running in user-space (within the QTEE supplicant:
>> +	  github.com/qualcomm/minkipc). Unlike the QCOMTEE driver, the QSEECOM
>> +	  driver used by the QSEECOM based uefisecapp does not support callback
>> +	  requests. And so on these platforms, the TEE based uefisecapp client
>> +	  driver must be used to ensure persistence of non-volatile EFI variables
>> +	  via writes through the RPMB service hosted in the QTEE supplicant.
>> +
>> +	  This module provides a TEE client driver for uefisecapp, installing efivar
>> +	  operations to allow the kernel and user-space access to EFI variables.
>> +
>> +	  Select m here to provide access to EFI variables on the aforementioned
>> +	  platforms if your Linux distribution has QTEE supplicant installed and
>> +	  running.
>> +
>>  endmenu
>> diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
>> index 0be40a1abc13..d780490b2865 100644
>> --- a/drivers/firmware/qcom/Makefile
>> +++ b/drivers/firmware/qcom/Makefile
>> @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
>>  obj-$(CONFIG_QCOM_TZMEM)	+= qcom_tzmem.o
>>  obj-$(CONFIG_QCOM_QSEECOM)	+= qcom_qseecom.o
>>  obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
>> +obj-$(CONFIG_QCOM_TEE_UEFISECAPP) += qcom_tee_uefisecapp.o
>> diff --git a/drivers/firmware/qcom/qcom_tee_uefisecapp.c b/drivers/firmware/qcom/qcom_tee_uefisecapp.c
>> new file mode 100644
>> index 000000000000..9a5a6f145a9f
>> --- /dev/null
>> +++ b/drivers/firmware/qcom/qcom_tee_uefisecapp.c
>> @@ -0,0 +1,525 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +#include <linux/efi.h>
>> +#include <linux/tee.h>
>> +#include <linux/tee_drv.h>
>> +#include <linux/ucs2_string.h>
>> +#include "qcom_tee_uefisecapp.h"
> 
> You are the only user, inline the header here.
> 
>> +
>> +static struct qcomtee_uefisec_app uefisec_app;
> 
> Do you need global data? Can it be obtained from other context variables
> using container_of()?
> 
> 


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

* Re: [PATCH v2 6/6] firmware: qcom: Add support for TEE based EFI-var client driver
  2026-07-24  9:14     ` Harshal Dev
@ 2026-07-24 10:09       ` Harshal Dev
  0 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-24 10:09 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm



On 24-07-2026 02:44 pm, Harshal Dev wrote:
> Hi Dmitry,
> 
> On 22-07-2026 02:07 pm, Dmitry Baryshkov wrote:
>> On Wed, Jul 22, 2026 at 12:29:17PM +0530, Harshal Dev wrote:
>>> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
>>> Replay Protected Memory Block (RPMB) which is only accessible by the
>>> Qualcomm Trusted Execution Environment (QTEE).
>>>
>>> For Qualcomm platforms without emulated RPMB support, specifically
>>> platforms where RPMB is not located within SPI-NOR storage and instead
>>> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
>>> a callback request from the UEFI Trusted Application (TA) to the RPMB
>>> service running in user-space (within the QTEE supplicant).
>>>
>>> Unlike the QCOMTEE driver, the QSEECOM driver (used by the current
>>> uefisecapp client driver) does not support callback requests. And on
>>> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
>>> QSEECOM interface fail due to lack of support within QTEE.
>>> On all such platforms, a TEE based uefisecapp client driver must be used to
>>> access cached/volatile EFI variables within the uefisecapp TA and ensure
>>> persistence of writes to non-volatile EFI variables through the RPMB
>>> service hosted in the QTEE supplicant.
>>>
>>> Add support for a TEE based uefisecapp client driver which installs efivar
>>> operations after obtaining an object reference to the uefisecapp service.
>>> This enables the kernel/user-space to access/modify both volatile EFI vars
>>> stored by the Secure Application (in-memory) and non-volatile ones stored
>>> within RPMB.
>>>
>>> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>>> ---
>>>  MAINTAINERS                                 |   7 +
>>>  drivers/firmware/qcom/Kconfig               |  24 ++
>>>  drivers/firmware/qcom/Makefile              |   1 +
>>>  drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
>>>  drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++
>>>  5 files changed, 677 insertions(+)
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 10d12b51b1f6..e8316007370f 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -22018,6 +22018,13 @@ L:	linux-arm-msm@vger.kernel.org
>>>  S:	Maintained
>>>  F:	drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
>>>  
>>> +QUALCOMM TEE UEFISECAPP DRIVER
>>> +M:	Harshal Dev <harshal.dev@oss.qualcomm.com>
>>> +L:	linux-arm-msm@vger.kernel.org
>>> +S:	Maintained
>>> +F:	drivers/firmware/qcom/qcom_tee_uefisecapp.c
>>> +F:	drivers/firmware/qcom/qcom_tee_uefisecapp.h
>>> +
>>>  QUALCOMM RMNET DRIVER
>>>  M:	Subash Abhinov Kasiviswanathan <subash.a.kasiviswanathan@oss.qualcomm.com>
>>>  M:	Sean Tranchetti <sean.tranchetti@oss.qualcomm.com>
>>> diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
>>> index b477d54b495a..20ce8b58e490 100644
>>> --- a/drivers/firmware/qcom/Kconfig
>>> +++ b/drivers/firmware/qcom/Kconfig
>>> @@ -74,4 +74,28 @@ config QCOM_QSEECOM_UEFISECAPP
>>>  	  Select Y here to provide access to EFI variables on the aforementioned
>>>  	  platforms.
>>>  
>>> +config QCOM_TEE_UEFISECAPP
>>> +	tristate "Qualcomm TEE UEFI Secure App client driver"
>>> +	depends on QCOMTEE
>>> +	depends on EFI
>>> +	depends on !QCOM_QSEECOM_UEFISECAPP
>>
>> Nope. The kernels can be built for multiple platforms. Implement a
>> runtime selection, which uefisecapp client is to be used.
>>
> 
> I agree. I reflected on this yesterday, and in hindsight it feels we do not
> really need to add a !QCOM_QSEECOM_UEFISECAPP. Both of these drivers can co-exist.
> 
> Both drivers attempt to register to the efivar interface via efivar_register(),
> but only one will ever succeed. Since both QCOM_QSEECOM_UEFISECAPP and QCOM_QSEECOM
> are built into the kernel with 'y' the default path will be QSEECOM based when
> both are supported.
> 
> I can drop this 'depends' in v3, and instead add a commit which enables this by
> default with CONFIG_QCOM_TEE_UEFISECAPP=m. Let me know your thoughts. 
>>> +	help
>>> +	  On Qualcomm SoC based platforms without emulated RPMB support,
>>
>> What is emulated RPMB support? How does a user (or a distro maintainer)
>> understand if this needs to be enabled or not?
> 
> Ack. I will try to use simpler terms here to help distro maintainers. If device has
> UFS/eMMC storage, this driver is the only way to access EFI variables within
> RPMB. So it should be set to 'm'.
> 
> If device is SPI-NOR based, this driver will still work. User can decide
> if they want to use this or continue with the old QSEECOM path.
> 
> Regards,
> Harshal
> 
>>
>>> +	  specifically platforms where RPMB is not present within SPI-NOR storage
>>> +	  and instead located on UFS/EMMC storage, non-volatile EFI variables can
>>> +	  only be set via a callback request from the UEFI Secure Application to
>>> +	  the RPMB service running in user-space (within the QTEE supplicant:
>>> +	  github.com/qualcomm/minkipc). Unlike the QCOMTEE driver, the QSEECOM
>>> +	  driver used by the QSEECOM based uefisecapp does not support callback
>>> +	  requests. And so on these platforms, the TEE based uefisecapp client
>>> +	  driver must be used to ensure persistence of non-volatile EFI variables
>>> +	  via writes through the RPMB service hosted in the QTEE supplicant.
>>> +
>>> +	  This module provides a TEE client driver for uefisecapp, installing efivar
>>> +	  operations to allow the kernel and user-space access to EFI variables.
>>> +
>>> +	  Select m here to provide access to EFI variables on the aforementioned
>>> +	  platforms if your Linux distribution has QTEE supplicant installed and
>>> +	  running.
>>> +
>>>  endmenu
>>> diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
>>> index 0be40a1abc13..d780490b2865 100644
>>> --- a/drivers/firmware/qcom/Makefile
>>> +++ b/drivers/firmware/qcom/Makefile
>>> @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
>>>  obj-$(CONFIG_QCOM_TZMEM)	+= qcom_tzmem.o
>>>  obj-$(CONFIG_QCOM_QSEECOM)	+= qcom_qseecom.o
>>>  obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
>>> +obj-$(CONFIG_QCOM_TEE_UEFISECAPP) += qcom_tee_uefisecapp.o
>>> diff --git a/drivers/firmware/qcom/qcom_tee_uefisecapp.c b/drivers/firmware/qcom/qcom_tee_uefisecapp.c
>>> new file mode 100644
>>> index 000000000000..9a5a6f145a9f
>>> --- /dev/null
>>> +++ b/drivers/firmware/qcom/qcom_tee_uefisecapp.c
>>> @@ -0,0 +1,525 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/*
>>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>>> + */
>>> +
>>> +#include <linux/efi.h>
>>> +#include <linux/tee.h>
>>> +#include <linux/tee_drv.h>
>>> +#include <linux/ucs2_string.h>
>>> +#include "qcom_tee_uefisecapp.h"
>>
>> You are the only user, inline the header here.

Ack. I will expand this header and place its contents in this .c file itself.
I hope this is what you meant by 'inline'.

>>
>>> +
>>> +static struct qcomtee_uefisec_app uefisec_app;
>>
>> Do you need global data? Can it be obtained from other context variables
>> using container_of()?

Actually I really did try to do this, but unfortunately the EFI subsystem's efivars_register()
API called by this driver doesn't provide a way to store a private pointer to a struct like this one.
And so none of the callbacks registered by this driver via qcom_efivar_ops{} can provide
access to this pointer by calling container_of() later. The other EFI drivers have a similar
constraint:
https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/efi/stmm/tee_stmm_efi.c#L27
https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c#L697

Apologies for missing out on these two comments in the previous reply.

Regards,
Harshal

>>
>>
> 


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

* Re: [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus
  2026-07-22  6:59 ` [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus Harshal Dev
  2026-07-22  8:29   ` Dmitry Baryshkov
@ 2026-07-29  7:05   ` Amirreza Zarrabi
  2026-07-31  8:35     ` Harshal Dev
  1 sibling, 1 reply; 24+ messages in thread
From: Amirreza Zarrabi @ 2026-07-29  7:05 UTC (permalink / raw)
  To: Harshal Dev, Jens Wiklander, Jens Wiklander, Sumit Garg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm

Hi Harshal,

On 7/22/2026 4:59 PM, Harshal Dev wrote:
> QTEE exposes certain secure services implemented either within the QTEE
> kernel or via pre-loaded Trusted Applications (TAs). Such always-available
> services can be readily accessed by TEE client drivers via QTEE's
> object-IPC protocol if the service is registered as a device on the TEE
> bus.
> 
> One such service is the EFI-variables service, implemented by the
> uefisecapp TA which enables kernel clients to access EFI variables at
> runtime.
> 
> Maintain a static list of such always-available secure services and add
> support for the QCOMTEE driver to register these services as devices on
> the TEE bus during probe.
> 
> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
> ---
>  drivers/tee/qcomtee/call.c           | 160 ++++++++++++++++++++++++++++++++++-
>  drivers/tee/qcomtee/core.c           |   9 +-
>  drivers/tee/qcomtee/qcomtee.h        |  12 +++
>  drivers/tee/qcomtee/qcomtee_msg.h    |   1 +
>  drivers/tee/qcomtee/qcomtee_object.h |   3 +-
>  5 files changed, 177 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c
> index c1bba5fbfa3e..e909955e6b21 100644
> --- a/drivers/tee/qcomtee/call.c
> +++ b/drivers/tee/qcomtee/call.c
> @@ -662,7 +662,7 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
>  {
>  	struct qcomtee_object *client_env, *service;
>  	struct qcomtee_arg u[3] = { 0 };
> -	int result;
> +	int result, error = 0;
>  
>  	struct qcomtee_object_invoke_ctx *oic __free(kfree) =
>  		qcomtee_object_invoke_ctx_alloc(ctx, true);
> @@ -675,9 +675,13 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
>  
>  	/* Get ''FeatureVersions Service'' object. */
>  	service = qcomtee_object_get_service(oic, client_env,
> -					     QCOMTEE_FEATURE_VER_UID);
> -	if (service == NULL_QCOMTEE_OBJECT)
> +					     QCOMTEE_FEATURE_VER_UID,
> +					     &error);
> +	if (service == NULL_QCOMTEE_OBJECT) {
> +		if (error)
> +			pr_err("Failed to get service! error: %d\n", error);
>  		goto out_failed;
> +	}

no need to check for !error (why new variable reuse result),
just print "FeatureVersions Service unavailable (%d)", result
The message "Failed to get service! error: %d\n" is not helpful.

>  
>  	/* IB: Feature to query. */
>  	u[0].b.addr = &id;
> @@ -697,6 +701,153 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
>  	qcomtee_object_put(client_env);
>  }
>  
> +/**
> + * is_qcomtee_service_available() - Check if the QTEE service identified by the UID
> + * is available
> + * @ctx: TEE context.
> + * @uid: 32-bit UID of the service.
> + *
> + * Returns true if the service exists and is available.
> + * Returns false if a service is not exposed by QTEE.
> + */
> +static bool is_qcomtee_service_available(struct tee_context *ctx, u32 uid)
> +{
> +	struct qcomtee_object *client_env;
> +	struct qcomtee_object *service;
> +	int error = 0;
> +	bool ret = false;
> +
> +	struct qcomtee_object_invoke_ctx *oic __free(kfree) =
> +		qcomtee_object_invoke_ctx_alloc(ctx, true);
> +	if (!oic)
> +		return ret;
> +
> +	client_env = qcomtee_object_get_client_env(oic);
> +	if (client_env == NULL_QCOMTEE_OBJECT)
> +		return ret;
> +
> +	/* Get service object corresponding to the uid. */
> +	service = qcomtee_object_get_service(oic, client_env, uid, &error);
> +	if (service != NULL_QCOMTEE_OBJECT) {
> +		qcomtee_object_put(service);
> +		ret = true;
> +	}
> +
> +	/* When we fail to get the service, QTEE provides the reason. */
> +	if (error)
> +		pr_err("Failed to get service! error: %d\n", error);
> +

This is not a useful message. We need to know which static service is missing:
e.g. print "%s is unavailable (%d)", qcom.tz.uefisecapp, error.
Also it is possible to re-org to avoid qcomtee_object_invoke_ctx_alloc() and
qcomtee_object_get_client_env() on each iteration? oic is reusable.

> +	qcomtee_object_put(client_env);
> +	return ret;
> +}
> +
> +/*
> + * QTEE Service UUID name space identifier
> + *
> + * A random UUID that is allocated as a name space identifier for forming UUID's
> + * representing secure services exposed by QTEE.
> + */
> +static const uuid_t qtee_service_uuid_ns = UUID_INIT(0xe1b48857, 0x6154, 0x49f9,
> +						     0x93, 0x4e, 0xa2, 0xf2,
> +						     0x0a, 0xba, 0x98, 0x42);
> +
> +static const struct qtee_service qtee_services[] = {
> +	{ "qcom.tz.uefisecapp",
> +	   QCOMTEE_UEFI_SEC_UID }
> +};
> +
> +static void qtee_release_service(struct device *dev)
> +{
> +	struct tee_client_device *qtee_service = to_tee_client_device(dev);
> +
> +	kfree(qtee_service);
> +}
> +
> +/**
> + * qtee_enumerate_service() - Enumerate a given QTEE service and register
> + * it on the TEE bus as a TEE client device
> + * @ctx: TEE context.
> + * @service_uuid: UUID of the service to be registered on the TEE bus.
> + * @uid: 32-bit UID used by QTEE to identify the service.
> + *
> + * Returns 0 on success and < 0 on failure.
> + */
> +static int qtee_enumerate_service(struct tee_context *ctx, const char *service_name,
> +				  const u32 uid)
> +{
> +	struct tee_client_device *qtee_service;
> +	uuid_t service_uuid;
> +	int rc;
> +
> +	if (!is_qcomtee_service_available(ctx, uid))
> +		return -ENXIO;

-EOPNOTSUPP?

> +
> +	tee_generate_uuid_v5(&service_uuid, &qtee_service_uuid_ns, service_name,
> +			     strlen(service_name));
> +
> +	qtee_service = kzalloc_obj(*qtee_service);
> +	if (!qtee_service)
> +		return -ENOMEM;
> +
> +	qtee_service->dev.bus = &tee_bus_type;
> +	qtee_service->dev.release = qtee_release_service;
> +	if (dev_set_name(&qtee_service->dev, "qtee-svc-%pUb", &service_uuid)) {
> +		kfree(qtee_service);
> +		return -ENOMEM;
> +	}
> +	uuid_copy(&qtee_service->id.uuid, &service_uuid);
> +
> +	rc = device_register(&qtee_service->dev);
> +	if (rc) {
> +		pr_err("QTEE service registration failed, err: %d\n", rc);
> +		put_device(&qtee_service->dev);
> +		kfree(qtee_service);

It is double free!? is not put_device enough?

> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * qtee_enumerate_services() - Enumerate all the secure services exposed by QTEE
> + * from the static 'qtee_services' list and register them on the TEE bus as
> + * TEE client devices.
> + *
> + * Not all versions of QTEE support a given service. Hence, we try to
> + * enumerate as many services from the 'qtee_services' list as possible.
> + * Not being able to enumerate a service shouldn't cause the driver probe
> + * to fail since none of the services in the list are mandatory for
> + * establishing communication with QTEE.
> + * @ctx: TEE context.
> + */
> +static void qtee_enumerate_services(struct tee_context *ctx)
> +{
> +	int rc;
> +	u32 idx;
> +
> +	for (idx = 0; idx < ARRAY_SIZE(qtee_services); idx++) {
> +		rc = qtee_enumerate_service(ctx, qtee_services[idx].name,
> +					    qtee_services[idx].uid);
> +		if (rc == -ENXIO)
> +			pr_err("QTEE does not implement service %d.\n",
> +			       qtee_services[idx].uid);

If you print in is_qcomtee_service_available(), why here again?

- Amir

> +	}
> +}
> +
> +static int qtee_unregister_service(struct device *dev, void *data)
> +{
> +	if (!strncmp(dev_name(dev), "qtee-svc", strlen("qtee-svc")))
> +		device_unregister(dev);
> +
> +	return 0;
> +}
> +
> +static void qtee_unregister_services(void)
> +{
> +	bus_for_each_dev(&tee_bus_type, NULL, NULL,
> +			 qtee_unregister_service);
> +}
> +
>  static const struct tee_driver_ops qcomtee_ops = {
>  	.get_version = qcomtee_get_version,
>  	.open = qcomtee_open,
> @@ -778,6 +929,8 @@ static int qcomtee_probe(struct platform_device *pdev)
>  		QTEE_VERSION_GET_MINOR(qcomtee->qtee_version),
>  		QTEE_VERSION_GET_PATCH(qcomtee->qtee_version));
>  
> +	qtee_enumerate_services(qcomtee->ctx);
> +
>  	return 0;
>  
>  err_dest_wq:
> @@ -807,6 +960,7 @@ static void qcomtee_remove(struct platform_device *pdev)
>  {
>  	struct qcomtee *qcomtee = platform_get_drvdata(pdev);
>  
> +	qtee_unregister_services();
>  	teedev_close_context(qcomtee->ctx);
>  	/* Wait for RELEASE operations to be processed for QTEE objects. */
>  	tee_device_unregister(qcomtee->teedev);
> diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c
> index b1cb50e434f0..4e39e867c3e9 100644
> --- a/drivers/tee/qcomtee/core.c
> +++ b/drivers/tee/qcomtee/core.c
> @@ -896,19 +896,20 @@ qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic)
>  
>  struct qcomtee_object *
>  qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic,
> -			   struct qcomtee_object *client_env, u32 uid)
> +			   struct qcomtee_object *client_env, u32 uid,
> +			   int *result)
>  {
>  	struct qcomtee_arg u[3] = { 0 };
> -	int ret, result;
> +	int ret;
>  
>  	u[0].b.addr = &uid;
>  	u[0].b.size = sizeof(uid);
>  	u[0].type = QCOMTEE_ARG_TYPE_IB;
>  	u[1].type = QCOMTEE_ARG_TYPE_OO;
>  	ret = qcomtee_object_do_invoke(oic, client_env, QCOMTEE_CLIENT_ENV_OPEN,
> -				       u, &result);
> +				       u, result);
>  
> -	if (ret || result)
> +	if (ret || *result)
>  		return NULL_QCOMTEE_OBJECT;
>  
>  	return u[1].o;
> diff --git a/drivers/tee/qcomtee/qcomtee.h b/drivers/tee/qcomtee/qcomtee.h
> index f39bf63fd1c2..66d305a46c0a 100644
> --- a/drivers/tee/qcomtee/qcomtee.h
> +++ b/drivers/tee/qcomtee/qcomtee.h
> @@ -17,6 +17,8 @@
>  #define QCOMTEE_OBJREF_FLAG_USER	BIT(1)
>  #define QCOMTEE_OBJREF_FLAG_MEM		BIT(2)
>  
> +#define QTEE_UUID_NS_NAME_SIZE	        128
> +
>  /**
>   * struct qcomtee - Main service struct.
>   * @teedev: client device.
> @@ -39,6 +41,16 @@ struct qcomtee {
>  	u32 qtee_version;
>  };
>  
> +/**
> + * struct qtee_service - A secure service exposed by QTEE identified by a 32-bit UID.
> + * @name: Name of the QTEE service.
> + * @uid: 32-bit UID used by QTEE to identify the service.
> + */
> +struct qtee_service {
> +	const char *name;
> +	const u32 uid;
> +};
> +
>  void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic);
>  struct qcomtee_object *qcomtee_idx_erase(struct qcomtee_object_invoke_ctx *oic,
>  					 u32 idx);
> diff --git a/drivers/tee/qcomtee/qcomtee_msg.h b/drivers/tee/qcomtee/qcomtee_msg.h
> index 878f70178a5b..ecaf8db67d45 100644
> --- a/drivers/tee/qcomtee/qcomtee_msg.h
> +++ b/drivers/tee/qcomtee/qcomtee_msg.h
> @@ -105,6 +105,7 @@ union qcomtee_msg_arg {
>  #define QTEE_VERSION_GET_MINOR(x) (((x) >> 12) & 0xffU)
>  #define QTEE_VERSION_GET_PATCH(x) ((x) >> 0 & 0xfffU)
>  
> +#define QCOMTEE_UEFI_SEC_UID            413
>  /* Response types as returned from qcomtee_object_invoke_ctx_invoke(). */
>  
>  /* The message contains a callback request. */
> diff --git a/drivers/tee/qcomtee/qcomtee_object.h b/drivers/tee/qcomtee/qcomtee_object.h
> index 7bd6e23b038c..f4cb9b8fcbd4 100644
> --- a/drivers/tee/qcomtee/qcomtee_object.h
> +++ b/drivers/tee/qcomtee/qcomtee_object.h
> @@ -316,6 +316,7 @@ qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic);
>  
>  struct qcomtee_object *
>  qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic,
> -			   struct qcomtee_object *client_env, u32 uid);
> +			   struct qcomtee_object *client_env, u32 uid,
> +			   int *result);
>  
>  #endif /* QCOMTEE_OBJECT_H */
> 


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

* Re: [PATCH v2 3/6] tee: qcomtee: Allow object invokes from kernel clients
  2026-07-22  6:59 ` [PATCH v2 3/6] tee: qcomtee: Allow object invokes from kernel clients Harshal Dev
@ 2026-07-29  7:06   ` Amirreza Zarrabi
  2026-07-31  7:38     ` Harshal Dev
  0 siblings, 1 reply; 24+ messages in thread
From: Amirreza Zarrabi @ 2026-07-29  7:06 UTC (permalink / raw)
  To: Harshal Dev, Jens Wiklander, Jens Wiklander, Sumit Garg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm

Hi Harshal,

On 7/22/2026 4:59 PM, Harshal Dev wrote:
> From: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
> 
> QCOMTEE currently treats UBUF parameters as userspace addresses and
> applies userspace restrictions when invoking the root object. This is
> not suitable for object invocation requests issued by kernel clients.
> 
> Use the kernel_ctx flag to distinguish kernel client requests from
> userspace requests. For kernel contexts, do not mark UBUF parameters as
> user addresses, and allow permitted root-object operations to proceed
> without applying the userspace-only checks.
> 
> This allows in-kernel users of tee_client_object_invoke_func() to issue
> object invocation requests through the qcomtee backend.
> 
> Co-developed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
> Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
> ---
>  drivers/tee/qcomtee/call.c           | 34 +++++++++++++++++++++++-----------
>  drivers/tee/qcomtee/qcomtee_object.h |  5 +++--
>  include/linux/tee_drv.h              |  5 ++++-
>  3 files changed, 30 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c
> index 03d33b118f6d..c1bba5fbfa3e 100644
> --- a/drivers/tee/qcomtee/call.c
> +++ b/drivers/tee/qcomtee/call.c
> @@ -202,7 +202,7 @@ int qcomtee_objref_from_arg(struct tee_param *param, struct qcomtee_arg *arg,
>   */
>  static int qcomtee_params_to_args(struct qcomtee_arg *u,
>  				  struct tee_param *params, int num_params,
> -				  struct tee_context *ctx)
> +				  struct qcomtee_object_invoke_ctx *oic)
>  {
>  	int i;
>  
> @@ -210,8 +210,14 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
>  		switch (params[i].attr) {
>  		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT:
>  		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:
> -			u[i].flags = QCOMTEE_ARG_FLAGS_UADDR;
> -			u[i].b.uaddr = params[i].u.ubuf.uaddr;
> +			u[i].flags = oic->kernel_ctx ? 0 :
> +				QCOMTEE_ARG_FLAGS_UADDR;
> +
> +			if (u[i].flags && QCOMTEE_ARG_FLAGS_UADDR)
> +				u[i].b.uaddr = params[i].u.ubuf.uaddr;
> +			else
> +				u[i].b.addr = params[i].u.ubuf.addr;
> +

it is & not &&.
Rather than ?:, can you have single if and update both flags and addr/uaddr.

- Amir

>  			u[i].b.size = params[i].u.ubuf.size;
>  
>  			if (params[i].attr ==
> @@ -223,7 +229,7 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
>  			break;
>  		case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT:
>  			u[i].type = QCOMTEE_ARG_TYPE_IO;
> -			if (qcomtee_objref_to_arg(&u[i], &params[i], ctx))
> +			if (qcomtee_objref_to_arg(&u[i], &params[i], oic->ctx))
>  				goto out_failed;
>  
>  			break;
> @@ -270,7 +276,7 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
>   */
>  static int qcomtee_params_from_args(struct tee_param *params,
>  				    struct qcomtee_arg *u, int num_params,
> -				    struct tee_context *ctx)
> +				    struct qcomtee_object_invoke_ctx *oic)
>  {
>  	int i, np;
>  
> @@ -288,7 +294,8 @@ static int qcomtee_params_from_args(struct tee_param *params,
>  			break;
>  		case QCOMTEE_ARG_TYPE_OO:
>  			/* TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT */
> -			if (qcomtee_objref_from_arg(&params[np], &u[np], ctx))
> +			if (qcomtee_objref_from_arg(&params[np], &u[np],
> +						    oic->ctx))
>  				goto out_failed;
>  
>  			break;
> @@ -304,7 +311,7 @@ static int qcomtee_params_from_args(struct tee_param *params,
>  	/* Undo qcomtee_objref_from_arg(). */
>  	for (i = 0; i < np; i++) {
>  		if (params[i].attr == TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT)
> -			qcomtee_context_del_qtee_object(&params[i], ctx);
> +			qcomtee_context_del_qtee_object(&params[i], oic->ctx);
>  	}
>  
>  	/* Release any IO and OO objects not processed. */
> @@ -357,7 +364,8 @@ static int qcomtee_params_check(struct tee_param *params, int num_params)
>  }
>  
>  /* Check if an operation on ROOT_QCOMTEE_OBJECT from userspace is permitted. */
> -static int qcomtee_root_object_check(u32 op, struct tee_param *params,
> +static int qcomtee_root_object_check(struct qcomtee_object_invoke_ctx *oic,
> +				     u32 op, struct tee_param *params,
>  				     int num_params)
>  {
>  	/* Some privileged operations recognized by QTEE. */
> @@ -366,6 +374,9 @@ static int qcomtee_root_object_check(u32 op, struct tee_param *params,
>  	    op == QCOMTEE_ROOT_OP_ADCI_SHUTDOWN)
>  		return -EINVAL;
>  
> +	if (oic->kernel_ctx)
> +		return 0;
> +
>  	/*
>  	 * QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS is to register with QTEE
>  	 * by passing a credential object as input OBJREF. TEE_OBJREF_NULL as a
> @@ -429,7 +440,8 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
>  	/* Get an object to invoke. */
>  	if (arg->id == TEE_OBJREF_NULL) {
>  		/* Use ROOT if TEE_OBJREF_NULL is invoked. */
> -		if (qcomtee_root_object_check(arg->op, params, arg->num_params))
> +		if (qcomtee_root_object_check(oic, arg->op, params,
> +					      arg->num_params))
>  			return -EINVAL;
>  
>  		object = ROOT_QCOMTEE_OBJECT;
> @@ -437,7 +449,7 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
>  		return -EINVAL;
>  	}
>  
> -	ret = qcomtee_params_to_args(u, params, arg->num_params, ctx);
> +	ret = qcomtee_params_to_args(u, params, arg->num_params, oic);
>  	if (ret)
>  		goto out;
>  
> @@ -455,7 +467,7 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
>  
>  	if (!result) {
>  		/* Assume service is UNAVAIL if unable to process the result. */
> -		if (qcomtee_params_from_args(params, u, arg->num_params, ctx))
> +		if (qcomtee_params_from_args(params, u, arg->num_params, oic))
>  			result = QCOMTEE_MSG_ERROR_UNAVAIL;
>  	} else {
>  		/*
> diff --git a/drivers/tee/qcomtee/qcomtee_object.h b/drivers/tee/qcomtee/qcomtee_object.h
> index 2528d07e4576..7bd6e23b038c 100644
> --- a/drivers/tee/qcomtee/qcomtee_object.h
> +++ b/drivers/tee/qcomtee/qcomtee_object.h
> @@ -112,8 +112,9 @@ struct qcomtee_buffer {
>   * @b: address and size if the type of argument is a buffer.
>   * @o: object instance if the type of argument is an object.
>   *
> - * &qcomtee_arg.flags only accepts %QCOMTEE_ARG_FLAGS_UADDR for now, which
> - * states that &qcomtee_arg.b contains a userspace address in uaddr.
> ++ * If %QCOMTEE_ARG_FLAGS_UADDR is set in &qcomtee_arg.flags then it implies
> ++ * that &qcomtee_arg.b contains a userspace address in uaddr.
> ++ * Otherwise, &qcomtee_arg.b contains a kernel address in addr.
>   */
>  struct qcomtee_arg {
>  	enum qcomtee_arg_type type;
> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
> index ca99c6b747a8..71d0536db60e 100644
> --- a/include/linux/tee_drv.h
> +++ b/include/linux/tee_drv.h
> @@ -83,7 +83,10 @@ struct tee_param_memref {
>  };
>  
>  struct tee_param_ubuf {
> -	void __user *uaddr;
> +	union {
> +		void *addr;
> +		void __user *uaddr;
> +	};
>  	size_t size;
>  };
>  
> 


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

* Re: [PATCH v2 3/6] tee: qcomtee: Allow object invokes from kernel clients
  2026-07-29  7:06   ` Amirreza Zarrabi
@ 2026-07-31  7:38     ` Harshal Dev
  0 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-31  7:38 UTC (permalink / raw)
  To: Amirreza Zarrabi
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Jens Wiklander, Sumit Garg,
	Bjorn Andersson, Konrad Dybcio, Dmitry Baryshkov

Hi Amir,

On 29-07-2026 12:36 pm, Amirreza Zarrabi wrote:
> Hi Harshal,
> 
> On 7/22/2026 4:59 PM, Harshal Dev wrote:
>> From: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
>>
>> QCOMTEE currently treats UBUF parameters as userspace addresses and
>> applies userspace restrictions when invoking the root object. This is
>> not suitable for object invocation requests issued by kernel clients.
>>
>> Use the kernel_ctx flag to distinguish kernel client requests from
>> userspace requests. For kernel contexts, do not mark UBUF parameters as
>> user addresses, and allow permitted root-object operations to proceed
>> without applying the userspace-only checks.
>>
>> This allows in-kernel users of tee_client_object_invoke_func() to issue
>> object invocation requests through the qcomtee backend.
>>
>> Co-developed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>> Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
>> ---
>>  drivers/tee/qcomtee/call.c           | 34 +++++++++++++++++++++++-----------
>>  drivers/tee/qcomtee/qcomtee_object.h |  5 +++--
>>  include/linux/tee_drv.h              |  5 ++++-
>>  3 files changed, 30 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c
>> index 03d33b118f6d..c1bba5fbfa3e 100644
>> --- a/drivers/tee/qcomtee/call.c
>> +++ b/drivers/tee/qcomtee/call.c
>> @@ -202,7 +202,7 @@ int qcomtee_objref_from_arg(struct tee_param *param, struct qcomtee_arg *arg,
>>   */
>>  static int qcomtee_params_to_args(struct qcomtee_arg *u,
>>  				  struct tee_param *params, int num_params,
>> -				  struct tee_context *ctx)
>> +				  struct qcomtee_object_invoke_ctx *oic)
>>  {
>>  	int i;
>>  
>> @@ -210,8 +210,14 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
>>  		switch (params[i].attr) {
>>  		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT:
>>  		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:
>> -			u[i].flags = QCOMTEE_ARG_FLAGS_UADDR;
>> -			u[i].b.uaddr = params[i].u.ubuf.uaddr;
>> +			u[i].flags = oic->kernel_ctx ? 0 :
>> +				QCOMTEE_ARG_FLAGS_UADDR;
>> +
>> +			if (u[i].flags && QCOMTEE_ARG_FLAGS_UADDR)
>> +				u[i].b.uaddr = params[i].u.ubuf.uaddr;
>> +			else
>> +				u[i].b.addr = params[i].u.ubuf.addr;
>> +
> 
> it is & not &&.
> Rather than ?:, can you have single if and update both flags and addr/uaddr.
>

Whoops, thank you for catching this. Ack, I will make this change.

Regards,
Harshal 
> - Amir
> 
>>  			u[i].b.size = params[i].u.ubuf.size;
>>  
>>  			if (params[i].attr ==
>> @@ -223,7 +229,7 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
>>  			break;
>>  		case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT:
>>  			u[i].type = QCOMTEE_ARG_TYPE_IO;
>> -			if (qcomtee_objref_to_arg(&u[i], &params[i], ctx))
>> +			if (qcomtee_objref_to_arg(&u[i], &params[i], oic->ctx))
>>  				goto out_failed;
>>  
>>  			break;
>> @@ -270,7 +276,7 @@ static int qcomtee_params_to_args(struct qcomtee_arg *u,
>>   */
>>  static int qcomtee_params_from_args(struct tee_param *params,
>>  				    struct qcomtee_arg *u, int num_params,
>> -				    struct tee_context *ctx)
>> +				    struct qcomtee_object_invoke_ctx *oic)
>>  {
>>  	int i, np;
>>  
>> @@ -288,7 +294,8 @@ static int qcomtee_params_from_args(struct tee_param *params,
>>  			break;
>>  		case QCOMTEE_ARG_TYPE_OO:
>>  			/* TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT */
>> -			if (qcomtee_objref_from_arg(&params[np], &u[np], ctx))
>> +			if (qcomtee_objref_from_arg(&params[np], &u[np],
>> +						    oic->ctx))
>>  				goto out_failed;
>>  
>>  			break;
>> @@ -304,7 +311,7 @@ static int qcomtee_params_from_args(struct tee_param *params,
>>  	/* Undo qcomtee_objref_from_arg(). */
>>  	for (i = 0; i < np; i++) {
>>  		if (params[i].attr == TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT)
>> -			qcomtee_context_del_qtee_object(&params[i], ctx);
>> +			qcomtee_context_del_qtee_object(&params[i], oic->ctx);
>>  	}
>>  
>>  	/* Release any IO and OO objects not processed. */
>> @@ -357,7 +364,8 @@ static int qcomtee_params_check(struct tee_param *params, int num_params)
>>  }
>>  
>>  /* Check if an operation on ROOT_QCOMTEE_OBJECT from userspace is permitted. */
>> -static int qcomtee_root_object_check(u32 op, struct tee_param *params,
>> +static int qcomtee_root_object_check(struct qcomtee_object_invoke_ctx *oic,
>> +				     u32 op, struct tee_param *params,
>>  				     int num_params)
>>  {
>>  	/* Some privileged operations recognized by QTEE. */
>> @@ -366,6 +374,9 @@ static int qcomtee_root_object_check(u32 op, struct tee_param *params,
>>  	    op == QCOMTEE_ROOT_OP_ADCI_SHUTDOWN)
>>  		return -EINVAL;
>>  
>> +	if (oic->kernel_ctx)
>> +		return 0;
>> +
>>  	/*
>>  	 * QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS is to register with QTEE
>>  	 * by passing a credential object as input OBJREF. TEE_OBJREF_NULL as a
>> @@ -429,7 +440,8 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
>>  	/* Get an object to invoke. */
>>  	if (arg->id == TEE_OBJREF_NULL) {
>>  		/* Use ROOT if TEE_OBJREF_NULL is invoked. */
>> -		if (qcomtee_root_object_check(arg->op, params, arg->num_params))
>> +		if (qcomtee_root_object_check(oic, arg->op, params,
>> +					      arg->num_params))
>>  			return -EINVAL;
>>  
>>  		object = ROOT_QCOMTEE_OBJECT;
>> @@ -437,7 +449,7 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
>>  		return -EINVAL;
>>  	}
>>  
>> -	ret = qcomtee_params_to_args(u, params, arg->num_params, ctx);
>> +	ret = qcomtee_params_to_args(u, params, arg->num_params, oic);
>>  	if (ret)
>>  		goto out;
>>  
>> @@ -455,7 +467,7 @@ static int qcomtee_object_invoke(struct tee_context *ctx,
>>  
>>  	if (!result) {
>>  		/* Assume service is UNAVAIL if unable to process the result. */
>> -		if (qcomtee_params_from_args(params, u, arg->num_params, ctx))
>> +		if (qcomtee_params_from_args(params, u, arg->num_params, oic))
>>  			result = QCOMTEE_MSG_ERROR_UNAVAIL;
>>  	} else {
>>  		/*
>> diff --git a/drivers/tee/qcomtee/qcomtee_object.h b/drivers/tee/qcomtee/qcomtee_object.h
>> index 2528d07e4576..7bd6e23b038c 100644
>> --- a/drivers/tee/qcomtee/qcomtee_object.h
>> +++ b/drivers/tee/qcomtee/qcomtee_object.h
>> @@ -112,8 +112,9 @@ struct qcomtee_buffer {
>>   * @b: address and size if the type of argument is a buffer.
>>   * @o: object instance if the type of argument is an object.
>>   *
>> - * &qcomtee_arg.flags only accepts %QCOMTEE_ARG_FLAGS_UADDR for now, which
>> - * states that &qcomtee_arg.b contains a userspace address in uaddr.
>> ++ * If %QCOMTEE_ARG_FLAGS_UADDR is set in &qcomtee_arg.flags then it implies
>> ++ * that &qcomtee_arg.b contains a userspace address in uaddr.
>> ++ * Otherwise, &qcomtee_arg.b contains a kernel address in addr.
>>   */
>>  struct qcomtee_arg {
>>  	enum qcomtee_arg_type type;
>> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
>> index ca99c6b747a8..71d0536db60e 100644
>> --- a/include/linux/tee_drv.h
>> +++ b/include/linux/tee_drv.h
>> @@ -83,7 +83,10 @@ struct tee_param_memref {
>>  };
>>  
>>  struct tee_param_ubuf {
>> -	void __user *uaddr;
>> +	union {
>> +		void *addr;
>> +		void __user *uaddr;
>> +	};
>>  	size_t size;
>>  };
>>  
>>
> 


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

* Re: [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus
  2026-07-29  7:05   ` Amirreza Zarrabi
@ 2026-07-31  8:35     ` Harshal Dev
  0 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-07-31  8:35 UTC (permalink / raw)
  To: Amirreza Zarrabi
  Cc: Basant Kumar, Apurupa Pattapu, Arun Kumar Neelakantam, op-tee,
	linux-kernel, linux-arm-msm, Dmitry Baryshkov, Konrad Dybcio,
	Jens Wiklander, Sumit Garg, Bjorn Andersson

Hi Amir,

On 29-07-2026 12:35 pm, Amirreza Zarrabi wrote:
> Hi Harshal,
> 
> On 7/22/2026 4:59 PM, Harshal Dev wrote:
>> QTEE exposes certain secure services implemented either within the QTEE
>> kernel or via pre-loaded Trusted Applications (TAs). Such always-available
>> services can be readily accessed by TEE client drivers via QTEE's
>> object-IPC protocol if the service is registered as a device on the TEE
>> bus.
>>
>> One such service is the EFI-variables service, implemented by the
>> uefisecapp TA which enables kernel clients to access EFI variables at
>> runtime.
>>
>> Maintain a static list of such always-available secure services and add
>> support for the QCOMTEE driver to register these services as devices on
>> the TEE bus during probe.
>>
>> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>> ---
>>  drivers/tee/qcomtee/call.c           | 160 ++++++++++++++++++++++++++++++++++-
>>  drivers/tee/qcomtee/core.c           |   9 +-
>>  drivers/tee/qcomtee/qcomtee.h        |  12 +++
>>  drivers/tee/qcomtee/qcomtee_msg.h    |   1 +
>>  drivers/tee/qcomtee/qcomtee_object.h |   3 +-
>>  5 files changed, 177 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c
>> index c1bba5fbfa3e..e909955e6b21 100644
>> --- a/drivers/tee/qcomtee/call.c
>> +++ b/drivers/tee/qcomtee/call.c
>> @@ -662,7 +662,7 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
>>  {
>>  	struct qcomtee_object *client_env, *service;
>>  	struct qcomtee_arg u[3] = { 0 };
>> -	int result;
>> +	int result, error = 0;
>>  
>>  	struct qcomtee_object_invoke_ctx *oic __free(kfree) =
>>  		qcomtee_object_invoke_ctx_alloc(ctx, true);
>> @@ -675,9 +675,13 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
>>  
>>  	/* Get ''FeatureVersions Service'' object. */
>>  	service = qcomtee_object_get_service(oic, client_env,
>> -					     QCOMTEE_FEATURE_VER_UID);
>> -	if (service == NULL_QCOMTEE_OBJECT)
>> +					     QCOMTEE_FEATURE_VER_UID,
>> +					     &error);
>> +	if (service == NULL_QCOMTEE_OBJECT) {
>> +		if (error)
>> +			pr_err("Failed to get service! error: %d\n", error);
>>  		goto out_failed;
>> +	}
> 
> no need to check for !error (why new variable reuse result),

Ack. will use 'result' everywhere where I am calling this. Makes sense.

> just print "FeatureVersions Service unavailable (%d)", result
> The message "Failed to get service! error: %d\n" is not helpful.

Ack.

> 
>>  
>>  	/* IB: Feature to query. */
>>  	u[0].b.addr = &id;
>> @@ -697,6 +701,153 @@ static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
>>  	qcomtee_object_put(client_env);
>>  }
>>  
>> +/**
>> + * is_qcomtee_service_available() - Check if the QTEE service identified by the UID
>> + * is available
>> + * @ctx: TEE context.
>> + * @uid: 32-bit UID of the service.
>> + *
>> + * Returns true if the service exists and is available.
>> + * Returns false if a service is not exposed by QTEE.
>> + */
>> +static bool is_qcomtee_service_available(struct tee_context *ctx, u32 uid)
>> +{
>> +	struct qcomtee_object *client_env;
>> +	struct qcomtee_object *service;
>> +	int error = 0;
>> +	bool ret = false;
>> +
>> +	struct qcomtee_object_invoke_ctx *oic __free(kfree) =
>> +		qcomtee_object_invoke_ctx_alloc(ctx, true);
>> +	if (!oic)
>> +		return ret;
>> +
>> +	client_env = qcomtee_object_get_client_env(oic);
>> +	if (client_env == NULL_QCOMTEE_OBJECT)
>> +		return ret;
>> +
>> +	/* Get service object corresponding to the uid. */
>> +	service = qcomtee_object_get_service(oic, client_env, uid, &error);
>> +	if (service != NULL_QCOMTEE_OBJECT) {
>> +		qcomtee_object_put(service);
>> +		ret = true;
>> +	}
>> +
>> +	/* When we fail to get the service, QTEE provides the reason. */
>> +	if (error)
>> +		pr_err("Failed to get service! error: %d\n", error);
>> +
> 
> This is not a useful message. We need to know which static service is missing:
> e.g. print "%s is unavailable (%d)", qcom.tz.uefisecapp, error.

Ack.

> Also it is possible to re-org to avoid qcomtee_object_invoke_ctx_alloc() and
> qcomtee_object_get_client_env() on each iteration? oic is reusable.
>

Agreed, since this is called in a loop, it results in unnecessary re-allocation
on every iteration and call to QTEE for getting client_env().
Ack. 
>> +	qcomtee_object_put(client_env);
>> +	return ret;
>> +}
>> +
>> +/*
>> + * QTEE Service UUID name space identifier
>> + *
>> + * A random UUID that is allocated as a name space identifier for forming UUID's
>> + * representing secure services exposed by QTEE.
>> + */
>> +static const uuid_t qtee_service_uuid_ns = UUID_INIT(0xe1b48857, 0x6154, 0x49f9,
>> +						     0x93, 0x4e, 0xa2, 0xf2,
>> +						     0x0a, 0xba, 0x98, 0x42);
>> +
>> +static const struct qtee_service qtee_services[] = {
>> +	{ "qcom.tz.uefisecapp",
>> +	   QCOMTEE_UEFI_SEC_UID }
>> +};
>> +
>> +static void qtee_release_service(struct device *dev)
>> +{
>> +	struct tee_client_device *qtee_service = to_tee_client_device(dev);
>> +
>> +	kfree(qtee_service);
>> +}
>> +
>> +/**
>> + * qtee_enumerate_service() - Enumerate a given QTEE service and register
>> + * it on the TEE bus as a TEE client device
>> + * @ctx: TEE context.
>> + * @service_uuid: UUID of the service to be registered on the TEE bus.
>> + * @uid: 32-bit UID used by QTEE to identify the service.
>> + *
>> + * Returns 0 on success and < 0 on failure.
>> + */
>> +static int qtee_enumerate_service(struct tee_context *ctx, const char *service_name,
>> +				  const u32 uid)
>> +{
>> +	struct tee_client_device *qtee_service;
>> +	uuid_t service_uuid;
>> +	int rc;
>> +
>> +	if (!is_qcomtee_service_available(ctx, uid))
>> +		return -ENXIO;
> 
> -EOPNOTSUPP?

Ack.

> 
>> +
>> +	tee_generate_uuid_v5(&service_uuid, &qtee_service_uuid_ns, service_name,
>> +			     strlen(service_name));
>> +
>> +	qtee_service = kzalloc_obj(*qtee_service);
>> +	if (!qtee_service)
>> +		return -ENOMEM;
>> +
>> +	qtee_service->dev.bus = &tee_bus_type;
>> +	qtee_service->dev.release = qtee_release_service;
>> +	if (dev_set_name(&qtee_service->dev, "qtee-svc-%pUb", &service_uuid)) {
>> +		kfree(qtee_service);
>> +		return -ENOMEM;
>> +	}
>> +	uuid_copy(&qtee_service->id.uuid, &service_uuid);
>> +
>> +	rc = device_register(&qtee_service->dev);
>> +	if (rc) {
>> +		pr_err("QTEE service registration failed, err: %d\n", rc);
>> +		put_device(&qtee_service->dev);
>> +		kfree(qtee_service);
> 
> It is double free!? is not put_device enough?
>

Thank you for catching this, I did not realize that put_device frees the entire
struct.

Ack. 
>> +		return rc;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * qtee_enumerate_services() - Enumerate all the secure services exposed by QTEE
>> + * from the static 'qtee_services' list and register them on the TEE bus as
>> + * TEE client devices.
>> + *
>> + * Not all versions of QTEE support a given service. Hence, we try to
>> + * enumerate as many services from the 'qtee_services' list as possible.
>> + * Not being able to enumerate a service shouldn't cause the driver probe
>> + * to fail since none of the services in the list are mandatory for
>> + * establishing communication with QTEE.
>> + * @ctx: TEE context.
>> + */
>> +static void qtee_enumerate_services(struct tee_context *ctx)
>> +{
>> +	int rc;
>> +	u32 idx;
>> +
>> +	for (idx = 0; idx < ARRAY_SIZE(qtee_services); idx++) {
>> +		rc = qtee_enumerate_service(ctx, qtee_services[idx].name,
>> +					    qtee_services[idx].uid);
>> +		if (rc == -ENXIO)
>> +			pr_err("QTEE does not implement service %d.\n",
>> +			       qtee_services[idx].uid);
> 
> If you print in is_qcomtee_service_available(), why here again?
>

Ack, will remove from here.

Regards,
Harshal 
> - Amir
> 
>> +	}
>> +}
>> +
>> +static int qtee_unregister_service(struct device *dev, void *data)
>> +{
>> +	if (!strncmp(dev_name(dev), "qtee-svc", strlen("qtee-svc")))
>> +		device_unregister(dev);
>> +
>> +	return 0;
>> +}
>> +
>> +static void qtee_unregister_services(void)
>> +{
>> +	bus_for_each_dev(&tee_bus_type, NULL, NULL,
>> +			 qtee_unregister_service);
>> +}
>> +
>>  static const struct tee_driver_ops qcomtee_ops = {
>>  	.get_version = qcomtee_get_version,
>>  	.open = qcomtee_open,
>> @@ -778,6 +929,8 @@ static int qcomtee_probe(struct platform_device *pdev)
>>  		QTEE_VERSION_GET_MINOR(qcomtee->qtee_version),
>>  		QTEE_VERSION_GET_PATCH(qcomtee->qtee_version));
>>  
>> +	qtee_enumerate_services(qcomtee->ctx);
>> +
>>  	return 0;
>>  
>>  err_dest_wq:
>> @@ -807,6 +960,7 @@ static void qcomtee_remove(struct platform_device *pdev)
>>  {
>>  	struct qcomtee *qcomtee = platform_get_drvdata(pdev);
>>  
>> +	qtee_unregister_services();
>>  	teedev_close_context(qcomtee->ctx);
>>  	/* Wait for RELEASE operations to be processed for QTEE objects. */
>>  	tee_device_unregister(qcomtee->teedev);
>> diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c
>> index b1cb50e434f0..4e39e867c3e9 100644
>> --- a/drivers/tee/qcomtee/core.c
>> +++ b/drivers/tee/qcomtee/core.c
>> @@ -896,19 +896,20 @@ qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic)
>>  
>>  struct qcomtee_object *
>>  qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic,
>> -			   struct qcomtee_object *client_env, u32 uid)
>> +			   struct qcomtee_object *client_env, u32 uid,
>> +			   int *result)
>>  {
>>  	struct qcomtee_arg u[3] = { 0 };
>> -	int ret, result;
>> +	int ret;
>>  
>>  	u[0].b.addr = &uid;
>>  	u[0].b.size = sizeof(uid);
>>  	u[0].type = QCOMTEE_ARG_TYPE_IB;
>>  	u[1].type = QCOMTEE_ARG_TYPE_OO;
>>  	ret = qcomtee_object_do_invoke(oic, client_env, QCOMTEE_CLIENT_ENV_OPEN,
>> -				       u, &result);
>> +				       u, result);
>>  
>> -	if (ret || result)
>> +	if (ret || *result)
>>  		return NULL_QCOMTEE_OBJECT;
>>  
>>  	return u[1].o;
>> diff --git a/drivers/tee/qcomtee/qcomtee.h b/drivers/tee/qcomtee/qcomtee.h
>> index f39bf63fd1c2..66d305a46c0a 100644
>> --- a/drivers/tee/qcomtee/qcomtee.h
>> +++ b/drivers/tee/qcomtee/qcomtee.h
>> @@ -17,6 +17,8 @@
>>  #define QCOMTEE_OBJREF_FLAG_USER	BIT(1)
>>  #define QCOMTEE_OBJREF_FLAG_MEM		BIT(2)
>>  
>> +#define QTEE_UUID_NS_NAME_SIZE	        128
>> +
>>  /**
>>   * struct qcomtee - Main service struct.
>>   * @teedev: client device.
>> @@ -39,6 +41,16 @@ struct qcomtee {
>>  	u32 qtee_version;
>>  };
>>  
>> +/**
>> + * struct qtee_service - A secure service exposed by QTEE identified by a 32-bit UID.
>> + * @name: Name of the QTEE service.
>> + * @uid: 32-bit UID used by QTEE to identify the service.
>> + */
>> +struct qtee_service {
>> +	const char *name;
>> +	const u32 uid;
>> +};
>> +
>>  void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic);
>>  struct qcomtee_object *qcomtee_idx_erase(struct qcomtee_object_invoke_ctx *oic,
>>  					 u32 idx);
>> diff --git a/drivers/tee/qcomtee/qcomtee_msg.h b/drivers/tee/qcomtee/qcomtee_msg.h
>> index 878f70178a5b..ecaf8db67d45 100644
>> --- a/drivers/tee/qcomtee/qcomtee_msg.h
>> +++ b/drivers/tee/qcomtee/qcomtee_msg.h
>> @@ -105,6 +105,7 @@ union qcomtee_msg_arg {
>>  #define QTEE_VERSION_GET_MINOR(x) (((x) >> 12) & 0xffU)
>>  #define QTEE_VERSION_GET_PATCH(x) ((x) >> 0 & 0xfffU)
>>  
>> +#define QCOMTEE_UEFI_SEC_UID            413
>>  /* Response types as returned from qcomtee_object_invoke_ctx_invoke(). */
>>  
>>  /* The message contains a callback request. */
>> diff --git a/drivers/tee/qcomtee/qcomtee_object.h b/drivers/tee/qcomtee/qcomtee_object.h
>> index 7bd6e23b038c..f4cb9b8fcbd4 100644
>> --- a/drivers/tee/qcomtee/qcomtee_object.h
>> +++ b/drivers/tee/qcomtee/qcomtee_object.h
>> @@ -316,6 +316,7 @@ qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic);
>>  
>>  struct qcomtee_object *
>>  qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic,
>> -			   struct qcomtee_object *client_env, u32 uid);
>> +			   struct qcomtee_object *client_env, u32 uid,
>> +			   int *result);
>>  
>>  #endif /* QCOMTEE_OBJECT_H */
>>
> 


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

* Re: [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
  2026-07-24  9:13   ` Harshal Dev
@ 2026-08-03 14:52     ` Harshal Dev
  2026-08-10  5:41       ` Harshal Dev
  2026-08-10  7:07     ` Dmitry Baryshkov
  1 sibling, 1 reply; 24+ messages in thread
From: Harshal Dev @ 2026-08-03 14:52 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

Hi Dmitry,

A gentle reminder, do let me know you opinion on my comments here.
I plan to spin a v3 once we're aligned on any open points.

Thanks,
Harshal

On 24-07-2026 02:43 pm, Harshal Dev wrote:
> Hi Dmitry,
> 
> On 22-07-2026 01:56 pm, Dmitry Baryshkov wrote:
>> On Wed, Jul 22, 2026 at 12:29:11PM +0530, Harshal Dev wrote:
>>> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
>>> Replay Protected Memory Block (RPMB) which is only accessible by the
>>> Qualcomm Trusted Execution Environment (QTEE).
>>
>> Is it so? I think RPMB is accessible to Linux...
> 
> I should have been more descriptive here, RPMB is accessible by Linux but
> its frames can only be prepared by QTEE.
> 
> The RPMB key which is one-time programmed into the storage controller to allow
> authentication of the RPMB frames is generated by and only available to a TEE.
> So on Qualcomm platforms (and many others platforms with a TEE) Linux can only
> route the RPMB frames generated by QTEE to the storage, it cannot create and
> write the RPMB frames itself (it doesn't have access to the key).
> 
> While it is possible for Linux to generate/program/store this key, on Qualcomm
> platforms we do not want Linux to do so because we do not trust it. We trust
> QTEE.
> 
> I will re-phrase this and make it a bit more clear everywhere.
> 
>>
>>> For Qualcomm platforms without emulated RPMB support, specifically
>>
>> What is emulated RPMB support? Why is it mentioned here? Which platforms
>> use emulated RPMB?
> 
> Emulated RPMB refers to RPMB on a storage which doesn't have its own firmware.
> Primarily, NAND/NOR storage. Unlike UFS/eMMC storage, NAND/NOR storage does not
> have a storage controller where we can program the RPMB key to be used by the
> firmware. So we must 'emulate' RPMB by moving the storage driver within QTEE
> and making the driver hold/use the key.
> 
> Qualcomm compute SoCs (Glymur, Hamoa) have RPMB available on SPI-*NOR* storage,
> and a driver for communicating with it is also available in QTEE. And so, these
> have 'emulated' RPMB.
> 
> I will add this detail in an updated cover letter.
>>
>>> platforms where RPMB is not located within SPI-NOR storage and instead
>>> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
>>> a callback request from the UEFI Secure Application to the RPMB service
>>> running in user-space (within the QTEE supplicant [1]).
>>
>> Can it be moved to the kernel?
> 
> We have a plan to move the RPMB service to the kernel similar to OPTEE:
> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/tee/optee/rpc.c#L449
> 
> It is a work in progress. Once this happens, we don't need QTEE supplicant available
> on the Linux distribution.
> 
>>
>>>
>>> Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
>>> QSEECOM based uefisecapp) does not support callback requests.
>>
>> How did it work then? I think Windows has been perfectly using QSEECOM
>> rather than QTEE.
> 
> It works because Windows on Arm on Qualcomm has SPI-NOR storage. A driver for which
> is available within QTEE, and so QTEE does not need to make a callback request
> to Linux to request RPMB frame routing. However, in case of UFS/eMMC storage the
> driver only exists in the Linux kernel and so QTEE must make a callback request.
> 
> And so, if you try to use the QSEECOM driver to write EFI-variables to RPMB
> on a device with UFS/eMMC storage, it won't work.
> 
>>
>>> And on
>>> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
>>> QSEECOM interface fail due to lack of support within Qualcomm TEE.
>>
>> So, I assume, on RB3 Gen2 the QSEECOM doesn't report uefisecapp as
>> supported. Does it?
> 
> It doesn't, this API returns -2 if I add RB3 Gen2 in the allow-list for QSEECOM:
> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/qcom/qcom_qseecom.c#L46
> 
>>
>>> On these platforms, a TEE based uefisecapp client driver is required to:
>>> 1. Access cached & volatile EFI variables stored in uefisecapp's memory.
>>> 2. Ensure persistence of non-volatile EFI variables via writes through
>>> the RPMB service hosted in the QTEE supplicant.
>>>
>>> This series introduces such a uefisecapp TEE client driver for the
>>> aforementioned Qualcomm platforms which installs efi-var operations _if_
>>> the QCOMTEE driver registers support for an object-IPC based uefisecapp
>>> service on the TEE bus during its probe. Only new QTEE firmware versions
>>> available at [2] provide this support.
>>
>> What about existing WoA devices?
> 
> New Windows on Arm devices like Hamoa/Glymur work perfectly fine with existing
> QSEECOM based uefisecapp. But they will also work with this new QCOMTEE based
> uefisecapp once they upgrade their firmware.
> 
> I need to double-check but this firmware release for Glymur on Qualcomm Linux
> is probably carrying the support for QCOMTEE based uefisecapp access:
> https://github.com/qualcomm-linux/meta-qcom/commit/728251fcbe5113980805ea6c571e33235062ee71
> If not, the next release will definitely have it since I have merged support for
> this in QTEE and talked to the boot firmware release team about this.
> 
> The next planned firmware upgrade for Hamoa will also provide this support for
> Qualcomm Linux. And similarly, for all other targets being supported upstream.
> 
>>
>>>
>>> Thus, QCOMTEE now maintains a static list of always-available object-IPC
>>> based secure services exposed by QTEE. These services are implemented either
>>> within the QTEE kernel or within a pre-loaded Trusted Application (TA)
>>> usually loaded by the bootloader. The uefisecapp TA is an example of a
>>> preloaded TA loaded by UEFI. A static list is required since QTEE does not
>>> yet expose any way to dynamically query and enumerate the services exposed by
>>> it.
>>
>> Can it be fixed instead of having static lists? In the end, we can't
>> guarantee that users update the firmware.
>>
> 
> Unfortunately, no existing QTEE release out there currently has this support.
> But support for this is currently being added by QTEE team last I checked with them.
> Once it is available, and a new QTEE firmware release is out there, we will add
> support for dynamically querying QTEE services in the QCOMTEE driver. 
>>>
>>> To facilitate object-IPC interactions from the kernel-space, this
>>> series also introduces a tee_client_object_invoke_func() to allow
>>> invocation of TEE objects similar to the existing tee_client_invoke_func()
>>> API exported by the TEE subsystem which allows invocation of TEE functions.
>>> Some suporting changes are also introduced to track and handle operations
>>> for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
>>> driver.
>>>
>>> Finally and as previously mentioned, access to the object-IPC based uefisecapp
>>> service is restricted on older QTEE firmware versions. A new QTEE firmware
>>> release must be picked up from QArtifactory [2] for all upstream supported
>>> Qualcomm SoCs to enable access to uefisecapp service via the TEE client
>>> driver.
>>
>> What about fused devices?
> 
> The procedure for updating the firmware on fused devices is slightly different.
> The firmware images need to be signed by the OEM using the security profile
> of the chipset before flashing/upgrading them. Security profiles are now public:
> https://github.com/qualcomm/security-profiles
> 
> Regards,
> Harshal
> 
>>
>>>
>>> This patch series has been validated on Kodiak RB3Gen2 platform with UFS
>>> storage by attempting to read/write EFI variables via the efivar tool [3]
>>> after mounting the efivarfs filesystem. See [4] for an example.
>>>
>>> Merge Strategy:
>>>
>>> This patch series could either be taken from the OP-TEE tree or the
>>> QCOM soc tree. I would prefer it to be picked by the OP-TEE tree since
>>> all except the uefisecapp TEE client driver patch in this series make
>>> changes relevant to the TEE subsystem. It would be great if the QCOM soc
>>> tree maintainers can Ack the uefisecapp driver patch.
>>>
>>> [1] https://github.com/qualcomm/minkipc
>>> [2] https://shorturl.at/zQU07
>>> [3] https://github.com/rhboot/efivar
>>> [4] https://docs.qualcomm.com/doc/80-70020-27/topic/manage_uefi_environment_variables_using_efivar_tool.html
>>>
>>> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>>> ---
>>> Changes in v2:
>>> - Drop using MSB of the object_id to distingush kernel and user object invoke contexts.
>>> - Introduce enum tee_object_invoke_origin to check the context of object invocation.
>>> - Link to v1: https://lore.kernel.org/r/20260707-qcom_uefisecapp_migrate_qcomtee-v1-0-f659cbd5d04c@oss.qualcomm.com
>>>
>>> ---
>>> Amirreza Zarrabi (2):
>>>       tee: Add kernel client object invoke helper
>>>       tee: qcomtee: Allow object invokes from kernel clients
>>>
>>> Harshal Dev (4):
>>>       tee: qcomtee: Track the object invocation context
>>>       tee: Export uuidv5 generation for TEE backends
>>>       tee: qcomtee: Add support for registering QTEE services on TEE bus
>>>       firmware: qcom: Add support for TEE based EFI-var client driver
>>>
>>>  MAINTAINERS                                 |   7 +
>>>  drivers/firmware/qcom/Kconfig               |  24 ++
>>>  drivers/firmware/qcom/Makefile              |   1 +
>>>  drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
>>>  drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++
>>
>> I don't see any changes to the QSEECOM drivers. Is it allowed to use
>> QSEECOM and QTEE access to uefisecapp at the same time?
>>
>>>  drivers/tee/qcomtee/call.c                  | 205 ++++++++++-
>>>  drivers/tee/qcomtee/core.c                  |   9 +-
>>>  drivers/tee/qcomtee/qcomtee.h               |  12 +
>>>  drivers/tee/qcomtee/qcomtee_msg.h           |   1 +
>>>  drivers/tee/qcomtee/qcomtee_object.h        |  16 +-
>>>  drivers/tee/tee_core.c                      |  24 +-
>>>  include/linux/tee_core.h                    |  23 +-
>>>  include/linux/tee_drv.h                     |  18 +-
>>>  13 files changed, 952 insertions(+), 33 deletions(-)
>>> ---
>>> base-commit: f3e6330d7fe42b204af05a2dbc68b379e0ad179e
>>> change-id: 20260408-qcom_uefisecapp_migrate_qcomtee-13869d45e014
>>>
>>> Best regards,
>>> -- 
>>> Harshal Dev <harshal.dev@oss.qualcomm.com>
>>>
>>
> 


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

* Re: [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
  2026-08-03 14:52     ` Harshal Dev
@ 2026-08-10  5:41       ` Harshal Dev
  0 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-08-10  5:41 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

Hi Dmitry,

Gentle Reminder.

Thanks,
Harshal

On 03-08-2026 08:22 pm, Harshal Dev wrote:
> Hi Dmitry,
> 
> A gentle reminder, do let me know you opinion on my comments here.
> I plan to spin a v3 once we're aligned on any open points.
> 
> Thanks,
> Harshal
> 
> On 24-07-2026 02:43 pm, Harshal Dev wrote:
>> Hi Dmitry,
>>
>> On 22-07-2026 01:56 pm, Dmitry Baryshkov wrote:
>>> On Wed, Jul 22, 2026 at 12:29:11PM +0530, Harshal Dev wrote:
>>>> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
>>>> Replay Protected Memory Block (RPMB) which is only accessible by the
>>>> Qualcomm Trusted Execution Environment (QTEE).
>>>
>>> Is it so? I think RPMB is accessible to Linux...
>>
>> I should have been more descriptive here, RPMB is accessible by Linux but
>> its frames can only be prepared by QTEE.
>>
>> The RPMB key which is one-time programmed into the storage controller to allow
>> authentication of the RPMB frames is generated by and only available to a TEE.
>> So on Qualcomm platforms (and many others platforms with a TEE) Linux can only
>> route the RPMB frames generated by QTEE to the storage, it cannot create and
>> write the RPMB frames itself (it doesn't have access to the key).
>>
>> While it is possible for Linux to generate/program/store this key, on Qualcomm
>> platforms we do not want Linux to do so because we do not trust it. We trust
>> QTEE.
>>
>> I will re-phrase this and make it a bit more clear everywhere.
>>
>>>
>>>> For Qualcomm platforms without emulated RPMB support, specifically
>>>
>>> What is emulated RPMB support? Why is it mentioned here? Which platforms
>>> use emulated RPMB?
>>
>> Emulated RPMB refers to RPMB on a storage which doesn't have its own firmware.
>> Primarily, NAND/NOR storage. Unlike UFS/eMMC storage, NAND/NOR storage does not
>> have a storage controller where we can program the RPMB key to be used by the
>> firmware. So we must 'emulate' RPMB by moving the storage driver within QTEE
>> and making the driver hold/use the key.
>>
>> Qualcomm compute SoCs (Glymur, Hamoa) have RPMB available on SPI-*NOR* storage,
>> and a driver for communicating with it is also available in QTEE. And so, these
>> have 'emulated' RPMB.
>>
>> I will add this detail in an updated cover letter.
>>>
>>>> platforms where RPMB is not located within SPI-NOR storage and instead
>>>> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
>>>> a callback request from the UEFI Secure Application to the RPMB service
>>>> running in user-space (within the QTEE supplicant [1]).
>>>
>>> Can it be moved to the kernel?
>>
>> We have a plan to move the RPMB service to the kernel similar to OPTEE:
>> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/tee/optee/rpc.c#L449
>>
>> It is a work in progress. Once this happens, we don't need QTEE supplicant available
>> on the Linux distribution.
>>
>>>
>>>>
>>>> Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
>>>> QSEECOM based uefisecapp) does not support callback requests.
>>>
>>> How did it work then? I think Windows has been perfectly using QSEECOM
>>> rather than QTEE.
>>
>> It works because Windows on Arm on Qualcomm has SPI-NOR storage. A driver for which
>> is available within QTEE, and so QTEE does not need to make a callback request
>> to Linux to request RPMB frame routing. However, in case of UFS/eMMC storage the
>> driver only exists in the Linux kernel and so QTEE must make a callback request.
>>
>> And so, if you try to use the QSEECOM driver to write EFI-variables to RPMB
>> on a device with UFS/eMMC storage, it won't work.
>>
>>>
>>>> And on
>>>> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
>>>> QSEECOM interface fail due to lack of support within Qualcomm TEE.
>>>
>>> So, I assume, on RB3 Gen2 the QSEECOM doesn't report uefisecapp as
>>> supported. Does it?
>>
>> It doesn't, this API returns -2 if I add RB3 Gen2 in the allow-list for QSEECOM:
>> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/qcom/qcom_qseecom.c#L46
>>
>>>
>>>> On these platforms, a TEE based uefisecapp client driver is required to:
>>>> 1. Access cached & volatile EFI variables stored in uefisecapp's memory.
>>>> 2. Ensure persistence of non-volatile EFI variables via writes through
>>>> the RPMB service hosted in the QTEE supplicant.
>>>>
>>>> This series introduces such a uefisecapp TEE client driver for the
>>>> aforementioned Qualcomm platforms which installs efi-var operations _if_
>>>> the QCOMTEE driver registers support for an object-IPC based uefisecapp
>>>> service on the TEE bus during its probe. Only new QTEE firmware versions
>>>> available at [2] provide this support.
>>>
>>> What about existing WoA devices?
>>
>> New Windows on Arm devices like Hamoa/Glymur work perfectly fine with existing
>> QSEECOM based uefisecapp. But they will also work with this new QCOMTEE based
>> uefisecapp once they upgrade their firmware.
>>
>> I need to double-check but this firmware release for Glymur on Qualcomm Linux
>> is probably carrying the support for QCOMTEE based uefisecapp access:
>> https://github.com/qualcomm-linux/meta-qcom/commit/728251fcbe5113980805ea6c571e33235062ee71
>> If not, the next release will definitely have it since I have merged support for
>> this in QTEE and talked to the boot firmware release team about this.
>>
>> The next planned firmware upgrade for Hamoa will also provide this support for
>> Qualcomm Linux. And similarly, for all other targets being supported upstream.
>>
>>>
>>>>
>>>> Thus, QCOMTEE now maintains a static list of always-available object-IPC
>>>> based secure services exposed by QTEE. These services are implemented either
>>>> within the QTEE kernel or within a pre-loaded Trusted Application (TA)
>>>> usually loaded by the bootloader. The uefisecapp TA is an example of a
>>>> preloaded TA loaded by UEFI. A static list is required since QTEE does not
>>>> yet expose any way to dynamically query and enumerate the services exposed by
>>>> it.
>>>
>>> Can it be fixed instead of having static lists? In the end, we can't
>>> guarantee that users update the firmware.
>>>
>>
>> Unfortunately, no existing QTEE release out there currently has this support.
>> But support for this is currently being added by QTEE team last I checked with them.
>> Once it is available, and a new QTEE firmware release is out there, we will add
>> support for dynamically querying QTEE services in the QCOMTEE driver. 
>>>>
>>>> To facilitate object-IPC interactions from the kernel-space, this
>>>> series also introduces a tee_client_object_invoke_func() to allow
>>>> invocation of TEE objects similar to the existing tee_client_invoke_func()
>>>> API exported by the TEE subsystem which allows invocation of TEE functions.
>>>> Some suporting changes are also introduced to track and handle operations
>>>> for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
>>>> driver.
>>>>
>>>> Finally and as previously mentioned, access to the object-IPC based uefisecapp
>>>> service is restricted on older QTEE firmware versions. A new QTEE firmware
>>>> release must be picked up from QArtifactory [2] for all upstream supported
>>>> Qualcomm SoCs to enable access to uefisecapp service via the TEE client
>>>> driver.
>>>
>>> What about fused devices?
>>
>> The procedure for updating the firmware on fused devices is slightly different.
>> The firmware images need to be signed by the OEM using the security profile
>> of the chipset before flashing/upgrading them. Security profiles are now public:
>> https://github.com/qualcomm/security-profiles
>>
>> Regards,
>> Harshal
>>
>>>
>>>>
>>>> This patch series has been validated on Kodiak RB3Gen2 platform with UFS
>>>> storage by attempting to read/write EFI variables via the efivar tool [3]
>>>> after mounting the efivarfs filesystem. See [4] for an example.
>>>>
>>>> Merge Strategy:
>>>>
>>>> This patch series could either be taken from the OP-TEE tree or the
>>>> QCOM soc tree. I would prefer it to be picked by the OP-TEE tree since
>>>> all except the uefisecapp TEE client driver patch in this series make
>>>> changes relevant to the TEE subsystem. It would be great if the QCOM soc
>>>> tree maintainers can Ack the uefisecapp driver patch.
>>>>
>>>> [1] https://github.com/qualcomm/minkipc
>>>> [2] https://shorturl.at/zQU07
>>>> [3] https://github.com/rhboot/efivar
>>>> [4] https://docs.qualcomm.com/doc/80-70020-27/topic/manage_uefi_environment_variables_using_efivar_tool.html
>>>>
>>>> Signed-off-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
>>>> ---
>>>> Changes in v2:
>>>> - Drop using MSB of the object_id to distingush kernel and user object invoke contexts.
>>>> - Introduce enum tee_object_invoke_origin to check the context of object invocation.
>>>> - Link to v1: https://lore.kernel.org/r/20260707-qcom_uefisecapp_migrate_qcomtee-v1-0-f659cbd5d04c@oss.qualcomm.com
>>>>
>>>> ---
>>>> Amirreza Zarrabi (2):
>>>>       tee: Add kernel client object invoke helper
>>>>       tee: qcomtee: Allow object invokes from kernel clients
>>>>
>>>> Harshal Dev (4):
>>>>       tee: qcomtee: Track the object invocation context
>>>>       tee: Export uuidv5 generation for TEE backends
>>>>       tee: qcomtee: Add support for registering QTEE services on TEE bus
>>>>       firmware: qcom: Add support for TEE based EFI-var client driver
>>>>
>>>>  MAINTAINERS                                 |   7 +
>>>>  drivers/firmware/qcom/Kconfig               |  24 ++
>>>>  drivers/firmware/qcom/Makefile              |   1 +
>>>>  drivers/firmware/qcom/qcom_tee_uefisecapp.c | 525 ++++++++++++++++++++++++++++
>>>>  drivers/firmware/qcom/qcom_tee_uefisecapp.h | 120 +++++++
>>>
>>> I don't see any changes to the QSEECOM drivers. Is it allowed to use
>>> QSEECOM and QTEE access to uefisecapp at the same time?
>>>
>>>>  drivers/tee/qcomtee/call.c                  | 205 ++++++++++-
>>>>  drivers/tee/qcomtee/core.c                  |   9 +-
>>>>  drivers/tee/qcomtee/qcomtee.h               |  12 +
>>>>  drivers/tee/qcomtee/qcomtee_msg.h           |   1 +
>>>>  drivers/tee/qcomtee/qcomtee_object.h        |  16 +-
>>>>  drivers/tee/tee_core.c                      |  24 +-
>>>>  include/linux/tee_core.h                    |  23 +-
>>>>  include/linux/tee_drv.h                     |  18 +-
>>>>  13 files changed, 952 insertions(+), 33 deletions(-)
>>>> ---
>>>> base-commit: f3e6330d7fe42b204af05a2dbc68b379e0ad179e
>>>> change-id: 20260408-qcom_uefisecapp_migrate_qcomtee-13869d45e014
>>>>
>>>> Best regards,
>>>> -- 
>>>> Harshal Dev <harshal.dev@oss.qualcomm.com>
>>>>
>>>
>>
> 


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

* Re: [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
  2026-07-24  9:13   ` Harshal Dev
  2026-08-03 14:52     ` Harshal Dev
@ 2026-08-10  7:07     ` Dmitry Baryshkov
  2026-08-12 11:30       ` Harshal Dev
  1 sibling, 1 reply; 24+ messages in thread
From: Dmitry Baryshkov @ 2026-08-10  7:07 UTC (permalink / raw)
  To: Harshal Dev
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

On Fri, Jul 24, 2026 at 02:43:42PM +0530, Harshal Dev wrote:
> Hi Dmitry,
> 
> On 22-07-2026 01:56 pm, Dmitry Baryshkov wrote:
> > On Wed, Jul 22, 2026 at 12:29:11PM +0530, Harshal Dev wrote:
> >> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
> >> Replay Protected Memory Block (RPMB) which is only accessible by the
> >> Qualcomm Trusted Execution Environment (QTEE).
> > 
> > Is it so? I think RPMB is accessible to Linux...
> 
> I should have been more descriptive here, RPMB is accessible by Linux but
> its frames can only be prepared by QTEE.
> 
> The RPMB key which is one-time programmed into the storage controller to allow
> authentication of the RPMB frames is generated by and only available to a TEE.
> So on Qualcomm platforms (and many others platforms with a TEE) Linux can only
> route the RPMB frames generated by QTEE to the storage, it cannot create and
> write the RPMB frames itself (it doesn't have access to the key).
> 
> While it is possible for Linux to generate/program/store this key, on Qualcomm
> platforms we do not want Linux to do so because we do not trust it. We trust
> QTEE.
> 
> I will re-phrase this and make it a bit more clear everywhere.

OK.

> 
> > 
> >> For Qualcomm platforms without emulated RPMB support, specifically
> > 
> > What is emulated RPMB support? Why is it mentioned here? Which platforms
> > use emulated RPMB?
> 
> Emulated RPMB refers to RPMB on a storage which doesn't have its own firmware.
> Primarily, NAND/NOR storage. Unlike UFS/eMMC storage, NAND/NOR storage does not
> have a storage controller where we can program the RPMB key to be used by the
> firmware. So we must 'emulate' RPMB by moving the storage driver within QTEE
> and making the driver hold/use the key.
> 
> Qualcomm compute SoCs (Glymur, Hamoa) have RPMB available on SPI-*NOR* storage,
> and a driver for communicating with it is also available in QTEE. And so, these
> have 'emulated' RPMB.

This needs to be explained in the cover letter.

> 
> I will add this detail in an updated cover letter.
> > 
> >> platforms where RPMB is not located within SPI-NOR storage and instead
> >> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
> >> a callback request from the UEFI Secure Application to the RPMB service
> >> running in user-space (within the QTEE supplicant [1]).
> > 
> > Can it be moved to the kernel?
> 
> We have a plan to move the RPMB service to the kernel similar to OPTEE:
> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/tee/optee/rpc.c#L449
> 
> It is a work in progress. Once this happens, we don't need QTEE supplicant available
> on the Linux distribution.

Ok.

> 
> > 
> >>
> >> Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
> >> QSEECOM based uefisecapp) does not support callback requests.
> > 
> > How did it work then? I think Windows has been perfectly using QSEECOM
> > rather than QTEE.
> 
> It works because Windows on Arm on Qualcomm has SPI-NOR storage. A driver for which

I have WoA devices without SPI NOR. Windows still can store UEFI
variables.

> is available within QTEE, and so QTEE does not need to make a callback request
> to Linux to request RPMB frame routing. However, in case of UFS/eMMC storage the
> driver only exists in the Linux kernel and so QTEE must make a callback request.
> 
> And so, if you try to use the QSEECOM driver to write EFI-variables to RPMB
> on a device with UFS/eMMC storage, it won't work.

Yep. It seems to work under Windows though.

> 
> > 
> >> And on
> >> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
> >> QSEECOM interface fail due to lack of support within Qualcomm TEE.
> > 
> > So, I assume, on RB3 Gen2 the QSEECOM doesn't report uefisecapp as
> > supported. Does it?
> 
> It doesn't, this API returns -2 if I add RB3 Gen2 in the allow-list for QSEECOM:
> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/qcom/qcom_qseecom.c#L46

Does it support QTEE-based uefi variable storage?

> >> On these platforms, a TEE based uefisecapp client driver is required to:
> >> 1. Access cached & volatile EFI variables stored in uefisecapp's memory.
> >> 2. Ensure persistence of non-volatile EFI variables via writes through
> >> the RPMB service hosted in the QTEE supplicant.
> >>
> >> This series introduces such a uefisecapp TEE client driver for the
> >> aforementioned Qualcomm platforms which installs efi-var operations _if_
> >> the QCOMTEE driver registers support for an object-IPC based uefisecapp
> >> service on the TEE bus during its probe. Only new QTEE firmware versions
> >> available at [2] provide this support.
> > 
> > What about existing WoA devices?
> 
> New Windows on Arm devices like Hamoa/Glymur work perfectly fine with existing
> QSEECOM based uefisecapp. But they will also work with this new QCOMTEE based
> uefisecapp once they upgrade their firmware.

Do extisting commercial devices suppot it? For example, does Lenovo T14s
support it? Will it continue to work with this patchset in place?

What about other existing devices? We have WoA devices starting with
MSM8998. The QSEECOM driver works on them, but, as you mentioned, it
can't flash updates to the backing storage.

> I need to double-check but this firmware release for Glymur on Qualcomm Linux
> is probably carrying the support for QCOMTEE based uefisecapp access:
> https://github.com/qualcomm-linux/meta-qcom/commit/728251fcbe5113980805ea6c571e33235062ee71
> If not, the next release will definitely have it since I have merged support for
> this in QTEE and talked to the boot firmware release team about this.

Does it work on the CRD?

> 
> The next planned firmware upgrade for Hamoa will also provide this support for
> Qualcomm Linux. And similarly, for all other targets being supported upstream.

So, we are forcing users to upgrade to the new firmware? That doesn't
sound nice.

> >> Thus, QCOMTEE now maintains a static list of always-available object-IPC
> >> based secure services exposed by QTEE. These services are implemented either
> >> within the QTEE kernel or within a pre-loaded Trusted Application (TA)
> >> usually loaded by the bootloader. The uefisecapp TA is an example of a
> >> preloaded TA loaded by UEFI. A static list is required since QTEE does not
> >> yet expose any way to dynamically query and enumerate the services exposed by
> >> it.
> > 
> > Can it be fixed instead of having static lists? In the end, we can't
> > guarantee that users update the firmware.
> >
> 
> Unfortunately, no existing QTEE release out there currently has this support.
> But support for this is currently being added by QTEE team last I checked with them.
> Once it is available, and a new QTEE firmware release is out there, we will add
> support for dynamically querying QTEE services in the QCOMTEE driver. 

It seems you are still rolling out QTEE-based support. In such a case,
please go back and implement dynamic detection of QTEE services.
Otherwise it would be a nightmare.

> >> To facilitate object-IPC interactions from the kernel-space, this
> >> series also introduces a tee_client_object_invoke_func() to allow
> >> invocation of TEE objects similar to the existing tee_client_invoke_func()
> >> API exported by the TEE subsystem which allows invocation of TEE functions.
> >> Some suporting changes are also introduced to track and handle operations
> >> for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
> >> driver.
> >>
> >> Finally and as previously mentioned, access to the object-IPC based uefisecapp
> >> service is restricted on older QTEE firmware versions. A new QTEE firmware
> >> release must be picked up from QArtifactory [2] for all upstream supported
> >> Qualcomm SoCs to enable access to uefisecapp service via the TEE client
> >> driver.
> > 
> > What about fused devices?
> 
> The procedure for updating the firmware on fused devices is slightly different.
> The firmware images need to be signed by the OEM using the security profile
> of the chipset before flashing/upgrading them. Security profiles are now public:
> https://github.com/qualcomm/security-profiles

Will OEMs release new firmware images? What about the devices which are
already out of the support phase? This whole story rotates about the 'we
are releasing new firmware with new features' paradigm. However there
are existing devices in the field, which typically can't be upgraded,
From your cover letter it seems they can't support UEFI variables
properly. However they do so in Windows.

-- 
With best wishes
Dmitry

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

* Re: [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
  2026-08-10  7:07     ` Dmitry Baryshkov
@ 2026-08-12 11:30       ` Harshal Dev
  2026-08-17  6:24         ` Harshal Dev
  0 siblings, 1 reply; 24+ messages in thread
From: Harshal Dev @ 2026-08-12 11:30 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Jens Wiklander, Sumit Garg, Amirreza Zarrabi,
	Bjorn Andersson, Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

Hi Dmitry,

On 10-08-2026 12:37 pm, Dmitry Baryshkov wrote:
> On Fri, Jul 24, 2026 at 02:43:42PM +0530, Harshal Dev wrote:
>> Hi Dmitry,
>>
>> On 22-07-2026 01:56 pm, Dmitry Baryshkov wrote:
>>> On Wed, Jul 22, 2026 at 12:29:11PM +0530, Harshal Dev wrote:
>>>> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
>>>> Replay Protected Memory Block (RPMB) which is only accessible by the
>>>> Qualcomm Trusted Execution Environment (QTEE).
>>>
>>> Is it so? I think RPMB is accessible to Linux...
>>
>> I should have been more descriptive here, RPMB is accessible by Linux but
>> its frames can only be prepared by QTEE.
>>
>> The RPMB key which is one-time programmed into the storage controller to allow
>> authentication of the RPMB frames is generated by and only available to a TEE.
>> So on Qualcomm platforms (and many others platforms with a TEE) Linux can only
>> route the RPMB frames generated by QTEE to the storage, it cannot create and
>> write the RPMB frames itself (it doesn't have access to the key).
>>
>> While it is possible for Linux to generate/program/store this key, on Qualcomm
>> platforms we do not want Linux to do so because we do not trust it. We trust
>> QTEE.
>>
>> I will re-phrase this and make it a bit more clear everywhere.
> 
> OK.
> 
>>
>>>
>>>> For Qualcomm platforms without emulated RPMB support, specifically
>>>
>>> What is emulated RPMB support? Why is it mentioned here? Which platforms
>>> use emulated RPMB?
>>
>> Emulated RPMB refers to RPMB on a storage which doesn't have its own firmware.
>> Primarily, NAND/NOR storage. Unlike UFS/eMMC storage, NAND/NOR storage does not
>> have a storage controller where we can program the RPMB key to be used by the
>> firmware. So we must 'emulate' RPMB by moving the storage driver within QTEE
>> and making the driver hold/use the key.
>>
>> Qualcomm compute SoCs (Glymur, Hamoa) have RPMB available on SPI-*NOR* storage,
>> and a driver for communicating with it is also available in QTEE. And so, these
>> have 'emulated' RPMB.
> 
> This needs to be explained in the cover letter.
>

Ack. 
>>
>> I will add this detail in an updated cover letter.
>>>
>>>> platforms where RPMB is not located within SPI-NOR storage and instead
>>>> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
>>>> a callback request from the UEFI Secure Application to the RPMB service
>>>> running in user-space (within the QTEE supplicant [1]).
>>>
>>> Can it be moved to the kernel?
>>
>> We have a plan to move the RPMB service to the kernel similar to OPTEE:
>> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/tee/optee/rpc.c#L449
>>
>> It is a work in progress. Once this happens, we don't need QTEE supplicant available
>> on the Linux distribution.
> 
> Ok.
> 
>>
>>>
>>>>
>>>> Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
>>>> QSEECOM based uefisecapp) does not support callback requests.
>>>
>>> How did it work then? I think Windows has been perfectly using QSEECOM
>>> rather than QTEE.
>>
>> It works because Windows on Arm on Qualcomm has SPI-NOR storage. A driver for which
> 
> I have WoA devices without SPI NOR. Windows still can store UEFI
> variables.
>

Ahh, the key point here is 'Windows'. Windows has a separate way of providing
RPMB access via a service in the TrEE driver within the OS:
https://github.com/microsoft/Windows-driver-samples/tree/main/TrEE

However, the Linux QSEECOM driver we have here in upstream does not have that support.
And so without the QCOMTEE + QTEE supplicant combination, we cannot access EFI
variables on these Qualcomm WoA platforms when they boot with upstream Linux.

>> is available within QTEE, and so QTEE does not need to make a callback request
>> to Linux to request RPMB frame routing. However, in case of UFS/eMMC storage the
>> driver only exists in the Linux kernel and so QTEE must make a callback request.
>>
>> And so, if you try to use the QSEECOM driver to write EFI-variables to RPMB
>> on a device with UFS/eMMC storage, it won't work.
> 
> Yep. It seems to work under Windows though.
>

As explained above, the mechanism is different for Windows. A different driver
and a different protocol. :)

>>
>>>
>>>> And on
>>>> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
>>>> QSEECOM interface fail due to lack of support within Qualcomm TEE.
>>>
>>> So, I assume, on RB3 Gen2 the QSEECOM doesn't report uefisecapp as
>>> supported. Does it?
>>
>> It doesn't, this API returns -2 if I add RB3 Gen2 in the allow-list for QSEECOM:
>> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/qcom/qcom_qseecom.c#L46
> 
> Does it support QTEE-based uefi variable storage?
>

It does, the QTEE-based uefi variable storage app, i.e. uefisecapp is loaded by
UEFI on RB3Gen2, however, the QSEECOM interface on RB3Gen2 is broken so it misreports
it as 'not supported'. But the app is loaded and available, which is why if you apply
this patch series, you can communicate with it. Just make sure you take the QTEE
release mentioned in this cover letter.

>>>> On these platforms, a TEE based uefisecapp client driver is required to:
>>>> 1. Access cached & volatile EFI variables stored in uefisecapp's memory.
>>>> 2. Ensure persistence of non-volatile EFI variables via writes through
>>>> the RPMB service hosted in the QTEE supplicant.
>>>>
>>>> This series introduces such a uefisecapp TEE client driver for the
>>>> aforementioned Qualcomm platforms which installs efi-var operations _if_
>>>> the QCOMTEE driver registers support for an object-IPC based uefisecapp
>>>> service on the TEE bus during its probe. Only new QTEE firmware versions
>>>> available at [2] provide this support.
>>>
>>> What about existing WoA devices?
>>
>> New Windows on Arm devices like Hamoa/Glymur work perfectly fine with existing
>> QSEECOM based uefisecapp. But they will also work with this new QCOMTEE based
>> uefisecapp once they upgrade their firmware.
> 
> Do extisting commercial devices suppot it? For example, does Lenovo T14s
> support it? Will it continue to work with this patchset in place?

Existing devices like the Lenovo T14s do not have mature QCOMTEE/SMCInvoke support
on QTEE side and new QTEE versions for it are not being rolled out. However, this
QCOMTEE based uefisecapp driver and the QSEECOM based uefisecapp driver can co-exist.
It will not cause any breakage of existing working functionality since the QSEECOM
path can probe and continue as usual.

As per your comments on patch 6 of this series, I plan to enable the QCOMTEE based
uefisecapp as default 'm'. That way we don't need to enable one over the other and
will continue supporting all existing functionality while extending it for devices
with UFS/eMMC storage and running upstream Linux.

Do let me know your opinion on it.

> 
> What about other existing devices? We have WoA devices starting with
> MSM8998. The QSEECOM driver works on them, but, as you mentioned, it
> can't flash updates to the backing storage.
>

Unfortunately, unless we roll out new QTEE firmware versions for devices like MSM8998
with QCOMTEE/SMCInvoke support + access to the Uefisecapp over SMCInvoke protocol,
they cannot be helped with this series.

>> I need to double-check but this firmware release for Glymur on Qualcomm Linux
>> is probably carrying the support for QCOMTEE based uefisecapp access:
>> https://github.com/qualcomm-linux/meta-qcom/commit/728251fcbe5113980805ea6c571e33235062ee71
>> If not, the next release will definitely have it since I have merged support for
>> this in QTEE and talked to the boot firmware release team about this.
> 
> Does it work on the CRD?
>

Yes it does, I have validated on Glymur CRD by locally switching it from the current QSEECOM
based uefisecapp to this new QCOMTEE based uefisecapp. This is the QTEE release which
needs to be consumed for it:
https://github.com/qualcomm-linux/meta-qcom/commit/5590c1dc631827624c110df282965b85ef2a2e60 

>>
>> The next planned firmware upgrade for Hamoa will also provide this support for
>> Qualcomm Linux. And similarly, for all other targets being supported upstream.
> 
> So, we are forcing users to upgrade to the new firmware? That doesn't
> sound nice.
>

We have an open ecosystem for all devices supported by the Qualcomm Linux distribution,
users can easily consume new releases (and new QTEE versions) to access new features.
Until now, developers/users of RB3Gen2 or IQ-9075 could not access EFI variables to
develop use-cases such as secure-boot key revocation, but by taking this patch series
as part of a subsequent Qualcomm Linux release, they will be able to.

>>>> Thus, QCOMTEE now maintains a static list of always-available object-IPC
>>>> based secure services exposed by QTEE. These services are implemented either
>>>> within the QTEE kernel or within a pre-loaded Trusted Application (TA)
>>>> usually loaded by the bootloader. The uefisecapp TA is an example of a
>>>> preloaded TA loaded by UEFI. A static list is required since QTEE does not
>>>> yet expose any way to dynamically query and enumerate the services exposed by
>>>> it.
>>>
>>> Can it be fixed instead of having static lists? In the end, we can't
>>> guarantee that users update the firmware.
>>>
>>
>> Unfortunately, no existing QTEE release out there currently has this support.
>> But support for this is currently being added by QTEE team last I checked with them.
>> Once it is available, and a new QTEE firmware release is out there, we will add
>> support for dynamically querying QTEE services in the QCOMTEE driver. 
> 
> It seems you are still rolling out QTEE-based support. In such a case,
> please go back and implement dynamic detection of QTEE services.
> Otherwise it would be a nightmare.
>

We are working on it, but until then there is no overhead involved in maintaining
this static list of services because we don't have to extend/modify this list when
adding support for a new Qualcomm platform upstream. If a particular service from
the list is not implemented/accessible from QTEE we log the event and silently avoid
probing the TEE driver for the service. We also don't add platform specific services
here. So the list doesn't need to be extended on a per-platform basis.

So unlike the QSEECOM driver, we don't have to keep maintaining this list forever
for all new platforms.

>>>> To facilitate object-IPC interactions from the kernel-space, this
>>>> series also introduces a tee_client_object_invoke_func() to allow
>>>> invocation of TEE objects similar to the existing tee_client_invoke_func()
>>>> API exported by the TEE subsystem which allows invocation of TEE functions.
>>>> Some suporting changes are also introduced to track and handle operations
>>>> for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
>>>> driver.
>>>>
>>>> Finally and as previously mentioned, access to the object-IPC based uefisecapp
>>>> service is restricted on older QTEE firmware versions. A new QTEE firmware
>>>> release must be picked up from QArtifactory [2] for all upstream supported
>>>> Qualcomm SoCs to enable access to uefisecapp service via the TEE client
>>>> driver.
>>>
>>> What about fused devices?
>>
>> The procedure for updating the firmware on fused devices is slightly different.
>> The firmware images need to be signed by the OEM using the security profile
>> of the chipset before flashing/upgrading them. Security profiles are now public:
>> https://github.com/qualcomm/security-profiles
> 
> Will OEMs release new firmware images? What about the devices which are
> already out of the support phase? This whole story rotates about the 'we
> are releasing new firmware with new features' paradigm. However there
> are existing devices in the field, which typically can't be upgraded,
> From your cover letter it seems they can't support UEFI variables
> properly. However they do so in Windows.
>

Yes Dmitry, this series is effectively forward looking. QSEECOM protocol/driver
support is essentially deprecated on QTEE side, no new features added to QTEE support
it, and it also doesn't work on many devices like the RB3Gen2.

For existing devices, if they boot with upstream Linux and have RPMB located on
UFS/eMMC this patch series cannot help them. But the focus of this series is not on the
past, it is on currently supported and future hardware. Every new Qualcomm platform
whose support is being up-streamed or is planned to be up-streamed will have access to
EFI variables via this series.

If someone wants to add support for older Qualcomm devices to access EFI variables
via QSEECOM that patch series will not conflict with this one. Like I said, both
QSEECOM and QCOMTEE based drivers can co-exist.

Regards,
Harshal


 


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

* Re: [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
  2026-08-12 11:30       ` Harshal Dev
@ 2026-08-17  6:24         ` Harshal Dev
  2026-08-21  8:34           ` Harshal Dev
  0 siblings, 1 reply; 24+ messages in thread
From: Harshal Dev @ 2026-08-17  6:24 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Sumit Garg, Amirreza Zarrabi, Bjorn Andersson,
	Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

Hi Dmitry,

Many thanks for your engagement and review on this series. I am looking forward
to your opinions on below comments so we can align on a a v3 of this series.

Best Regards,
Harshal

On 12-08-2026 05:00 pm, Harshal Dev wrote:
> Hi Dmitry,
> 
> On 10-08-2026 12:37 pm, Dmitry Baryshkov wrote:
>> On Fri, Jul 24, 2026 at 02:43:42PM +0530, Harshal Dev wrote:
>>> Hi Dmitry,
>>>
>>> On 22-07-2026 01:56 pm, Dmitry Baryshkov wrote:
>>>> On Wed, Jul 22, 2026 at 12:29:11PM +0530, Harshal Dev wrote:
>>>>> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
>>>>> Replay Protected Memory Block (RPMB) which is only accessible by the
>>>>> Qualcomm Trusted Execution Environment (QTEE).
>>>>
>>>> Is it so? I think RPMB is accessible to Linux...
>>>
>>> I should have been more descriptive here, RPMB is accessible by Linux but
>>> its frames can only be prepared by QTEE.
>>>
>>> The RPMB key which is one-time programmed into the storage controller to allow
>>> authentication of the RPMB frames is generated by and only available to a TEE.
>>> So on Qualcomm platforms (and many others platforms with a TEE) Linux can only
>>> route the RPMB frames generated by QTEE to the storage, it cannot create and
>>> write the RPMB frames itself (it doesn't have access to the key).
>>>
>>> While it is possible for Linux to generate/program/store this key, on Qualcomm
>>> platforms we do not want Linux to do so because we do not trust it. We trust
>>> QTEE.
>>>
>>> I will re-phrase this and make it a bit more clear everywhere.
>>
>> OK.
>>
>>>
>>>>
>>>>> For Qualcomm platforms without emulated RPMB support, specifically
>>>>
>>>> What is emulated RPMB support? Why is it mentioned here? Which platforms
>>>> use emulated RPMB?
>>>
>>> Emulated RPMB refers to RPMB on a storage which doesn't have its own firmware.
>>> Primarily, NAND/NOR storage. Unlike UFS/eMMC storage, NAND/NOR storage does not
>>> have a storage controller where we can program the RPMB key to be used by the
>>> firmware. So we must 'emulate' RPMB by moving the storage driver within QTEE
>>> and making the driver hold/use the key.
>>>
>>> Qualcomm compute SoCs (Glymur, Hamoa) have RPMB available on SPI-*NOR* storage,
>>> and a driver for communicating with it is also available in QTEE. And so, these
>>> have 'emulated' RPMB.
>>
>> This needs to be explained in the cover letter.
>>
> 
> Ack. 
>>>
>>> I will add this detail in an updated cover letter.
>>>>
>>>>> platforms where RPMB is not located within SPI-NOR storage and instead
>>>>> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
>>>>> a callback request from the UEFI Secure Application to the RPMB service
>>>>> running in user-space (within the QTEE supplicant [1]).
>>>>
>>>> Can it be moved to the kernel?
>>>
>>> We have a plan to move the RPMB service to the kernel similar to OPTEE:
>>> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/tee/optee/rpc.c#L449
>>>
>>> It is a work in progress. Once this happens, we don't need QTEE supplicant available
>>> on the Linux distribution.
>>
>> Ok.
>>
>>>
>>>>
>>>>>
>>>>> Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
>>>>> QSEECOM based uefisecapp) does not support callback requests.
>>>>
>>>> How did it work then? I think Windows has been perfectly using QSEECOM
>>>> rather than QTEE.
>>>
>>> It works because Windows on Arm on Qualcomm has SPI-NOR storage. A driver for which
>>
>> I have WoA devices without SPI NOR. Windows still can store UEFI
>> variables.
>>
> 
> Ahh, the key point here is 'Windows'. Windows has a separate way of providing
> RPMB access via a service in the TrEE driver within the OS:
> https://github.com/microsoft/Windows-driver-samples/tree/main/TrEE
> 
> However, the Linux QSEECOM driver we have here in upstream does not have that support.
> And so without the QCOMTEE + QTEE supplicant combination, we cannot access EFI
> variables on these Qualcomm WoA platforms when they boot with upstream Linux.
> 
>>> is available within QTEE, and so QTEE does not need to make a callback request
>>> to Linux to request RPMB frame routing. However, in case of UFS/eMMC storage the
>>> driver only exists in the Linux kernel and so QTEE must make a callback request.
>>>
>>> And so, if you try to use the QSEECOM driver to write EFI-variables to RPMB
>>> on a device with UFS/eMMC storage, it won't work.
>>
>> Yep. It seems to work under Windows though.
>>
> 
> As explained above, the mechanism is different for Windows. A different driver
> and a different protocol. :)
> 
>>>
>>>>
>>>>> And on
>>>>> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
>>>>> QSEECOM interface fail due to lack of support within Qualcomm TEE.
>>>>
>>>> So, I assume, on RB3 Gen2 the QSEECOM doesn't report uefisecapp as
>>>> supported. Does it?
>>>
>>> It doesn't, this API returns -2 if I add RB3 Gen2 in the allow-list for QSEECOM:
>>> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/qcom/qcom_qseecom.c#L46
>>
>> Does it support QTEE-based uefi variable storage?
>>
> 
> It does, the QTEE-based uefi variable storage app, i.e. uefisecapp is loaded by
> UEFI on RB3Gen2, however, the QSEECOM interface on RB3Gen2 is broken so it misreports
> it as 'not supported'. But the app is loaded and available, which is why if you apply
> this patch series, you can communicate with it. Just make sure you take the QTEE
> release mentioned in this cover letter.
> 
>>>>> On these platforms, a TEE based uefisecapp client driver is required to:
>>>>> 1. Access cached & volatile EFI variables stored in uefisecapp's memory.
>>>>> 2. Ensure persistence of non-volatile EFI variables via writes through
>>>>> the RPMB service hosted in the QTEE supplicant.
>>>>>
>>>>> This series introduces such a uefisecapp TEE client driver for the
>>>>> aforementioned Qualcomm platforms which installs efi-var operations _if_
>>>>> the QCOMTEE driver registers support for an object-IPC based uefisecapp
>>>>> service on the TEE bus during its probe. Only new QTEE firmware versions
>>>>> available at [2] provide this support.
>>>>
>>>> What about existing WoA devices?
>>>
>>> New Windows on Arm devices like Hamoa/Glymur work perfectly fine with existing
>>> QSEECOM based uefisecapp. But they will also work with this new QCOMTEE based
>>> uefisecapp once they upgrade their firmware.
>>
>> Do extisting commercial devices suppot it? For example, does Lenovo T14s
>> support it? Will it continue to work with this patchset in place?
> 
> Existing devices like the Lenovo T14s do not have mature QCOMTEE/SMCInvoke support
> on QTEE side and new QTEE versions for it are not being rolled out. However, this
> QCOMTEE based uefisecapp driver and the QSEECOM based uefisecapp driver can co-exist.
> It will not cause any breakage of existing working functionality since the QSEECOM
> path can probe and continue as usual.
> 
> As per your comments on patch 6 of this series, I plan to enable the QCOMTEE based
> uefisecapp as default 'm'. That way we don't need to enable one over the other and
> will continue supporting all existing functionality while extending it for devices
> with UFS/eMMC storage and running upstream Linux.
> 
> Do let me know your opinion on it.
> 
>>
>> What about other existing devices? We have WoA devices starting with
>> MSM8998. The QSEECOM driver works on them, but, as you mentioned, it
>> can't flash updates to the backing storage.
>>
> 
> Unfortunately, unless we roll out new QTEE firmware versions for devices like MSM8998
> with QCOMTEE/SMCInvoke support + access to the Uefisecapp over SMCInvoke protocol,
> they cannot be helped with this series.
> 
>>> I need to double-check but this firmware release for Glymur on Qualcomm Linux
>>> is probably carrying the support for QCOMTEE based uefisecapp access:
>>> https://github.com/qualcomm-linux/meta-qcom/commit/728251fcbe5113980805ea6c571e33235062ee71
>>> If not, the next release will definitely have it since I have merged support for
>>> this in QTEE and talked to the boot firmware release team about this.
>>
>> Does it work on the CRD?
>>
> 
> Yes it does, I have validated on Glymur CRD by locally switching it from the current QSEECOM
> based uefisecapp to this new QCOMTEE based uefisecapp. This is the QTEE release which
> needs to be consumed for it:
> https://github.com/qualcomm-linux/meta-qcom/commit/5590c1dc631827624c110df282965b85ef2a2e60 
> 
>>>
>>> The next planned firmware upgrade for Hamoa will also provide this support for
>>> Qualcomm Linux. And similarly, for all other targets being supported upstream.
>>
>> So, we are forcing users to upgrade to the new firmware? That doesn't
>> sound nice.
>>
> 
> We have an open ecosystem for all devices supported by the Qualcomm Linux distribution,
> users can easily consume new releases (and new QTEE versions) to access new features.
> Until now, developers/users of RB3Gen2 or IQ-9075 could not access EFI variables to
> develop use-cases such as secure-boot key revocation, but by taking this patch series
> as part of a subsequent Qualcomm Linux release, they will be able to.
> 
>>>>> Thus, QCOMTEE now maintains a static list of always-available object-IPC
>>>>> based secure services exposed by QTEE. These services are implemented either
>>>>> within the QTEE kernel or within a pre-loaded Trusted Application (TA)
>>>>> usually loaded by the bootloader. The uefisecapp TA is an example of a
>>>>> preloaded TA loaded by UEFI. A static list is required since QTEE does not
>>>>> yet expose any way to dynamically query and enumerate the services exposed by
>>>>> it.
>>>>
>>>> Can it be fixed instead of having static lists? In the end, we can't
>>>> guarantee that users update the firmware.
>>>>
>>>
>>> Unfortunately, no existing QTEE release out there currently has this support.
>>> But support for this is currently being added by QTEE team last I checked with them.
>>> Once it is available, and a new QTEE firmware release is out there, we will add
>>> support for dynamically querying QTEE services in the QCOMTEE driver. 
>>
>> It seems you are still rolling out QTEE-based support. In such a case,
>> please go back and implement dynamic detection of QTEE services.
>> Otherwise it would be a nightmare.
>>
> 
> We are working on it, but until then there is no overhead involved in maintaining
> this static list of services because we don't have to extend/modify this list when
> adding support for a new Qualcomm platform upstream. If a particular service from
> the list is not implemented/accessible from QTEE we log the event and silently avoid
> probing the TEE driver for the service. We also don't add platform specific services
> here. So the list doesn't need to be extended on a per-platform basis.
> 
> So unlike the QSEECOM driver, we don't have to keep maintaining this list forever
> for all new platforms.
> 
>>>>> To facilitate object-IPC interactions from the kernel-space, this
>>>>> series also introduces a tee_client_object_invoke_func() to allow
>>>>> invocation of TEE objects similar to the existing tee_client_invoke_func()
>>>>> API exported by the TEE subsystem which allows invocation of TEE functions.
>>>>> Some suporting changes are also introduced to track and handle operations
>>>>> for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
>>>>> driver.
>>>>>
>>>>> Finally and as previously mentioned, access to the object-IPC based uefisecapp
>>>>> service is restricted on older QTEE firmware versions. A new QTEE firmware
>>>>> release must be picked up from QArtifactory [2] for all upstream supported
>>>>> Qualcomm SoCs to enable access to uefisecapp service via the TEE client
>>>>> driver.
>>>>
>>>> What about fused devices?
>>>
>>> The procedure for updating the firmware on fused devices is slightly different.
>>> The firmware images need to be signed by the OEM using the security profile
>>> of the chipset before flashing/upgrading them. Security profiles are now public:
>>> https://github.com/qualcomm/security-profiles
>>
>> Will OEMs release new firmware images? What about the devices which are
>> already out of the support phase? This whole story rotates about the 'we
>> are releasing new firmware with new features' paradigm. However there
>> are existing devices in the field, which typically can't be upgraded,
>> From your cover letter it seems they can't support UEFI variables
>> properly. However they do so in Windows.
>>
> 
> Yes Dmitry, this series is effectively forward looking. QSEECOM protocol/driver
> support is essentially deprecated on QTEE side, no new features added to QTEE support
> it, and it also doesn't work on many devices like the RB3Gen2.
> 
> For existing devices, if they boot with upstream Linux and have RPMB located on
> UFS/eMMC this patch series cannot help them. But the focus of this series is not on the
> past, it is on currently supported and future hardware. Every new Qualcomm platform
> whose support is being up-streamed or is planned to be up-streamed will have access to
> EFI variables via this series.
> 
> If someone wants to add support for older Qualcomm devices to access EFI variables
> via QSEECOM that patch series will not conflict with this one. Like I said, both
> QSEECOM and QCOMTEE based drivers can co-exist.
> 
> Regards,
> Harshal
> 
> 
>  
> 


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

* Re: [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application
  2026-08-17  6:24         ` Harshal Dev
@ 2026-08-21  8:34           ` Harshal Dev
  0 siblings, 0 replies; 24+ messages in thread
From: Harshal Dev @ 2026-08-21  8:34 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Jens Wiklander, Sumit Garg, Amirreza Zarrabi, Bjorn Andersson,
	Konrad Dybcio, Basant Kumar, Apurupa Pattapu,
	Arun Kumar Neelakantam, op-tee, linux-kernel, linux-arm-msm

Hello Dmitry,

A gentle reminder. Hopefully we can align on below points and move to
a v3 of this series.

Regards,
Harshal

On 17-08-2026 11:54 am, Harshal Dev wrote:
> Hi Dmitry,
> 
> Many thanks for your engagement and review on this series. I am looking forward
> to your opinions on below comments so we can align on a a v3 of this series.
> 
> Best Regards,
> Harshal
> 
> On 12-08-2026 05:00 pm, Harshal Dev wrote:
>> Hi Dmitry,
>>
>> On 10-08-2026 12:37 pm, Dmitry Baryshkov wrote:
>>> On Fri, Jul 24, 2026 at 02:43:42PM +0530, Harshal Dev wrote:
>>>> Hi Dmitry,
>>>>
>>>> On 22-07-2026 01:56 pm, Dmitry Baryshkov wrote:
>>>>> On Wed, Jul 22, 2026 at 12:29:11PM +0530, Harshal Dev wrote:
>>>>>> On Qualcomm SoC based platforms, UEFI stores EFI variables within the
>>>>>> Replay Protected Memory Block (RPMB) which is only accessible by the
>>>>>> Qualcomm Trusted Execution Environment (QTEE).
>>>>>
>>>>> Is it so? I think RPMB is accessible to Linux...
>>>>
>>>> I should have been more descriptive here, RPMB is accessible by Linux but
>>>> its frames can only be prepared by QTEE.
>>>>
>>>> The RPMB key which is one-time programmed into the storage controller to allow
>>>> authentication of the RPMB frames is generated by and only available to a TEE.
>>>> So on Qualcomm platforms (and many others platforms with a TEE) Linux can only
>>>> route the RPMB frames generated by QTEE to the storage, it cannot create and
>>>> write the RPMB frames itself (it doesn't have access to the key).
>>>>
>>>> While it is possible for Linux to generate/program/store this key, on Qualcomm
>>>> platforms we do not want Linux to do so because we do not trust it. We trust
>>>> QTEE.
>>>>
>>>> I will re-phrase this and make it a bit more clear everywhere.
>>>
>>> OK.
>>>
>>>>
>>>>>
>>>>>> For Qualcomm platforms without emulated RPMB support, specifically
>>>>>
>>>>> What is emulated RPMB support? Why is it mentioned here? Which platforms
>>>>> use emulated RPMB?
>>>>
>>>> Emulated RPMB refers to RPMB on a storage which doesn't have its own firmware.
>>>> Primarily, NAND/NOR storage. Unlike UFS/eMMC storage, NAND/NOR storage does not
>>>> have a storage controller where we can program the RPMB key to be used by the
>>>> firmware. So we must 'emulate' RPMB by moving the storage driver within QTEE
>>>> and making the driver hold/use the key.
>>>>
>>>> Qualcomm compute SoCs (Glymur, Hamoa) have RPMB available on SPI-*NOR* storage,
>>>> and a driver for communicating with it is also available in QTEE. And so, these
>>>> have 'emulated' RPMB.
>>>
>>> This needs to be explained in the cover letter.
>>>
>>
>> Ack. 
>>>>
>>>> I will add this detail in an updated cover letter.
>>>>>
>>>>>> platforms where RPMB is not located within SPI-NOR storage and instead
>>>>>> located on UFS/EMMC storage, non-volatile EFI variables can only be set via
>>>>>> a callback request from the UEFI Secure Application to the RPMB service
>>>>>> running in user-space (within the QTEE supplicant [1]).
>>>>>
>>>>> Can it be moved to the kernel?
>>>>
>>>> We have a plan to move the RPMB service to the kernel similar to OPTEE:
>>>> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/tee/optee/rpc.c#L449
>>>>
>>>> It is a work in progress. Once this happens, we don't need QTEE supplicant available
>>>> on the Linux distribution.
>>>
>>> Ok.
>>>
>>>>
>>>>>
>>>>>>
>>>>>> Unlike the QCOM-TEE driver, the QSEECOM driver (used by the current
>>>>>> QSEECOM based uefisecapp) does not support callback requests.
>>>>>
>>>>> How did it work then? I think Windows has been perfectly using QSEECOM
>>>>> rather than QTEE.
>>>>
>>>> It works because Windows on Arm on Qualcomm has SPI-NOR storage. A driver for which
>>>
>>> I have WoA devices without SPI NOR. Windows still can store UEFI
>>> variables.
>>>
>>
>> Ahh, the key point here is 'Windows'. Windows has a separate way of providing
>> RPMB access via a service in the TrEE driver within the OS:
>> https://github.com/microsoft/Windows-driver-samples/tree/main/TrEE
>>
>> However, the Linux QSEECOM driver we have here in upstream does not have that support.
>> And so without the QCOMTEE + QTEE supplicant combination, we cannot access EFI
>> variables on these Qualcomm WoA platforms when they boot with upstream Linux.
>>
>>>> is available within QTEE, and so QTEE does not need to make a callback request
>>>> to Linux to request RPMB frame routing. However, in case of UFS/eMMC storage the
>>>> driver only exists in the Linux kernel and so QTEE must make a callback request.
>>>>
>>>> And so, if you try to use the QSEECOM driver to write EFI-variables to RPMB
>>>> on a device with UFS/eMMC storage, it won't work.
>>>
>>> Yep. It seems to work under Windows though.
>>>
>>
>> As explained above, the mechanism is different for Windows. A different driver
>> and a different protocol. :)
>>
>>>>
>>>>>
>>>>>> And on
>>>>>> certain Qualcomm platforms such as the RB3Gen2, attempts to access the
>>>>>> QSEECOM interface fail due to lack of support within Qualcomm TEE.
>>>>>
>>>>> So, I assume, on RB3 Gen2 the QSEECOM doesn't report uefisecapp as
>>>>> supported. Does it?
>>>>
>>>> It doesn't, this API returns -2 if I add RB3 Gen2 in the allow-list for QSEECOM:
>>>> https://elixir.bootlin.com/linux/v7.2-rc3/source/drivers/firmware/qcom/qcom_qseecom.c#L46
>>>
>>> Does it support QTEE-based uefi variable storage?
>>>
>>
>> It does, the QTEE-based uefi variable storage app, i.e. uefisecapp is loaded by
>> UEFI on RB3Gen2, however, the QSEECOM interface on RB3Gen2 is broken so it misreports
>> it as 'not supported'. But the app is loaded and available, which is why if you apply
>> this patch series, you can communicate with it. Just make sure you take the QTEE
>> release mentioned in this cover letter.
>>
>>>>>> On these platforms, a TEE based uefisecapp client driver is required to:
>>>>>> 1. Access cached & volatile EFI variables stored in uefisecapp's memory.
>>>>>> 2. Ensure persistence of non-volatile EFI variables via writes through
>>>>>> the RPMB service hosted in the QTEE supplicant.
>>>>>>
>>>>>> This series introduces such a uefisecapp TEE client driver for the
>>>>>> aforementioned Qualcomm platforms which installs efi-var operations _if_
>>>>>> the QCOMTEE driver registers support for an object-IPC based uefisecapp
>>>>>> service on the TEE bus during its probe. Only new QTEE firmware versions
>>>>>> available at [2] provide this support.
>>>>>
>>>>> What about existing WoA devices?
>>>>
>>>> New Windows on Arm devices like Hamoa/Glymur work perfectly fine with existing
>>>> QSEECOM based uefisecapp. But they will also work with this new QCOMTEE based
>>>> uefisecapp once they upgrade their firmware.
>>>
>>> Do extisting commercial devices suppot it? For example, does Lenovo T14s
>>> support it? Will it continue to work with this patchset in place?
>>
>> Existing devices like the Lenovo T14s do not have mature QCOMTEE/SMCInvoke support
>> on QTEE side and new QTEE versions for it are not being rolled out. However, this
>> QCOMTEE based uefisecapp driver and the QSEECOM based uefisecapp driver can co-exist.
>> It will not cause any breakage of existing working functionality since the QSEECOM
>> path can probe and continue as usual.
>>
>> As per your comments on patch 6 of this series, I plan to enable the QCOMTEE based
>> uefisecapp as default 'm'. That way we don't need to enable one over the other and
>> will continue supporting all existing functionality while extending it for devices
>> with UFS/eMMC storage and running upstream Linux.
>>
>> Do let me know your opinion on it.
>>
>>>
>>> What about other existing devices? We have WoA devices starting with
>>> MSM8998. The QSEECOM driver works on them, but, as you mentioned, it
>>> can't flash updates to the backing storage.
>>>
>>
>> Unfortunately, unless we roll out new QTEE firmware versions for devices like MSM8998
>> with QCOMTEE/SMCInvoke support + access to the Uefisecapp over SMCInvoke protocol,
>> they cannot be helped with this series.
>>
>>>> I need to double-check but this firmware release for Glymur on Qualcomm Linux
>>>> is probably carrying the support for QCOMTEE based uefisecapp access:
>>>> https://github.com/qualcomm-linux/meta-qcom/commit/728251fcbe5113980805ea6c571e33235062ee71
>>>> If not, the next release will definitely have it since I have merged support for
>>>> this in QTEE and talked to the boot firmware release team about this.
>>>
>>> Does it work on the CRD?
>>>
>>
>> Yes it does, I have validated on Glymur CRD by locally switching it from the current QSEECOM
>> based uefisecapp to this new QCOMTEE based uefisecapp. This is the QTEE release which
>> needs to be consumed for it:
>> https://github.com/qualcomm-linux/meta-qcom/commit/5590c1dc631827624c110df282965b85ef2a2e60 
>>
>>>>
>>>> The next planned firmware upgrade for Hamoa will also provide this support for
>>>> Qualcomm Linux. And similarly, for all other targets being supported upstream.
>>>
>>> So, we are forcing users to upgrade to the new firmware? That doesn't
>>> sound nice.
>>>
>>
>> We have an open ecosystem for all devices supported by the Qualcomm Linux distribution,
>> users can easily consume new releases (and new QTEE versions) to access new features.
>> Until now, developers/users of RB3Gen2 or IQ-9075 could not access EFI variables to
>> develop use-cases such as secure-boot key revocation, but by taking this patch series
>> as part of a subsequent Qualcomm Linux release, they will be able to.
>>
>>>>>> Thus, QCOMTEE now maintains a static list of always-available object-IPC
>>>>>> based secure services exposed by QTEE. These services are implemented either
>>>>>> within the QTEE kernel or within a pre-loaded Trusted Application (TA)
>>>>>> usually loaded by the bootloader. The uefisecapp TA is an example of a
>>>>>> preloaded TA loaded by UEFI. A static list is required since QTEE does not
>>>>>> yet expose any way to dynamically query and enumerate the services exposed by
>>>>>> it.
>>>>>
>>>>> Can it be fixed instead of having static lists? In the end, we can't
>>>>> guarantee that users update the firmware.
>>>>>
>>>>
>>>> Unfortunately, no existing QTEE release out there currently has this support.
>>>> But support for this is currently being added by QTEE team last I checked with them.
>>>> Once it is available, and a new QTEE firmware release is out there, we will add
>>>> support for dynamically querying QTEE services in the QCOMTEE driver. 
>>>
>>> It seems you are still rolling out QTEE-based support. In such a case,
>>> please go back and implement dynamic detection of QTEE services.
>>> Otherwise it would be a nightmare.
>>>
>>
>> We are working on it, but until then there is no overhead involved in maintaining
>> this static list of services because we don't have to extend/modify this list when
>> adding support for a new Qualcomm platform upstream. If a particular service from
>> the list is not implemented/accessible from QTEE we log the event and silently avoid
>> probing the TEE driver for the service. We also don't add platform specific services
>> here. So the list doesn't need to be extended on a per-platform basis.
>>
>> So unlike the QSEECOM driver, we don't have to keep maintaining this list forever
>> for all new platforms.
>>
>>>>>> To facilitate object-IPC interactions from the kernel-space, this
>>>>>> series also introduces a tee_client_object_invoke_func() to allow
>>>>>> invocation of TEE objects similar to the existing tee_client_invoke_func()
>>>>>> API exported by the TEE subsystem which allows invocation of TEE functions.
>>>>>> Some suporting changes are also introduced to track and handle operations
>>>>>> for TEE contexts opened from the kernel-space in the back-end QCOM-TEE
>>>>>> driver.
>>>>>>
>>>>>> Finally and as previously mentioned, access to the object-IPC based uefisecapp
>>>>>> service is restricted on older QTEE firmware versions. A new QTEE firmware
>>>>>> release must be picked up from QArtifactory [2] for all upstream supported
>>>>>> Qualcomm SoCs to enable access to uefisecapp service via the TEE client
>>>>>> driver.
>>>>>
>>>>> What about fused devices?
>>>>
>>>> The procedure for updating the firmware on fused devices is slightly different.
>>>> The firmware images need to be signed by the OEM using the security profile
>>>> of the chipset before flashing/upgrading them. Security profiles are now public:
>>>> https://github.com/qualcomm/security-profiles
>>>
>>> Will OEMs release new firmware images? What about the devices which are
>>> already out of the support phase? This whole story rotates about the 'we
>>> are releasing new firmware with new features' paradigm. However there
>>> are existing devices in the field, which typically can't be upgraded,
>>> From your cover letter it seems they can't support UEFI variables
>>> properly. However they do so in Windows.
>>>
>>
>> Yes Dmitry, this series is effectively forward looking. QSEECOM protocol/driver
>> support is essentially deprecated on QTEE side, no new features added to QTEE support
>> it, and it also doesn't work on many devices like the RB3Gen2.
>>
>> For existing devices, if they boot with upstream Linux and have RPMB located on
>> UFS/eMMC this patch series cannot help them. But the focus of this series is not on the
>> past, it is on currently supported and future hardware. Every new Qualcomm platform
>> whose support is being up-streamed or is planned to be up-streamed will have access to
>> EFI variables via this series.
>>
>> If someone wants to add support for older Qualcomm devices to access EFI variables
>> via QSEECOM that patch series will not conflict with this one. Like I said, both
>> QSEECOM and QCOMTEE based drivers can co-exist.
>>
>> Regards,
>> Harshal
>>
>>
>>  
>>
> 


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

end of thread, other threads:[~2026-08-21  8:34 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-22  6:59 [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Harshal Dev
2026-07-22  6:59 ` [PATCH v2 1/6] tee: qcomtee: Track the object invocation context Harshal Dev
2026-07-22  6:59 ` [PATCH v2 2/6] tee: Add kernel client object invoke helper Harshal Dev
2026-07-22  6:59 ` [PATCH v2 3/6] tee: qcomtee: Allow object invokes from kernel clients Harshal Dev
2026-07-29  7:06   ` Amirreza Zarrabi
2026-07-31  7:38     ` Harshal Dev
2026-07-22  6:59 ` [PATCH v2 4/6] tee: Export uuidv5 generation for TEE backends Harshal Dev
2026-07-22  6:59 ` [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus Harshal Dev
2026-07-22  8:29   ` Dmitry Baryshkov
2026-07-24  9:13     ` Harshal Dev
2026-07-29  7:05   ` Amirreza Zarrabi
2026-07-31  8:35     ` Harshal Dev
2026-07-22  6:59 ` [PATCH v2 6/6] firmware: qcom: Add support for TEE based EFI-var client driver Harshal Dev
2026-07-22  8:37   ` Dmitry Baryshkov
2026-07-24  9:14     ` Harshal Dev
2026-07-24 10:09       ` Harshal Dev
2026-07-22  8:26 ` [PATCH v2 0/6] Add TEE based client driver for UEFI Secure Application Dmitry Baryshkov
2026-07-24  9:13   ` Harshal Dev
2026-08-03 14:52     ` Harshal Dev
2026-08-10  5:41       ` Harshal Dev
2026-08-10  7:07     ` Dmitry Baryshkov
2026-08-12 11:30       ` Harshal Dev
2026-08-17  6:24         ` Harshal Dev
2026-08-21  8:34           ` Harshal Dev

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®