Re: [PATCH v3 5/6] tee: qcomtee: Add support for registering QTEE services on TEE bus
From: Harshal Dev
Date: Mon Oct 05 2026 - 01:11:04 EST
Hi Sumit,
On 01-10-2026 06:27 pm, Sumit Garg wrote:
> On Thu, 01 Oct 2026 at 16:32:37 +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.
>>
>> Signed-off-by: Harshal Dev <harshal.dev@xxxxxxxxxxxxxxxx>
>> ---
>> drivers/tee/qcomtee/call.c | 161 ++++++++++++++++++++++++++++++++++-
>> 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, 179 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c
>> index b361d9c04de0..8fadb7b13e61 100644
>> --- a/drivers/tee/qcomtee/call.c
>> +++ b/drivers/tee/qcomtee/call.c
>> @@ -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,
>> + &result);
>> + if (service == NULL_QCOMTEE_OBJECT) {
>> + if (result)
>> + pr_err("FeatureVersions Service unavailable (%d)\n", result);
>
> Do we really want to error out if a service isn't available? Is it
> really the case that every QTEE firmware will implement each service?
>
We must error out here, otherwise we would try to query the feature identified
by 'id' by invoking a NULL object below.
Not every QTEE firmware version will implement the 'FeatureVersion' service. But
this function, which is called during probe to print the QTEE version depends on
this service being available.
>> goto out_failed;
>> + }
>>
>> /* IB: Feature to query. */
>> u[0].b.addr = &id;
>> @@ -697,6 +701,156 @@ 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
>> + * @oic: context to use for the current invocation.
>> + * @client_env: Client environment object.
>> + * @service_name: Name of the QTEE service.
>> + * @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 qcomtee_object_invoke_ctx *oic,
>> + struct qcomtee_object *client_env,
>> + const char *service_name, u32 uid)
>> +{
>> + struct qcomtee_object *service;
>> + int error = 0;
>> + bool ret = false;
>> +
>> + /* 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("%s is unavailable (%d)\n", service_name, error);
>
> Ditto here, rather convert this into a debug message.
>
Ack, I will convert this to a debug message since some services might not
be available for a particular QTEE version.
>> +
>> + 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
>> + * @oic: context to use for the current invocation.
>> + * @client_env: Client environment object.
>> + * @service_name: Name of the QTEE service to be enumerated.
>> + * @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 qcomtee_object_invoke_ctx *oic,
>> + struct qcomtee_object *client_env,
>> + const char *service_name,
>> + const u32 uid)
>> +{
>> + struct tee_client_device *qtee_service;
>> + uuid_t service_uuid;
>> + int rc;
>> +
>> + if (!is_qcomtee_service_available(oic, client_env, service_name, uid))
>> + return -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);
>> + 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)
>> +{
>> + u32 idx;
>> + struct qcomtee_object *client_env;
>> +
>> + struct qcomtee_object_invoke_ctx *oic __free(kfree) =
>> + qcomtee_object_invoke_ctx_alloc(ctx, true);
>> + if (!oic)
>> + return;
>> +
>> + client_env = qcomtee_object_get_client_env(oic);
>> + if (client_env == NULL_QCOMTEE_OBJECT)
>> + return;
>> +
>> + for (idx = 0; idx < ARRAY_SIZE(qtee_services); idx++)
>> + qtee_enumerate_service(oic, client_env,
>> + qtee_services[idx].name,
>> + qtee_services[idx].uid);
>> +
>> + qcomtee_object_put(client_env);
>> +}
>> +
>> +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 +932,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);
>
> Rather call it qtee_register_services() matching it's counterpart below.
>
Ack, will re-name.
Regards,
Harshal
> -Sumit
>
>> +
>> return 0;
>>
>> err_dest_wq:
>> @@ -807,6 +963,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 60fe3b5776e3..4a523a95bf0e 100644
>> --- a/drivers/tee/qcomtee/core.c
>> +++ b/drivers/tee/qcomtee/core.c
>> @@ -898,19 +898,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 5d7b21fdd368..9278a361dc70 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 d3740099fae0..901ba3565a73 100644
>> --- a/drivers/tee/qcomtee/qcomtee_object.h
>> +++ b/drivers/tee/qcomtee/qcomtee_object.h
>> @@ -317,6 +317,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
>>