Re: [PATCH v2 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus

Harshal Dev <[email protected]>
Newsgroups org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-kernel,org.trustedfirmware.lists.op-tee
Organization Qualcomm
Message-ID <[email protected]>
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 <[email protected]>
>> ---
>>  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 */
>>
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.