public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 1/1] tee: optee: expose OS revision via sysfs
@ 2025-11-21 14:12 Wei Ming Chen
  2025-11-22  7:36 ` Harshal Dev
  2025-11-22 14:59 ` [PATCH v2 " Wei Ming Chen
  0 siblings, 2 replies; 42+ messages in thread
From: Wei Ming Chen @ 2025-11-21 14:12 UTC (permalink / raw)
  To: linux-kernel; +Cc: jens.wiklander, sumit.garg, op-tee, Aristo Chen

From: Aristo Chen <aristo.chen@canonical.com>

Today the only way to read the OP-TEE OS version is from dmesg/journal
logs, which can be lost as buffers roll over. Add a minimal
optee_version_info (major/minor/build) and get_optee_revision hook,
collect the OS revision in both SMC and FF-A ABIs, and publish
/sys/class/tee/tee*/optee_os_revision for a stable userspace readout.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 drivers/tee/optee/ffa_abi.c       | 27 +++++++++++-
 drivers/tee/optee/optee_private.h |  1 +
 drivers/tee/optee/smc_abi.c       | 27 +++++++++++-
 drivers/tee/tee_core.c            | 73 ++++++++++++++++++++++++++++++-
 include/linux/tee_core.h          |  2 +
 include/linux/tee_drv.h           | 12 +++++
 6 files changed, 137 insertions(+), 5 deletions(-)

diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index bf8390789ecf..291ba3bfde7f 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
  */
 
 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
-					const struct ffa_ops *ops)
+					const struct ffa_ops *ops,
+					struct optee_version_info *version_info)
 {
 	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
 	struct ffa_send_direct_data data = {
@@ -806,6 +807,12 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 		pr_err("Unexpected error %d\n", rc);
 		return false;
 	}
+	if (version_info) {
+		version_info->os_major = data.data0;
+		version_info->os_minor = data.data1;
+		version_info->os_build_id = data.data2;
+	}
+
 	if (data.data2)
 		pr_info("revision %lu.%lu (%08lx)",
 			data.data0, data.data1, data.data2);
@@ -893,6 +900,18 @@ static void optee_ffa_get_version(struct tee_device *teedev,
 	*vers = v;
 }
 
+static int optee_ffa_get_optee_revision(struct tee_device *teedev,
+					struct optee_version_info *vers)
+{
+	struct optee *optee = tee_get_drvdata(teedev);
+
+	if (!optee)
+		return -ENODEV;
+
+	*vers = optee->version_info;
+	return 0;
+}
+
 static int optee_ffa_open(struct tee_context *ctx)
 {
 	return optee_open(ctx, true);
@@ -900,6 +919,7 @@ static int optee_ffa_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_ffa_clnt_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_optee_revision = optee_ffa_get_optee_revision,
 	.open = optee_ffa_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -918,6 +938,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
 
 static const struct tee_driver_ops optee_ffa_supp_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_optee_revision = optee_ffa_get_optee_revision,
 	.open = optee_ffa_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1034,6 +1055,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 {
 	const struct ffa_notifier_ops *notif_ops;
 	const struct ffa_ops *ffa_ops;
+	struct optee_version_info version_info = { };
 	unsigned int max_notif_value;
 	unsigned int rpc_param_count;
 	struct tee_shm_pool *pool;
@@ -1047,7 +1069,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	ffa_ops = ffa_dev->ops;
 	notif_ops = ffa_ops->notifier_ops;
 
-	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
+	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &version_info))
 		return -EINVAL;
 
 	if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
@@ -1059,6 +1081,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
 	if (!optee)
 		return -ENOMEM;
+	optee->version_info = version_info;
 
 	pool = optee_ffa_shm_pool_alloc_pages();
 	if (IS_ERR(pool)) {
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index db9ea673fbca..967c015e8ffb 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -249,6 +249,7 @@ struct optee {
 	bool in_kernel_rpmb_routing;
 	struct work_struct scan_bus_work;
 	struct work_struct rpmb_scan_bus_work;
+	struct optee_version_info version_info;
 };
 
 struct optee_session {
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 0be663fcd52b..1e412949898f 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -1232,6 +1232,18 @@ static void optee_get_version(struct tee_device *teedev,
 	*vers = v;
 }
 
+static int optee_get_optee_revision(struct tee_device *teedev,
+				    struct optee_version_info *vers)
+{
+	struct optee *optee = tee_get_drvdata(teedev);
+
+	if (!optee)
+		return -ENODEV;
+
+	*vers = optee->version_info;
+	return 0;
+}
+
 static int optee_smc_open(struct tee_context *ctx)
 {
 	struct optee *optee = tee_get_drvdata(ctx->teedev);
@@ -1242,6 +1254,7 @@ static int optee_smc_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_clnt_ops = {
 	.get_version = optee_get_version,
+	.get_optee_revision = optee_get_optee_revision,
 	.open = optee_smc_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -1261,6 +1274,7 @@ static const struct tee_desc optee_clnt_desc = {
 
 static const struct tee_driver_ops optee_supp_ops = {
 	.get_version = optee_get_version,
+	.get_optee_revision = optee_get_optee_revision,
 	.open = optee_smc_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1323,7 +1337,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
 }
 #endif
 
-static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
+static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
+				      struct optee_version_info *version_info)
 {
 	union {
 		struct arm_smccc_res smccc;
@@ -1337,6 +1352,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
 		  &res.smccc);
 
+	if (version_info) {
+		version_info->os_major = res.result.major;
+		version_info->os_minor = res.result.minor;
+		version_info->os_build_id = res.result.build_id;
+	}
+
 	if (res.result.build_id)
 		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
 			res.result.minor, (int)sizeof(res.result.build_id) * 2,
@@ -1727,6 +1748,7 @@ static int optee_probe(struct platform_device *pdev)
 	unsigned int thread_count;
 	struct tee_device *teedev;
 	struct tee_context *ctx;
+	struct optee_version_info version_info = { };
 	u32 max_notif_value;
 	u32 arg_cache_flags;
 	u32 sec_caps;
@@ -1745,7 +1767,7 @@ static int optee_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	optee_msg_get_os_revision(invoke_fn);
+	optee_msg_get_os_revision(invoke_fn, &version_info);
 
 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
 		pr_warn("api revision mismatch\n");
@@ -1814,6 +1836,7 @@ static int optee_probe(struct platform_device *pdev)
 		rc = -ENOMEM;
 		goto err_free_shm_pool;
 	}
+	optee->version_info = version_info;
 
 	optee->ops = &optee_ops;
 	optee->smc.invoke_fn = invoke_fn;
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index d65d47cc154e..dc23058e7be6 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -1141,12 +1141,83 @@ static ssize_t implementation_id_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(implementation_id);
 
+static int tee_get_optee_revision(struct tee_device *teedev,
+				  struct optee_version_info *ver_info)
+{
+	if (!teedev->desc->ops->get_optee_revision)
+		return -ENODEV;
+
+	return teedev->desc->ops->get_optee_revision(teedev, ver_info);
+}
+
+static bool tee_is_optee(struct tee_device *teedev)
+{
+	struct tee_ioctl_version_data vers;
+
+	teedev->desc->ops->get_version(teedev, &vers);
+
+	return vers.impl_id == TEE_IMPL_ID_OPTEE;
+}
+
+static ssize_t optee_os_revision_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+	struct optee_version_info ver_info;
+	int ret;
+
+	if (!tee_is_optee(teedev))
+		return -ENODEV;
+
+	ret = tee_get_optee_revision(teedev, &ver_info);
+	if (ret)
+		return ret;
+
+	if (ver_info.os_build_id)
+		return sysfs_emit(buf, "%u.%u (%08x)\n", ver_info.os_major,
+				  ver_info.os_minor, ver_info.os_build_id);
+
+	return sysfs_emit(buf, "%u.%u\n", ver_info.os_major,
+			  ver_info.os_minor);
+}
+static DEVICE_ATTR_RO(optee_os_revision);
+
 static struct attribute *tee_dev_attrs[] = {
 	&dev_attr_implementation_id.attr,
 	NULL
 };
 
-ATTRIBUTE_GROUPS(tee_dev);
+static struct attribute *tee_optee_attrs[] = {
+	&dev_attr_optee_os_revision.attr,
+	NULL
+};
+
+static umode_t tee_optee_attr_is_visible(struct kobject *kobj,
+					 struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+	if (tee_is_optee(teedev) && teedev->desc->ops->get_optee_revision)
+		return attr->mode;
+
+	return 0;
+}
+
+static const struct attribute_group tee_dev_group = {
+	.attrs = tee_dev_attrs,
+};
+
+static const struct attribute_group tee_optee_group = {
+	.attrs = tee_optee_attrs,
+	.is_visible = tee_optee_attr_is_visible,
+};
+
+static const struct attribute_group *tee_dev_groups[] = {
+	&tee_dev_group,
+	&tee_optee_group,
+	NULL
+};
 
 static const struct class tee_class = {
 	.name = "tee",
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
index 1f3e5dad6d0d..4bd9b6b191c9 100644
--- a/include/linux/tee_core.h
+++ b/include/linux/tee_core.h
@@ -98,6 +98,8 @@ struct tee_device {
 struct tee_driver_ops {
 	void (*get_version)(struct tee_device *teedev,
 			    struct tee_ioctl_version_data *vers);
+	int (*get_optee_revision)(struct tee_device *teedev,
+				  struct optee_version_info *vers);
 	int (*open)(struct tee_context *ctx);
 	void (*close_context)(struct tee_context *ctx);
 	void (*release)(struct tee_context *ctx);
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 88a6f9697c89..64a2fea11cb9 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -20,6 +20,18 @@
 
 struct tee_device;
 
+/**
+ * struct optee_version_info - OP-TEE version information
+ * @os_major:		OS major version
+ * @os_minor:		OS minor version
+ * @os_build_id:	OS build identifier (0 if unspecified)
+ */
+struct optee_version_info {
+	u32 os_major;
+	u32 os_minor;
+	u32 os_build_id;
+};
+
 /**
  * struct tee_context - driver specific context on file pointer data
  * @teedev:	pointer to this drivers struct tee_device
-- 
2.43.0


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

* Re: [PATCH v1 1/1] tee: optee: expose OS revision via sysfs
  2025-11-21 14:12 [PATCH v1 1/1] tee: optee: expose OS revision via sysfs Wei Ming Chen
@ 2025-11-22  7:36 ` Harshal Dev
  2025-11-22 14:59 ` [PATCH v2 " Wei Ming Chen
  1 sibling, 0 replies; 42+ messages in thread
From: Harshal Dev @ 2025-11-22  7:36 UTC (permalink / raw)
  To: Wei Ming Chen, linux-kernel; +Cc: sumit.garg, op-tee, Aristo Chen

Hi Aristo,

On 11/21/2025 7:42 PM, Wei Ming Chen wrote:
> From: Aristo Chen <aristo.chen@canonical.com>
> 
> Today the only way to read the OP-TEE OS version is from dmesg/journal
> logs, which can be lost as buffers roll over. Add a minimal
> optee_version_info (major/minor/build) and get_optee_revision hook,
> collect the OS revision in both SMC and FF-A ABIs, and publish
> /sys/class/tee/tee*/optee_os_revision for a stable userspace readout.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  drivers/tee/optee/ffa_abi.c       | 27 +++++++++++-
>  drivers/tee/optee/optee_private.h |  1 +
>  drivers/tee/optee/smc_abi.c       | 27 +++++++++++-
>  drivers/tee/tee_core.c            | 73 ++++++++++++++++++++++++++++++-
>  include/linux/tee_core.h          |  2 +
>  include/linux/tee_drv.h           | 12 +++++
>  6 files changed, 137 insertions(+), 5 deletions(-)

[..]

> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index d65d47cc154e..dc23058e7be6 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -1141,12 +1141,83 @@ static ssize_t implementation_id_show(struct device *dev,
>  }
>  static DEVICE_ATTR_RO(implementation_id);
>  
> +static int tee_get_optee_revision(struct tee_device *teedev,
> +				  struct optee_version_info *ver_info)
> +{
> +	if (!teedev->desc->ops->get_optee_revision)
> +		return -ENODEV;
> +
> +	return teedev->desc->ops->get_optee_revision(teedev, ver_info);
> +}
> +

I don't think implementing functions with a TEE back-end driver specific name and implementation
is a good idea in TEE core.

> +static bool tee_is_optee(struct tee_device *teedev)
> +{
> +	struct tee_ioctl_version_data vers;
> +
> +	teedev->desc->ops->get_version(teedev, &vers);
> +
> +	return vers.impl_id == TEE_IMPL_ID_OPTEE;
> +}
> +
> +static ssize_t optee_os_revision_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +	struct optee_version_info ver_info;
> +	int ret;
> +
> +	if (!tee_is_optee(teedev))
> +		return -ENODEV;
> +
> +	ret = tee_get_optee_revision(teedev, &ver_info);
> +	if (ret)
> +		return ret;
> +
> +	if (ver_info.os_build_id)
> +		return sysfs_emit(buf, "%u.%u (%08x)\n", ver_info.os_major,
> +				  ver_info.os_minor, ver_info.os_build_id);
> +
> +	return sysfs_emit(buf, "%u.%u\n", ver_info.os_major,
> +			  ver_info.os_minor);
> +}

[..]

> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
> index 1f3e5dad6d0d..4bd9b6b191c9 100644
> --- a/include/linux/tee_core.h
> +++ b/include/linux/tee_core.h
> @@ -98,6 +98,8 @@ struct tee_device {
>  struct tee_driver_ops {
>  	void (*get_version)(struct tee_device *teedev,
>  			    struct tee_ioctl_version_data *vers);
> +	int (*get_optee_revision)(struct tee_device *teedev,
> +				  struct optee_version_info *vers);

I think it would be better if this patchset could be made OPTEE agnostic. After-all,
the callbacks defined in tee_driver_ops are supposed to be implemented by each TEE
back-end driver as per their implementation.

>  	int (*open)(struct tee_context *ctx);
>  	void (*close_context)(struct tee_context *ctx);
>  	void (*release)(struct tee_context *ctx);
> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
> index 88a6f9697c89..64a2fea11cb9 100644
> --- a/include/linux/tee_drv.h
> +++ b/include/linux/tee_drv.h
> @@ -20,6 +20,18 @@
>  
>  struct tee_device;
>  
> +/**
> + * struct optee_version_info - OP-TEE version information
> + * @os_major:		OS major version
> + * @os_minor:		OS minor version
> + * @os_build_id:	OS build identifier (0 if unspecified)
> + */
> +struct optee_version_info {
> +	u32 os_major;
> +	u32 os_minor;
> +	u32 os_build_id;
> +};
> +

It is not entirely clear from the structure what kind of version information for
OPTEE is being provided. I see from the implementation that when FFA is enabled,
this provides FFA version implemented by OPTEE but when FFA is not used, it provides
OPTEE OS version. This can be confusing for a user trying to report an OPTEE 'version'.

>  /**
>   * struct tee_context - driver specific context on file pointer data
>   * @teedev:	pointer to this drivers struct tee_device

Thanks
Harshal

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

* [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-11-21 14:12 [PATCH v1 1/1] tee: optee: expose OS revision via sysfs Wei Ming Chen
  2025-11-22  7:36 ` Harshal Dev
@ 2025-11-22 14:59 ` Wei Ming Chen
  2025-11-24  7:15   ` Jens Wiklander
  2025-12-26 13:19   ` [PATCH v3 " Aristo Chen
  1 sibling, 2 replies; 42+ messages in thread
From: Wei Ming Chen @ 2025-11-22 14:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev, Aristo Chen

From: Aristo Chen <aristo.chen@canonical.com>

Today the only way to read the OP-TEE OS version is from dmesg/journal
logs, which can be lost as buffers roll over. Capture the OS revision
(major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
it in the OP-TEE driver, and expose a stable userspace readout via
/sys/class/tee/tee*/optee_os_revision.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 drivers/tee/optee/core.c          | 19 +++++++++++++++++++
 drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
 drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
 drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
 4 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 5b62139714ce..66409cf5da1c 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -83,8 +83,27 @@ static ssize_t rpmb_routing_model_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(rpmb_routing_model);
 
+static ssize_t optee_os_revision_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct optee *optee = dev_get_drvdata(dev);
+	struct optee_version_info *v;
+
+	if (!optee)
+		return -ENODEV;
+
+	v = &optee->version_info;
+	if (v->os_build_id)
+		return sysfs_emit(buf, "%u.%u (%016llx)\n", v->os_major,
+				  v->os_minor, (unsigned long long)v->os_build_id);
+
+	return sysfs_emit(buf, "%u.%u\n", v->os_major, v->os_minor);
+}
+static DEVICE_ATTR_RO(optee_os_revision);
+
 static struct attribute *optee_dev_attrs[] = {
 	&dev_attr_rpmb_routing_model.attr,
+	&dev_attr_optee_os_revision.attr,
 	NULL
 };
 
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index bf8390789ecf..3d4f35599dd1 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
  */
 
 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
-					const struct ffa_ops *ops)
+					const struct ffa_ops *ops,
+					struct optee_version_info *version_info)
 {
 	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
 	struct ffa_send_direct_data data = {
@@ -806,6 +807,12 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 		pr_err("Unexpected error %d\n", rc);
 		return false;
 	}
+	if (version_info) {
+		version_info->os_major = data.data0;
+		version_info->os_minor = data.data1;
+		version_info->os_build_id = data.data2;
+	}
+
 	if (data.data2)
 		pr_info("revision %lu.%lu (%08lx)",
 			data.data0, data.data1, data.data2);
@@ -1034,6 +1041,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 {
 	const struct ffa_notifier_ops *notif_ops;
 	const struct ffa_ops *ffa_ops;
+	struct optee_version_info version_info = { };
 	unsigned int max_notif_value;
 	unsigned int rpc_param_count;
 	struct tee_shm_pool *pool;
@@ -1047,7 +1055,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	ffa_ops = ffa_dev->ops;
 	notif_ops = ffa_ops->notifier_ops;
 
-	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
+	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &version_info))
 		return -EINVAL;
 
 	if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
@@ -1059,6 +1067,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
 	if (!optee)
 		return -ENOMEM;
+	optee->version_info = version_info;
 
 	pool = optee_ffa_shm_pool_alloc_pages();
 	if (IS_ERR(pool)) {
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index db9ea673fbca..3e7bcd44976b 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -19,6 +19,22 @@
 
 #define OPTEE_MAX_ARG_SIZE	1024
 
+/**
+ * struct optee_version_info - OP-TEE OS revision reported by secure world
+ * @os_major:		OP-TEE OS major version
+ * @os_minor:		OP-TEE OS minor version
+ * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
+ *
+ * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
+ * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
+ * FF-A ABI version.
+ */
+struct optee_version_info {
+	u32 os_major;
+	u32 os_minor;
+	u64 os_build_id;
+};
+
 /* Some Global Platform error codes used in this driver */
 #define TEEC_SUCCESS			0x00000000
 #define TEEC_ERROR_BAD_PARAMETERS	0xFFFF0006
@@ -249,6 +265,7 @@ struct optee {
 	bool in_kernel_rpmb_routing;
 	struct work_struct scan_bus_work;
 	struct work_struct rpmb_scan_bus_work;
+	struct optee_version_info version_info;
 };
 
 struct optee_session {
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 0be663fcd52b..07c703609320 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -1323,7 +1323,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
 }
 #endif
 
-static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
+static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
+				      struct optee_version_info *version_info)
 {
 	union {
 		struct arm_smccc_res smccc;
@@ -1337,6 +1338,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
 		  &res.smccc);
 
+	if (version_info) {
+		version_info->os_major = res.result.major;
+		version_info->os_minor = res.result.minor;
+		version_info->os_build_id = res.result.build_id;
+	}
+
 	if (res.result.build_id)
 		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
 			res.result.minor, (int)sizeof(res.result.build_id) * 2,
@@ -1727,6 +1734,7 @@ static int optee_probe(struct platform_device *pdev)
 	unsigned int thread_count;
 	struct tee_device *teedev;
 	struct tee_context *ctx;
+	struct optee_version_info version_info = { };
 	u32 max_notif_value;
 	u32 arg_cache_flags;
 	u32 sec_caps;
@@ -1745,7 +1753,7 @@ static int optee_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	optee_msg_get_os_revision(invoke_fn);
+	optee_msg_get_os_revision(invoke_fn, &version_info);
 
 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
 		pr_warn("api revision mismatch\n");
@@ -1814,6 +1822,7 @@ static int optee_probe(struct platform_device *pdev)
 		rc = -ENOMEM;
 		goto err_free_shm_pool;
 	}
+	optee->version_info = version_info;
 
 	optee->ops = &optee_ops;
 	optee->smc.invoke_fn = invoke_fn;
-- 
2.43.0


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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-11-22 14:59 ` [PATCH v2 " Wei Ming Chen
@ 2025-11-24  7:15   ` Jens Wiklander
  2025-11-25  7:53     ` Sumit Garg
  2025-12-26 13:19   ` [PATCH v3 " Aristo Chen
  1 sibling, 1 reply; 42+ messages in thread
From: Jens Wiklander @ 2025-11-24  7:15 UTC (permalink / raw)
  To: Wei Ming Chen
  Cc: linux-kernel, sumit.garg, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Balint Dobszay, Rijo Thomas, Amirreza Zarrabi

Hi,

On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
>
> From: Aristo Chen <aristo.chen@canonical.com>
>
> Today the only way to read the OP-TEE OS version is from dmesg/journal
> logs, which can be lost as buffers roll over. Capture the OS revision
> (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> it in the OP-TEE driver, and expose a stable userspace readout via
> /sys/class/tee/tee*/optee_os_revision.
>
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
>  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
>  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
>  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
>  4 files changed, 58 insertions(+), 4 deletions(-)

This appears to be a feature that could be useful for all TEEs. If so,
let's take a step back to see what's needed. We can add the sysfs
attribute from drivers/tee/tee_core.c and add another optional
callback to struct tee_driver_ops, such as get_tee_revision(). For
OP-TEE, the specific information we want to share is clear, but other
TEEs might have additional or different data. What do others think?

Cheers,
Jens

>
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index 5b62139714ce..66409cf5da1c 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -83,8 +83,27 @@ static ssize_t rpmb_routing_model_show(struct device *dev,
>  }
>  static DEVICE_ATTR_RO(rpmb_routing_model);
>
> +static ssize_t optee_os_revision_show(struct device *dev,
> +                                     struct device_attribute *attr, char *buf)
> +{
> +       struct optee *optee = dev_get_drvdata(dev);
> +       struct optee_version_info *v;
> +
> +       if (!optee)
> +               return -ENODEV;
> +
> +       v = &optee->version_info;
> +       if (v->os_build_id)
> +               return sysfs_emit(buf, "%u.%u (%016llx)\n", v->os_major,
> +                                 v->os_minor, (unsigned long long)v->os_build_id);
> +
> +       return sysfs_emit(buf, "%u.%u\n", v->os_major, v->os_minor);
> +}
> +static DEVICE_ATTR_RO(optee_os_revision);
> +
>  static struct attribute *optee_dev_attrs[] = {
>         &dev_attr_rpmb_routing_model.attr,
> +       &dev_attr_optee_os_revision.attr,
>         NULL
>  };
>
> diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> index bf8390789ecf..3d4f35599dd1 100644
> --- a/drivers/tee/optee/ffa_abi.c
> +++ b/drivers/tee/optee/ffa_abi.c
> @@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
>   */
>
>  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> -                                       const struct ffa_ops *ops)
> +                                       const struct ffa_ops *ops,
> +                                       struct optee_version_info *version_info)
>  {
>         const struct ffa_msg_ops *msg_ops = ops->msg_ops;
>         struct ffa_send_direct_data data = {
> @@ -806,6 +807,12 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>                 pr_err("Unexpected error %d\n", rc);
>                 return false;
>         }
> +       if (version_info) {
> +               version_info->os_major = data.data0;
> +               version_info->os_minor = data.data1;
> +               version_info->os_build_id = data.data2;
> +       }
> +
>         if (data.data2)
>                 pr_info("revision %lu.%lu (%08lx)",
>                         data.data0, data.data1, data.data2);
> @@ -1034,6 +1041,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  {
>         const struct ffa_notifier_ops *notif_ops;
>         const struct ffa_ops *ffa_ops;
> +       struct optee_version_info version_info = { };
>         unsigned int max_notif_value;
>         unsigned int rpc_param_count;
>         struct tee_shm_pool *pool;
> @@ -1047,7 +1055,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>         ffa_ops = ffa_dev->ops;
>         notif_ops = ffa_ops->notifier_ops;
>
> -       if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
> +       if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &version_info))
>                 return -EINVAL;
>
>         if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
> @@ -1059,6 +1067,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>         optee = kzalloc(sizeof(*optee), GFP_KERNEL);
>         if (!optee)
>                 return -ENOMEM;
> +       optee->version_info = version_info;
>
>         pool = optee_ffa_shm_pool_alloc_pages();
>         if (IS_ERR(pool)) {
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index db9ea673fbca..3e7bcd44976b 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -19,6 +19,22 @@
>
>  #define OPTEE_MAX_ARG_SIZE     1024
>
> +/**
> + * struct optee_version_info - OP-TEE OS revision reported by secure world
> + * @os_major:          OP-TEE OS major version
> + * @os_minor:          OP-TEE OS minor version
> + * @os_build_id:       OP-TEE OS build identifier (0 if unspecified)
> + *
> + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> + * FF-A ABI version.
> + */
> +struct optee_version_info {
> +       u32 os_major;
> +       u32 os_minor;
> +       u64 os_build_id;
> +};
> +
>  /* Some Global Platform error codes used in this driver */
>  #define TEEC_SUCCESS                   0x00000000
>  #define TEEC_ERROR_BAD_PARAMETERS      0xFFFF0006
> @@ -249,6 +265,7 @@ struct optee {
>         bool in_kernel_rpmb_routing;
>         struct work_struct scan_bus_work;
>         struct work_struct rpmb_scan_bus_work;
> +       struct optee_version_info version_info;
>  };
>
>  struct optee_session {
> diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> index 0be663fcd52b..07c703609320 100644
> --- a/drivers/tee/optee/smc_abi.c
> +++ b/drivers/tee/optee/smc_abi.c
> @@ -1323,7 +1323,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
>  }
>  #endif
>
> -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> +                                     struct optee_version_info *version_info)
>  {
>         union {
>                 struct arm_smccc_res smccc;
> @@ -1337,6 +1338,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
>         invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
>                   &res.smccc);
>
> +       if (version_info) {
> +               version_info->os_major = res.result.major;
> +               version_info->os_minor = res.result.minor;
> +               version_info->os_build_id = res.result.build_id;
> +       }
> +
>         if (res.result.build_id)
>                 pr_info("revision %lu.%lu (%0*lx)", res.result.major,
>                         res.result.minor, (int)sizeof(res.result.build_id) * 2,
> @@ -1727,6 +1734,7 @@ static int optee_probe(struct platform_device *pdev)
>         unsigned int thread_count;
>         struct tee_device *teedev;
>         struct tee_context *ctx;
> +       struct optee_version_info version_info = { };
>         u32 max_notif_value;
>         u32 arg_cache_flags;
>         u32 sec_caps;
> @@ -1745,7 +1753,7 @@ static int optee_probe(struct platform_device *pdev)
>                 return -EINVAL;
>         }
>
> -       optee_msg_get_os_revision(invoke_fn);
> +       optee_msg_get_os_revision(invoke_fn, &version_info);
>
>         if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
>                 pr_warn("api revision mismatch\n");
> @@ -1814,6 +1822,7 @@ static int optee_probe(struct platform_device *pdev)
>                 rc = -ENOMEM;
>                 goto err_free_shm_pool;
>         }
> +       optee->version_info = version_info;
>
>         optee->ops = &optee_ops;
>         optee->smc.invoke_fn = invoke_fn;
> --
> 2.43.0
>

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-11-24  7:15   ` Jens Wiklander
@ 2025-11-25  7:53     ` Sumit Garg
  2025-11-25  7:55       ` Sumit Garg
  0 siblings, 1 reply; 42+ messages in thread
From: Sumit Garg @ 2025-11-25  7:53 UTC (permalink / raw)
  To: Jens Wiklander
  Cc: Wei Ming Chen, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Balint Dobszay, Rijo Thomas, Amirreza Zarrabi

On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> Hi,
> 
> On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> >
> > From: Aristo Chen <aristo.chen@canonical.com>
> >
> > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > logs, which can be lost as buffers roll over. Capture the OS revision
> > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > it in the OP-TEE driver, and expose a stable userspace readout via
> > /sys/class/tee/tee*/optee_os_revision.
> >
> > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > ---
> >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> >  4 files changed, 58 insertions(+), 4 deletions(-)
> 
> This appears to be a feature that could be useful for all TEEs.

True, it is something that TEE core should support. Although I would
have preferred to extend TEE_IOC_VERSION since that's the common way the
user-space library get's TEE implementation specific information. But
since it being already a user-space ABI which doesn't offer extension.
Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.

But before doing that we need to know who is the actual consumer here
from user-space perspective? Will the client applications also depend on
the TEE implementation revision?

> If so,
> let's take a step back to see what's needed. We can add the sysfs
> attribute from drivers/tee/tee_core.c and add another optional
> callback to struct tee_driver_ops, such as get_tee_revision(). For
> OP-TEE, the specific information we want to share is clear, but other
> TEEs might have additional or different data. What do others think?

Implementation wise, this sounds like a reasonable approach.

-Sumit

> 
> Cheers,
> Jens
> 
> >
> > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > index 5b62139714ce..66409cf5da1c 100644
> > --- a/drivers/tee/optee/core.c
> > +++ b/drivers/tee/optee/core.c
> > @@ -83,8 +83,27 @@ static ssize_t rpmb_routing_model_show(struct device *dev,
> >  }
> >  static DEVICE_ATTR_RO(rpmb_routing_model);
> >
> > +static ssize_t optee_os_revision_show(struct device *dev,
> > +                                     struct device_attribute *attr, char *buf)
> > +{
> > +       struct optee *optee = dev_get_drvdata(dev);
> > +       struct optee_version_info *v;
> > +
> > +       if (!optee)
> > +               return -ENODEV;
> > +
> > +       v = &optee->version_info;
> > +       if (v->os_build_id)
> > +               return sysfs_emit(buf, "%u.%u (%016llx)\n", v->os_major,
> > +                                 v->os_minor, (unsigned long long)v->os_build_id);
> > +
> > +       return sysfs_emit(buf, "%u.%u\n", v->os_major, v->os_minor);
> > +}
> > +static DEVICE_ATTR_RO(optee_os_revision);
> > +
> >  static struct attribute *optee_dev_attrs[] = {
> >         &dev_attr_rpmb_routing_model.attr,
> > +       &dev_attr_optee_os_revision.attr,
> >         NULL
> >  };
> >
> > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> > index bf8390789ecf..3d4f35599dd1 100644
> > --- a/drivers/tee/optee/ffa_abi.c
> > +++ b/drivers/tee/optee/ffa_abi.c
> > @@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
> >   */
> >
> >  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > -                                       const struct ffa_ops *ops)
> > +                                       const struct ffa_ops *ops,
> > +                                       struct optee_version_info *version_info)
> >  {
> >         const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> >         struct ffa_send_direct_data data = {
> > @@ -806,6 +807,12 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> >                 pr_err("Unexpected error %d\n", rc);
> >                 return false;
> >         }
> > +       if (version_info) {
> > +               version_info->os_major = data.data0;
> > +               version_info->os_minor = data.data1;
> > +               version_info->os_build_id = data.data2;
> > +       }
> > +
> >         if (data.data2)
> >                 pr_info("revision %lu.%lu (%08lx)",
> >                         data.data0, data.data1, data.data2);
> > @@ -1034,6 +1041,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> >  {
> >         const struct ffa_notifier_ops *notif_ops;
> >         const struct ffa_ops *ffa_ops;
> > +       struct optee_version_info version_info = { };
> >         unsigned int max_notif_value;
> >         unsigned int rpc_param_count;
> >         struct tee_shm_pool *pool;
> > @@ -1047,7 +1055,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> >         ffa_ops = ffa_dev->ops;
> >         notif_ops = ffa_ops->notifier_ops;
> >
> > -       if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
> > +       if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &version_info))
> >                 return -EINVAL;
> >
> >         if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
> > @@ -1059,6 +1067,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> >         optee = kzalloc(sizeof(*optee), GFP_KERNEL);
> >         if (!optee)
> >                 return -ENOMEM;
> > +       optee->version_info = version_info;
> >
> >         pool = optee_ffa_shm_pool_alloc_pages();
> >         if (IS_ERR(pool)) {
> > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > index db9ea673fbca..3e7bcd44976b 100644
> > --- a/drivers/tee/optee/optee_private.h
> > +++ b/drivers/tee/optee/optee_private.h
> > @@ -19,6 +19,22 @@
> >
> >  #define OPTEE_MAX_ARG_SIZE     1024
> >
> > +/**
> > + * struct optee_version_info - OP-TEE OS revision reported by secure world
> > + * @os_major:          OP-TEE OS major version
> > + * @os_minor:          OP-TEE OS minor version
> > + * @os_build_id:       OP-TEE OS build identifier (0 if unspecified)
> > + *
> > + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> > + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> > + * FF-A ABI version.
> > + */
> > +struct optee_version_info {
> > +       u32 os_major;
> > +       u32 os_minor;
> > +       u64 os_build_id;
> > +};
> > +
> >  /* Some Global Platform error codes used in this driver */
> >  #define TEEC_SUCCESS                   0x00000000
> >  #define TEEC_ERROR_BAD_PARAMETERS      0xFFFF0006
> > @@ -249,6 +265,7 @@ struct optee {
> >         bool in_kernel_rpmb_routing;
> >         struct work_struct scan_bus_work;
> >         struct work_struct rpmb_scan_bus_work;
> > +       struct optee_version_info version_info;
> >  };
> >
> >  struct optee_session {
> > diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> > index 0be663fcd52b..07c703609320 100644
> > --- a/drivers/tee/optee/smc_abi.c
> > +++ b/drivers/tee/optee/smc_abi.c
> > @@ -1323,7 +1323,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
> >  }
> >  #endif
> >
> > -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> > +                                     struct optee_version_info *version_info)
> >  {
> >         union {
> >                 struct arm_smccc_res smccc;
> > @@ -1337,6 +1338,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> >         invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
> >                   &res.smccc);
> >
> > +       if (version_info) {
> > +               version_info->os_major = res.result.major;
> > +               version_info->os_minor = res.result.minor;
> > +               version_info->os_build_id = res.result.build_id;
> > +       }
> > +
> >         if (res.result.build_id)
> >                 pr_info("revision %lu.%lu (%0*lx)", res.result.major,
> >                         res.result.minor, (int)sizeof(res.result.build_id) * 2,
> > @@ -1727,6 +1734,7 @@ static int optee_probe(struct platform_device *pdev)
> >         unsigned int thread_count;
> >         struct tee_device *teedev;
> >         struct tee_context *ctx;
> > +       struct optee_version_info version_info = { };
> >         u32 max_notif_value;
> >         u32 arg_cache_flags;
> >         u32 sec_caps;
> > @@ -1745,7 +1753,7 @@ static int optee_probe(struct platform_device *pdev)
> >                 return -EINVAL;
> >         }
> >
> > -       optee_msg_get_os_revision(invoke_fn);
> > +       optee_msg_get_os_revision(invoke_fn, &version_info);
> >
> >         if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
> >                 pr_warn("api revision mismatch\n");
> > @@ -1814,6 +1822,7 @@ static int optee_probe(struct platform_device *pdev)
> >                 rc = -ENOMEM;
> >                 goto err_free_shm_pool;
> >         }
> > +       optee->version_info = version_info;
> >
> >         optee->ops = &optee_ops;
> >         optee->smc.invoke_fn = invoke_fn;
> > --
> > 2.43.0
> >

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-11-25  7:53     ` Sumit Garg
@ 2025-11-25  7:55       ` Sumit Garg
  2025-12-01 11:47         ` Aristo Chen
  0 siblings, 1 reply; 42+ messages in thread
From: Sumit Garg @ 2025-11-25  7:55 UTC (permalink / raw)
  To: Jens Wiklander, Wei Ming Chen, linux-kernel, op-tee, harshal.dev,
	Aristo Chen, mario.limonciello, Rijo Thomas, Amirreza Zarrabi

On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > Hi,
> > 
> > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > >
> > > From: Aristo Chen <aristo.chen@canonical.com>
> > >
> > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > /sys/class/tee/tee*/optee_os_revision.
> > >
> > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > ---
> > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > 
> > This appears to be a feature that could be useful for all TEEs.
> 
> True, it is something that TEE core should support. Although I would
> have preferred to extend TEE_IOC_VERSION since that's the common way the
> user-space library get's TEE implementation specific information. But
> since it being already a user-space ABI which doesn't offer extension.
> Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.

Ah, typo here:

s/TEE_IOC_REVERSION/TEE_IOC_REVISION/

-Sumit

> 
> But before doing that we need to know who is the actual consumer here
> from user-space perspective? Will the client applications also depend on
> the TEE implementation revision?
> 
> > If so,
> > let's take a step back to see what's needed. We can add the sysfs
> > attribute from drivers/tee/tee_core.c and add another optional
> > callback to struct tee_driver_ops, such as get_tee_revision(). For
> > OP-TEE, the specific information we want to share is clear, but other
> > TEEs might have additional or different data. What do others think?
> 
> Implementation wise, this sounds like a reasonable approach.
> 
> -Sumit
> 
> > 
> > Cheers,
> > Jens
> > 
> > >
> > > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > > index 5b62139714ce..66409cf5da1c 100644
> > > --- a/drivers/tee/optee/core.c
> > > +++ b/drivers/tee/optee/core.c
> > > @@ -83,8 +83,27 @@ static ssize_t rpmb_routing_model_show(struct device *dev,
> > >  }
> > >  static DEVICE_ATTR_RO(rpmb_routing_model);
> > >
> > > +static ssize_t optee_os_revision_show(struct device *dev,
> > > +                                     struct device_attribute *attr, char *buf)
> > > +{
> > > +       struct optee *optee = dev_get_drvdata(dev);
> > > +       struct optee_version_info *v;
> > > +
> > > +       if (!optee)
> > > +               return -ENODEV;
> > > +
> > > +       v = &optee->version_info;
> > > +       if (v->os_build_id)
> > > +               return sysfs_emit(buf, "%u.%u (%016llx)\n", v->os_major,
> > > +                                 v->os_minor, (unsigned long long)v->os_build_id);
> > > +
> > > +       return sysfs_emit(buf, "%u.%u\n", v->os_major, v->os_minor);
> > > +}
> > > +static DEVICE_ATTR_RO(optee_os_revision);
> > > +
> > >  static struct attribute *optee_dev_attrs[] = {
> > >         &dev_attr_rpmb_routing_model.attr,
> > > +       &dev_attr_optee_os_revision.attr,
> > >         NULL
> > >  };
> > >
> > > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> > > index bf8390789ecf..3d4f35599dd1 100644
> > > --- a/drivers/tee/optee/ffa_abi.c
> > > +++ b/drivers/tee/optee/ffa_abi.c
> > > @@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
> > >   */
> > >
> > >  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > > -                                       const struct ffa_ops *ops)
> > > +                                       const struct ffa_ops *ops,
> > > +                                       struct optee_version_info *version_info)
> > >  {
> > >         const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> > >         struct ffa_send_direct_data data = {
> > > @@ -806,6 +807,12 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > >                 pr_err("Unexpected error %d\n", rc);
> > >                 return false;
> > >         }
> > > +       if (version_info) {
> > > +               version_info->os_major = data.data0;
> > > +               version_info->os_minor = data.data1;
> > > +               version_info->os_build_id = data.data2;
> > > +       }
> > > +
> > >         if (data.data2)
> > >                 pr_info("revision %lu.%lu (%08lx)",
> > >                         data.data0, data.data1, data.data2);
> > > @@ -1034,6 +1041,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > >  {
> > >         const struct ffa_notifier_ops *notif_ops;
> > >         const struct ffa_ops *ffa_ops;
> > > +       struct optee_version_info version_info = { };
> > >         unsigned int max_notif_value;
> > >         unsigned int rpc_param_count;
> > >         struct tee_shm_pool *pool;
> > > @@ -1047,7 +1055,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > >         ffa_ops = ffa_dev->ops;
> > >         notif_ops = ffa_ops->notifier_ops;
> > >
> > > -       if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
> > > +       if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &version_info))
> > >                 return -EINVAL;
> > >
> > >         if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
> > > @@ -1059,6 +1067,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > >         optee = kzalloc(sizeof(*optee), GFP_KERNEL);
> > >         if (!optee)
> > >                 return -ENOMEM;
> > > +       optee->version_info = version_info;
> > >
> > >         pool = optee_ffa_shm_pool_alloc_pages();
> > >         if (IS_ERR(pool)) {
> > > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > > index db9ea673fbca..3e7bcd44976b 100644
> > > --- a/drivers/tee/optee/optee_private.h
> > > +++ b/drivers/tee/optee/optee_private.h
> > > @@ -19,6 +19,22 @@
> > >
> > >  #define OPTEE_MAX_ARG_SIZE     1024
> > >
> > > +/**
> > > + * struct optee_version_info - OP-TEE OS revision reported by secure world
> > > + * @os_major:          OP-TEE OS major version
> > > + * @os_minor:          OP-TEE OS minor version
> > > + * @os_build_id:       OP-TEE OS build identifier (0 if unspecified)
> > > + *
> > > + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> > > + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> > > + * FF-A ABI version.
> > > + */
> > > +struct optee_version_info {
> > > +       u32 os_major;
> > > +       u32 os_minor;
> > > +       u64 os_build_id;
> > > +};
> > > +
> > >  /* Some Global Platform error codes used in this driver */
> > >  #define TEEC_SUCCESS                   0x00000000
> > >  #define TEEC_ERROR_BAD_PARAMETERS      0xFFFF0006
> > > @@ -249,6 +265,7 @@ struct optee {
> > >         bool in_kernel_rpmb_routing;
> > >         struct work_struct scan_bus_work;
> > >         struct work_struct rpmb_scan_bus_work;
> > > +       struct optee_version_info version_info;
> > >  };
> > >
> > >  struct optee_session {
> > > diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> > > index 0be663fcd52b..07c703609320 100644
> > > --- a/drivers/tee/optee/smc_abi.c
> > > +++ b/drivers/tee/optee/smc_abi.c
> > > @@ -1323,7 +1323,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
> > >  }
> > >  #endif
> > >
> > > -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > > +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> > > +                                     struct optee_version_info *version_info)
> > >  {
> > >         union {
> > >                 struct arm_smccc_res smccc;
> > > @@ -1337,6 +1338,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > >         invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
> > >                   &res.smccc);
> > >
> > > +       if (version_info) {
> > > +               version_info->os_major = res.result.major;
> > > +               version_info->os_minor = res.result.minor;
> > > +               version_info->os_build_id = res.result.build_id;
> > > +       }
> > > +
> > >         if (res.result.build_id)
> > >                 pr_info("revision %lu.%lu (%0*lx)", res.result.major,
> > >                         res.result.minor, (int)sizeof(res.result.build_id) * 2,
> > > @@ -1727,6 +1734,7 @@ static int optee_probe(struct platform_device *pdev)
> > >         unsigned int thread_count;
> > >         struct tee_device *teedev;
> > >         struct tee_context *ctx;
> > > +       struct optee_version_info version_info = { };
> > >         u32 max_notif_value;
> > >         u32 arg_cache_flags;
> > >         u32 sec_caps;
> > > @@ -1745,7 +1753,7 @@ static int optee_probe(struct platform_device *pdev)
> > >                 return -EINVAL;
> > >         }
> > >
> > > -       optee_msg_get_os_revision(invoke_fn);
> > > +       optee_msg_get_os_revision(invoke_fn, &version_info);
> > >
> > >         if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
> > >                 pr_warn("api revision mismatch\n");
> > > @@ -1814,6 +1822,7 @@ static int optee_probe(struct platform_device *pdev)
> > >                 rc = -ENOMEM;
> > >                 goto err_free_shm_pool;
> > >         }
> > > +       optee->version_info = version_info;
> > >
> > >         optee->ops = &optee_ops;
> > >         optee->smc.invoke_fn = invoke_fn;
> > > --
> > > 2.43.0
> > >

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-11-25  7:55       ` Sumit Garg
@ 2025-12-01 11:47         ` Aristo Chen
  2025-12-01 13:06           ` Jens Wiklander
  0 siblings, 1 reply; 42+ messages in thread
From: Aristo Chen @ 2025-12-01 11:47 UTC (permalink / raw)
  To: Sumit Garg
  Cc: Jens Wiklander, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

Hi,

Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
>
> On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > Hi,
> > >
> > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > >
> > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > >
> > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > /sys/class/tee/tee*/optee_os_revision.
> > > >
> > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > ---
> > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > >
> > > This appears to be a feature that could be useful for all TEEs.
> >
> > True, it is something that TEE core should support. Although I would
> > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > user-space library get's TEE implementation specific information. But
> > since it being already a user-space ABI which doesn't offer extension.
> > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
>
> Ah, typo here:
>
> s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
>
> -Sumit
>
> >
> > But before doing that we need to know who is the actual consumer here
> > from user-space perspective? Will the client applications also depend on
> > the TEE implementation revision?
My current thinking is that if the TEE revision is exposed, users can write a
script to capture the platform state and record the exact secure OS revision
even after the dmesg/journalctl logs have rolled over. This would significantly
improve bug triage and regression tracking.

In my case, I have a package with precompiled xtest binaries for multiple
releases (from 3.14 to 4.6), and I work with different platforms that run
different OP-TEE OS versions. Having a reliable way to obtain the TEE
revision would help a lot, as it would allow me to select the correct xtest
version when running tests.
> >
> > > If so,
> > > let's take a step back to see what's needed. We can add the sysfs
> > > attribute from drivers/tee/tee_core.c and add another optional
> > > callback to struct tee_driver_ops, such as get_tee_revision(). For
> > > OP-TEE, the specific information we want to share is clear, but other
> > > TEEs might have additional or different data. What do others think?
> >
> > Implementation wise, this sounds like a reasonable approach.
> >
> > -Sumit
> >
> > >
> > > Cheers,
> > > Jens
> > >
> > > >
> > > > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > > > index 5b62139714ce..66409cf5da1c 100644
> > > > --- a/drivers/tee/optee/core.c
> > > > +++ b/drivers/tee/optee/core.c
> > > > @@ -83,8 +83,27 @@ static ssize_t rpmb_routing_model_show(struct device *dev,
> > > >  }
> > > >  static DEVICE_ATTR_RO(rpmb_routing_model);
> > > >
> > > > +static ssize_t optee_os_revision_show(struct device *dev,
> > > > +                                     struct device_attribute *attr, char *buf)
> > > > +{
> > > > +       struct optee *optee = dev_get_drvdata(dev);
> > > > +       struct optee_version_info *v;
> > > > +
> > > > +       if (!optee)
> > > > +               return -ENODEV;
> > > > +
> > > > +       v = &optee->version_info;
> > > > +       if (v->os_build_id)
> > > > +               return sysfs_emit(buf, "%u.%u (%016llx)\n", v->os_major,
> > > > +                                 v->os_minor, (unsigned long long)v->os_build_id);
> > > > +
> > > > +       return sysfs_emit(buf, "%u.%u\n", v->os_major, v->os_minor);
> > > > +}
> > > > +static DEVICE_ATTR_RO(optee_os_revision);
> > > > +
> > > >  static struct attribute *optee_dev_attrs[] = {
> > > >         &dev_attr_rpmb_routing_model.attr,
> > > > +       &dev_attr_optee_os_revision.attr,
> > > >         NULL
> > > >  };
> > > >
> > > > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> > > > index bf8390789ecf..3d4f35599dd1 100644
> > > > --- a/drivers/tee/optee/ffa_abi.c
> > > > +++ b/drivers/tee/optee/ffa_abi.c
> > > > @@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
> > > >   */
> > > >
> > > >  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > > > -                                       const struct ffa_ops *ops)
> > > > +                                       const struct ffa_ops *ops,
> > > > +                                       struct optee_version_info *version_info)
> > > >  {
> > > >         const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> > > >         struct ffa_send_direct_data data = {
> > > > @@ -806,6 +807,12 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > > >                 pr_err("Unexpected error %d\n", rc);
> > > >                 return false;
> > > >         }
> > > > +       if (version_info) {
> > > > +               version_info->os_major = data.data0;
> > > > +               version_info->os_minor = data.data1;
> > > > +               version_info->os_build_id = data.data2;
> > > > +       }
> > > > +
> > > >         if (data.data2)
> > > >                 pr_info("revision %lu.%lu (%08lx)",
> > > >                         data.data0, data.data1, data.data2);
> > > > @@ -1034,6 +1041,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > > >  {
> > > >         const struct ffa_notifier_ops *notif_ops;
> > > >         const struct ffa_ops *ffa_ops;
> > > > +       struct optee_version_info version_info = { };
> > > >         unsigned int max_notif_value;
> > > >         unsigned int rpc_param_count;
> > > >         struct tee_shm_pool *pool;
> > > > @@ -1047,7 +1055,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > > >         ffa_ops = ffa_dev->ops;
> > > >         notif_ops = ffa_ops->notifier_ops;
> > > >
> > > > -       if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
> > > > +       if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &version_info))
> > > >                 return -EINVAL;
> > > >
> > > >         if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
> > > > @@ -1059,6 +1067,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > > >         optee = kzalloc(sizeof(*optee), GFP_KERNEL);
> > > >         if (!optee)
> > > >                 return -ENOMEM;
> > > > +       optee->version_info = version_info;
> > > >
> > > >         pool = optee_ffa_shm_pool_alloc_pages();
> > > >         if (IS_ERR(pool)) {
> > > > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > > > index db9ea673fbca..3e7bcd44976b 100644
> > > > --- a/drivers/tee/optee/optee_private.h
> > > > +++ b/drivers/tee/optee/optee_private.h
> > > > @@ -19,6 +19,22 @@
> > > >
> > > >  #define OPTEE_MAX_ARG_SIZE     1024
> > > >
> > > > +/**
> > > > + * struct optee_version_info - OP-TEE OS revision reported by secure world
> > > > + * @os_major:          OP-TEE OS major version
> > > > + * @os_minor:          OP-TEE OS minor version
> > > > + * @os_build_id:       OP-TEE OS build identifier (0 if unspecified)
> > > > + *
> > > > + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> > > > + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> > > > + * FF-A ABI version.
> > > > + */
> > > > +struct optee_version_info {
> > > > +       u32 os_major;
> > > > +       u32 os_minor;
> > > > +       u64 os_build_id;
> > > > +};
> > > > +
> > > >  /* Some Global Platform error codes used in this driver */
> > > >  #define TEEC_SUCCESS                   0x00000000
> > > >  #define TEEC_ERROR_BAD_PARAMETERS      0xFFFF0006
> > > > @@ -249,6 +265,7 @@ struct optee {
> > > >         bool in_kernel_rpmb_routing;
> > > >         struct work_struct scan_bus_work;
> > > >         struct work_struct rpmb_scan_bus_work;
> > > > +       struct optee_version_info version_info;
> > > >  };
> > > >
> > > >  struct optee_session {
> > > > diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> > > > index 0be663fcd52b..07c703609320 100644
> > > > --- a/drivers/tee/optee/smc_abi.c
> > > > +++ b/drivers/tee/optee/smc_abi.c
> > > > @@ -1323,7 +1323,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
> > > >  }
> > > >  #endif
> > > >
> > > > -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > > > +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> > > > +                                     struct optee_version_info *version_info)
> > > >  {
> > > >         union {
> > > >                 struct arm_smccc_res smccc;
> > > > @@ -1337,6 +1338,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > > >         invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
> > > >                   &res.smccc);
> > > >
> > > > +       if (version_info) {
> > > > +               version_info->os_major = res.result.major;
> > > > +               version_info->os_minor = res.result.minor;
> > > > +               version_info->os_build_id = res.result.build_id;
> > > > +       }
> > > > +
> > > >         if (res.result.build_id)
> > > >                 pr_info("revision %lu.%lu (%0*lx)", res.result.major,
> > > >                         res.result.minor, (int)sizeof(res.result.build_id) * 2,
> > > > @@ -1727,6 +1734,7 @@ static int optee_probe(struct platform_device *pdev)
> > > >         unsigned int thread_count;
> > > >         struct tee_device *teedev;
> > > >         struct tee_context *ctx;
> > > > +       struct optee_version_info version_info = { };
> > > >         u32 max_notif_value;
> > > >         u32 arg_cache_flags;
> > > >         u32 sec_caps;
> > > > @@ -1745,7 +1753,7 @@ static int optee_probe(struct platform_device *pdev)
> > > >                 return -EINVAL;
> > > >         }
> > > >
> > > > -       optee_msg_get_os_revision(invoke_fn);
> > > > +       optee_msg_get_os_revision(invoke_fn, &version_info);
> > > >
> > > >         if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
> > > >                 pr_warn("api revision mismatch\n");
> > > > @@ -1814,6 +1822,7 @@ static int optee_probe(struct platform_device *pdev)
> > > >                 rc = -ENOMEM;
> > > >                 goto err_free_shm_pool;
> > > >         }
> > > > +       optee->version_info = version_info;
> > > >
> > > >         optee->ops = &optee_ops;
> > > >         optee->smc.invoke_fn = invoke_fn;
> > > > --
> > > > 2.43.0
> > > >

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-12-01 11:47         ` Aristo Chen
@ 2025-12-01 13:06           ` Jens Wiklander
  2025-12-02  9:54             ` Aristo Chen
  0 siblings, 1 reply; 42+ messages in thread
From: Jens Wiklander @ 2025-12-01 13:06 UTC (permalink / raw)
  To: Aristo Chen
  Cc: Sumit Garg, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

Hi,

On Mon, Dec 1, 2025 at 12:48 PM Aristo Chen <jj251510319013@gmail.com> wrote:
>
> Hi,
>
> Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
> >
> > On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > > Hi,
> > > >
> > > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > > >
> > > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > > >
> > > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > > /sys/class/tee/tee*/optee_os_revision.
> > > > >
> > > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > > ---
> > > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > > >
> > > > This appears to be a feature that could be useful for all TEEs.
> > >
> > > True, it is something that TEE core should support. Although I would
> > > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > > user-space library get's TEE implementation specific information. But
> > > since it being already a user-space ABI which doesn't offer extension.
> > > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
> >
> > Ah, typo here:
> >
> > s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
> >
> > -Sumit
> >
> > >
> > > But before doing that we need to know who is the actual consumer here
> > > from user-space perspective? Will the client applications also depend on
> > > the TEE implementation revision?
> My current thinking is that if the TEE revision is exposed, users can write a
> script to capture the platform state and record the exact secure OS revision
> even after the dmesg/journalctl logs have rolled over. This would significantly
> improve bug triage and regression tracking.
>
> In my case, I have a package with precompiled xtest binaries for multiple
> releases (from 3.14 to 4.6), and I work with different platforms that run
> different OP-TEE OS versions. Having a reliable way to obtain the TEE
> revision would help a lot, as it would allow me to select the correct xtest
> version when running tests.

I'm concerned that the ABI might be misused to be part of what the
client expects from the TEE. You even express that as a use case. I'd
rather fix the problem with xtest.

Cheers,
Jens

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-12-01 13:06           ` Jens Wiklander
@ 2025-12-02  9:54             ` Aristo Chen
  2025-12-03  7:50               ` Jens Wiklander
  0 siblings, 1 reply; 42+ messages in thread
From: Aristo Chen @ 2025-12-02  9:54 UTC (permalink / raw)
  To: Jens Wiklander
  Cc: Sumit Garg, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

Hi Jens

Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月1日週一 下午9:06寫道:
>
> Hi,
>
> On Mon, Dec 1, 2025 at 12:48 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> >
> > Hi,
> >
> > Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
> > >
> > > On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > > > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > > > Hi,
> > > > >
> > > > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > > > >
> > > > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > > > >
> > > > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > > > /sys/class/tee/tee*/optee_os_revision.
> > > > > >
> > > > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > > > ---
> > > > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > > > >
> > > > > This appears to be a feature that could be useful for all TEEs.
> > > >
> > > > True, it is something that TEE core should support. Although I would
> > > > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > > > user-space library get's TEE implementation specific information. But
> > > > since it being already a user-space ABI which doesn't offer extension.
> > > > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
> > >
> > > Ah, typo here:
> > >
> > > s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
> > >
> > > -Sumit
> > >
> > > >
> > > > But before doing that we need to know who is the actual consumer here
> > > > from user-space perspective? Will the client applications also depend on
> > > > the TEE implementation revision?
> > My current thinking is that if the TEE revision is exposed, users can write a
> > script to capture the platform state and record the exact secure OS revision
> > even after the dmesg/journalctl logs have rolled over. This would significantly
> > improve bug triage and regression tracking.
> >
> > In my case, I have a package with precompiled xtest binaries for multiple
> > releases (from 3.14 to 4.6), and I work with different platforms that run
> > different OP-TEE OS versions. Having a reliable way to obtain the TEE
> > revision would help a lot, as it would allow me to select the correct xtest
> > version when running tests.
>
> I'm concerned that the ABI might be misused to be part of what the
> client expects from the TEE. You even express that as a use case. I'd
> rather fix the problem with xtest.

Thanks for the feedback! To clarify: currently, the OP-TEE OS revision
I expose in
sysfs is the same value already printed in dmesg at boot
 (e.g., “optee: revision 4.8 (XXXXXX)”).

Are your concerns specifically about clients inferring capabilities
from a revision
string (“rev X.Y implies feature Z”)? If so, I agree that’s fragile
and not the intent.
I’m happy to add a short note in the doc that this is informational
only and that
feature detection must use proper capability queries.

Please let me know if that addresses the worry, or if there’s another
concern I’m
missing.

Thanks,
Aristo
>
> Cheers,
> Jens

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-12-02  9:54             ` Aristo Chen
@ 2025-12-03  7:50               ` Jens Wiklander
  2025-12-07 14:01                 ` Aristo Chen
  0 siblings, 1 reply; 42+ messages in thread
From: Jens Wiklander @ 2025-12-03  7:50 UTC (permalink / raw)
  To: Aristo Chen
  Cc: Sumit Garg, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

Hi,

On Tue, Dec 2, 2025 at 10:54 AM Aristo Chen <jj251510319013@gmail.com> wrote:
>
> Hi Jens
>
> Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月1日週一 下午9:06寫道:
> >
> > Hi,
> >
> > On Mon, Dec 1, 2025 at 12:48 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> > >
> > > Hi,
> > >
> > > Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
> > > >
> > > > On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > > > > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > > > > Hi,
> > > > > >
> > > > > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > > > > >
> > > > > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > > > > >
> > > > > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > > > > /sys/class/tee/tee*/optee_os_revision.
> > > > > > >
> > > > > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > ---
> > > > > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > > > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > > > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > > > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > > > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > > > > >
> > > > > > This appears to be a feature that could be useful for all TEEs.
> > > > >
> > > > > True, it is something that TEE core should support. Although I would
> > > > > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > > > > user-space library get's TEE implementation specific information. But
> > > > > since it being already a user-space ABI which doesn't offer extension.
> > > > > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
> > > >
> > > > Ah, typo here:
> > > >
> > > > s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
> > > >
> > > > -Sumit
> > > >
> > > > >
> > > > > But before doing that we need to know who is the actual consumer here
> > > > > from user-space perspective? Will the client applications also depend on
> > > > > the TEE implementation revision?
> > > My current thinking is that if the TEE revision is exposed, users can write a
> > > script to capture the platform state and record the exact secure OS revision
> > > even after the dmesg/journalctl logs have rolled over. This would significantly
> > > improve bug triage and regression tracking.
> > >
> > > In my case, I have a package with precompiled xtest binaries for multiple
> > > releases (from 3.14 to 4.6), and I work with different platforms that run
> > > different OP-TEE OS versions. Having a reliable way to obtain the TEE
> > > revision would help a lot, as it would allow me to select the correct xtest
> > > version when running tests.
> >
> > I'm concerned that the ABI might be misused to be part of what the
> > client expects from the TEE. You even express that as a use case. I'd
> > rather fix the problem with xtest.
>
> Thanks for the feedback! To clarify: currently, the OP-TEE OS revision
> I expose in
> sysfs is the same value already printed in dmesg at boot
>  (e.g., “optee: revision 4.8 (XXXXXX)”).
>
> Are your concerns specifically about clients inferring capabilities
> from a revision
> string (“rev X.Y implies feature Z”)? If so, I agree that’s fragile
> and not the intent.

Yes

> I’m happy to add a short note in the doc that this is informational
> only and that
> feature detection must use proper capability queries.
>
> Please let me know if that addresses the worry, or if there’s another
> concern I’m
> missing.

Adding APIs that aren't supposed to be used seems odd. Do you know if
there are examples in the kernel for this kind of thing?

Cheers,
Jens

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-12-03  7:50               ` Jens Wiklander
@ 2025-12-07 14:01                 ` Aristo Chen
  2025-12-09  8:30                   ` Jens Wiklander
  0 siblings, 1 reply; 42+ messages in thread
From: Aristo Chen @ 2025-12-07 14:01 UTC (permalink / raw)
  To: Jens Wiklander
  Cc: Sumit Garg, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

Hi Jens,

Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月3日週三 下午3:51寫道:
>
> Hi,
>
> On Tue, Dec 2, 2025 at 10:54 AM Aristo Chen <jj251510319013@gmail.com> wrote:
> >
> > Hi Jens
> >
> > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月1日週一 下午9:06寫道:
> > >
> > > Hi,
> > >
> > > On Mon, Dec 1, 2025 at 12:48 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > >
> > > > Hi,
> > > >
> > > > Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
> > > > >
> > > > > On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > > > > > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > > > > > Hi,
> > > > > > >
> > > > > > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > > > > > >
> > > > > > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > >
> > > > > > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > > > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > > > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > > > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > > > > > /sys/class/tee/tee*/optee_os_revision.
> > > > > > > >
> > > > > > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > ---
> > > > > > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > > > > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > > > > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > > > > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > > > > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > > > > > >
> > > > > > > This appears to be a feature that could be useful for all TEEs.
> > > > > >
> > > > > > True, it is something that TEE core should support. Although I would
> > > > > > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > > > > > user-space library get's TEE implementation specific information. But
> > > > > > since it being already a user-space ABI which doesn't offer extension.
> > > > > > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
> > > > >
> > > > > Ah, typo here:
> > > > >
> > > > > s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
> > > > >
> > > > > -Sumit
> > > > >
> > > > > >
> > > > > > But before doing that we need to know who is the actual consumer here
> > > > > > from user-space perspective? Will the client applications also depend on
> > > > > > the TEE implementation revision?
> > > > My current thinking is that if the TEE revision is exposed, users can write a
> > > > script to capture the platform state and record the exact secure OS revision
> > > > even after the dmesg/journalctl logs have rolled over. This would significantly
> > > > improve bug triage and regression tracking.
> > > >
> > > > In my case, I have a package with precompiled xtest binaries for multiple
> > > > releases (from 3.14 to 4.6), and I work with different platforms that run
> > > > different OP-TEE OS versions. Having a reliable way to obtain the TEE
> > > > revision would help a lot, as it would allow me to select the correct xtest
> > > > version when running tests.
> > >
> > > I'm concerned that the ABI might be misused to be part of what the
> > > client expects from the TEE. You even express that as a use case. I'd
> > > rather fix the problem with xtest.
> >
> > Thanks for the feedback! To clarify: currently, the OP-TEE OS revision
> > I expose in
> > sysfs is the same value already printed in dmesg at boot
> >  (e.g., “optee: revision 4.8 (XXXXXX)”).
> >
> > Are your concerns specifically about clients inferring capabilities
> > from a revision
> > string (“rev X.Y implies feature Z”)? If so, I agree that’s fragile
> > and not the intent.
>
> Yes

Thanks for clarifying the concern!

>
> > I’m happy to add a short note in the doc that this is informational
> > only and that
> > feature detection must use proper capability queries.
> >
> > Please let me know if that addresses the worry, or if there’s another
> > concern I’m
> > missing.
>
> Adding APIs that aren't supposed to be used seems odd. Do you know if
> there are examples in the kernel for this kind of thing?
I’ve done some research and, as far as I can tell, the TEE core already
provides an informational-only file at /sys/class/tee/tee0/implementation_id.
My understanding is that it was introduced roughly 10 years ago. However,
I haven’t found any documentation clarifying its intended purpose, so I’m
assuming this may be a similar situation. I’d appreciate it if you could correct
me if I’m wrong.

Also, here are some files with similiar purposes:
- /sys/devices/system/cpu/cpu*/microcode/version
- /sys/devices/virtual/dmi/id/{bios_date,bios_release,bios_vendor,bios_version}
- /sys/kernel/security/apparmor/revision

>
> Cheers,
> Jens

Best Regards,
Aristo

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-12-07 14:01                 ` Aristo Chen
@ 2025-12-09  8:30                   ` Jens Wiklander
  2025-12-19 15:38                     ` Aristo Chen
  0 siblings, 1 reply; 42+ messages in thread
From: Jens Wiklander @ 2025-12-09  8:30 UTC (permalink / raw)
  To: Aristo Chen
  Cc: Sumit Garg, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

Hi Aristo,

On Sun, Dec 7, 2025 at 3:01 PM Aristo Chen <jj251510319013@gmail.com> wrote:
>
> Hi Jens,
>
> Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月3日週三 下午3:51寫道:
> >
> > Hi,
> >
> > On Tue, Dec 2, 2025 at 10:54 AM Aristo Chen <jj251510319013@gmail.com> wrote:
> > >
> > > Hi Jens
> > >
> > > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月1日週一 下午9:06寫道:
> > > >
> > > > Hi,
> > > >
> > > > On Mon, Dec 1, 2025 at 12:48 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > > >
> > > > > Hi,
> > > > >
> > > > > Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
> > > > > >
> > > > > > On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > > > > > > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > > > > > > Hi,
> > > > > > > >
> > > > > > > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > > > > > > >
> > > > > > > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > >
> > > > > > > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > > > > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > > > > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > > > > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > > > > > > /sys/class/tee/tee*/optee_os_revision.
> > > > > > > > >
> > > > > > > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > > ---
> > > > > > > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > > > > > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > > > > > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > > > > > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > > > > > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > > > > > > >
> > > > > > > > This appears to be a feature that could be useful for all TEEs.
> > > > > > >
> > > > > > > True, it is something that TEE core should support. Although I would
> > > > > > > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > > > > > > user-space library get's TEE implementation specific information. But
> > > > > > > since it being already a user-space ABI which doesn't offer extension.
> > > > > > > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
> > > > > >
> > > > > > Ah, typo here:
> > > > > >
> > > > > > s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
> > > > > >
> > > > > > -Sumit
> > > > > >
> > > > > > >
> > > > > > > But before doing that we need to know who is the actual consumer here
> > > > > > > from user-space perspective? Will the client applications also depend on
> > > > > > > the TEE implementation revision?
> > > > > My current thinking is that if the TEE revision is exposed, users can write a
> > > > > script to capture the platform state and record the exact secure OS revision
> > > > > even after the dmesg/journalctl logs have rolled over. This would significantly
> > > > > improve bug triage and regression tracking.
> > > > >
> > > > > In my case, I have a package with precompiled xtest binaries for multiple
> > > > > releases (from 3.14 to 4.6), and I work with different platforms that run
> > > > > different OP-TEE OS versions. Having a reliable way to obtain the TEE
> > > > > revision would help a lot, as it would allow me to select the correct xtest
> > > > > version when running tests.
> > > >
> > > > I'm concerned that the ABI might be misused to be part of what the
> > > > client expects from the TEE. You even express that as a use case. I'd
> > > > rather fix the problem with xtest.
> > >
> > > Thanks for the feedback! To clarify: currently, the OP-TEE OS revision
> > > I expose in
> > > sysfs is the same value already printed in dmesg at boot
> > >  (e.g., “optee: revision 4.8 (XXXXXX)”).
> > >
> > > Are your concerns specifically about clients inferring capabilities
> > > from a revision
> > > string (“rev X.Y implies feature Z”)? If so, I agree that’s fragile
> > > and not the intent.
> >
> > Yes
>
> Thanks for clarifying the concern!
>
> >
> > > I’m happy to add a short note in the doc that this is informational
> > > only and that
> > > feature detection must use proper capability queries.
> > >
> > > Please let me know if that addresses the worry, or if there’s another
> > > concern I’m
> > > missing.
> >
> > Adding APIs that aren't supposed to be used seems odd. Do you know if
> > there are examples in the kernel for this kind of thing?
> I’ve done some research and, as far as I can tell, the TEE core already
> provides an informational-only file at /sys/class/tee/tee0/implementation_id.
> My understanding is that it was introduced roughly 10 years ago. However,
> I haven’t found any documentation clarifying its intended purpose, so I’m
> assuming this may be a similar situation. I’d appreciate it if you could correct
> me if I’m wrong.

That one is for a quick way for a client to tell the different TEE
device implementations apart. You're right, it resembles your case,
except that this is part of a well-defined ABI.

>
> Also, here are some files with similiar purposes:
> - /sys/devices/system/cpu/cpu*/microcode/version
> - /sys/devices/virtual/dmi/id/{bios_date,bios_release,bios_vendor,bios_version}
> - /sys/kernel/security/apparmor/revision

Thanks, this is good background information.

We have a BoF session on the TEE subsystem at LPC on Friday [1]. We'll
take the opportunity to discuss it there.

[1] https://lpc.events/event/19/contributions/2107/

Cheers,
Jens

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-12-09  8:30                   ` Jens Wiklander
@ 2025-12-19 15:38                     ` Aristo Chen
  2025-12-22  8:34                       ` Jens Wiklander
  0 siblings, 1 reply; 42+ messages in thread
From: Aristo Chen @ 2025-12-19 15:38 UTC (permalink / raw)
  To: Jens Wiklander
  Cc: Sumit Garg, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

Hi Jens

Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月9日週二 下午4:31寫道:
>
> Hi Aristo,
>
> On Sun, Dec 7, 2025 at 3:01 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> >
> > Hi Jens,
> >
> > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月3日週三 下午3:51寫道:
> > >
> > > Hi,
> > >
> > > On Tue, Dec 2, 2025 at 10:54 AM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > >
> > > > Hi Jens
> > > >
> > > > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月1日週一 下午9:06寫道:
> > > > >
> > > > > Hi,
> > > > >
> > > > > On Mon, Dec 1, 2025 at 12:48 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > > > >
> > > > > > Hi,
> > > > > >
> > > > > > Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
> > > > > > >
> > > > > > > On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > > > > > > > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > > > > > > > Hi,
> > > > > > > > >
> > > > > > > > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > > > > > > > >
> > > > > > > > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > > >
> > > > > > > > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > > > > > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > > > > > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > > > > > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > > > > > > > /sys/class/tee/tee*/optee_os_revision.
> > > > > > > > > >
> > > > > > > > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > > > ---
> > > > > > > > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > > > > > > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > > > > > > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > > > > > > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > > > > > > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > > > > > > > >
> > > > > > > > > This appears to be a feature that could be useful for all TEEs.
> > > > > > > >
> > > > > > > > True, it is something that TEE core should support. Although I would
> > > > > > > > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > > > > > > > user-space library get's TEE implementation specific information. But
> > > > > > > > since it being already a user-space ABI which doesn't offer extension.
> > > > > > > > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
> > > > > > >
> > > > > > > Ah, typo here:
> > > > > > >
> > > > > > > s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
> > > > > > >
> > > > > > > -Sumit
> > > > > > >
> > > > > > > >
> > > > > > > > But before doing that we need to know who is the actual consumer here
> > > > > > > > from user-space perspective? Will the client applications also depend on
> > > > > > > > the TEE implementation revision?
> > > > > > My current thinking is that if the TEE revision is exposed, users can write a
> > > > > > script to capture the platform state and record the exact secure OS revision
> > > > > > even after the dmesg/journalctl logs have rolled over. This would significantly
> > > > > > improve bug triage and regression tracking.
> > > > > >
> > > > > > In my case, I have a package with precompiled xtest binaries for multiple
> > > > > > releases (from 3.14 to 4.6), and I work with different platforms that run
> > > > > > different OP-TEE OS versions. Having a reliable way to obtain the TEE
> > > > > > revision would help a lot, as it would allow me to select the correct xtest
> > > > > > version when running tests.
> > > > >
> > > > > I'm concerned that the ABI might be misused to be part of what the
> > > > > client expects from the TEE. You even express that as a use case. I'd
> > > > > rather fix the problem with xtest.
> > > >
> > > > Thanks for the feedback! To clarify: currently, the OP-TEE OS revision
> > > > I expose in
> > > > sysfs is the same value already printed in dmesg at boot
> > > >  (e.g., “optee: revision 4.8 (XXXXXX)”).
> > > >
> > > > Are your concerns specifically about clients inferring capabilities
> > > > from a revision
> > > > string (“rev X.Y implies feature Z”)? If so, I agree that’s fragile
> > > > and not the intent.
> > >
> > > Yes
> >
> > Thanks for clarifying the concern!
> >
> > >
> > > > I’m happy to add a short note in the doc that this is informational
> > > > only and that
> > > > feature detection must use proper capability queries.
> > > >
> > > > Please let me know if that addresses the worry, or if there’s another
> > > > concern I’m
> > > > missing.
> > >
> > > Adding APIs that aren't supposed to be used seems odd. Do you know if
> > > there are examples in the kernel for this kind of thing?
> > I’ve done some research and, as far as I can tell, the TEE core already
> > provides an informational-only file at /sys/class/tee/tee0/implementation_id.
> > My understanding is that it was introduced roughly 10 years ago. However,
> > I haven’t found any documentation clarifying its intended purpose, so I’m
> > assuming this may be a similar situation. I’d appreciate it if you could correct
> > me if I’m wrong.
>
> That one is for a quick way for a client to tell the different TEE
> device implementations apart. You're right, it resembles your case,
> except that this is part of a well-defined ABI.
>
> >
> > Also, here are some files with similiar purposes:
> > - /sys/devices/system/cpu/cpu*/microcode/version
> > - /sys/devices/virtual/dmi/id/{bios_date,bios_release,bios_vendor,bios_version}
> > - /sys/kernel/security/apparmor/revision
>
> Thanks, this is good background information.
>
> We have a BoF session on the TEE subsystem at LPC on Friday [1]. We'll
> take the opportunity to discuss it there.

Just a quick follow-up on this patch, has there been any decision or
direction from that discussion?
I’m happy to rework the patch in whatever direction the group prefers.

>
> [1] https://lpc.events/event/19/contributions/2107/
>
> Cheers,
> Jens

Best regards,
Aristo

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-12-19 15:38                     ` Aristo Chen
@ 2025-12-22  8:34                       ` Jens Wiklander
  2025-12-22 10:07                         ` Sumit Garg
  0 siblings, 1 reply; 42+ messages in thread
From: Jens Wiklander @ 2025-12-22  8:34 UTC (permalink / raw)
  To: Aristo Chen
  Cc: Sumit Garg, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

Hi Aristo,

On Fri, Dec 19, 2025 at 4:39 PM Aristo Chen <jj251510319013@gmail.com> wrote:
>
> Hi Jens
>
> Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月9日週二 下午4:31寫道:
> >
> > Hi Aristo,
> >
> > On Sun, Dec 7, 2025 at 3:01 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> > >
> > > Hi Jens,
> > >
> > > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月3日週三 下午3:51寫道:
> > > >
> > > > Hi,
> > > >
> > > > On Tue, Dec 2, 2025 at 10:54 AM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > > >
> > > > > Hi Jens
> > > > >
> > > > > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月1日週一 下午9:06寫道:
> > > > > >
> > > > > > Hi,
> > > > > >
> > > > > > On Mon, Dec 1, 2025 at 12:48 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > > > > >
> > > > > > > Hi,
> > > > > > >
> > > > > > > Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
> > > > > > > >
> > > > > > > > On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > > > > > > > > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > > > > > > > > Hi,
> > > > > > > > > >
> > > > > > > > > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > > > > > > > > >
> > > > > > > > > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > > > >
> > > > > > > > > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > > > > > > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > > > > > > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > > > > > > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > > > > > > > > /sys/class/tee/tee*/optee_os_revision.
> > > > > > > > > > >
> > > > > > > > > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > > > > ---
> > > > > > > > > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > > > > > > > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > > > > > > > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > > > > > > > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > > > > > > > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > > > > > > > > >
> > > > > > > > > > This appears to be a feature that could be useful for all TEEs.
> > > > > > > > >
> > > > > > > > > True, it is something that TEE core should support. Although I would
> > > > > > > > > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > > > > > > > > user-space library get's TEE implementation specific information. But
> > > > > > > > > since it being already a user-space ABI which doesn't offer extension.
> > > > > > > > > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
> > > > > > > >
> > > > > > > > Ah, typo here:
> > > > > > > >
> > > > > > > > s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
> > > > > > > >
> > > > > > > > -Sumit
> > > > > > > >
> > > > > > > > >
> > > > > > > > > But before doing that we need to know who is the actual consumer here
> > > > > > > > > from user-space perspective? Will the client applications also depend on
> > > > > > > > > the TEE implementation revision?
> > > > > > > My current thinking is that if the TEE revision is exposed, users can write a
> > > > > > > script to capture the platform state and record the exact secure OS revision
> > > > > > > even after the dmesg/journalctl logs have rolled over. This would significantly
> > > > > > > improve bug triage and regression tracking.
> > > > > > >
> > > > > > > In my case, I have a package with precompiled xtest binaries for multiple
> > > > > > > releases (from 3.14 to 4.6), and I work with different platforms that run
> > > > > > > different OP-TEE OS versions. Having a reliable way to obtain the TEE
> > > > > > > revision would help a lot, as it would allow me to select the correct xtest
> > > > > > > version when running tests.
> > > > > >
> > > > > > I'm concerned that the ABI might be misused to be part of what the
> > > > > > client expects from the TEE. You even express that as a use case. I'd
> > > > > > rather fix the problem with xtest.
> > > > >
> > > > > Thanks for the feedback! To clarify: currently, the OP-TEE OS revision
> > > > > I expose in
> > > > > sysfs is the same value already printed in dmesg at boot
> > > > >  (e.g., “optee: revision 4.8 (XXXXXX)”).
> > > > >
> > > > > Are your concerns specifically about clients inferring capabilities
> > > > > from a revision
> > > > > string (“rev X.Y implies feature Z”)? If so, I agree that’s fragile
> > > > > and not the intent.
> > > >
> > > > Yes
> > >
> > > Thanks for clarifying the concern!
> > >
> > > >
> > > > > I’m happy to add a short note in the doc that this is informational
> > > > > only and that
> > > > > feature detection must use proper capability queries.
> > > > >
> > > > > Please let me know if that addresses the worry, or if there’s another
> > > > > concern I’m
> > > > > missing.
> > > >
> > > > Adding APIs that aren't supposed to be used seems odd. Do you know if
> > > > there are examples in the kernel for this kind of thing?
> > > I’ve done some research and, as far as I can tell, the TEE core already
> > > provides an informational-only file at /sys/class/tee/tee0/implementation_id.
> > > My understanding is that it was introduced roughly 10 years ago. However,
> > > I haven’t found any documentation clarifying its intended purpose, so I’m
> > > assuming this may be a similar situation. I’d appreciate it if you could correct
> > > me if I’m wrong.
> >
> > That one is for a quick way for a client to tell the different TEE
> > device implementations apart. You're right, it resembles your case,
> > except that this is part of a well-defined ABI.
> >
> > >
> > > Also, here are some files with similiar purposes:
> > > - /sys/devices/system/cpu/cpu*/microcode/version
> > > - /sys/devices/virtual/dmi/id/{bios_date,bios_release,bios_vendor,bios_version}
> > > - /sys/kernel/security/apparmor/revision
> >
> > Thanks, this is good background information.
> >
> > We have a BoF session on the TEE subsystem at LPC on Friday [1]. We'll
> > take the opportunity to discuss it there.
>
> Just a quick follow-up on this patch, has there been any decision or
> direction from that discussion?
> I’m happy to rework the patch in whatever direction the group prefers.

No one was against it. We didn't discuss the details, but here's what
I'd like to see:
- The callback name should be get_tee_revision() or get_tee_fw_version()
- The FW version is returned as a string for flexibility
- A note that the FW version is not intended to be used to determine
what features, etc, are available, TEE_IOC_VERSION should cover that.

Sumit, what do you think?

Cheers,
Jens

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

* Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
  2025-12-22  8:34                       ` Jens Wiklander
@ 2025-12-22 10:07                         ` Sumit Garg
  0 siblings, 0 replies; 42+ messages in thread
From: Sumit Garg @ 2025-12-22 10:07 UTC (permalink / raw)
  To: Jens Wiklander
  Cc: Aristo Chen, linux-kernel, op-tee, harshal.dev, Aristo Chen,
	mario.limonciello, Rijo Thomas, Amirreza Zarrabi

On Mon, Dec 22, 2025 at 09:34:24AM +0100, Jens Wiklander wrote:
> Hi Aristo,
> 
> On Fri, Dec 19, 2025 at 4:39 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> >
> > Hi Jens
> >
> > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月9日週二 下午4:31寫道:
> > >
> > > Hi Aristo,
> > >
> > > On Sun, Dec 7, 2025 at 3:01 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > >
> > > > Hi Jens,
> > > >
> > > > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月3日週三 下午3:51寫道:
> > > > >
> > > > > Hi,
> > > > >
> > > > > On Tue, Dec 2, 2025 at 10:54 AM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > > > >
> > > > > > Hi Jens
> > > > > >
> > > > > > Jens Wiklander <jens.wiklander@linaro.org> 於 2025年12月1日週一 下午9:06寫道:
> > > > > > >
> > > > > > > Hi,
> > > > > > >
> > > > > > > On Mon, Dec 1, 2025 at 12:48 PM Aristo Chen <jj251510319013@gmail.com> wrote:
> > > > > > > >
> > > > > > > > Hi,
> > > > > > > >
> > > > > > > > Sumit Garg <sumit.garg@kernel.org> 於 2025年11月25日週二 下午3:55寫道:
> > > > > > > > >
> > > > > > > > > On Tue, Nov 25, 2025 at 01:23:22PM +0530, Sumit Garg via OP-TEE wrote:
> > > > > > > > > > On Mon, Nov 24, 2025 at 08:15:04AM +0100, Jens Wiklander wrote:
> > > > > > > > > > > Hi,
> > > > > > > > > > >
> > > > > > > > > > > On Sat, Nov 22, 2025 at 4:00 PM Wei Ming Chen <jj251510319013@gmail.com> wrote:
> > > > > > > > > > > >
> > > > > > > > > > > > From: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > > > > >
> > > > > > > > > > > > Today the only way to read the OP-TEE OS version is from dmesg/journal
> > > > > > > > > > > > logs, which can be lost as buffers roll over. Capture the OS revision
> > > > > > > > > > > > (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> > > > > > > > > > > > it in the OP-TEE driver, and expose a stable userspace readout via
> > > > > > > > > > > > /sys/class/tee/tee*/optee_os_revision.
> > > > > > > > > > > >
> > > > > > > > > > > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > > > > > > > > > > ---
> > > > > > > > > > > >  drivers/tee/optee/core.c          | 19 +++++++++++++++++++
> > > > > > > > > > > >  drivers/tee/optee/ffa_abi.c       | 13 +++++++++++--
> > > > > > > > > > > >  drivers/tee/optee/optee_private.h | 17 +++++++++++++++++
> > > > > > > > > > > >  drivers/tee/optee/smc_abi.c       | 13 +++++++++++--
> > > > > > > > > > > >  4 files changed, 58 insertions(+), 4 deletions(-)
> > > > > > > > > > >
> > > > > > > > > > > This appears to be a feature that could be useful for all TEEs.
> > > > > > > > > >
> > > > > > > > > > True, it is something that TEE core should support. Although I would
> > > > > > > > > > have preferred to extend TEE_IOC_VERSION since that's the common way the
> > > > > > > > > > user-space library get's TEE implementation specific information. But
> > > > > > > > > > since it being already a user-space ABI which doesn't offer extension.
> > > > > > > > > > Maybe we can consider adding TEE_IOC_REVERSION instead of sysfs.
> > > > > > > > >
> > > > > > > > > Ah, typo here:
> > > > > > > > >
> > > > > > > > > s/TEE_IOC_REVERSION/TEE_IOC_REVISION/
> > > > > > > > >
> > > > > > > > > -Sumit
> > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > But before doing that we need to know who is the actual consumer here
> > > > > > > > > > from user-space perspective? Will the client applications also depend on
> > > > > > > > > > the TEE implementation revision?
> > > > > > > > My current thinking is that if the TEE revision is exposed, users can write a
> > > > > > > > script to capture the platform state and record the exact secure OS revision
> > > > > > > > even after the dmesg/journalctl logs have rolled over. This would significantly
> > > > > > > > improve bug triage and regression tracking.
> > > > > > > >
> > > > > > > > In my case, I have a package with precompiled xtest binaries for multiple
> > > > > > > > releases (from 3.14 to 4.6), and I work with different platforms that run
> > > > > > > > different OP-TEE OS versions. Having a reliable way to obtain the TEE
> > > > > > > > revision would help a lot, as it would allow me to select the correct xtest
> > > > > > > > version when running tests.
> > > > > > >
> > > > > > > I'm concerned that the ABI might be misused to be part of what the
> > > > > > > client expects from the TEE. You even express that as a use case. I'd
> > > > > > > rather fix the problem with xtest.
> > > > > >
> > > > > > Thanks for the feedback! To clarify: currently, the OP-TEE OS revision
> > > > > > I expose in
> > > > > > sysfs is the same value already printed in dmesg at boot
> > > > > >  (e.g., “optee: revision 4.8 (XXXXXX)”).
> > > > > >
> > > > > > Are your concerns specifically about clients inferring capabilities
> > > > > > from a revision
> > > > > > string (“rev X.Y implies feature Z”)? If so, I agree that’s fragile
> > > > > > and not the intent.
> > > > >
> > > > > Yes
> > > >
> > > > Thanks for clarifying the concern!
> > > >
> > > > >
> > > > > > I’m happy to add a short note in the doc that this is informational
> > > > > > only and that
> > > > > > feature detection must use proper capability queries.
> > > > > >
> > > > > > Please let me know if that addresses the worry, or if there’s another
> > > > > > concern I’m
> > > > > > missing.
> > > > >
> > > > > Adding APIs that aren't supposed to be used seems odd. Do you know if
> > > > > there are examples in the kernel for this kind of thing?
> > > > I’ve done some research and, as far as I can tell, the TEE core already
> > > > provides an informational-only file at /sys/class/tee/tee0/implementation_id.
> > > > My understanding is that it was introduced roughly 10 years ago. However,
> > > > I haven’t found any documentation clarifying its intended purpose, so I’m
> > > > assuming this may be a similar situation. I’d appreciate it if you could correct
> > > > me if I’m wrong.
> > >
> > > That one is for a quick way for a client to tell the different TEE
> > > device implementations apart. You're right, it resembles your case,
> > > except that this is part of a well-defined ABI.
> > >
> > > >
> > > > Also, here are some files with similiar purposes:
> > > > - /sys/devices/system/cpu/cpu*/microcode/version
> > > > - /sys/devices/virtual/dmi/id/{bios_date,bios_release,bios_vendor,bios_version}
> > > > - /sys/kernel/security/apparmor/revision
> > >
> > > Thanks, this is good background information.
> > >
> > > We have a BoF session on the TEE subsystem at LPC on Friday [1]. We'll
> > > take the opportunity to discuss it there.
> >
> > Just a quick follow-up on this patch, has there been any decision or
> > direction from that discussion?
> > I’m happy to rework the patch in whatever direction the group prefers.
> 
> No one was against it. We didn't discuss the details, but here's what
> I'd like to see:
> - The callback name should be get_tee_revision() or get_tee_fw_version()
> - The FW version is returned as a string for flexibility
> - A note that the FW version is not intended to be used to determine
> what features, etc, are available, TEE_IOC_VERSION should cover that.
> 
> Sumit, what do you think?

That sounds reasonable to me.

-Sumit

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

* [PATCH v3 1/1] tee: optee: expose OS revision via sysfs
  2025-11-22 14:59 ` [PATCH v2 " Wei Ming Chen
  2025-11-24  7:15   ` Jens Wiklander
@ 2025-12-26 13:19   ` Aristo Chen
  2025-12-29  4:59     ` Sumit Garg
  2025-12-30  5:17     ` [PATCH v4 1/2] tee: add revision sysfs attribute Aristo Chen
  1 sibling, 2 replies; 42+ messages in thread
From: Aristo Chen @ 2025-12-26 13:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Today the only way to read the OP-TEE OS version is from dmesg/journal
logs, which can be lost as buffers roll over. Capture the OS revision
(major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
it in the OP-TEE driver, and expose a stable userspace readout via
/sys/class/tee/tee*/revision.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 Documentation/ABI/testing/sysfs-class-tee | 10 +++++
 drivers/tee/optee/core.c                  | 22 ++++++++++
 drivers/tee/optee/ffa_abi.c               | 25 ++++++++++-
 drivers/tee/optee/optee_private.h         | 19 +++++++++
 drivers/tee/optee/smc_abi.c               | 25 ++++++++++-
 drivers/tee/tee_core.c                    | 52 ++++++++++++++++++++++-
 include/linux/tee_core.h                  |  5 +++
 include/linux/tee_drv.h                   |  3 ++
 8 files changed, 156 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
index c9144d16003e..6e783210104e 100644
--- a/Documentation/ABI/testing/sysfs-class-tee
+++ b/Documentation/ABI/testing/sysfs-class-tee
@@ -13,3 +13,13 @@ Description:
 		space if the variable is absent. The primary purpose
 		of this variable is to let systemd know whether
 		tee-supplicant is needed in the early boot with initramfs.
+
+What:		/sys/class/tee/tee{,priv}X/revision
+Date:		Dec 2025
+KernelVersion:	6.18
+Contact:	op-tee@lists.trustedfirmware.org
+Description:
+		Read-only revision string reported by the TEE driver. This is
+		for diagnostics only and must not be used to infer feature
+		support. Use TEE_IOC_VERSION for capability and compatibility
+		checks.
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 5b62139714ce..58ee9ac0e467 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -63,6 +63,28 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
 	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
 }
 
+int optee_get_revision(struct optee *optee, char *buf, size_t len)
+{
+	u64 build_id;
+
+	if (!optee)
+		return -ENODEV;
+	if (!buf || !len)
+		return -EINVAL;
+
+	build_id = optee->revision.os_build_id;
+	if (build_id)
+		scnprintf(buf, len, "%u.%u (%016llx)",
+			  optee->revision.os_major,
+			  optee->revision.os_minor,
+			  (unsigned long long)build_id);
+	else
+		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
+			  optee->revision.os_minor);
+
+	return 0;
+}
+
 static void optee_bus_scan(struct work_struct *work)
 {
 	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index bf8390789ecf..0a2990c2491e 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
  */
 
 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
-					const struct ffa_ops *ops)
+					const struct ffa_ops *ops,
+					struct optee_revision *revision)
 {
 	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
 	struct ffa_send_direct_data data = {
@@ -806,6 +807,12 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 		pr_err("Unexpected error %d\n", rc);
 		return false;
 	}
+	if (revision) {
+		revision->os_major = data.data0;
+		revision->os_minor = data.data1;
+		revision->os_build_id = data.data2;
+	}
+
 	if (data.data2)
 		pr_info("revision %lu.%lu (%08lx)",
 			data.data0, data.data1, data.data2);
@@ -898,8 +905,12 @@ static int optee_ffa_open(struct tee_context *ctx)
 	return optee_open(ctx, true);
 }
 
+static int optee_ffa_get_tee_revision(struct tee_device *teedev,
+				      char *buf, size_t len);
+
 static const struct tee_driver_ops optee_ffa_clnt_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_ffa_get_tee_revision,
 	.open = optee_ffa_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -918,6 +929,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
 
 static const struct tee_driver_ops optee_ffa_supp_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_ffa_get_tee_revision,
 	.open = optee_ffa_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1034,6 +1046,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 {
 	const struct ffa_notifier_ops *notif_ops;
 	const struct ffa_ops *ffa_ops;
+	struct optee_revision revision = { };
 	unsigned int max_notif_value;
 	unsigned int rpc_param_count;
 	struct tee_shm_pool *pool;
@@ -1047,7 +1060,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	ffa_ops = ffa_dev->ops;
 	notif_ops = ffa_ops->notifier_ops;
 
-	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
+	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &revision))
 		return -EINVAL;
 
 	if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
@@ -1059,6 +1072,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
 	if (!optee)
 		return -ENOMEM;
+	optee->revision = revision;
 
 	pool = optee_ffa_shm_pool_alloc_pages();
 	if (IS_ERR(pool)) {
@@ -1194,3 +1208,10 @@ void optee_ffa_abi_unregister(void)
 	if (IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT))
 		ffa_unregister(&optee_ffa_driver);
 }
+static int optee_ffa_get_tee_revision(struct tee_device *teedev,
+				      char *buf, size_t len)
+{
+	struct optee *optee = tee_get_drvdata(teedev);
+
+	return optee_get_revision(optee, buf, len);
+}
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index db9ea673fbca..8d65f8b16b4a 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -171,6 +171,24 @@ struct optee_ffa {
 
 struct optee;
 
+/**
+ * struct optee_revision - OP-TEE OS revision reported by secure world
+ * @os_major:		OP-TEE OS major version
+ * @os_minor:		OP-TEE OS minor version
+ * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
+ *
+ * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
+ * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
+ * FF-A ABI version.
+ */
+struct optee_revision {
+	u32 os_major;
+	u32 os_minor;
+	u64 os_build_id;
+};
+
+int optee_get_revision(struct optee *optee, char *buf, size_t len);
+
 /**
  * struct optee_ops - OP-TEE driver internal operations
  * @do_call_with_arg:	enters OP-TEE in secure world
@@ -249,6 +267,7 @@ struct optee {
 	bool in_kernel_rpmb_routing;
 	struct work_struct scan_bus_work;
 	struct work_struct rpmb_scan_bus_work;
+	struct optee_revision revision;
 };
 
 struct optee_session {
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 0be663fcd52b..4dc2c16147ee 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -1240,8 +1240,12 @@ static int optee_smc_open(struct tee_context *ctx)
 	return optee_open(ctx, sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL);
 }
 
+static int optee_get_tee_revision(struct tee_device *teedev,
+				  char *buf, size_t len);
+
 static const struct tee_driver_ops optee_clnt_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_tee_revision,
 	.open = optee_smc_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -1261,6 +1265,7 @@ static const struct tee_desc optee_clnt_desc = {
 
 static const struct tee_driver_ops optee_supp_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_tee_revision,
 	.open = optee_smc_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1323,7 +1328,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
 }
 #endif
 
-static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
+static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
+				      struct optee_revision *revision)
 {
 	union {
 		struct arm_smccc_res smccc;
@@ -1337,6 +1343,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
 		  &res.smccc);
 
+	if (revision) {
+		revision->os_major = res.result.major;
+		revision->os_minor = res.result.minor;
+		revision->os_build_id = res.result.build_id;
+	}
+
 	if (res.result.build_id)
 		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
 			res.result.minor, (int)sizeof(res.result.build_id) * 2,
@@ -1727,6 +1739,7 @@ static int optee_probe(struct platform_device *pdev)
 	unsigned int thread_count;
 	struct tee_device *teedev;
 	struct tee_context *ctx;
+	struct optee_revision revision = { };
 	u32 max_notif_value;
 	u32 arg_cache_flags;
 	u32 sec_caps;
@@ -1745,7 +1758,7 @@ static int optee_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	optee_msg_get_os_revision(invoke_fn);
+	optee_msg_get_os_revision(invoke_fn, &revision);
 
 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
 		pr_warn("api revision mismatch\n");
@@ -1814,6 +1827,7 @@ static int optee_probe(struct platform_device *pdev)
 		rc = -ENOMEM;
 		goto err_free_shm_pool;
 	}
+	optee->revision = revision;
 
 	optee->ops = &optee_ops;
 	optee->smc.invoke_fn = invoke_fn;
@@ -1971,3 +1985,10 @@ void optee_smc_abi_unregister(void)
 {
 	platform_driver_unregister(&optee_driver);
 }
+static int optee_get_tee_revision(struct tee_device *teedev,
+				  char *buf, size_t len)
+{
+	struct optee *optee = tee_get_drvdata(teedev);
+
+	return optee_get_revision(optee, buf, len);
+}
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index d65d47cc154e..0ba0e16462b9 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -13,6 +13,7 @@
 #include <linux/overflow.h>
 #include <linux/slab.h>
 #include <linux/tee_core.h>
+#include <linux/tee_drv.h>
 #include <linux/uaccess.h>
 #include <crypto/sha1.h>
 #include "tee_private.h"
@@ -1146,7 +1147,56 @@ static struct attribute *tee_dev_attrs[] = {
 	NULL
 };
 
-ATTRIBUTE_GROUPS(tee_dev);
+static const struct attribute_group tee_dev_group = {
+	.attrs = tee_dev_attrs,
+};
+
+static ssize_t revision_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+	char version[TEE_REVISION_STR_SIZE];
+	int ret;
+
+	if (!teedev->desc->ops->get_tee_revision)
+		return -ENODEV;
+
+	ret = teedev->desc->ops->get_tee_revision(teedev, version,
+						  sizeof(version));
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%s\n", version);
+}
+static DEVICE_ATTR_RO(revision);
+
+static struct attribute *tee_revision_attrs[] = {
+	&dev_attr_revision.attr,
+	NULL
+};
+
+static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
+					    struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+	if (teedev->desc->ops->get_tee_revision)
+		return attr->mode;
+
+	return 0;
+}
+
+static const struct attribute_group tee_revision_group = {
+	.attrs = tee_revision_attrs,
+	.is_visible = tee_revision_attr_is_visible,
+};
+
+static const struct attribute_group *tee_dev_groups[] = {
+	&tee_dev_group,
+	&tee_revision_group,
+	NULL
+};
 
 static const struct class tee_class = {
 	.name = "tee",
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
index 1f3e5dad6d0d..de11612afa62 100644
--- a/include/linux/tee_core.h
+++ b/include/linux/tee_core.h
@@ -76,6 +76,9 @@ struct tee_device {
 /**
  * struct tee_driver_ops - driver operations vtable
  * @get_version:	returns version of driver
+ * @get_tee_revision:	returns revision string (diagnostic only);
+ *			do not infer feature support from this, use
+ *			TEE_IOC_VERSION instead
  * @open:		called for a context when the device file is opened
  * @close_context:	called when the device file is closed
  * @release:		called to release the context
@@ -98,6 +101,8 @@ struct tee_device {
 struct tee_driver_ops {
 	void (*get_version)(struct tee_device *teedev,
 			    struct tee_ioctl_version_data *vers);
+	int (*get_tee_revision)(struct tee_device *teedev,
+				char *buf, size_t len);
 	int (*open)(struct tee_context *ctx);
 	void (*close_context)(struct tee_context *ctx);
 	void (*release)(struct tee_context *ctx);
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 88a6f9697c89..e76238d435ce 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -322,4 +322,7 @@ struct tee_client_driver {
 #define to_tee_client_driver(d) \
 		container_of_const(d, struct tee_client_driver, driver)
 
+/* Size for TEE revision string buffer used by get_tee_revision(). */
+#define TEE_REVISION_STR_SIZE	128
+
 #endif /*__TEE_DRV_H*/
-- 
2.43.0


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

* Re: [PATCH v3 1/1] tee: optee: expose OS revision via sysfs
  2025-12-26 13:19   ` [PATCH v3 " Aristo Chen
@ 2025-12-29  4:59     ` Sumit Garg
  2025-12-30  5:17     ` [PATCH v4 1/2] tee: add revision sysfs attribute Aristo Chen
  1 sibling, 0 replies; 42+ messages in thread
From: Sumit Garg @ 2025-12-29  4:59 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Hi Aristo,

On Fri, Dec 26, 2025 at 09:19:13PM +0800, Aristo Chen wrote:
> Today the only way to read the OP-TEE OS version is from dmesg/journal
> logs, which can be lost as buffers roll over. Capture the OS revision
> (major/minor/build_id) from secure world for both SMC and FF-A ABIs, store
> it in the OP-TEE driver, and expose a stable userspace readout via
> /sys/class/tee/tee*/revision.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  Documentation/ABI/testing/sysfs-class-tee | 10 +++++
>  drivers/tee/optee/core.c                  | 22 ++++++++++
>  drivers/tee/optee/ffa_abi.c               | 25 ++++++++++-
>  drivers/tee/optee/optee_private.h         | 19 +++++++++
>  drivers/tee/optee/smc_abi.c               | 25 ++++++++++-
>  drivers/tee/tee_core.c                    | 52 ++++++++++++++++++++++-
>  include/linux/tee_core.h                  |  5 +++
>  include/linux/tee_drv.h                   |  3 ++
>  8 files changed, 156 insertions(+), 5 deletions(-)

Please split up this patch properly as to what goes into the generic TEE
driver vs the OP-TEE changes.

> 
> diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
> index c9144d16003e..6e783210104e 100644
> --- a/Documentation/ABI/testing/sysfs-class-tee
> +++ b/Documentation/ABI/testing/sysfs-class-tee
> @@ -13,3 +13,13 @@ Description:
>  		space if the variable is absent. The primary purpose
>  		of this variable is to let systemd know whether
>  		tee-supplicant is needed in the early boot with initramfs.
> +
> +What:		/sys/class/tee/tee{,priv}X/revision
> +Date:		Dec 2025
> +KernelVersion:	6.18
> +Contact:	op-tee@lists.trustedfirmware.org
> +Description:
> +		Read-only revision string reported by the TEE driver. This is
> +		for diagnostics only and must not be used to infer feature
> +		support. Use TEE_IOC_VERSION for capability and compatibility
> +		checks.
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index 5b62139714ce..58ee9ac0e467 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -63,6 +63,28 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
>  	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
>  }
>  
> +int optee_get_revision(struct optee *optee, char *buf, size_t len)
> +{
> +	u64 build_id;
> +
> +	if (!optee)
> +		return -ENODEV;
> +	if (!buf || !len)
> +		return -EINVAL;
> +
> +	build_id = optee->revision.os_build_id;
> +	if (build_id)
> +		scnprintf(buf, len, "%u.%u (%016llx)",
> +			  optee->revision.os_major,
> +			  optee->revision.os_minor,
> +			  (unsigned long long)build_id);
> +	else
> +		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> +			  optee->revision.os_minor);
> +
> +	return 0;
> +}
> +
>  static void optee_bus_scan(struct work_struct *work)
>  {
>  	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> index bf8390789ecf..0a2990c2491e 100644
> --- a/drivers/tee/optee/ffa_abi.c
> +++ b/drivers/tee/optee/ffa_abi.c
> @@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
>   */
>  
>  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> -					const struct ffa_ops *ops)
> +					const struct ffa_ops *ops,
> +					struct optee_revision *revision)
>  {
>  	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
>  	struct ffa_send_direct_data data = {
> @@ -806,6 +807,12 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>  		pr_err("Unexpected error %d\n", rc);
>  		return false;
>  	}
> +	if (revision) {
> +		revision->os_major = data.data0;
> +		revision->os_minor = data.data1;
> +		revision->os_build_id = data.data2;
> +	}
> +
>  	if (data.data2)
>  		pr_info("revision %lu.%lu (%08lx)",
>  			data.data0, data.data1, data.data2);
> @@ -898,8 +905,12 @@ static int optee_ffa_open(struct tee_context *ctx)
>  	return optee_open(ctx, true);
>  }
>  
> +static int optee_ffa_get_tee_revision(struct tee_device *teedev,
> +				      char *buf, size_t len);

I don't think you need a wrapper here but insted you can just use the
generic optee_get_revision() callback.

> +
>  static const struct tee_driver_ops optee_ffa_clnt_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_ffa_get_tee_revision,

This will then become:

        .get_tee_revision = optee_get_revision,

>  	.open = optee_ffa_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -918,6 +929,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_ffa_supp_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_ffa_get_tee_revision,

ditto.

>  	.open = optee_ffa_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1034,6 +1046,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  {
>  	const struct ffa_notifier_ops *notif_ops;
>  	const struct ffa_ops *ffa_ops;
> +	struct optee_revision revision = { };
>  	unsigned int max_notif_value;
>  	unsigned int rpc_param_count;
>  	struct tee_shm_pool *pool;
> @@ -1047,7 +1060,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  	ffa_ops = ffa_dev->ops;
>  	notif_ops = ffa_ops->notifier_ops;
>  
> -	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
> +	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &revision))
>  		return -EINVAL;
>  
>  	if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
> @@ -1059,6 +1072,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
>  	if (!optee)
>  		return -ENOMEM;
> +	optee->revision = revision;
>  
>  	pool = optee_ffa_shm_pool_alloc_pages();
>  	if (IS_ERR(pool)) {
> @@ -1194,3 +1208,10 @@ void optee_ffa_abi_unregister(void)
>  	if (IS_REACHABLE(CONFIG_ARM_FFA_TRANSPORT))
>  		ffa_unregister(&optee_ffa_driver);
>  }
> +static int optee_ffa_get_tee_revision(struct tee_device *teedev,
> +				      char *buf, size_t len)
> +{
> +	struct optee *optee = tee_get_drvdata(teedev);
> +
> +	return optee_get_revision(optee, buf, len);
> +}
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index db9ea673fbca..8d65f8b16b4a 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -171,6 +171,24 @@ struct optee_ffa {
>  
>  struct optee;
>  
> +/**
> + * struct optee_revision - OP-TEE OS revision reported by secure world
> + * @os_major:		OP-TEE OS major version
> + * @os_minor:		OP-TEE OS minor version
> + * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
> + *
> + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> + * FF-A ABI version.
> + */
> +struct optee_revision {
> +	u32 os_major;
> +	u32 os_minor;
> +	u64 os_build_id;
> +};
> +
> +int optee_get_revision(struct optee *optee, char *buf, size_t len);
> +
>  /**
>   * struct optee_ops - OP-TEE driver internal operations
>   * @do_call_with_arg:	enters OP-TEE in secure world
> @@ -249,6 +267,7 @@ struct optee {
>  	bool in_kernel_rpmb_routing;
>  	struct work_struct scan_bus_work;
>  	struct work_struct rpmb_scan_bus_work;
> +	struct optee_revision revision;
>  };
>  
>  struct optee_session {
> diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> index 0be663fcd52b..4dc2c16147ee 100644
> --- a/drivers/tee/optee/smc_abi.c
> +++ b/drivers/tee/optee/smc_abi.c
> @@ -1240,8 +1240,12 @@ static int optee_smc_open(struct tee_context *ctx)
>  	return optee_open(ctx, sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL);
>  }
>  
> +static int optee_get_tee_revision(struct tee_device *teedev,
> +				  char *buf, size_t len);
> +
>  static const struct tee_driver_ops optee_clnt_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_tee_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -1261,6 +1265,7 @@ static const struct tee_desc optee_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_supp_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_tee_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1323,7 +1328,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
>  }
>  #endif
>  
> -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> +				      struct optee_revision *revision)
>  {
>  	union {
>  		struct arm_smccc_res smccc;
> @@ -1337,6 +1343,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
>  	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
>  		  &res.smccc);
>  
> +	if (revision) {
> +		revision->os_major = res.result.major;
> +		revision->os_minor = res.result.minor;
> +		revision->os_build_id = res.result.build_id;
> +	}
> +
>  	if (res.result.build_id)
>  		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
>  			res.result.minor, (int)sizeof(res.result.build_id) * 2,
> @@ -1727,6 +1739,7 @@ static int optee_probe(struct platform_device *pdev)
>  	unsigned int thread_count;
>  	struct tee_device *teedev;
>  	struct tee_context *ctx;
> +	struct optee_revision revision = { };
>  	u32 max_notif_value;
>  	u32 arg_cache_flags;
>  	u32 sec_caps;
> @@ -1745,7 +1758,7 @@ static int optee_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> -	optee_msg_get_os_revision(invoke_fn);
> +	optee_msg_get_os_revision(invoke_fn, &revision);
>  
>  	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
>  		pr_warn("api revision mismatch\n");
> @@ -1814,6 +1827,7 @@ static int optee_probe(struct platform_device *pdev)
>  		rc = -ENOMEM;
>  		goto err_free_shm_pool;
>  	}
> +	optee->revision = revision;
>  
>  	optee->ops = &optee_ops;
>  	optee->smc.invoke_fn = invoke_fn;
> @@ -1971,3 +1985,10 @@ void optee_smc_abi_unregister(void)
>  {
>  	platform_driver_unregister(&optee_driver);
>  }
> +static int optee_get_tee_revision(struct tee_device *teedev,
> +				  char *buf, size_t len)

Ditto here, you don't need this extra wrapper here.

> +{
> +	struct optee *optee = tee_get_drvdata(teedev);
> +
> +	return optee_get_revision(optee, buf, len);
> +}
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index d65d47cc154e..0ba0e16462b9 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -13,6 +13,7 @@
>  #include <linux/overflow.h>
>  #include <linux/slab.h>
>  #include <linux/tee_core.h>
> +#include <linux/tee_drv.h>

This include is rather meant for TEE client drivers, don't include it
here. Instead use linux/tee_core.h.

>  #include <linux/uaccess.h>
>  #include <crypto/sha1.h>
>  #include "tee_private.h"
> @@ -1146,7 +1147,56 @@ static struct attribute *tee_dev_attrs[] = {
>  	NULL
>  };
>  
> -ATTRIBUTE_GROUPS(tee_dev);
> +static const struct attribute_group tee_dev_group = {
> +	.attrs = tee_dev_attrs,
> +};
> +
> +static ssize_t revision_show(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +	char version[TEE_REVISION_STR_SIZE];
> +	int ret;
> +
> +	if (!teedev->desc->ops->get_tee_revision)
> +		return -ENODEV;
> +
> +	ret = teedev->desc->ops->get_tee_revision(teedev, version,
> +						  sizeof(version));
> +	if (ret)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%s\n", version);
> +}
> +static DEVICE_ATTR_RO(revision);
> +
> +static struct attribute *tee_revision_attrs[] = {
> +	&dev_attr_revision.attr,
> +	NULL
> +};
> +
> +static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
> +					    struct attribute *attr, int n)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +
> +	if (teedev->desc->ops->get_tee_revision)
> +		return attr->mode;
> +
> +	return 0;
> +}
> +
> +static const struct attribute_group tee_revision_group = {
> +	.attrs = tee_revision_attrs,
> +	.is_visible = tee_revision_attr_is_visible,
> +};
> +
> +static const struct attribute_group *tee_dev_groups[] = {
> +	&tee_dev_group,
> +	&tee_revision_group,
> +	NULL
> +};
>  
>  static const struct class tee_class = {
>  	.name = "tee",
> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
> index 1f3e5dad6d0d..de11612afa62 100644
> --- a/include/linux/tee_core.h
> +++ b/include/linux/tee_core.h
> @@ -76,6 +76,9 @@ struct tee_device {
>  /**
>   * struct tee_driver_ops - driver operations vtable
>   * @get_version:	returns version of driver
> + * @get_tee_revision:	returns revision string (diagnostic only);
> + *			do not infer feature support from this, use
> + *			TEE_IOC_VERSION instead
>   * @open:		called for a context when the device file is opened
>   * @close_context:	called when the device file is closed
>   * @release:		called to release the context
> @@ -98,6 +101,8 @@ struct tee_device {
>  struct tee_driver_ops {
>  	void (*get_version)(struct tee_device *teedev,
>  			    struct tee_ioctl_version_data *vers);
> +	int (*get_tee_revision)(struct tee_device *teedev,
> +				char *buf, size_t len);
>  	int (*open)(struct tee_context *ctx);
>  	void (*close_context)(struct tee_context *ctx);
>  	void (*release)(struct tee_context *ctx);
> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
> index 88a6f9697c89..e76238d435ce 100644
> --- a/include/linux/tee_drv.h
> +++ b/include/linux/tee_drv.h
> @@ -322,4 +322,7 @@ struct tee_client_driver {
>  #define to_tee_client_driver(d) \
>  		container_of_const(d, struct tee_client_driver, driver)
>  
> +/* Size for TEE revision string buffer used by get_tee_revision(). */
> +#define TEE_REVISION_STR_SIZE	128

This should rather go to linux/tee_core.h.

-Sumit

> +
>  #endif /*__TEE_DRV_H*/
> -- 
> 2.43.0
> 

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

* [PATCH v4 1/2] tee: add revision sysfs attribute
  2025-12-26 13:19   ` [PATCH v3 " Aristo Chen
  2025-12-29  4:59     ` Sumit Garg
@ 2025-12-30  5:17     ` Aristo Chen
  2025-12-30  5:17       ` [PATCH v4 2/2] tee: optee: store OS revision for TEE core Aristo Chen
                         ` (2 more replies)
  1 sibling, 3 replies; 42+ messages in thread
From: Aristo Chen @ 2025-12-30  5:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Add a generic TEE revision sysfs attribute backed by a new optional
get_tee_revision() callback. The revision string is diagnostic-only and
must not be used to infer feature support.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 Documentation/ABI/testing/sysfs-class-tee | 10 +++++
 drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
 include/linux/tee_core.h                  |  8 ++++
 3 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
index c9144d16003e..6e783210104e 100644
--- a/Documentation/ABI/testing/sysfs-class-tee
+++ b/Documentation/ABI/testing/sysfs-class-tee
@@ -13,3 +13,13 @@ Description:
 		space if the variable is absent. The primary purpose
 		of this variable is to let systemd know whether
 		tee-supplicant is needed in the early boot with initramfs.
+
+What:		/sys/class/tee/tee{,priv}X/revision
+Date:		Dec 2025
+KernelVersion:	6.18
+Contact:	op-tee@lists.trustedfirmware.org
+Description:
+		Read-only revision string reported by the TEE driver. This is
+		for diagnostics only and must not be used to infer feature
+		support. Use TEE_IOC_VERSION for capability and compatibility
+		checks.
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index d65d47cc154e..0a00499811c1 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
 	NULL
 };
 
-ATTRIBUTE_GROUPS(tee_dev);
+static const struct attribute_group tee_dev_group = {
+	.attrs = tee_dev_attrs,
+};
+
+static ssize_t revision_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+	char version[TEE_REVISION_STR_SIZE];
+	int ret;
+
+	if (!teedev->desc->ops->get_tee_revision)
+		return -ENODEV;
+
+	ret = teedev->desc->ops->get_tee_revision(teedev, version,
+						  sizeof(version));
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%s\n", version);
+}
+static DEVICE_ATTR_RO(revision);
+
+static struct attribute *tee_revision_attrs[] = {
+	&dev_attr_revision.attr,
+	NULL
+};
+
+static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
+					    struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+	if (teedev->desc->ops->get_tee_revision)
+		return attr->mode;
+
+	return 0;
+}
+
+static const struct attribute_group tee_revision_group = {
+	.attrs = tee_revision_attrs,
+	.is_visible = tee_revision_attr_is_visible,
+};
+
+static const struct attribute_group *tee_dev_groups[] = {
+	&tee_dev_group,
+	&tee_revision_group,
+	NULL
+};
 
 static const struct class tee_class = {
 	.name = "tee",
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
index 1f3e5dad6d0d..c214c38898ca 100644
--- a/include/linux/tee_core.h
+++ b/include/linux/tee_core.h
@@ -76,6 +76,9 @@ struct tee_device {
 /**
  * struct tee_driver_ops - driver operations vtable
  * @get_version:	returns version of driver
+ * @get_tee_revision:	returns revision string (diagnostic only);
+ *			do not infer feature support from this, use
+ *			TEE_IOC_VERSION instead
  * @open:		called for a context when the device file is opened
  * @close_context:	called when the device file is closed
  * @release:		called to release the context
@@ -98,6 +101,8 @@ struct tee_device {
 struct tee_driver_ops {
 	void (*get_version)(struct tee_device *teedev,
 			    struct tee_ioctl_version_data *vers);
+	int (*get_tee_revision)(struct tee_device *teedev,
+				char *buf, size_t len);
 	int (*open)(struct tee_context *ctx);
 	void (*close_context)(struct tee_context *ctx);
 	void (*release)(struct tee_context *ctx);
@@ -292,6 +297,9 @@ struct tee_shm_pool *tee_shm_pool_alloc_res_mem(unsigned long vaddr,
 						phys_addr_t paddr, size_t size,
 						int min_alloc_order);
 
+/* Size for TEE revision string buffer used by get_tee_revision(). */
+#define TEE_REVISION_STR_SIZE	128
+
 /**
  * tee_shm_pool_free() - Free a shared memory pool
  * @pool:	The shared memory pool to free
-- 
2.43.0


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

* [PATCH v4 2/2] tee: optee: store OS revision for TEE core
  2025-12-30  5:17     ` [PATCH v4 1/2] tee: add revision sysfs attribute Aristo Chen
@ 2025-12-30  5:17       ` Aristo Chen
  2026-01-05  5:20         ` Sumit Garg
  2026-01-05  4:53       ` [PATCH v4 1/2] tee: add revision sysfs attribute Sumit Garg
  2026-01-07 15:26       ` [PATCH v5 " Aristo Chen
  2 siblings, 1 reply; 42+ messages in thread
From: Aristo Chen @ 2025-12-30  5:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Collect OP-TEE OS revision from secure world for both SMC and FF-A ABIs,
store it in the OP-TEE driver, and expose it through the generic
get_tee_revision() callback.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 drivers/tee/optee/core.c          | 23 +++++++++++++++++++++++
 drivers/tee/optee/ffa_abi.c       | 14 ++++++++++++--
 drivers/tee/optee/optee_private.h | 19 +++++++++++++++++++
 drivers/tee/optee/smc_abi.c       | 15 +++++++++++++--
 4 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 5b62139714ce..2d807bc748bc 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
 	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
 }
 
+int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
+{
+	struct optee *optee = tee_get_drvdata(teedev);
+	u64 build_id;
+
+	if (!optee)
+		return -ENODEV;
+	if (!buf || !len)
+		return -EINVAL;
+
+	build_id = optee->revision.os_build_id;
+	if (build_id)
+		scnprintf(buf, len, "%u.%u (%016llx)",
+			  optee->revision.os_major,
+			  optee->revision.os_minor,
+			  (unsigned long long)build_id);
+	else
+		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
+			  optee->revision.os_minor);
+
+	return 0;
+}
+
 static void optee_bus_scan(struct work_struct *work)
 {
 	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index bf8390789ecf..d67ca1ec9506 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
  */
 
 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
-					const struct ffa_ops *ops)
+					const struct ffa_ops *ops,
+					struct optee_revision *revision)
 {
 	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
 	struct ffa_send_direct_data data = {
@@ -806,6 +807,11 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 		pr_err("Unexpected error %d\n", rc);
 		return false;
 	}
+	if (revision) {
+		revision->os_major = data.data0;
+		revision->os_minor = data.data1;
+		revision->os_build_id = data.data2;
+	}
 	if (data.data2)
 		pr_info("revision %lu.%lu (%08lx)",
 			data.data0, data.data1, data.data2);
@@ -900,6 +906,7 @@ static int optee_ffa_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_ffa_clnt_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_ffa_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -918,6 +925,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
 
 static const struct tee_driver_ops optee_ffa_supp_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_ffa_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1034,6 +1042,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 {
 	const struct ffa_notifier_ops *notif_ops;
 	const struct ffa_ops *ffa_ops;
+	struct optee_revision revision = { };
 	unsigned int max_notif_value;
 	unsigned int rpc_param_count;
 	struct tee_shm_pool *pool;
@@ -1047,7 +1056,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	ffa_ops = ffa_dev->ops;
 	notif_ops = ffa_ops->notifier_ops;
 
-	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
+	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &revision))
 		return -EINVAL;
 
 	if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
@@ -1059,6 +1068,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
 	if (!optee)
 		return -ENOMEM;
+	optee->revision = revision;
 
 	pool = optee_ffa_shm_pool_alloc_pages();
 	if (IS_ERR(pool)) {
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index db9ea673fbca..acd3051c4879 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -171,6 +171,24 @@ struct optee_ffa {
 
 struct optee;
 
+/**
+ * struct optee_revision - OP-TEE OS revision reported by secure world
+ * @os_major:		OP-TEE OS major version
+ * @os_minor:		OP-TEE OS minor version
+ * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
+ *
+ * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
+ * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
+ * FF-A ABI version.
+ */
+struct optee_revision {
+	u32 os_major;
+	u32 os_minor;
+	u64 os_build_id;
+};
+
+int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
+
 /**
  * struct optee_ops - OP-TEE driver internal operations
  * @do_call_with_arg:	enters OP-TEE in secure world
@@ -249,6 +267,7 @@ struct optee {
 	bool in_kernel_rpmb_routing;
 	struct work_struct scan_bus_work;
 	struct work_struct rpmb_scan_bus_work;
+	struct optee_revision revision;
 };
 
 struct optee_session {
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 0be663fcd52b..0baaf7986a35 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_clnt_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_smc_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
 
 static const struct tee_driver_ops optee_supp_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_smc_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
 }
 #endif
 
-static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
+static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
+				      struct optee_revision *revision)
 {
 	union {
 		struct arm_smccc_res smccc;
@@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
 		  &res.smccc);
 
+	if (revision) {
+		revision->os_major = res.result.major;
+		revision->os_minor = res.result.minor;
+		revision->os_build_id = res.result.build_id;
+	}
+
 	if (res.result.build_id)
 		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
 			res.result.minor, (int)sizeof(res.result.build_id) * 2,
@@ -1727,6 +1736,7 @@ static int optee_probe(struct platform_device *pdev)
 	unsigned int thread_count;
 	struct tee_device *teedev;
 	struct tee_context *ctx;
+	struct optee_revision revision = { };
 	u32 max_notif_value;
 	u32 arg_cache_flags;
 	u32 sec_caps;
@@ -1745,7 +1755,7 @@ static int optee_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	optee_msg_get_os_revision(invoke_fn);
+	optee_msg_get_os_revision(invoke_fn, &revision);
 
 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
 		pr_warn("api revision mismatch\n");
@@ -1837,6 +1847,7 @@ static int optee_probe(struct platform_device *pdev)
 		goto err_unreg_teedev;
 	}
 	optee->supp_teedev = teedev;
+	optee->revision = revision;
 
 	optee_set_dev_group(optee);
 
-- 
2.43.0


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

* Re: [PATCH v4 1/2] tee: add revision sysfs attribute
  2025-12-30  5:17     ` [PATCH v4 1/2] tee: add revision sysfs attribute Aristo Chen
  2025-12-30  5:17       ` [PATCH v4 2/2] tee: optee: store OS revision for TEE core Aristo Chen
@ 2026-01-05  4:53       ` Sumit Garg
  2026-01-07 15:26       ` [PATCH v5 " Aristo Chen
  2 siblings, 0 replies; 42+ messages in thread
From: Sumit Garg @ 2026-01-05  4:53 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

On Tue, Dec 30, 2025 at 01:17:58PM +0800, Aristo Chen wrote:
> Add a generic TEE revision sysfs attribute backed by a new optional
> get_tee_revision() callback. The revision string is diagnostic-only and
> must not be used to infer feature support.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  Documentation/ABI/testing/sysfs-class-tee | 10 +++++
>  drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
>  include/linux/tee_core.h                  |  8 ++++
>  3 files changed, 68 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
> index c9144d16003e..6e783210104e 100644
> --- a/Documentation/ABI/testing/sysfs-class-tee
> +++ b/Documentation/ABI/testing/sysfs-class-tee
> @@ -13,3 +13,13 @@ Description:
>  		space if the variable is absent. The primary purpose
>  		of this variable is to let systemd know whether
>  		tee-supplicant is needed in the early boot with initramfs.
> +
> +What:		/sys/class/tee/tee{,priv}X/revision
> +Date:		Dec 2025
> +KernelVersion:	6.18
> +Contact:	op-tee@lists.trustedfirmware.org
> +Description:
> +		Read-only revision string reported by the TEE driver. This is
> +		for diagnostics only and must not be used to infer feature
> +		support. Use TEE_IOC_VERSION for capability and compatibility
> +		checks.
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index d65d47cc154e..0a00499811c1 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
>  	NULL
>  };
>  
> -ATTRIBUTE_GROUPS(tee_dev);
> +static const struct attribute_group tee_dev_group = {
> +	.attrs = tee_dev_attrs,
> +};
> +
> +static ssize_t revision_show(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +	char version[TEE_REVISION_STR_SIZE];
> +	int ret;
> +
> +	if (!teedev->desc->ops->get_tee_revision)
> +		return -ENODEV;
> +
> +	ret = teedev->desc->ops->get_tee_revision(teedev, version,
> +						  sizeof(version));
> +	if (ret)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%s\n", version);
> +}
> +static DEVICE_ATTR_RO(revision);
> +
> +static struct attribute *tee_revision_attrs[] = {
> +	&dev_attr_revision.attr,
> +	NULL
> +};
> +
> +static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
> +					    struct attribute *attr, int n)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +
> +	if (teedev->desc->ops->get_tee_revision)
> +		return attr->mode;
> +
> +	return 0;
> +}
> +
> +static const struct attribute_group tee_revision_group = {
> +	.attrs = tee_revision_attrs,
> +	.is_visible = tee_revision_attr_is_visible,
> +};
> +
> +static const struct attribute_group *tee_dev_groups[] = {
> +	&tee_dev_group,
> +	&tee_revision_group,
> +	NULL
> +};
>  
>  static const struct class tee_class = {
>  	.name = "tee",
> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
> index 1f3e5dad6d0d..c214c38898ca 100644
> --- a/include/linux/tee_core.h
> +++ b/include/linux/tee_core.h
> @@ -76,6 +76,9 @@ struct tee_device {
>  /**
>   * struct tee_driver_ops - driver operations vtable
>   * @get_version:	returns version of driver
> + * @get_tee_revision:	returns revision string (diagnostic only);
> + *			do not infer feature support from this, use
> + *			TEE_IOC_VERSION instead
>   * @open:		called for a context when the device file is opened
>   * @close_context:	called when the device file is closed
>   * @release:		called to release the context
> @@ -98,6 +101,8 @@ struct tee_device {
>  struct tee_driver_ops {
>  	void (*get_version)(struct tee_device *teedev,
>  			    struct tee_ioctl_version_data *vers);
> +	int (*get_tee_revision)(struct tee_device *teedev,
> +				char *buf, size_t len);
>  	int (*open)(struct tee_context *ctx);
>  	void (*close_context)(struct tee_context *ctx);
>  	void (*release)(struct tee_context *ctx);
> @@ -292,6 +297,9 @@ struct tee_shm_pool *tee_shm_pool_alloc_res_mem(unsigned long vaddr,
>  						phys_addr_t paddr, size_t size,
>  						int min_alloc_order);
>  
> +/* Size for TEE revision string buffer used by get_tee_revision(). */
> +#define TEE_REVISION_STR_SIZE	128
> +

Move this macro alongside get_tee_revision() callback. With that feel
free to add:

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

-Sumit

>  /**
>   * tee_shm_pool_free() - Free a shared memory pool
>   * @pool:	The shared memory pool to free
> -- 
> 2.43.0
> 

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

* Re: [PATCH v4 2/2] tee: optee: store OS revision for TEE core
  2025-12-30  5:17       ` [PATCH v4 2/2] tee: optee: store OS revision for TEE core Aristo Chen
@ 2026-01-05  5:20         ` Sumit Garg
  2026-01-05  8:13           ` Aristo Chen
  0 siblings, 1 reply; 42+ messages in thread
From: Sumit Garg @ 2026-01-05  5:20 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

On Tue, Dec 30, 2025 at 01:17:59PM +0800, Aristo Chen wrote:
> Collect OP-TEE OS revision from secure world for both SMC and FF-A ABIs,
> store it in the OP-TEE driver, and expose it through the generic
> get_tee_revision() callback.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  drivers/tee/optee/core.c          | 23 +++++++++++++++++++++++
>  drivers/tee/optee/ffa_abi.c       | 14 ++++++++++++--
>  drivers/tee/optee/optee_private.h | 19 +++++++++++++++++++
>  drivers/tee/optee/smc_abi.c       | 15 +++++++++++++--
>  4 files changed, 67 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index 5b62139714ce..2d807bc748bc 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
>  	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
>  }
>  
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> +{
> +	struct optee *optee = tee_get_drvdata(teedev);
> +	u64 build_id;
> +
> +	if (!optee)
> +		return -ENODEV;
> +	if (!buf || !len)
> +		return -EINVAL;
> +
> +	build_id = optee->revision.os_build_id;
> +	if (build_id)
> +		scnprintf(buf, len, "%u.%u (%016llx)",
> +			  optee->revision.os_major,
> +			  optee->revision.os_minor,
> +			  (unsigned long long)build_id);
> +	else
> +		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> +			  optee->revision.os_minor);
> +
> +	return 0;
> +}
> +
>  static void optee_bus_scan(struct work_struct *work)
>  {
>  	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> index bf8390789ecf..d67ca1ec9506 100644
> --- a/drivers/tee/optee/ffa_abi.c
> +++ b/drivers/tee/optee/ffa_abi.c
> @@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
>   */
>  
>  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> -					const struct ffa_ops *ops)
> +					const struct ffa_ops *ops,
> +					struct optee_revision *revision)
>  {
>  	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
>  	struct ffa_send_direct_data data = {
> @@ -806,6 +807,11 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>  		pr_err("Unexpected error %d\n", rc);
>  		return false;
>  	}
> +	if (revision) {
> +		revision->os_major = data.data0;
> +		revision->os_minor = data.data1;
> +		revision->os_build_id = data.data2;
> +	}
>  	if (data.data2)
>  		pr_info("revision %lu.%lu (%08lx)",
>  			data.data0, data.data1, data.data2);
> @@ -900,6 +906,7 @@ static int optee_ffa_open(struct tee_context *ctx)
>  
>  static const struct tee_driver_ops optee_ffa_clnt_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_ffa_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -918,6 +925,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_ffa_supp_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_ffa_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1034,6 +1042,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  {
>  	const struct ffa_notifier_ops *notif_ops;
>  	const struct ffa_ops *ffa_ops;
> +	struct optee_revision revision = { };

No need for this redundant variable on stack when...

>  	unsigned int max_notif_value;
>  	unsigned int rpc_param_count;
>  	struct tee_shm_pool *pool;
> @@ -1047,7 +1056,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  	ffa_ops = ffa_dev->ops;
>  	notif_ops = ffa_ops->notifier_ops;
>  
> -	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
> +	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &revision))

...you can just invoke this API as rather:

	if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &optee->revision))

>  		return -EINVAL;
>  
>  	if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
> @@ -1059,6 +1068,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
>  	if (!optee)
>  		return -ENOMEM;
> +	optee->revision = revision;
>  
>  	pool = optee_ffa_shm_pool_alloc_pages();
>  	if (IS_ERR(pool)) {
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index db9ea673fbca..acd3051c4879 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -171,6 +171,24 @@ struct optee_ffa {
>  
>  struct optee;
>  
> +/**
> + * struct optee_revision - OP-TEE OS revision reported by secure world
> + * @os_major:		OP-TEE OS major version
> + * @os_minor:		OP-TEE OS minor version
> + * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
> + *
> + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> + * FF-A ABI version.
> + */
> +struct optee_revision {
> +	u32 os_major;
> +	u32 os_minor;
> +	u64 os_build_id;
> +};
> +
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> +
>  /**
>   * struct optee_ops - OP-TEE driver internal operations
>   * @do_call_with_arg:	enters OP-TEE in secure world
> @@ -249,6 +267,7 @@ struct optee {
>  	bool in_kernel_rpmb_routing;
>  	struct work_struct scan_bus_work;
>  	struct work_struct rpmb_scan_bus_work;
> +	struct optee_revision revision;
>  };
>  
>  struct optee_session {
> diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> index 0be663fcd52b..0baaf7986a35 100644
> --- a/drivers/tee/optee/smc_abi.c
> +++ b/drivers/tee/optee/smc_abi.c
> @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
>  
>  static const struct tee_driver_ops optee_clnt_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_supp_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
>  }
>  #endif
>  
> -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> +				      struct optee_revision *revision)
>  {
>  	union {
>  		struct arm_smccc_res smccc;
> @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
>  	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
>  		  &res.smccc);
>  
> +	if (revision) {
> +		revision->os_major = res.result.major;
> +		revision->os_minor = res.result.minor;
> +		revision->os_build_id = res.result.build_id;
> +	}
> +
>  	if (res.result.build_id)
>  		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
>  			res.result.minor, (int)sizeof(res.result.build_id) * 2,
> @@ -1727,6 +1736,7 @@ static int optee_probe(struct platform_device *pdev)
>  	unsigned int thread_count;
>  	struct tee_device *teedev;
>  	struct tee_context *ctx;
> +	struct optee_revision revision = { };

Ditto here.

-Sumit

>  	u32 max_notif_value;
>  	u32 arg_cache_flags;
>  	u32 sec_caps;
> @@ -1745,7 +1755,7 @@ static int optee_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> -	optee_msg_get_os_revision(invoke_fn);
> +	optee_msg_get_os_revision(invoke_fn, &revision);
>  
>  	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
>  		pr_warn("api revision mismatch\n");
> @@ -1837,6 +1847,7 @@ static int optee_probe(struct platform_device *pdev)
>  		goto err_unreg_teedev;
>  	}
>  	optee->supp_teedev = teedev;
> +	optee->revision = revision;
>  
>  	optee_set_dev_group(optee);
>  
> -- 
> 2.43.0
> 

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

* Re: [PATCH v4 2/2] tee: optee: store OS revision for TEE core
  2026-01-05  5:20         ` Sumit Garg
@ 2026-01-05  8:13           ` Aristo Chen
  2026-01-05  8:48             ` Sumit Garg
  0 siblings, 1 reply; 42+ messages in thread
From: Aristo Chen @ 2026-01-05  8:13 UTC (permalink / raw)
  To: Sumit Garg
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Hi Sumit,

Sumit Garg <sumit.garg@kernel.org> 於 2026年1月5日週一 下午1:20寫道:
>
> On Tue, Dec 30, 2025 at 01:17:59PM +0800, Aristo Chen wrote:
> > Collect OP-TEE OS revision from secure world for both SMC and FF-A ABIs,
> > store it in the OP-TEE driver, and expose it through the generic
> > get_tee_revision() callback.
> >
> > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > ---
> >  drivers/tee/optee/core.c          | 23 +++++++++++++++++++++++
> >  drivers/tee/optee/ffa_abi.c       | 14 ++++++++++++--
> >  drivers/tee/optee/optee_private.h | 19 +++++++++++++++++++
> >  drivers/tee/optee/smc_abi.c       | 15 +++++++++++++--
> >  4 files changed, 67 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > index 5b62139714ce..2d807bc748bc 100644
> > --- a/drivers/tee/optee/core.c
> > +++ b/drivers/tee/optee/core.c
> > @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
> >       return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
> >  }
> >
> > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> > +{
> > +     struct optee *optee = tee_get_drvdata(teedev);
> > +     u64 build_id;
> > +
> > +     if (!optee)
> > +             return -ENODEV;
> > +     if (!buf || !len)
> > +             return -EINVAL;
> > +
> > +     build_id = optee->revision.os_build_id;
> > +     if (build_id)
> > +             scnprintf(buf, len, "%u.%u (%016llx)",
> > +                       optee->revision.os_major,
> > +                       optee->revision.os_minor,
> > +                       (unsigned long long)build_id);
> > +     else
> > +             scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> > +                       optee->revision.os_minor);
> > +
> > +     return 0;
> > +}
> > +
> >  static void optee_bus_scan(struct work_struct *work)
> >  {
> >       WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> > index bf8390789ecf..d67ca1ec9506 100644
> > --- a/drivers/tee/optee/ffa_abi.c
> > +++ b/drivers/tee/optee/ffa_abi.c
> > @@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
> >   */
> >
> >  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > -                                     const struct ffa_ops *ops)
> > +                                     const struct ffa_ops *ops,
> > +                                     struct optee_revision *revision)
> >  {
> >       const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> >       struct ffa_send_direct_data data = {
> > @@ -806,6 +807,11 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> >               pr_err("Unexpected error %d\n", rc);
> >               return false;
> >       }
> > +     if (revision) {
> > +             revision->os_major = data.data0;
> > +             revision->os_minor = data.data1;
> > +             revision->os_build_id = data.data2;
> > +     }
> >       if (data.data2)
> >               pr_info("revision %lu.%lu (%08lx)",
> >                       data.data0, data.data1, data.data2);
> > @@ -900,6 +906,7 @@ static int optee_ffa_open(struct tee_context *ctx)
> >
> >  static const struct tee_driver_ops optee_ffa_clnt_ops = {
> >       .get_version = optee_ffa_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_ffa_open,
> >       .release = optee_release,
> >       .open_session = optee_open_session,
> > @@ -918,6 +925,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
> >
> >  static const struct tee_driver_ops optee_ffa_supp_ops = {
> >       .get_version = optee_ffa_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_ffa_open,
> >       .release = optee_release_supp,
> >       .supp_recv = optee_supp_recv,
> > @@ -1034,6 +1042,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> >  {
> >       const struct ffa_notifier_ops *notif_ops;
> >       const struct ffa_ops *ffa_ops;
> > +     struct optee_revision revision = { };
>
> No need for this redundant variable on stack when...
>
> >       unsigned int max_notif_value;
> >       unsigned int rpc_param_count;
> >       struct tee_shm_pool *pool;
> > @@ -1047,7 +1056,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> >       ffa_ops = ffa_dev->ops;
> >       notif_ops = ffa_ops->notifier_ops;
> >
> > -     if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
> > +     if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &revision))
>
> ...you can just invoke this API as rather:
>
>         if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &optee->revision))
>
Thanks for the review. To avoid the temporary struct optee_revision,
I need to move the optee allocation earlier so we can pass
&optee->revision into optee_ffa_api_is_compatible().

AFAICT, there aren’t kernel selftests covering this, the only test that
I am aware of is the xtest, so I’m slightly cautious about touching
probe ordering. If you prefer to avoid the early allocation, I can keep
the original order and use a local struct optee_revision instead.

Please let me know which you’d prefer

> >               return -EINVAL;
> >
> >       if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
> > @@ -1059,6 +1068,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> >       optee = kzalloc(sizeof(*optee), GFP_KERNEL);
> >       if (!optee)
> >               return -ENOMEM;
> > +     optee->revision = revision;
> >
> >       pool = optee_ffa_shm_pool_alloc_pages();
> >       if (IS_ERR(pool)) {
> > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > index db9ea673fbca..acd3051c4879 100644
> > --- a/drivers/tee/optee/optee_private.h
> > +++ b/drivers/tee/optee/optee_private.h
> > @@ -171,6 +171,24 @@ struct optee_ffa {
> >
> >  struct optee;
> >
> > +/**
> > + * struct optee_revision - OP-TEE OS revision reported by secure world
> > + * @os_major:                OP-TEE OS major version
> > + * @os_minor:                OP-TEE OS minor version
> > + * @os_build_id:     OP-TEE OS build identifier (0 if unspecified)
> > + *
> > + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> > + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> > + * FF-A ABI version.
> > + */
> > +struct optee_revision {
> > +     u32 os_major;
> > +     u32 os_minor;
> > +     u64 os_build_id;
> > +};
> > +
> > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> > +
> >  /**
> >   * struct optee_ops - OP-TEE driver internal operations
> >   * @do_call_with_arg:        enters OP-TEE in secure world
> > @@ -249,6 +267,7 @@ struct optee {
> >       bool in_kernel_rpmb_routing;
> >       struct work_struct scan_bus_work;
> >       struct work_struct rpmb_scan_bus_work;
> > +     struct optee_revision revision;
> >  };
> >
> >  struct optee_session {
> > diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> > index 0be663fcd52b..0baaf7986a35 100644
> > --- a/drivers/tee/optee/smc_abi.c
> > +++ b/drivers/tee/optee/smc_abi.c
> > @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
> >
> >  static const struct tee_driver_ops optee_clnt_ops = {
> >       .get_version = optee_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_smc_open,
> >       .release = optee_release,
> >       .open_session = optee_open_session,
> > @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
> >
> >  static const struct tee_driver_ops optee_supp_ops = {
> >       .get_version = optee_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_smc_open,
> >       .release = optee_release_supp,
> >       .supp_recv = optee_supp_recv,
> > @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
> >  }
> >  #endif
> >
> > -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> > +                                   struct optee_revision *revision)
> >  {
> >       union {
> >               struct arm_smccc_res smccc;
> > @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> >       invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
> >                 &res.smccc);
> >
> > +     if (revision) {
> > +             revision->os_major = res.result.major;
> > +             revision->os_minor = res.result.minor;
> > +             revision->os_build_id = res.result.build_id;
> > +     }
> > +
> >       if (res.result.build_id)
> >               pr_info("revision %lu.%lu (%0*lx)", res.result.major,
> >                       res.result.minor, (int)sizeof(res.result.build_id) * 2,
> > @@ -1727,6 +1736,7 @@ static int optee_probe(struct platform_device *pdev)
> >       unsigned int thread_count;
> >       struct tee_device *teedev;
> >       struct tee_context *ctx;
> > +     struct optee_revision revision = { };
>
> Ditto here.
>
> -Sumit
>
> >       u32 max_notif_value;
> >       u32 arg_cache_flags;
> >       u32 sec_caps;
> > @@ -1745,7 +1755,7 @@ static int optee_probe(struct platform_device *pdev)
> >               return -EINVAL;
> >       }
> >
> > -     optee_msg_get_os_revision(invoke_fn);
> > +     optee_msg_get_os_revision(invoke_fn, &revision);
> >
> >       if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
> >               pr_warn("api revision mismatch\n");
> > @@ -1837,6 +1847,7 @@ static int optee_probe(struct platform_device *pdev)
> >               goto err_unreg_teedev;
> >       }
> >       optee->supp_teedev = teedev;
> > +     optee->revision = revision;
> >
> >       optee_set_dev_group(optee);
> >
> > --
> > 2.43.0
> >

Best regards,
Aristo

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

* Re: [PATCH v4 2/2] tee: optee: store OS revision for TEE core
  2026-01-05  8:13           ` Aristo Chen
@ 2026-01-05  8:48             ` Sumit Garg
  0 siblings, 0 replies; 42+ messages in thread
From: Sumit Garg @ 2026-01-05  8:48 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

On Mon, Jan 05, 2026 at 04:13:52PM +0800, Aristo Chen wrote:
> Hi Sumit,
> 
> Sumit Garg <sumit.garg@kernel.org> 於 2026年1月5日週一 下午1:20寫道:
> >
> > On Tue, Dec 30, 2025 at 01:17:59PM +0800, Aristo Chen wrote:
> > > Collect OP-TEE OS revision from secure world for both SMC and FF-A ABIs,
> > > store it in the OP-TEE driver, and expose it through the generic
> > > get_tee_revision() callback.
> > >
> > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > ---
> > >  drivers/tee/optee/core.c          | 23 +++++++++++++++++++++++
> > >  drivers/tee/optee/ffa_abi.c       | 14 ++++++++++++--
> > >  drivers/tee/optee/optee_private.h | 19 +++++++++++++++++++
> > >  drivers/tee/optee/smc_abi.c       | 15 +++++++++++++--
> > >  4 files changed, 67 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > > index 5b62139714ce..2d807bc748bc 100644
> > > --- a/drivers/tee/optee/core.c
> > > +++ b/drivers/tee/optee/core.c
> > > @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
> > >       return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
> > >  }
> > >
> > > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> > > +{
> > > +     struct optee *optee = tee_get_drvdata(teedev);
> > > +     u64 build_id;
> > > +
> > > +     if (!optee)
> > > +             return -ENODEV;
> > > +     if (!buf || !len)
> > > +             return -EINVAL;
> > > +
> > > +     build_id = optee->revision.os_build_id;
> > > +     if (build_id)
> > > +             scnprintf(buf, len, "%u.%u (%016llx)",
> > > +                       optee->revision.os_major,
> > > +                       optee->revision.os_minor,
> > > +                       (unsigned long long)build_id);
> > > +     else
> > > +             scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> > > +                       optee->revision.os_minor);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > >  static void optee_bus_scan(struct work_struct *work)
> > >  {
> > >       WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> > > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> > > index bf8390789ecf..d67ca1ec9506 100644
> > > --- a/drivers/tee/optee/ffa_abi.c
> > > +++ b/drivers/tee/optee/ffa_abi.c
> > > @@ -776,7 +776,8 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
> > >   */
> > >
> > >  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > > -                                     const struct ffa_ops *ops)
> > > +                                     const struct ffa_ops *ops,
> > > +                                     struct optee_revision *revision)
> > >  {
> > >       const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> > >       struct ffa_send_direct_data data = {
> > > @@ -806,6 +807,11 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > >               pr_err("Unexpected error %d\n", rc);
> > >               return false;
> > >       }
> > > +     if (revision) {
> > > +             revision->os_major = data.data0;
> > > +             revision->os_minor = data.data1;
> > > +             revision->os_build_id = data.data2;
> > > +     }
> > >       if (data.data2)
> > >               pr_info("revision %lu.%lu (%08lx)",
> > >                       data.data0, data.data1, data.data2);
> > > @@ -900,6 +906,7 @@ static int optee_ffa_open(struct tee_context *ctx)
> > >
> > >  static const struct tee_driver_ops optee_ffa_clnt_ops = {
> > >       .get_version = optee_ffa_get_version,
> > > +     .get_tee_revision = optee_get_revision,
> > >       .open = optee_ffa_open,
> > >       .release = optee_release,
> > >       .open_session = optee_open_session,
> > > @@ -918,6 +925,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
> > >
> > >  static const struct tee_driver_ops optee_ffa_supp_ops = {
> > >       .get_version = optee_ffa_get_version,
> > > +     .get_tee_revision = optee_get_revision,
> > >       .open = optee_ffa_open,
> > >       .release = optee_release_supp,
> > >       .supp_recv = optee_supp_recv,
> > > @@ -1034,6 +1042,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > >  {
> > >       const struct ffa_notifier_ops *notif_ops;
> > >       const struct ffa_ops *ffa_ops;
> > > +     struct optee_revision revision = { };
> >
> > No need for this redundant variable on stack when...
> >
> > >       unsigned int max_notif_value;
> > >       unsigned int rpc_param_count;
> > >       struct tee_shm_pool *pool;
> > > @@ -1047,7 +1056,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > >       ffa_ops = ffa_dev->ops;
> > >       notif_ops = ffa_ops->notifier_ops;
> > >
> > > -     if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
> > > +     if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &revision))
> >
> > ...you can just invoke this API as rather:
> >
> >         if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops, &optee->revision))
> >
> Thanks for the review. To avoid the temporary struct optee_revision,
> I need to move the optee allocation earlier so we can pass
> &optee->revision into optee_ffa_api_is_compatible().

I would rather suggest to split this API to add a new one like
optee_ffa_get_os_revision() and then move it's invocation once optee
struct has been allocated.

> 
> AFAICT, there aren’t kernel selftests covering this, the only test that
> I am aware of is the xtest, so I’m slightly cautious about touching
> probe ordering. If you prefer to avoid the early allocation, I can keep
> the original order and use a local struct optee_revision instead.

With above suggestion, the probe ordering won't change much but rather
the point changes when you ask OP-TEE for it's revision.

-Sumit

> 
> Please let me know which you’d prefer
> 
> > >               return -EINVAL;
> > >
> > >       if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
> > > @@ -1059,6 +1068,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> > >       optee = kzalloc(sizeof(*optee), GFP_KERNEL);
> > >       if (!optee)
> > >               return -ENOMEM;
> > > +     optee->revision = revision;
> > >
> > >       pool = optee_ffa_shm_pool_alloc_pages();
> > >       if (IS_ERR(pool)) {
> > > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > > index db9ea673fbca..acd3051c4879 100644
> > > --- a/drivers/tee/optee/optee_private.h
> > > +++ b/drivers/tee/optee/optee_private.h
> > > @@ -171,6 +171,24 @@ struct optee_ffa {
> > >
> > >  struct optee;
> > >
> > > +/**
> > > + * struct optee_revision - OP-TEE OS revision reported by secure world
> > > + * @os_major:                OP-TEE OS major version
> > > + * @os_minor:                OP-TEE OS minor version
> > > + * @os_build_id:     OP-TEE OS build identifier (0 if unspecified)
> > > + *
> > > + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> > > + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> > > + * FF-A ABI version.
> > > + */
> > > +struct optee_revision {
> > > +     u32 os_major;
> > > +     u32 os_minor;
> > > +     u64 os_build_id;
> > > +};
> > > +
> > > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> > > +
> > >  /**
> > >   * struct optee_ops - OP-TEE driver internal operations
> > >   * @do_call_with_arg:        enters OP-TEE in secure world
> > > @@ -249,6 +267,7 @@ struct optee {
> > >       bool in_kernel_rpmb_routing;
> > >       struct work_struct scan_bus_work;
> > >       struct work_struct rpmb_scan_bus_work;
> > > +     struct optee_revision revision;
> > >  };
> > >
> > >  struct optee_session {
> > > diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> > > index 0be663fcd52b..0baaf7986a35 100644
> > > --- a/drivers/tee/optee/smc_abi.c
> > > +++ b/drivers/tee/optee/smc_abi.c
> > > @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
> > >
> > >  static const struct tee_driver_ops optee_clnt_ops = {
> > >       .get_version = optee_get_version,
> > > +     .get_tee_revision = optee_get_revision,
> > >       .open = optee_smc_open,
> > >       .release = optee_release,
> > >       .open_session = optee_open_session,
> > > @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
> > >
> > >  static const struct tee_driver_ops optee_supp_ops = {
> > >       .get_version = optee_get_version,
> > > +     .get_tee_revision = optee_get_revision,
> > >       .open = optee_smc_open,
> > >       .release = optee_release_supp,
> > >       .supp_recv = optee_supp_recv,
> > > @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
> > >  }
> > >  #endif
> > >
> > > -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > > +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> > > +                                   struct optee_revision *revision)
> > >  {
> > >       union {
> > >               struct arm_smccc_res smccc;
> > > @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > >       invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
> > >                 &res.smccc);
> > >
> > > +     if (revision) {
> > > +             revision->os_major = res.result.major;
> > > +             revision->os_minor = res.result.minor;
> > > +             revision->os_build_id = res.result.build_id;
> > > +     }
> > > +
> > >       if (res.result.build_id)
> > >               pr_info("revision %lu.%lu (%0*lx)", res.result.major,
> > >                       res.result.minor, (int)sizeof(res.result.build_id) * 2,
> > > @@ -1727,6 +1736,7 @@ static int optee_probe(struct platform_device *pdev)
> > >       unsigned int thread_count;
> > >       struct tee_device *teedev;
> > >       struct tee_context *ctx;
> > > +     struct optee_revision revision = { };
> >
> > Ditto here.
> >
> > -Sumit
> >
> > >       u32 max_notif_value;
> > >       u32 arg_cache_flags;
> > >       u32 sec_caps;
> > > @@ -1745,7 +1755,7 @@ static int optee_probe(struct platform_device *pdev)
> > >               return -EINVAL;
> > >       }
> > >
> > > -     optee_msg_get_os_revision(invoke_fn);
> > > +     optee_msg_get_os_revision(invoke_fn, &revision);
> > >
> > >       if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
> > >               pr_warn("api revision mismatch\n");
> > > @@ -1837,6 +1847,7 @@ static int optee_probe(struct platform_device *pdev)
> > >               goto err_unreg_teedev;
> > >       }
> > >       optee->supp_teedev = teedev;
> > > +     optee->revision = revision;
> > >
> > >       optee_set_dev_group(optee);
> > >
> > > --
> > > 2.43.0
> > >
> 
> Best regards,
> Aristo

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

* [PATCH v5 1/2] tee: add revision sysfs attribute
  2025-12-30  5:17     ` [PATCH v4 1/2] tee: add revision sysfs attribute Aristo Chen
  2025-12-30  5:17       ` [PATCH v4 2/2] tee: optee: store OS revision for TEE core Aristo Chen
  2026-01-05  4:53       ` [PATCH v4 1/2] tee: add revision sysfs attribute Sumit Garg
@ 2026-01-07 15:26       ` Aristo Chen
  2026-01-07 15:26         ` [PATCH v5 2/2] tee: optee: store OS revision for TEE core Aristo Chen
                           ` (2 more replies)
  2 siblings, 3 replies; 42+ messages in thread
From: Aristo Chen @ 2026-01-07 15:26 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Add a generic TEE revision sysfs attribute backed by a new
optional get_tee_revision() callback. The revision string is
diagnostic-only and must not be used to infer feature support.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 Documentation/ABI/testing/sysfs-class-tee | 10 +++++
 drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
 include/linux/tee_core.h                  |  9 ++++
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
index c9144d16003e..6e783210104e 100644
--- a/Documentation/ABI/testing/sysfs-class-tee
+++ b/Documentation/ABI/testing/sysfs-class-tee
@@ -13,3 +13,13 @@ Description:
 		space if the variable is absent. The primary purpose
 		of this variable is to let systemd know whether
 		tee-supplicant is needed in the early boot with initramfs.
+
+What:		/sys/class/tee/tee{,priv}X/revision
+Date:		Dec 2025
+KernelVersion:	6.18
+Contact:	op-tee@lists.trustedfirmware.org
+Description:
+		Read-only revision string reported by the TEE driver. This is
+		for diagnostics only and must not be used to infer feature
+		support. Use TEE_IOC_VERSION for capability and compatibility
+		checks.
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index d65d47cc154e..0a00499811c1 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
 	NULL
 };
 
-ATTRIBUTE_GROUPS(tee_dev);
+static const struct attribute_group tee_dev_group = {
+	.attrs = tee_dev_attrs,
+};
+
+static ssize_t revision_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+	char version[TEE_REVISION_STR_SIZE];
+	int ret;
+
+	if (!teedev->desc->ops->get_tee_revision)
+		return -ENODEV;
+
+	ret = teedev->desc->ops->get_tee_revision(teedev, version,
+						  sizeof(version));
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%s\n", version);
+}
+static DEVICE_ATTR_RO(revision);
+
+static struct attribute *tee_revision_attrs[] = {
+	&dev_attr_revision.attr,
+	NULL
+};
+
+static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
+					    struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+	if (teedev->desc->ops->get_tee_revision)
+		return attr->mode;
+
+	return 0;
+}
+
+static const struct attribute_group tee_revision_group = {
+	.attrs = tee_revision_attrs,
+	.is_visible = tee_revision_attr_is_visible,
+};
+
+static const struct attribute_group *tee_dev_groups[] = {
+	&tee_dev_group,
+	&tee_revision_group,
+	NULL
+};
 
 static const struct class tee_class = {
 	.name = "tee",
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
index 1f3e5dad6d0d..ee5f0bd41f43 100644
--- a/include/linux/tee_core.h
+++ b/include/linux/tee_core.h
@@ -76,6 +76,9 @@ struct tee_device {
 /**
  * struct tee_driver_ops - driver operations vtable
  * @get_version:	returns version of driver
+ * @get_tee_revision:	returns revision string (diagnostic only);
+ *			do not infer feature support from this, use
+ *			TEE_IOC_VERSION instead
  * @open:		called for a context when the device file is opened
  * @close_context:	called when the device file is closed
  * @release:		called to release the context
@@ -95,9 +98,12 @@ struct tee_device {
  * client closes the device file, even if there are existing references to the
  * context. The TEE driver can use @close_context to start cleaning up.
  */
+
 struct tee_driver_ops {
 	void (*get_version)(struct tee_device *teedev,
 			    struct tee_ioctl_version_data *vers);
+	int (*get_tee_revision)(struct tee_device *teedev,
+				char *buf, size_t len);
 	int (*open)(struct tee_context *ctx);
 	void (*close_context)(struct tee_context *ctx);
 	void (*release)(struct tee_context *ctx);
@@ -123,6 +129,9 @@ struct tee_driver_ops {
 	int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
 };
 
+/* Size for TEE revision string buffer used by get_tee_revision(). */
+#define TEE_REVISION_STR_SIZE	128
+
 /**
  * struct tee_desc - Describes the TEE driver to the subsystem
  * @name:	name of driver
-- 
2.43.0


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

* [PATCH v5 2/2] tee: optee: store OS revision for TEE core
  2026-01-07 15:26       ` [PATCH v5 " Aristo Chen
@ 2026-01-07 15:26         ` Aristo Chen
  2026-01-07 15:28         ` [PATCH v5 1/2] tee: add revision sysfs attribute Mario Limonciello
  2026-01-08  6:45         ` [PATCH v6 " Aristo Chen
  2 siblings, 0 replies; 42+ messages in thread
From: Aristo Chen @ 2026-01-07 15:26 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Collect OP-TEE OS revision from secure world for both SMC and FF-A
ABIs, store it in the OP-TEE driver, and expose it through the
generic get_tee_revision() callback.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 drivers/tee/optee/core.c          | 23 +++++++++++++
 drivers/tee/optee/ffa_abi.c       | 57 ++++++++++++++++++++++++-------
 drivers/tee/optee/optee_private.h | 19 +++++++++++
 drivers/tee/optee/smc_abi.c       | 15 ++++++--
 4 files changed, 99 insertions(+), 15 deletions(-)

diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 5b62139714ce..2d807bc748bc 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
 	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
 }
 
+int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
+{
+	struct optee *optee = tee_get_drvdata(teedev);
+	u64 build_id;
+
+	if (!optee)
+		return -ENODEV;
+	if (!buf || !len)
+		return -EINVAL;
+
+	build_id = optee->revision.os_build_id;
+	if (build_id)
+		scnprintf(buf, len, "%u.%u (%016llx)",
+			  optee->revision.os_major,
+			  optee->revision.os_minor,
+			  (unsigned long long)build_id);
+	else
+		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
+			  optee->revision.os_minor);
+
+	return 0;
+}
+
 static void optee_bus_scan(struct work_struct *work)
 {
 	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index bf8390789ecf..82dbed1c87e5 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -775,6 +775,42 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
  * with a matching configuration.
  */
 
+static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
+					const struct ffa_ops *ops,
+					struct optee_revision *revision,
+					bool log)
+{
+	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
+	struct ffa_send_direct_data data = {
+		.data0 = OPTEE_FFA_GET_OS_VERSION,
+	};
+	int rc;
+
+	msg_ops->mode_32bit_set(ffa_dev);
+
+	rc = msg_ops->sync_send_receive(ffa_dev, &data);
+	if (rc) {
+		pr_err("Unexpected error %d\n", rc);
+		return false;
+	}
+
+	if (revision) {
+		revision->os_major = data.data0;
+		revision->os_minor = data.data1;
+		revision->os_build_id = data.data2;
+	}
+
+	if (log) {
+		if (data.data2)
+			pr_info("revision %lu.%lu (%08lx)",
+				data.data0, data.data1, data.data2);
+		else
+			pr_info("revision %lu.%lu", data.data0, data.data1);
+	}
+
+	return true;
+}
+
 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 					const struct ffa_ops *ops)
 {
@@ -798,19 +834,8 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 		return false;
 	}
 
-	data = (struct ffa_send_direct_data){
-		.data0 = OPTEE_FFA_GET_OS_VERSION,
-	};
-	rc = msg_ops->sync_send_receive(ffa_dev, &data);
-	if (rc) {
-		pr_err("Unexpected error %d\n", rc);
+	if (!optee_ffa_get_os_revision(ffa_dev, ops, NULL, true))
 		return false;
-	}
-	if (data.data2)
-		pr_info("revision %lu.%lu (%08lx)",
-			data.data0, data.data1, data.data2);
-	else
-		pr_info("revision %lu.%lu", data.data0, data.data1);
 
 	return true;
 }
@@ -900,6 +925,7 @@ static int optee_ffa_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_ffa_clnt_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_ffa_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -918,6 +944,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
 
 static const struct tee_driver_ops optee_ffa_supp_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_ffa_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1060,6 +1087,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	if (!optee)
 		return -ENOMEM;
 
+	if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision,
+					 false)) {
+		rc = -EINVAL;
+		goto err_free_optee;
+	}
+
 	pool = optee_ffa_shm_pool_alloc_pages();
 	if (IS_ERR(pool)) {
 		rc = PTR_ERR(pool);
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index db9ea673fbca..acd3051c4879 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -171,6 +171,24 @@ struct optee_ffa {
 
 struct optee;
 
+/**
+ * struct optee_revision - OP-TEE OS revision reported by secure world
+ * @os_major:		OP-TEE OS major version
+ * @os_minor:		OP-TEE OS minor version
+ * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
+ *
+ * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
+ * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
+ * FF-A ABI version.
+ */
+struct optee_revision {
+	u32 os_major;
+	u32 os_minor;
+	u64 os_build_id;
+};
+
+int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
+
 /**
  * struct optee_ops - OP-TEE driver internal operations
  * @do_call_with_arg:	enters OP-TEE in secure world
@@ -249,6 +267,7 @@ struct optee {
 	bool in_kernel_rpmb_routing;
 	struct work_struct scan_bus_work;
 	struct work_struct rpmb_scan_bus_work;
+	struct optee_revision revision;
 };
 
 struct optee_session {
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 0be663fcd52b..51fae1ab8ef8 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_clnt_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_smc_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
 
 static const struct tee_driver_ops optee_supp_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_smc_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
 }
 #endif
 
-static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
+static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
+				      struct optee_revision *revision)
 {
 	union {
 		struct arm_smccc_res smccc;
@@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
 		  &res.smccc);
 
+	if (revision) {
+		revision->os_major = res.result.major;
+		revision->os_minor = res.result.minor;
+		revision->os_build_id = res.result.build_id;
+	}
+
 	if (res.result.build_id)
 		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
 			res.result.minor, (int)sizeof(res.result.build_id) * 2,
@@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	optee_msg_get_os_revision(invoke_fn);
-
 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
 		pr_warn("api revision mismatch\n");
 		return -EINVAL;
@@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
 		goto err_free_shm_pool;
 	}
 
+	optee_msg_get_os_revision(invoke_fn, &optee->revision);
+
 	optee->ops = &optee_ops;
 	optee->smc.invoke_fn = invoke_fn;
 	optee->smc.sec_caps = sec_caps;
-- 
2.43.0


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

* Re: [PATCH v5 1/2] tee: add revision sysfs attribute
  2026-01-07 15:26       ` [PATCH v5 " Aristo Chen
  2026-01-07 15:26         ` [PATCH v5 2/2] tee: optee: store OS revision for TEE core Aristo Chen
@ 2026-01-07 15:28         ` Mario Limonciello
  2026-01-08  2:55           ` Aristo Chen
  2026-01-08  6:45         ` [PATCH v6 " Aristo Chen
  2 siblings, 1 reply; 42+ messages in thread
From: Mario Limonciello @ 2026-01-07 15:28 UTC (permalink / raw)
  To: Aristo Chen, linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev, Rijo-john.Thomas,
	amirreza.zarrabi, Aristo Chen

On 1/7/26 9:26 AM, Aristo Chen wrote:
> Add a generic TEE revision sysfs attribute backed by a new
> optional get_tee_revision() callback. The revision string is
> diagnostic-only and must not be used to infer feature support.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>   Documentation/ABI/testing/sysfs-class-tee | 10 +++++
>   drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
>   include/linux/tee_core.h                  |  9 ++++
>   3 files changed, 69 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
> index c9144d16003e..6e783210104e 100644
> --- a/Documentation/ABI/testing/sysfs-class-tee
> +++ b/Documentation/ABI/testing/sysfs-class-tee
> @@ -13,3 +13,13 @@ Description:
>   		space if the variable is absent. The primary purpose
>   		of this variable is to let systemd know whether
>   		tee-supplicant is needed in the early boot with initramfs.
> +
> +What:		/sys/class/tee/tee{,priv}X/revision
> +Date:		Dec 2025
> +KernelVersion:	6.18

This needs to be bumped up and dates pushed out.

> +Contact:	op-tee@lists.trustedfirmware.org
> +Description:
> +		Read-only revision string reported by the TEE driver. This is
> +		for diagnostics only and must not be used to infer feature
> +		support. Use TEE_IOC_VERSION for capability and compatibility
> +		checks.
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index d65d47cc154e..0a00499811c1 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
>   	NULL
>   };
>   
> -ATTRIBUTE_GROUPS(tee_dev);
> +static const struct attribute_group tee_dev_group = {
> +	.attrs = tee_dev_attrs,
> +};
> +
> +static ssize_t revision_show(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +	char version[TEE_REVISION_STR_SIZE];
> +	int ret;
> +
> +	if (!teedev->desc->ops->get_tee_revision)
> +		return -ENODEV;
> +
> +	ret = teedev->desc->ops->get_tee_revision(teedev, version,
> +						  sizeof(version));
> +	if (ret)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%s\n", version);
> +}
> +static DEVICE_ATTR_RO(revision);
> +
> +static struct attribute *tee_revision_attrs[] = {
> +	&dev_attr_revision.attr,
> +	NULL
> +};
> +
> +static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
> +					    struct attribute *attr, int n)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +
> +	if (teedev->desc->ops->get_tee_revision)
> +		return attr->mode;
> +
> +	return 0;
> +}
> +
> +static const struct attribute_group tee_revision_group = {
> +	.attrs = tee_revision_attrs,
> +	.is_visible = tee_revision_attr_is_visible,
> +};
> +
> +static const struct attribute_group *tee_dev_groups[] = {
> +	&tee_dev_group,
> +	&tee_revision_group,
> +	NULL
> +};
>   
>   static const struct class tee_class = {
>   	.name = "tee",
> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
> index 1f3e5dad6d0d..ee5f0bd41f43 100644
> --- a/include/linux/tee_core.h
> +++ b/include/linux/tee_core.h
> @@ -76,6 +76,9 @@ struct tee_device {
>   /**
>    * struct tee_driver_ops - driver operations vtable
>    * @get_version:	returns version of driver
> + * @get_tee_revision:	returns revision string (diagnostic only);

Why is this comment here about it being for diagnostics only?  I feel 
it's up to the implementation how it would be used.

> + *			do not infer feature support from this, use
> + *			TEE_IOC_VERSION instead
>    * @open:		called for a context when the device file is opened
>    * @close_context:	called when the device file is closed
>    * @release:		called to release the context
> @@ -95,9 +98,12 @@ struct tee_device {
>    * client closes the device file, even if there are existing references to the
>    * context. The TEE driver can use @close_context to start cleaning up.
>    */
> +
>   struct tee_driver_ops {
>   	void (*get_version)(struct tee_device *teedev,
>   			    struct tee_ioctl_version_data *vers);
> +	int (*get_tee_revision)(struct tee_device *teedev,
> +				char *buf, size_t len);
>   	int (*open)(struct tee_context *ctx);
>   	void (*close_context)(struct tee_context *ctx);
>   	void (*release)(struct tee_context *ctx);
> @@ -123,6 +129,9 @@ struct tee_driver_ops {
>   	int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
>   };
>   
> +/* Size for TEE revision string buffer used by get_tee_revision(). */
> +#define TEE_REVISION_STR_SIZE	128
> +
>   /**
>    * struct tee_desc - Describes the TEE driver to the subsystem
>    * @name:	name of driver


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

* Re: [PATCH v5 1/2] tee: add revision sysfs attribute
  2026-01-07 15:28         ` [PATCH v5 1/2] tee: add revision sysfs attribute Mario Limonciello
@ 2026-01-08  2:55           ` Aristo Chen
  2026-01-08  3:01             ` Mario Limonciello (AMD) (kernel.org)
  0 siblings, 1 reply; 42+ messages in thread
From: Aristo Chen @ 2026-01-08  2:55 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: linux-kernel, jens.wiklander, sumit.garg, op-tee, harshal.dev,
	Rijo-john.Thomas, amirreza.zarrabi, Aristo Chen

Hi Mario,

Mario Limonciello <superm1@kernel.org> 於 2026年1月7日週三 下午11:28寫道:
>
> On 1/7/26 9:26 AM, Aristo Chen wrote:
> > Add a generic TEE revision sysfs attribute backed by a new
> > optional get_tee_revision() callback. The revision string is
> > diagnostic-only and must not be used to infer feature support.
> >
> > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > ---
> >   Documentation/ABI/testing/sysfs-class-tee | 10 +++++
> >   drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
> >   include/linux/tee_core.h                  |  9 ++++
> >   3 files changed, 69 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
> > index c9144d16003e..6e783210104e 100644
> > --- a/Documentation/ABI/testing/sysfs-class-tee
> > +++ b/Documentation/ABI/testing/sysfs-class-tee
> > @@ -13,3 +13,13 @@ Description:
> >               space if the variable is absent. The primary purpose
> >               of this variable is to let systemd know whether
> >               tee-supplicant is needed in the early boot with initramfs.
> > +
> > +What:                /sys/class/tee/tee{,priv}X/revision
> > +Date:                Dec 2025
> > +KernelVersion:       6.18
>
> This needs to be bumped up and dates pushed out.

I will fix this in the v6 patch, thanks!

>
> > +Contact:     op-tee@lists.trustedfirmware.org
> > +Description:
> > +             Read-only revision string reported by the TEE driver. This is
> > +             for diagnostics only and must not be used to infer feature
> > +             support. Use TEE_IOC_VERSION for capability and compatibility
> > +             checks.
> > diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> > index d65d47cc154e..0a00499811c1 100644
> > --- a/drivers/tee/tee_core.c
> > +++ b/drivers/tee/tee_core.c
> > @@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
> >       NULL
> >   };
> >
> > -ATTRIBUTE_GROUPS(tee_dev);
> > +static const struct attribute_group tee_dev_group = {
> > +     .attrs = tee_dev_attrs,
> > +};
> > +
> > +static ssize_t revision_show(struct device *dev,
> > +                          struct device_attribute *attr, char *buf)
> > +{
> > +     struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> > +     char version[TEE_REVISION_STR_SIZE];
> > +     int ret;
> > +
> > +     if (!teedev->desc->ops->get_tee_revision)
> > +             return -ENODEV;
> > +
> > +     ret = teedev->desc->ops->get_tee_revision(teedev, version,
> > +                                               sizeof(version));
> > +     if (ret)
> > +             return ret;
> > +
> > +     return sysfs_emit(buf, "%s\n", version);
> > +}
> > +static DEVICE_ATTR_RO(revision);
> > +
> > +static struct attribute *tee_revision_attrs[] = {
> > +     &dev_attr_revision.attr,
> > +     NULL
> > +};
> > +
> > +static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
> > +                                         struct attribute *attr, int n)
> > +{
> > +     struct device *dev = kobj_to_dev(kobj);
> > +     struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> > +
> > +     if (teedev->desc->ops->get_tee_revision)
> > +             return attr->mode;
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct attribute_group tee_revision_group = {
> > +     .attrs = tee_revision_attrs,
> > +     .is_visible = tee_revision_attr_is_visible,
> > +};
> > +
> > +static const struct attribute_group *tee_dev_groups[] = {
> > +     &tee_dev_group,
> > +     &tee_revision_group,
> > +     NULL
> > +};
> >
> >   static const struct class tee_class = {
> >       .name = "tee",
> > diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
> > index 1f3e5dad6d0d..ee5f0bd41f43 100644
> > --- a/include/linux/tee_core.h
> > +++ b/include/linux/tee_core.h
> > @@ -76,6 +76,9 @@ struct tee_device {
> >   /**
> >    * struct tee_driver_ops - driver operations vtable
> >    * @get_version:    returns version of driver
> > + * @get_tee_revision:        returns revision string (diagnostic only);
>
> Why is this comment here about it being for diagnostics only?  I feel
> it's up to the implementation how it would be used.

According to the previous discussion, we would like to prevent user
thinking about optee os version x.y means z feature, and we should
always use TEE_IOC_VERSION for capability and compatibility
check.

Is there any other specific use case that makes you think removing
the wording is required?

>
> > + *                   do not infer feature support from this, use
> > + *                   TEE_IOC_VERSION instead
> >    * @open:           called for a context when the device file is opened
> >    * @close_context:  called when the device file is closed
> >    * @release:                called to release the context
> > @@ -95,9 +98,12 @@ struct tee_device {
> >    * client closes the device file, even if there are existing references to the
> >    * context. The TEE driver can use @close_context to start cleaning up.
> >    */
> > +
> >   struct tee_driver_ops {
> >       void (*get_version)(struct tee_device *teedev,
> >                           struct tee_ioctl_version_data *vers);
> > +     int (*get_tee_revision)(struct tee_device *teedev,
> > +                             char *buf, size_t len);
> >       int (*open)(struct tee_context *ctx);
> >       void (*close_context)(struct tee_context *ctx);
> >       void (*release)(struct tee_context *ctx);
> > @@ -123,6 +129,9 @@ struct tee_driver_ops {
> >       int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
> >   };
> >
> > +/* Size for TEE revision string buffer used by get_tee_revision(). */
> > +#define TEE_REVISION_STR_SIZE        128
> > +
> >   /**
> >    * struct tee_desc - Describes the TEE driver to the subsystem
> >    * @name:   name of driver
>

Best regards,
Aristo

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

* Re: [PATCH v5 1/2] tee: add revision sysfs attribute
  2026-01-08  2:55           ` Aristo Chen
@ 2026-01-08  3:01             ` Mario Limonciello (AMD) (kernel.org)
  0 siblings, 0 replies; 42+ messages in thread
From: Mario Limonciello (AMD) (kernel.org) @ 2026-01-08  3:01 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, sumit.garg, op-tee, harshal.dev,
	Rijo-john.Thomas, amirreza.zarrabi, Aristo Chen



On 1/7/2026 8:55 PM, Aristo Chen wrote:
> Hi Mario,
> 
> Mario Limonciello <superm1@kernel.org> 於 2026年1月7日週三 下午11:28寫道:
>>
>> On 1/7/26 9:26 AM, Aristo Chen wrote:
>>> Add a generic TEE revision sysfs attribute backed by a new
>>> optional get_tee_revision() callback. The revision string is
>>> diagnostic-only and must not be used to infer feature support.
>>>
>>> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
>>> ---
>>>    Documentation/ABI/testing/sysfs-class-tee | 10 +++++
>>>    drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
>>>    include/linux/tee_core.h                  |  9 ++++
>>>    3 files changed, 69 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
>>> index c9144d16003e..6e783210104e 100644
>>> --- a/Documentation/ABI/testing/sysfs-class-tee
>>> +++ b/Documentation/ABI/testing/sysfs-class-tee
>>> @@ -13,3 +13,13 @@ Description:
>>>                space if the variable is absent. The primary purpose
>>>                of this variable is to let systemd know whether
>>>                tee-supplicant is needed in the early boot with initramfs.
>>> +
>>> +What:                /sys/class/tee/tee{,priv}X/revision
>>> +Date:                Dec 2025
>>> +KernelVersion:       6.18
>>
>> This needs to be bumped up and dates pushed out.
> 
> I will fix this in the v6 patch, thanks!
> 
>>
>>> +Contact:     op-tee@lists.trustedfirmware.org
>>> +Description:
>>> +             Read-only revision string reported by the TEE driver. This is
>>> +             for diagnostics only and must not be used to infer feature
>>> +             support. Use TEE_IOC_VERSION for capability and compatibility
>>> +             checks.
>>> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
>>> index d65d47cc154e..0a00499811c1 100644
>>> --- a/drivers/tee/tee_core.c
>>> +++ b/drivers/tee/tee_core.c
>>> @@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
>>>        NULL
>>>    };
>>>
>>> -ATTRIBUTE_GROUPS(tee_dev);
>>> +static const struct attribute_group tee_dev_group = {
>>> +     .attrs = tee_dev_attrs,
>>> +};
>>> +
>>> +static ssize_t revision_show(struct device *dev,
>>> +                          struct device_attribute *attr, char *buf)
>>> +{
>>> +     struct tee_device *teedev = container_of(dev, struct tee_device, dev);
>>> +     char version[TEE_REVISION_STR_SIZE];
>>> +     int ret;
>>> +
>>> +     if (!teedev->desc->ops->get_tee_revision)
>>> +             return -ENODEV;
>>> +
>>> +     ret = teedev->desc->ops->get_tee_revision(teedev, version,
>>> +                                               sizeof(version));
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     return sysfs_emit(buf, "%s\n", version);
>>> +}
>>> +static DEVICE_ATTR_RO(revision);
>>> +
>>> +static struct attribute *tee_revision_attrs[] = {
>>> +     &dev_attr_revision.attr,
>>> +     NULL
>>> +};
>>> +
>>> +static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
>>> +                                         struct attribute *attr, int n)
>>> +{
>>> +     struct device *dev = kobj_to_dev(kobj);
>>> +     struct tee_device *teedev = container_of(dev, struct tee_device, dev);
>>> +
>>> +     if (teedev->desc->ops->get_tee_revision)
>>> +             return attr->mode;
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static const struct attribute_group tee_revision_group = {
>>> +     .attrs = tee_revision_attrs,
>>> +     .is_visible = tee_revision_attr_is_visible,
>>> +};
>>> +
>>> +static const struct attribute_group *tee_dev_groups[] = {
>>> +     &tee_dev_group,
>>> +     &tee_revision_group,
>>> +     NULL
>>> +};
>>>
>>>    static const struct class tee_class = {
>>>        .name = "tee",
>>> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
>>> index 1f3e5dad6d0d..ee5f0bd41f43 100644
>>> --- a/include/linux/tee_core.h
>>> +++ b/include/linux/tee_core.h
>>> @@ -76,6 +76,9 @@ struct tee_device {
>>>    /**
>>>     * struct tee_driver_ops - driver operations vtable
>>>     * @get_version:    returns version of driver
>>> + * @get_tee_revision:        returns revision string (diagnostic only);
>>
>> Why is this comment here about it being for diagnostics only?  I feel
>> it's up to the implementation how it would be used.
> 
> According to the previous discussion, we would like to prevent user
> thinking about optee os version x.y means z feature, and we should
> always use TEE_IOC_VERSION for capability and compatibility
> check.
> 
> Is there any other specific use case that makes you think removing
> the wording is required?

Ah I didn't realize there was previous discussion that lead to this, I 
saw some earlier versions in my holiday mailbox glut but ignored them 
when I saw the new one.

Leave it as is then.

> 
>>
>>> + *                   do not infer feature support from this, use
>>> + *                   TEE_IOC_VERSION instead
>>>     * @open:           called for a context when the device file is opened
>>>     * @close_context:  called when the device file is closed
>>>     * @release:                called to release the context
>>> @@ -95,9 +98,12 @@ struct tee_device {
>>>     * client closes the device file, even if there are existing references to the
>>>     * context. The TEE driver can use @close_context to start cleaning up.
>>>     */
>>> +
>>>    struct tee_driver_ops {
>>>        void (*get_version)(struct tee_device *teedev,
>>>                            struct tee_ioctl_version_data *vers);
>>> +     int (*get_tee_revision)(struct tee_device *teedev,
>>> +                             char *buf, size_t len);
>>>        int (*open)(struct tee_context *ctx);
>>>        void (*close_context)(struct tee_context *ctx);
>>>        void (*release)(struct tee_context *ctx);
>>> @@ -123,6 +129,9 @@ struct tee_driver_ops {
>>>        int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
>>>    };
>>>
>>> +/* Size for TEE revision string buffer used by get_tee_revision(). */
>>> +#define TEE_REVISION_STR_SIZE        128
>>> +
>>>    /**
>>>     * struct tee_desc - Describes the TEE driver to the subsystem
>>>     * @name:   name of driver
>>
> 
> Best regards,
> Aristo


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

* [PATCH v6 1/2] tee: add revision sysfs attribute
  2026-01-07 15:26       ` [PATCH v5 " Aristo Chen
  2026-01-07 15:26         ` [PATCH v5 2/2] tee: optee: store OS revision for TEE core Aristo Chen
  2026-01-07 15:28         ` [PATCH v5 1/2] tee: add revision sysfs attribute Mario Limonciello
@ 2026-01-08  6:45         ` Aristo Chen
  2026-01-08  6:45           ` [PATCH v6 2/2] tee: optee: store OS revision for TEE core Aristo Chen
                             ` (3 more replies)
  2 siblings, 4 replies; 42+ messages in thread
From: Aristo Chen @ 2026-01-08  6:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Add a generic TEE revision sysfs attribute backed by a new
optional get_tee_revision() callback. The revision string is
diagnostic-only and must not be used to infer feature support.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 Documentation/ABI/testing/sysfs-class-tee | 10 +++++
 drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
 include/linux/tee_core.h                  |  9 ++++
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
index c9144d16003e..1a0a3050aaa9 100644
--- a/Documentation/ABI/testing/sysfs-class-tee
+++ b/Documentation/ABI/testing/sysfs-class-tee
@@ -13,3 +13,13 @@ Description:
 		space if the variable is absent. The primary purpose
 		of this variable is to let systemd know whether
 		tee-supplicant is needed in the early boot with initramfs.
+
+What:		/sys/class/tee/tee{,priv}X/revision
+Date:		Jan 2026
+KernelVersion:	6.19
+Contact:	op-tee@lists.trustedfirmware.org
+Description:
+		Read-only revision string reported by the TEE driver. This is
+		for diagnostics only and must not be used to infer feature
+		support. Use TEE_IOC_VERSION for capability and compatibility
+		checks.
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index d65d47cc154e..0a00499811c1 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
 	NULL
 };
 
-ATTRIBUTE_GROUPS(tee_dev);
+static const struct attribute_group tee_dev_group = {
+	.attrs = tee_dev_attrs,
+};
+
+static ssize_t revision_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+	char version[TEE_REVISION_STR_SIZE];
+	int ret;
+
+	if (!teedev->desc->ops->get_tee_revision)
+		return -ENODEV;
+
+	ret = teedev->desc->ops->get_tee_revision(teedev, version,
+						  sizeof(version));
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%s\n", version);
+}
+static DEVICE_ATTR_RO(revision);
+
+static struct attribute *tee_revision_attrs[] = {
+	&dev_attr_revision.attr,
+	NULL
+};
+
+static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
+					    struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+	if (teedev->desc->ops->get_tee_revision)
+		return attr->mode;
+
+	return 0;
+}
+
+static const struct attribute_group tee_revision_group = {
+	.attrs = tee_revision_attrs,
+	.is_visible = tee_revision_attr_is_visible,
+};
+
+static const struct attribute_group *tee_dev_groups[] = {
+	&tee_dev_group,
+	&tee_revision_group,
+	NULL
+};
 
 static const struct class tee_class = {
 	.name = "tee",
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
index 1f3e5dad6d0d..ee5f0bd41f43 100644
--- a/include/linux/tee_core.h
+++ b/include/linux/tee_core.h
@@ -76,6 +76,9 @@ struct tee_device {
 /**
  * struct tee_driver_ops - driver operations vtable
  * @get_version:	returns version of driver
+ * @get_tee_revision:	returns revision string (diagnostic only);
+ *			do not infer feature support from this, use
+ *			TEE_IOC_VERSION instead
  * @open:		called for a context when the device file is opened
  * @close_context:	called when the device file is closed
  * @release:		called to release the context
@@ -95,9 +98,12 @@ struct tee_device {
  * client closes the device file, even if there are existing references to the
  * context. The TEE driver can use @close_context to start cleaning up.
  */
+
 struct tee_driver_ops {
 	void (*get_version)(struct tee_device *teedev,
 			    struct tee_ioctl_version_data *vers);
+	int (*get_tee_revision)(struct tee_device *teedev,
+				char *buf, size_t len);
 	int (*open)(struct tee_context *ctx);
 	void (*close_context)(struct tee_context *ctx);
 	void (*release)(struct tee_context *ctx);
@@ -123,6 +129,9 @@ struct tee_driver_ops {
 	int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
 };
 
+/* Size for TEE revision string buffer used by get_tee_revision(). */
+#define TEE_REVISION_STR_SIZE	128
+
 /**
  * struct tee_desc - Describes the TEE driver to the subsystem
  * @name:	name of driver
-- 
2.43.0


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

* [PATCH v6 2/2] tee: optee: store OS revision for TEE core
  2026-01-08  6:45         ` [PATCH v6 " Aristo Chen
@ 2026-01-08  6:45           ` Aristo Chen
  2026-01-09 11:50             ` Sumit Garg
  2026-01-12  9:55             ` Jens Wiklander
  2026-01-09 11:48           ` [PATCH v6 1/2] tee: add revision sysfs attribute Sumit Garg
                             ` (2 subsequent siblings)
  3 siblings, 2 replies; 42+ messages in thread
From: Aristo Chen @ 2026-01-08  6:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Collect OP-TEE OS revision from secure world for both SMC and FF-A
ABIs, store it in the OP-TEE driver, and expose it through the
generic get_tee_revision() callback.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 drivers/tee/optee/core.c          | 23 +++++++++++++
 drivers/tee/optee/ffa_abi.c       | 57 ++++++++++++++++++++++++-------
 drivers/tee/optee/optee_private.h | 19 +++++++++++
 drivers/tee/optee/smc_abi.c       | 15 ++++++--
 4 files changed, 99 insertions(+), 15 deletions(-)

diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 5b62139714ce..2d807bc748bc 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
 	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
 }
 
+int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
+{
+	struct optee *optee = tee_get_drvdata(teedev);
+	u64 build_id;
+
+	if (!optee)
+		return -ENODEV;
+	if (!buf || !len)
+		return -EINVAL;
+
+	build_id = optee->revision.os_build_id;
+	if (build_id)
+		scnprintf(buf, len, "%u.%u (%016llx)",
+			  optee->revision.os_major,
+			  optee->revision.os_minor,
+			  (unsigned long long)build_id);
+	else
+		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
+			  optee->revision.os_minor);
+
+	return 0;
+}
+
 static void optee_bus_scan(struct work_struct *work)
 {
 	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index bf8390789ecf..82dbed1c87e5 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -775,6 +775,42 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
  * with a matching configuration.
  */
 
+static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
+					const struct ffa_ops *ops,
+					struct optee_revision *revision,
+					bool log)
+{
+	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
+	struct ffa_send_direct_data data = {
+		.data0 = OPTEE_FFA_GET_OS_VERSION,
+	};
+	int rc;
+
+	msg_ops->mode_32bit_set(ffa_dev);
+
+	rc = msg_ops->sync_send_receive(ffa_dev, &data);
+	if (rc) {
+		pr_err("Unexpected error %d\n", rc);
+		return false;
+	}
+
+	if (revision) {
+		revision->os_major = data.data0;
+		revision->os_minor = data.data1;
+		revision->os_build_id = data.data2;
+	}
+
+	if (log) {
+		if (data.data2)
+			pr_info("revision %lu.%lu (%08lx)",
+				data.data0, data.data1, data.data2);
+		else
+			pr_info("revision %lu.%lu", data.data0, data.data1);
+	}
+
+	return true;
+}
+
 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 					const struct ffa_ops *ops)
 {
@@ -798,19 +834,8 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 		return false;
 	}
 
-	data = (struct ffa_send_direct_data){
-		.data0 = OPTEE_FFA_GET_OS_VERSION,
-	};
-	rc = msg_ops->sync_send_receive(ffa_dev, &data);
-	if (rc) {
-		pr_err("Unexpected error %d\n", rc);
+	if (!optee_ffa_get_os_revision(ffa_dev, ops, NULL, true))
 		return false;
-	}
-	if (data.data2)
-		pr_info("revision %lu.%lu (%08lx)",
-			data.data0, data.data1, data.data2);
-	else
-		pr_info("revision %lu.%lu", data.data0, data.data1);
 
 	return true;
 }
@@ -900,6 +925,7 @@ static int optee_ffa_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_ffa_clnt_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_ffa_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -918,6 +944,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
 
 static const struct tee_driver_ops optee_ffa_supp_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_ffa_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1060,6 +1087,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	if (!optee)
 		return -ENOMEM;
 
+	if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision,
+					 false)) {
+		rc = -EINVAL;
+		goto err_free_optee;
+	}
+
 	pool = optee_ffa_shm_pool_alloc_pages();
 	if (IS_ERR(pool)) {
 		rc = PTR_ERR(pool);
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index db9ea673fbca..acd3051c4879 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -171,6 +171,24 @@ struct optee_ffa {
 
 struct optee;
 
+/**
+ * struct optee_revision - OP-TEE OS revision reported by secure world
+ * @os_major:		OP-TEE OS major version
+ * @os_minor:		OP-TEE OS minor version
+ * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
+ *
+ * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
+ * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
+ * FF-A ABI version.
+ */
+struct optee_revision {
+	u32 os_major;
+	u32 os_minor;
+	u64 os_build_id;
+};
+
+int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
+
 /**
  * struct optee_ops - OP-TEE driver internal operations
  * @do_call_with_arg:	enters OP-TEE in secure world
@@ -249,6 +267,7 @@ struct optee {
 	bool in_kernel_rpmb_routing;
 	struct work_struct scan_bus_work;
 	struct work_struct rpmb_scan_bus_work;
+	struct optee_revision revision;
 };
 
 struct optee_session {
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 0be663fcd52b..51fae1ab8ef8 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_clnt_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_smc_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
 
 static const struct tee_driver_ops optee_supp_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_smc_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
 }
 #endif
 
-static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
+static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
+				      struct optee_revision *revision)
 {
 	union {
 		struct arm_smccc_res smccc;
@@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
 		  &res.smccc);
 
+	if (revision) {
+		revision->os_major = res.result.major;
+		revision->os_minor = res.result.minor;
+		revision->os_build_id = res.result.build_id;
+	}
+
 	if (res.result.build_id)
 		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
 			res.result.minor, (int)sizeof(res.result.build_id) * 2,
@@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	optee_msg_get_os_revision(invoke_fn);
-
 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
 		pr_warn("api revision mismatch\n");
 		return -EINVAL;
@@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
 		goto err_free_shm_pool;
 	}
 
+	optee_msg_get_os_revision(invoke_fn, &optee->revision);
+
 	optee->ops = &optee_ops;
 	optee->smc.invoke_fn = invoke_fn;
 	optee->smc.sec_caps = sec_caps;
-- 
2.43.0


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

* Re: [PATCH v6 1/2] tee: add revision sysfs attribute
  2026-01-08  6:45         ` [PATCH v6 " Aristo Chen
  2026-01-08  6:45           ` [PATCH v6 2/2] tee: optee: store OS revision for TEE core Aristo Chen
@ 2026-01-09 11:48           ` Sumit Garg
  2026-01-12  9:50           ` Jens Wiklander
  2026-01-12 15:48           ` [PATCH v7 " Aristo Chen
  3 siblings, 0 replies; 42+ messages in thread
From: Sumit Garg @ 2026-01-09 11:48 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

On Thu, Jan 08, 2026 at 02:45:08PM +0800, Aristo Chen wrote:
> Add a generic TEE revision sysfs attribute backed by a new
> optional get_tee_revision() callback. The revision string is
> diagnostic-only and must not be used to infer feature support.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  Documentation/ABI/testing/sysfs-class-tee | 10 +++++
>  drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
>  include/linux/tee_core.h                  |  9 ++++
>  3 files changed, 69 insertions(+), 1 deletion(-)

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

-Sumit

> 
> diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
> index c9144d16003e..1a0a3050aaa9 100644
> --- a/Documentation/ABI/testing/sysfs-class-tee
> +++ b/Documentation/ABI/testing/sysfs-class-tee
> @@ -13,3 +13,13 @@ Description:
>  		space if the variable is absent. The primary purpose
>  		of this variable is to let systemd know whether
>  		tee-supplicant is needed in the early boot with initramfs.
> +
> +What:		/sys/class/tee/tee{,priv}X/revision
> +Date:		Jan 2026
> +KernelVersion:	6.19
> +Contact:	op-tee@lists.trustedfirmware.org
> +Description:
> +		Read-only revision string reported by the TEE driver. This is
> +		for diagnostics only and must not be used to infer feature
> +		support. Use TEE_IOC_VERSION for capability and compatibility
> +		checks.
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index d65d47cc154e..0a00499811c1 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
>  	NULL
>  };
>  
> -ATTRIBUTE_GROUPS(tee_dev);
> +static const struct attribute_group tee_dev_group = {
> +	.attrs = tee_dev_attrs,
> +};
> +
> +static ssize_t revision_show(struct device *dev,
> +			     struct device_attribute *attr, char *buf)
> +{
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +	char version[TEE_REVISION_STR_SIZE];
> +	int ret;
> +
> +	if (!teedev->desc->ops->get_tee_revision)
> +		return -ENODEV;
> +
> +	ret = teedev->desc->ops->get_tee_revision(teedev, version,
> +						  sizeof(version));
> +	if (ret)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%s\n", version);
> +}
> +static DEVICE_ATTR_RO(revision);
> +
> +static struct attribute *tee_revision_attrs[] = {
> +	&dev_attr_revision.attr,
> +	NULL
> +};
> +
> +static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
> +					    struct attribute *attr, int n)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +
> +	if (teedev->desc->ops->get_tee_revision)
> +		return attr->mode;
> +
> +	return 0;
> +}
> +
> +static const struct attribute_group tee_revision_group = {
> +	.attrs = tee_revision_attrs,
> +	.is_visible = tee_revision_attr_is_visible,
> +};
> +
> +static const struct attribute_group *tee_dev_groups[] = {
> +	&tee_dev_group,
> +	&tee_revision_group,
> +	NULL
> +};
>  
>  static const struct class tee_class = {
>  	.name = "tee",
> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
> index 1f3e5dad6d0d..ee5f0bd41f43 100644
> --- a/include/linux/tee_core.h
> +++ b/include/linux/tee_core.h
> @@ -76,6 +76,9 @@ struct tee_device {
>  /**
>   * struct tee_driver_ops - driver operations vtable
>   * @get_version:	returns version of driver
> + * @get_tee_revision:	returns revision string (diagnostic only);
> + *			do not infer feature support from this, use
> + *			TEE_IOC_VERSION instead
>   * @open:		called for a context when the device file is opened
>   * @close_context:	called when the device file is closed
>   * @release:		called to release the context
> @@ -95,9 +98,12 @@ struct tee_device {
>   * client closes the device file, even if there are existing references to the
>   * context. The TEE driver can use @close_context to start cleaning up.
>   */
> +
>  struct tee_driver_ops {
>  	void (*get_version)(struct tee_device *teedev,
>  			    struct tee_ioctl_version_data *vers);
> +	int (*get_tee_revision)(struct tee_device *teedev,
> +				char *buf, size_t len);
>  	int (*open)(struct tee_context *ctx);
>  	void (*close_context)(struct tee_context *ctx);
>  	void (*release)(struct tee_context *ctx);
> @@ -123,6 +129,9 @@ struct tee_driver_ops {
>  	int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
>  };
>  
> +/* Size for TEE revision string buffer used by get_tee_revision(). */
> +#define TEE_REVISION_STR_SIZE	128
> +
>  /**
>   * struct tee_desc - Describes the TEE driver to the subsystem
>   * @name:	name of driver
> -- 
> 2.43.0
> 

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

* Re: [PATCH v6 2/2] tee: optee: store OS revision for TEE core
  2026-01-08  6:45           ` [PATCH v6 2/2] tee: optee: store OS revision for TEE core Aristo Chen
@ 2026-01-09 11:50             ` Sumit Garg
  2026-01-09 15:07               ` Aristo Chen
  2026-01-12  9:55             ` Jens Wiklander
  1 sibling, 1 reply; 42+ messages in thread
From: Sumit Garg @ 2026-01-09 11:50 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

On Thu, Jan 08, 2026 at 02:45:09PM +0800, Aristo Chen wrote:
> Collect OP-TEE OS revision from secure world for both SMC and FF-A
> ABIs, store it in the OP-TEE driver, and expose it through the
> generic get_tee_revision() callback.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  drivers/tee/optee/core.c          | 23 +++++++++++++
>  drivers/tee/optee/ffa_abi.c       | 57 ++++++++++++++++++++++++-------
>  drivers/tee/optee/optee_private.h | 19 +++++++++++
>  drivers/tee/optee/smc_abi.c       | 15 ++++++--
>  4 files changed, 99 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index 5b62139714ce..2d807bc748bc 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
>  	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
>  }
>  
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> +{
> +	struct optee *optee = tee_get_drvdata(teedev);
> +	u64 build_id;
> +
> +	if (!optee)
> +		return -ENODEV;
> +	if (!buf || !len)
> +		return -EINVAL;
> +
> +	build_id = optee->revision.os_build_id;
> +	if (build_id)
> +		scnprintf(buf, len, "%u.%u (%016llx)",
> +			  optee->revision.os_major,
> +			  optee->revision.os_minor,
> +			  (unsigned long long)build_id);
> +	else
> +		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> +			  optee->revision.os_minor);
> +
> +	return 0;
> +}
> +
>  static void optee_bus_scan(struct work_struct *work)
>  {
>  	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> index bf8390789ecf..82dbed1c87e5 100644
> --- a/drivers/tee/optee/ffa_abi.c
> +++ b/drivers/tee/optee/ffa_abi.c
> @@ -775,6 +775,42 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
>   * with a matching configuration.
>   */
>  
> +static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
> +					const struct ffa_ops *ops,
> +					struct optee_revision *revision,
> +					bool log)
> +{
> +	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> +	struct ffa_send_direct_data data = {
> +		.data0 = OPTEE_FFA_GET_OS_VERSION,
> +	};
> +	int rc;
> +
> +	msg_ops->mode_32bit_set(ffa_dev);
> +
> +	rc = msg_ops->sync_send_receive(ffa_dev, &data);
> +	if (rc) {
> +		pr_err("Unexpected error %d\n", rc);
> +		return false;
> +	}
> +
> +	if (revision) {
> +		revision->os_major = data.data0;
> +		revision->os_minor = data.data1;
> +		revision->os_build_id = data.data2;
> +	}
> +
> +	if (log) {
> +		if (data.data2)
> +			pr_info("revision %lu.%lu (%08lx)",
> +				data.data0, data.data1, data.data2);
> +		else
> +			pr_info("revision %lu.%lu", data.data0, data.data1);
> +	}
> +
> +	return true;
> +}
> +
>  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>  					const struct ffa_ops *ops)
>  {
> @@ -798,19 +834,8 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>  		return false;
>  	}
>  
> -	data = (struct ffa_send_direct_data){
> -		.data0 = OPTEE_FFA_GET_OS_VERSION,
> -	};
> -	rc = msg_ops->sync_send_receive(ffa_dev, &data);
> -	if (rc) {
> -		pr_err("Unexpected error %d\n", rc);
> +	if (!optee_ffa_get_os_revision(ffa_dev, ops, NULL, true))

Why do you need to invoke optee_ffa_get_os_revision() here?

-Sumit

>  		return false;
> -	}
> -	if (data.data2)
> -		pr_info("revision %lu.%lu (%08lx)",
> -			data.data0, data.data1, data.data2);
> -	else
> -		pr_info("revision %lu.%lu", data.data0, data.data1);
>  
>  	return true;
>  }
> @@ -900,6 +925,7 @@ static int optee_ffa_open(struct tee_context *ctx)
>  
>  static const struct tee_driver_ops optee_ffa_clnt_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_ffa_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -918,6 +944,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_ffa_supp_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_ffa_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1060,6 +1087,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  	if (!optee)
>  		return -ENOMEM;
>  
> +	if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision,
> +					 false)) {
> +		rc = -EINVAL;
> +		goto err_free_optee;
> +	}
> +
>  	pool = optee_ffa_shm_pool_alloc_pages();
>  	if (IS_ERR(pool)) {
>  		rc = PTR_ERR(pool);
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index db9ea673fbca..acd3051c4879 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -171,6 +171,24 @@ struct optee_ffa {
>  
>  struct optee;
>  
> +/**
> + * struct optee_revision - OP-TEE OS revision reported by secure world
> + * @os_major:		OP-TEE OS major version
> + * @os_minor:		OP-TEE OS minor version
> + * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
> + *
> + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> + * FF-A ABI version.
> + */
> +struct optee_revision {
> +	u32 os_major;
> +	u32 os_minor;
> +	u64 os_build_id;
> +};
> +
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> +
>  /**
>   * struct optee_ops - OP-TEE driver internal operations
>   * @do_call_with_arg:	enters OP-TEE in secure world
> @@ -249,6 +267,7 @@ struct optee {
>  	bool in_kernel_rpmb_routing;
>  	struct work_struct scan_bus_work;
>  	struct work_struct rpmb_scan_bus_work;
> +	struct optee_revision revision;
>  };
>  
>  struct optee_session {
> diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> index 0be663fcd52b..51fae1ab8ef8 100644
> --- a/drivers/tee/optee/smc_abi.c
> +++ b/drivers/tee/optee/smc_abi.c
> @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
>  
>  static const struct tee_driver_ops optee_clnt_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_supp_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
>  }
>  #endif
>  
> -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> +				      struct optee_revision *revision)
>  {
>  	union {
>  		struct arm_smccc_res smccc;
> @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
>  	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
>  		  &res.smccc);
>  
> +	if (revision) {
> +		revision->os_major = res.result.major;
> +		revision->os_minor = res.result.minor;
> +		revision->os_build_id = res.result.build_id;
> +	}
> +
>  	if (res.result.build_id)
>  		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
>  			res.result.minor, (int)sizeof(res.result.build_id) * 2,
> @@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> -	optee_msg_get_os_revision(invoke_fn);
> -
>  	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
>  		pr_warn("api revision mismatch\n");
>  		return -EINVAL;
> @@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
>  		goto err_free_shm_pool;
>  	}
>  
> +	optee_msg_get_os_revision(invoke_fn, &optee->revision);
> +
>  	optee->ops = &optee_ops;
>  	optee->smc.invoke_fn = invoke_fn;
>  	optee->smc.sec_caps = sec_caps;
> -- 
> 2.43.0
> 

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

* Re: [PATCH v6 2/2] tee: optee: store OS revision for TEE core
  2026-01-09 11:50             ` Sumit Garg
@ 2026-01-09 15:07               ` Aristo Chen
  2026-01-12 11:22                 ` Sumit Garg
  0 siblings, 1 reply; 42+ messages in thread
From: Aristo Chen @ 2026-01-09 15:07 UTC (permalink / raw)
  To: Sumit Garg
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Hi Sumit

Sumit Garg <sumit.garg@kernel.org> 於 2026年1月9日週五 下午7:50寫道:
>
> On Thu, Jan 08, 2026 at 02:45:09PM +0800, Aristo Chen wrote:
> > Collect OP-TEE OS revision from secure world for both SMC and FF-A
> > ABIs, store it in the OP-TEE driver, and expose it through the
> > generic get_tee_revision() callback.
> >
> > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > ---
> >  drivers/tee/optee/core.c          | 23 +++++++++++++
> >  drivers/tee/optee/ffa_abi.c       | 57 ++++++++++++++++++++++++-------
> >  drivers/tee/optee/optee_private.h | 19 +++++++++++
> >  drivers/tee/optee/smc_abi.c       | 15 ++++++--
> >  4 files changed, 99 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > index 5b62139714ce..2d807bc748bc 100644
> > --- a/drivers/tee/optee/core.c
> > +++ b/drivers/tee/optee/core.c
> > @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
> >       return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
> >  }
> >
> > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> > +{
> > +     struct optee *optee = tee_get_drvdata(teedev);
> > +     u64 build_id;
> > +
> > +     if (!optee)
> > +             return -ENODEV;
> > +     if (!buf || !len)
> > +             return -EINVAL;
> > +
> > +     build_id = optee->revision.os_build_id;
> > +     if (build_id)
> > +             scnprintf(buf, len, "%u.%u (%016llx)",
> > +                       optee->revision.os_major,
> > +                       optee->revision.os_minor,
> > +                       (unsigned long long)build_id);
> > +     else
> > +             scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> > +                       optee->revision.os_minor);
> > +
> > +     return 0;
> > +}
> > +
> >  static void optee_bus_scan(struct work_struct *work)
> >  {
> >       WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> > index bf8390789ecf..82dbed1c87e5 100644
> > --- a/drivers/tee/optee/ffa_abi.c
> > +++ b/drivers/tee/optee/ffa_abi.c
> > @@ -775,6 +775,42 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
> >   * with a matching configuration.
> >   */
> >
> > +static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
> > +                                     const struct ffa_ops *ops,
> > +                                     struct optee_revision *revision,
> > +                                     bool log)
> > +{
> > +     const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> > +     struct ffa_send_direct_data data = {
> > +             .data0 = OPTEE_FFA_GET_OS_VERSION,
> > +     };
> > +     int rc;
> > +
> > +     msg_ops->mode_32bit_set(ffa_dev);
> > +
> > +     rc = msg_ops->sync_send_receive(ffa_dev, &data);
> > +     if (rc) {
> > +             pr_err("Unexpected error %d\n", rc);
> > +             return false;
> > +     }
> > +
> > +     if (revision) {
> > +             revision->os_major = data.data0;
> > +             revision->os_minor = data.data1;
> > +             revision->os_build_id = data.data2;
> > +     }
> > +
> > +     if (log) {
> > +             if (data.data2)
> > +                     pr_info("revision %lu.%lu (%08lx)",
> > +                             data.data0, data.data1, data.data2);
> > +             else
> > +                     pr_info("revision %lu.%lu", data.data0, data.data1);
> > +     }
> > +
> > +     return true;
> > +}
> > +
> >  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> >                                       const struct ffa_ops *ops)
> >  {
> > @@ -798,19 +834,8 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> >               return false;
> >       }
> >
> > -     data = (struct ffa_send_direct_data){
> > -             .data0 = OPTEE_FFA_GET_OS_VERSION,
> > -     };
> > -     rc = msg_ops->sync_send_receive(ffa_dev, &data);
> > -     if (rc) {
> > -             pr_err("Unexpected error %d\n", rc);
> > +     if (!optee_ffa_get_os_revision(ffa_dev, ops, NULL, true))
>
> Why do you need to invoke optee_ffa_get_os_revision() here?

I’m calling optee_ffa_get_os_revision() here to avoid duplicating the
GET_OS_VERSION call/printing logic. The original code in
optee_ffa_api_is_compatible() already did the OS version query and
printed it; after factoring it out, the helper keeps that behavior in one
place. If we don’t call it there, we’d either lose the existing dmesg log
or re‑implement the same OS‑version query/print block again, which I’m
trying to avoid.

If you’d rather avoid the extra call at this stage, maybe we can always
print the log in the optee_ffa_get_os_revision() and remove the call
from optee_ffa_api_is_compatible() entirely.

>
> -Sumit
>
> >               return false;
> > -     }
> > -     if (data.data2)
> > -             pr_info("revision %lu.%lu (%08lx)",
> > -                     data.data0, data.data1, data.data2);
> > -     else
> > -             pr_info("revision %lu.%lu", data.data0, data.data1);
> >
> >       return true;
> >  }
> > @@ -900,6 +925,7 @@ static int optee_ffa_open(struct tee_context *ctx)
> >
> >  static const struct tee_driver_ops optee_ffa_clnt_ops = {
> >       .get_version = optee_ffa_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_ffa_open,
> >       .release = optee_release,
> >       .open_session = optee_open_session,
> > @@ -918,6 +944,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
> >
> >  static const struct tee_driver_ops optee_ffa_supp_ops = {
> >       .get_version = optee_ffa_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_ffa_open,
> >       .release = optee_release_supp,
> >       .supp_recv = optee_supp_recv,
> > @@ -1060,6 +1087,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> >       if (!optee)
> >               return -ENOMEM;
> >
> > +     if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision,
> > +                                      false)) {
> > +             rc = -EINVAL;
> > +             goto err_free_optee;
> > +     }
> > +
> >       pool = optee_ffa_shm_pool_alloc_pages();
> >       if (IS_ERR(pool)) {
> >               rc = PTR_ERR(pool);
> > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > index db9ea673fbca..acd3051c4879 100644
> > --- a/drivers/tee/optee/optee_private.h
> > +++ b/drivers/tee/optee/optee_private.h
> > @@ -171,6 +171,24 @@ struct optee_ffa {
> >
> >  struct optee;
> >
> > +/**
> > + * struct optee_revision - OP-TEE OS revision reported by secure world
> > + * @os_major:                OP-TEE OS major version
> > + * @os_minor:                OP-TEE OS minor version
> > + * @os_build_id:     OP-TEE OS build identifier (0 if unspecified)
> > + *
> > + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> > + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> > + * FF-A ABI version.
> > + */
> > +struct optee_revision {
> > +     u32 os_major;
> > +     u32 os_minor;
> > +     u64 os_build_id;
> > +};
> > +
> > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> > +
> >  /**
> >   * struct optee_ops - OP-TEE driver internal operations
> >   * @do_call_with_arg:        enters OP-TEE in secure world
> > @@ -249,6 +267,7 @@ struct optee {
> >       bool in_kernel_rpmb_routing;
> >       struct work_struct scan_bus_work;
> >       struct work_struct rpmb_scan_bus_work;
> > +     struct optee_revision revision;
> >  };
> >
> >  struct optee_session {
> > diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> > index 0be663fcd52b..51fae1ab8ef8 100644
> > --- a/drivers/tee/optee/smc_abi.c
> > +++ b/drivers/tee/optee/smc_abi.c
> > @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
> >
> >  static const struct tee_driver_ops optee_clnt_ops = {
> >       .get_version = optee_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_smc_open,
> >       .release = optee_release,
> >       .open_session = optee_open_session,
> > @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
> >
> >  static const struct tee_driver_ops optee_supp_ops = {
> >       .get_version = optee_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_smc_open,
> >       .release = optee_release_supp,
> >       .supp_recv = optee_supp_recv,
> > @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
> >  }
> >  #endif
> >
> > -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> > +                                   struct optee_revision *revision)
> >  {
> >       union {
> >               struct arm_smccc_res smccc;
> > @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> >       invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
> >                 &res.smccc);
> >
> > +     if (revision) {
> > +             revision->os_major = res.result.major;
> > +             revision->os_minor = res.result.minor;
> > +             revision->os_build_id = res.result.build_id;
> > +     }
> > +
> >       if (res.result.build_id)
> >               pr_info("revision %lu.%lu (%0*lx)", res.result.major,
> >                       res.result.minor, (int)sizeof(res.result.build_id) * 2,
> > @@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
> >               return -EINVAL;
> >       }
> >
> > -     optee_msg_get_os_revision(invoke_fn);
> > -
> >       if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
> >               pr_warn("api revision mismatch\n");
> >               return -EINVAL;
> > @@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
> >               goto err_free_shm_pool;
> >       }
> >
> > +     optee_msg_get_os_revision(invoke_fn, &optee->revision);
> > +
> >       optee->ops = &optee_ops;
> >       optee->smc.invoke_fn = invoke_fn;
> >       optee->smc.sec_caps = sec_caps;
> > --
> > 2.43.0
> >

Best regards,
Aristo

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

* Re: [PATCH v6 1/2] tee: add revision sysfs attribute
  2026-01-08  6:45         ` [PATCH v6 " Aristo Chen
  2026-01-08  6:45           ` [PATCH v6 2/2] tee: optee: store OS revision for TEE core Aristo Chen
  2026-01-09 11:48           ` [PATCH v6 1/2] tee: add revision sysfs attribute Sumit Garg
@ 2026-01-12  9:50           ` Jens Wiklander
  2026-01-12 15:48           ` [PATCH v7 " Aristo Chen
  3 siblings, 0 replies; 42+ messages in thread
From: Jens Wiklander @ 2026-01-12  9:50 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, sumit.garg, op-tee, harshal.dev, mario.limonciello,
	Rijo-john.Thomas, amirreza.zarrabi, Aristo Chen

On Thu, Jan 8, 2026 at 7:45 AM Aristo Chen <jj251510319013@gmail.com> wrote:
>
> Add a generic TEE revision sysfs attribute backed by a new
> optional get_tee_revision() callback. The revision string is
> diagnostic-only and must not be used to infer feature support.
>
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  Documentation/ABI/testing/sysfs-class-tee | 10 +++++
>  drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
>  include/linux/tee_core.h                  |  9 ++++
>  3 files changed, 69 insertions(+), 1 deletion(-)

checkpatch complains with:

WARNING: From:/Signed-off-by: email address mismatch: 'From: Aristo
Chen <jj251510319013@gmail.com>' != 'Signed-off-by: Aristo Chen
<aristo.chen@canonical.com>'

total: 0 errors, 1 warnings, 0 checks, 100 lines checked

Cheers,
Jens

>
> diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
> index c9144d16003e..1a0a3050aaa9 100644
> --- a/Documentation/ABI/testing/sysfs-class-tee
> +++ b/Documentation/ABI/testing/sysfs-class-tee
> @@ -13,3 +13,13 @@ Description:
>                 space if the variable is absent. The primary purpose
>                 of this variable is to let systemd know whether
>                 tee-supplicant is needed in the early boot with initramfs.
> +
> +What:          /sys/class/tee/tee{,priv}X/revision
> +Date:          Jan 2026
> +KernelVersion: 6.19
> +Contact:       op-tee@lists.trustedfirmware.org
> +Description:
> +               Read-only revision string reported by the TEE driver. This is
> +               for diagnostics only and must not be used to infer feature
> +               support. Use TEE_IOC_VERSION for capability and compatibility
> +               checks.
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index d65d47cc154e..0a00499811c1 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
>         NULL
>  };
>
> -ATTRIBUTE_GROUPS(tee_dev);
> +static const struct attribute_group tee_dev_group = {
> +       .attrs = tee_dev_attrs,
> +};
> +
> +static ssize_t revision_show(struct device *dev,
> +                            struct device_attribute *attr, char *buf)
> +{
> +       struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +       char version[TEE_REVISION_STR_SIZE];
> +       int ret;
> +
> +       if (!teedev->desc->ops->get_tee_revision)
> +               return -ENODEV;
> +
> +       ret = teedev->desc->ops->get_tee_revision(teedev, version,
> +                                                 sizeof(version));
> +       if (ret)
> +               return ret;
> +
> +       return sysfs_emit(buf, "%s\n", version);
> +}
> +static DEVICE_ATTR_RO(revision);
> +
> +static struct attribute *tee_revision_attrs[] = {
> +       &dev_attr_revision.attr,
> +       NULL
> +};
> +
> +static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
> +                                           struct attribute *attr, int n)
> +{
> +       struct device *dev = kobj_to_dev(kobj);
> +       struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +
> +       if (teedev->desc->ops->get_tee_revision)
> +               return attr->mode;
> +
> +       return 0;
> +}
> +
> +static const struct attribute_group tee_revision_group = {
> +       .attrs = tee_revision_attrs,
> +       .is_visible = tee_revision_attr_is_visible,
> +};
> +
> +static const struct attribute_group *tee_dev_groups[] = {
> +       &tee_dev_group,
> +       &tee_revision_group,
> +       NULL
> +};
>
>  static const struct class tee_class = {
>         .name = "tee",
> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
> index 1f3e5dad6d0d..ee5f0bd41f43 100644
> --- a/include/linux/tee_core.h
> +++ b/include/linux/tee_core.h
> @@ -76,6 +76,9 @@ struct tee_device {
>  /**
>   * struct tee_driver_ops - driver operations vtable
>   * @get_version:       returns version of driver
> + * @get_tee_revision:  returns revision string (diagnostic only);
> + *                     do not infer feature support from this, use
> + *                     TEE_IOC_VERSION instead
>   * @open:              called for a context when the device file is opened
>   * @close_context:     called when the device file is closed
>   * @release:           called to release the context
> @@ -95,9 +98,12 @@ struct tee_device {
>   * client closes the device file, even if there are existing references to the
>   * context. The TEE driver can use @close_context to start cleaning up.
>   */
> +
>  struct tee_driver_ops {
>         void (*get_version)(struct tee_device *teedev,
>                             struct tee_ioctl_version_data *vers);
> +       int (*get_tee_revision)(struct tee_device *teedev,
> +                               char *buf, size_t len);
>         int (*open)(struct tee_context *ctx);
>         void (*close_context)(struct tee_context *ctx);
>         void (*release)(struct tee_context *ctx);
> @@ -123,6 +129,9 @@ struct tee_driver_ops {
>         int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
>  };
>
> +/* Size for TEE revision string buffer used by get_tee_revision(). */
> +#define TEE_REVISION_STR_SIZE  128
> +
>  /**
>   * struct tee_desc - Describes the TEE driver to the subsystem
>   * @name:      name of driver
> --
> 2.43.0
>

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

* Re: [PATCH v6 2/2] tee: optee: store OS revision for TEE core
  2026-01-08  6:45           ` [PATCH v6 2/2] tee: optee: store OS revision for TEE core Aristo Chen
  2026-01-09 11:50             ` Sumit Garg
@ 2026-01-12  9:55             ` Jens Wiklander
  2026-01-12 10:43               ` Aristo Chen
  1 sibling, 1 reply; 42+ messages in thread
From: Jens Wiklander @ 2026-01-12  9:55 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, sumit.garg, op-tee, harshal.dev, mario.limonciello,
	Rijo-john.Thomas, amirreza.zarrabi, Aristo Chen

On Thu, Jan 08, 2026 at 02:45:09PM +0800, Aristo Chen wrote:
> Collect OP-TEE OS revision from secure world for both SMC and FF-A
> ABIs, store it in the OP-TEE driver, and expose it through the
> generic get_tee_revision() callback.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  drivers/tee/optee/core.c          | 23 +++++++++++++
>  drivers/tee/optee/ffa_abi.c       | 57 ++++++++++++++++++++++++-------
>  drivers/tee/optee/optee_private.h | 19 +++++++++++
>  drivers/tee/optee/smc_abi.c       | 15 ++++++--
>  4 files changed, 99 insertions(+), 15 deletions(-)

Checkpatch complains with:
CHECK: Alignment should match open parenthesis
#62: FILE: drivers/tee/optee/ffa_abi.c:779:
+static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
+					const struct ffa_ops *ops,

CHECK: Alignment should match open parenthesis
#142: FILE: drivers/tee/optee/ffa_abi.c:1091:
+	if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision,
+					 false)) {

WARNING: From:/Signed-off-by: email address mismatch: 'From: Aristo Chen <jj251510319013@gmail.com>' != 'Signed-off-by: Aristo Chen <aristo.chen@canonical.com>'

total: 0 errors, 1 warnings, 2 checks, 199 lines checked

Cheers,
Jens

> 
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index 5b62139714ce..2d807bc748bc 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
>  	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
>  }
>  
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> +{
> +	struct optee *optee = tee_get_drvdata(teedev);
> +	u64 build_id;
> +
> +	if (!optee)
> +		return -ENODEV;
> +	if (!buf || !len)
> +		return -EINVAL;
> +
> +	build_id = optee->revision.os_build_id;
> +	if (build_id)
> +		scnprintf(buf, len, "%u.%u (%016llx)",
> +			  optee->revision.os_major,
> +			  optee->revision.os_minor,
> +			  (unsigned long long)build_id);
> +	else
> +		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> +			  optee->revision.os_minor);
> +
> +	return 0;
> +}
> +
>  static void optee_bus_scan(struct work_struct *work)
>  {
>  	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> index bf8390789ecf..82dbed1c87e5 100644
> --- a/drivers/tee/optee/ffa_abi.c
> +++ b/drivers/tee/optee/ffa_abi.c
> @@ -775,6 +775,42 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
>   * with a matching configuration.
>   */
>  
> +static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
> +					const struct ffa_ops *ops,
> +					struct optee_revision *revision,
> +					bool log)
> +{
> +	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> +	struct ffa_send_direct_data data = {
> +		.data0 = OPTEE_FFA_GET_OS_VERSION,
> +	};
> +	int rc;
> +
> +	msg_ops->mode_32bit_set(ffa_dev);
> +
> +	rc = msg_ops->sync_send_receive(ffa_dev, &data);
> +	if (rc) {
> +		pr_err("Unexpected error %d\n", rc);
> +		return false;
> +	}
> +
> +	if (revision) {
> +		revision->os_major = data.data0;
> +		revision->os_minor = data.data1;
> +		revision->os_build_id = data.data2;
> +	}
> +
> +	if (log) {
> +		if (data.data2)
> +			pr_info("revision %lu.%lu (%08lx)",
> +				data.data0, data.data1, data.data2);
> +		else
> +			pr_info("revision %lu.%lu", data.data0, data.data1);
> +	}
> +
> +	return true;
> +}
> +
>  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>  					const struct ffa_ops *ops)
>  {
> @@ -798,19 +834,8 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>  		return false;
>  	}
>  
> -	data = (struct ffa_send_direct_data){
> -		.data0 = OPTEE_FFA_GET_OS_VERSION,
> -	};
> -	rc = msg_ops->sync_send_receive(ffa_dev, &data);
> -	if (rc) {
> -		pr_err("Unexpected error %d\n", rc);
> +	if (!optee_ffa_get_os_revision(ffa_dev, ops, NULL, true))
>  		return false;
> -	}
> -	if (data.data2)
> -		pr_info("revision %lu.%lu (%08lx)",
> -			data.data0, data.data1, data.data2);
> -	else
> -		pr_info("revision %lu.%lu", data.data0, data.data1);
>  
>  	return true;
>  }
> @@ -900,6 +925,7 @@ static int optee_ffa_open(struct tee_context *ctx)
>  
>  static const struct tee_driver_ops optee_ffa_clnt_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_ffa_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -918,6 +944,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_ffa_supp_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_ffa_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1060,6 +1087,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  	if (!optee)
>  		return -ENOMEM;
>  
> +	if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision,
> +					 false)) {
> +		rc = -EINVAL;
> +		goto err_free_optee;
> +	}
> +
>  	pool = optee_ffa_shm_pool_alloc_pages();
>  	if (IS_ERR(pool)) {
>  		rc = PTR_ERR(pool);
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index db9ea673fbca..acd3051c4879 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -171,6 +171,24 @@ struct optee_ffa {
>  
>  struct optee;
>  
> +/**
> + * struct optee_revision - OP-TEE OS revision reported by secure world
> + * @os_major:		OP-TEE OS major version
> + * @os_minor:		OP-TEE OS minor version
> + * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
> + *
> + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> + * FF-A ABI version.
> + */
> +struct optee_revision {
> +	u32 os_major;
> +	u32 os_minor;
> +	u64 os_build_id;
> +};
> +
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> +
>  /**
>   * struct optee_ops - OP-TEE driver internal operations
>   * @do_call_with_arg:	enters OP-TEE in secure world
> @@ -249,6 +267,7 @@ struct optee {
>  	bool in_kernel_rpmb_routing;
>  	struct work_struct scan_bus_work;
>  	struct work_struct rpmb_scan_bus_work;
> +	struct optee_revision revision;
>  };
>  
>  struct optee_session {
> diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> index 0be663fcd52b..51fae1ab8ef8 100644
> --- a/drivers/tee/optee/smc_abi.c
> +++ b/drivers/tee/optee/smc_abi.c
> @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
>  
>  static const struct tee_driver_ops optee_clnt_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_supp_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
>  }
>  #endif
>  
> -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> +				      struct optee_revision *revision)
>  {
>  	union {
>  		struct arm_smccc_res smccc;
> @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
>  	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
>  		  &res.smccc);
>  
> +	if (revision) {
> +		revision->os_major = res.result.major;
> +		revision->os_minor = res.result.minor;
> +		revision->os_build_id = res.result.build_id;
> +	}
> +
>  	if (res.result.build_id)
>  		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
>  			res.result.minor, (int)sizeof(res.result.build_id) * 2,
> @@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> -	optee_msg_get_os_revision(invoke_fn);
> -
>  	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
>  		pr_warn("api revision mismatch\n");
>  		return -EINVAL;
> @@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
>  		goto err_free_shm_pool;
>  	}
>  
> +	optee_msg_get_os_revision(invoke_fn, &optee->revision);
> +
>  	optee->ops = &optee_ops;
>  	optee->smc.invoke_fn = invoke_fn;
>  	optee->smc.sec_caps = sec_caps;
> -- 
> 2.43.0
> 

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

* Re: [PATCH v6 2/2] tee: optee: store OS revision for TEE core
  2026-01-12  9:55             ` Jens Wiklander
@ 2026-01-12 10:43               ` Aristo Chen
  0 siblings, 0 replies; 42+ messages in thread
From: Aristo Chen @ 2026-01-12 10:43 UTC (permalink / raw)
  To: Jens Wiklander
  Cc: linux-kernel, sumit.garg, op-tee, harshal.dev, mario.limonciello,
	Rijo-john.Thomas, amirreza.zarrabi, Aristo Chen

Hi Jens,

Jens Wiklander <jens.wiklander@linaro.org> 於 2026年1月12日週一 下午5:55寫道:
>
> On Thu, Jan 08, 2026 at 02:45:09PM +0800, Aristo Chen wrote:
> > Collect OP-TEE OS revision from secure world for both SMC and FF-A
> > ABIs, store it in the OP-TEE driver, and expose it through the
> > generic get_tee_revision() callback.
> >
> > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > ---
> >  drivers/tee/optee/core.c          | 23 +++++++++++++
> >  drivers/tee/optee/ffa_abi.c       | 57 ++++++++++++++++++++++++-------
> >  drivers/tee/optee/optee_private.h | 19 +++++++++++
> >  drivers/tee/optee/smc_abi.c       | 15 ++++++--
> >  4 files changed, 99 insertions(+), 15 deletions(-)
>
> Checkpatch complains with:
> CHECK: Alignment should match open parenthesis
> #62: FILE: drivers/tee/optee/ffa_abi.c:779:
> +static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
> +                                       const struct ffa_ops *ops,
>
> CHECK: Alignment should match open parenthesis
> #142: FILE: drivers/tee/optee/ffa_abi.c:1091:
> +       if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision,
> +                                        false)) {
>
> WARNING: From:/Signed-off-by: email address mismatch: 'From: Aristo Chen <jj251510319013@gmail.com>' != 'Signed-off-by: Aristo Chen <aristo.chen@canonical.com>'
>
> total: 0 errors, 1 warnings, 2 checks, 199 lines checked

Sorry for causing the inconvenience, somehow I did not get complained
by the checkpatch.pl
and I will fix the warnings in v7

just out of curiosity and trying to prevent from making the same
mistake again, are you using
command like this?

```
$ ./scripts/checkpatch.pl v6_patch/*
-------------------------------------------------------
v6_patch/v6-0001-tee-add-revision-sysfs-attribute.patch
-------------------------------------------------------
total: 0 errors, 0 warnings, 100 lines checked

v6_patch/v6-0001-tee-add-revision-sysfs-attribute.patch has no obvious
style problems and is ready for submission.
---------------------------------------------------------------
v6_patch/v6-0002-tee-optee-store-OS-revision-for-TEE-core.patch
---------------------------------------------------------------
total: 0 errors, 0 warnings, 199 lines checked

v6_patch/v6-0002-tee-optee-store-OS-revision-for-TEE-core.patch has no
obvious style problems and is ready for submission.
```

As you can see, I did not see any complain from the output, so I was
assuming they are
in a good shape.

>
> Cheers,
> Jens
>
> >
> > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > index 5b62139714ce..2d807bc748bc 100644
> > --- a/drivers/tee/optee/core.c
> > +++ b/drivers/tee/optee/core.c
> > @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
> >       return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
> >  }
> >
> > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> > +{
> > +     struct optee *optee = tee_get_drvdata(teedev);
> > +     u64 build_id;
> > +
> > +     if (!optee)
> > +             return -ENODEV;
> > +     if (!buf || !len)
> > +             return -EINVAL;
> > +
> > +     build_id = optee->revision.os_build_id;
> > +     if (build_id)
> > +             scnprintf(buf, len, "%u.%u (%016llx)",
> > +                       optee->revision.os_major,
> > +                       optee->revision.os_minor,
> > +                       (unsigned long long)build_id);
> > +     else
> > +             scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> > +                       optee->revision.os_minor);
> > +
> > +     return 0;
> > +}
> > +
> >  static void optee_bus_scan(struct work_struct *work)
> >  {
> >       WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> > index bf8390789ecf..82dbed1c87e5 100644
> > --- a/drivers/tee/optee/ffa_abi.c
> > +++ b/drivers/tee/optee/ffa_abi.c
> > @@ -775,6 +775,42 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
> >   * with a matching configuration.
> >   */
> >
> > +static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
> > +                                     const struct ffa_ops *ops,
> > +                                     struct optee_revision *revision,
> > +                                     bool log)
> > +{
> > +     const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> > +     struct ffa_send_direct_data data = {
> > +             .data0 = OPTEE_FFA_GET_OS_VERSION,
> > +     };
> > +     int rc;
> > +
> > +     msg_ops->mode_32bit_set(ffa_dev);
> > +
> > +     rc = msg_ops->sync_send_receive(ffa_dev, &data);
> > +     if (rc) {
> > +             pr_err("Unexpected error %d\n", rc);
> > +             return false;
> > +     }
> > +
> > +     if (revision) {
> > +             revision->os_major = data.data0;
> > +             revision->os_minor = data.data1;
> > +             revision->os_build_id = data.data2;
> > +     }
> > +
> > +     if (log) {
> > +             if (data.data2)
> > +                     pr_info("revision %lu.%lu (%08lx)",
> > +                             data.data0, data.data1, data.data2);
> > +             else
> > +                     pr_info("revision %lu.%lu", data.data0, data.data1);
> > +     }
> > +
> > +     return true;
> > +}
> > +
> >  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> >                                       const struct ffa_ops *ops)
> >  {
> > @@ -798,19 +834,8 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> >               return false;
> >       }
> >
> > -     data = (struct ffa_send_direct_data){
> > -             .data0 = OPTEE_FFA_GET_OS_VERSION,
> > -     };
> > -     rc = msg_ops->sync_send_receive(ffa_dev, &data);
> > -     if (rc) {
> > -             pr_err("Unexpected error %d\n", rc);
> > +     if (!optee_ffa_get_os_revision(ffa_dev, ops, NULL, true))
> >               return false;
> > -     }
> > -     if (data.data2)
> > -             pr_info("revision %lu.%lu (%08lx)",
> > -                     data.data0, data.data1, data.data2);
> > -     else
> > -             pr_info("revision %lu.%lu", data.data0, data.data1);
> >
> >       return true;
> >  }
> > @@ -900,6 +925,7 @@ static int optee_ffa_open(struct tee_context *ctx)
> >
> >  static const struct tee_driver_ops optee_ffa_clnt_ops = {
> >       .get_version = optee_ffa_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_ffa_open,
> >       .release = optee_release,
> >       .open_session = optee_open_session,
> > @@ -918,6 +944,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
> >
> >  static const struct tee_driver_ops optee_ffa_supp_ops = {
> >       .get_version = optee_ffa_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_ffa_open,
> >       .release = optee_release_supp,
> >       .supp_recv = optee_supp_recv,
> > @@ -1060,6 +1087,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
> >       if (!optee)
> >               return -ENOMEM;
> >
> > +     if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision,
> > +                                      false)) {
> > +             rc = -EINVAL;
> > +             goto err_free_optee;
> > +     }
> > +
> >       pool = optee_ffa_shm_pool_alloc_pages();
> >       if (IS_ERR(pool)) {
> >               rc = PTR_ERR(pool);
> > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> > index db9ea673fbca..acd3051c4879 100644
> > --- a/drivers/tee/optee/optee_private.h
> > +++ b/drivers/tee/optee/optee_private.h
> > @@ -171,6 +171,24 @@ struct optee_ffa {
> >
> >  struct optee;
> >
> > +/**
> > + * struct optee_revision - OP-TEE OS revision reported by secure world
> > + * @os_major:                OP-TEE OS major version
> > + * @os_minor:                OP-TEE OS minor version
> > + * @os_build_id:     OP-TEE OS build identifier (0 if unspecified)
> > + *
> > + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> > + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> > + * FF-A ABI version.
> > + */
> > +struct optee_revision {
> > +     u32 os_major;
> > +     u32 os_minor;
> > +     u64 os_build_id;
> > +};
> > +
> > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> > +
> >  /**
> >   * struct optee_ops - OP-TEE driver internal operations
> >   * @do_call_with_arg:        enters OP-TEE in secure world
> > @@ -249,6 +267,7 @@ struct optee {
> >       bool in_kernel_rpmb_routing;
> >       struct work_struct scan_bus_work;
> >       struct work_struct rpmb_scan_bus_work;
> > +     struct optee_revision revision;
> >  };
> >
> >  struct optee_session {
> > diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> > index 0be663fcd52b..51fae1ab8ef8 100644
> > --- a/drivers/tee/optee/smc_abi.c
> > +++ b/drivers/tee/optee/smc_abi.c
> > @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
> >
> >  static const struct tee_driver_ops optee_clnt_ops = {
> >       .get_version = optee_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_smc_open,
> >       .release = optee_release,
> >       .open_session = optee_open_session,
> > @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
> >
> >  static const struct tee_driver_ops optee_supp_ops = {
> >       .get_version = optee_get_version,
> > +     .get_tee_revision = optee_get_revision,
> >       .open = optee_smc_open,
> >       .release = optee_release_supp,
> >       .supp_recv = optee_supp_recv,
> > @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
> >  }
> >  #endif
> >
> > -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> > +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> > +                                   struct optee_revision *revision)
> >  {
> >       union {
> >               struct arm_smccc_res smccc;
> > @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> >       invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
> >                 &res.smccc);
> >
> > +     if (revision) {
> > +             revision->os_major = res.result.major;
> > +             revision->os_minor = res.result.minor;
> > +             revision->os_build_id = res.result.build_id;
> > +     }
> > +
> >       if (res.result.build_id)
> >               pr_info("revision %lu.%lu (%0*lx)", res.result.major,
> >                       res.result.minor, (int)sizeof(res.result.build_id) * 2,
> > @@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
> >               return -EINVAL;
> >       }
> >
> > -     optee_msg_get_os_revision(invoke_fn);
> > -
> >       if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
> >               pr_warn("api revision mismatch\n");
> >               return -EINVAL;
> > @@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
> >               goto err_free_shm_pool;
> >       }
> >
> > +     optee_msg_get_os_revision(invoke_fn, &optee->revision);
> > +
> >       optee->ops = &optee_ops;
> >       optee->smc.invoke_fn = invoke_fn;
> >       optee->smc.sec_caps = sec_caps;
> > --
> > 2.43.0
> >

Best regards,
Aristo

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

* Re: [PATCH v6 2/2] tee: optee: store OS revision for TEE core
  2026-01-09 15:07               ` Aristo Chen
@ 2026-01-12 11:22                 ` Sumit Garg
  0 siblings, 0 replies; 42+ messages in thread
From: Sumit Garg @ 2026-01-12 11:22 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

On Fri, Jan 09, 2026 at 11:07:40PM +0800, Aristo Chen wrote:
> Hi Sumit
> 
> Sumit Garg <sumit.garg@kernel.org> 於 2026年1月9日週五 下午7:50寫道:
> >
> > On Thu, Jan 08, 2026 at 02:45:09PM +0800, Aristo Chen wrote:
> > > Collect OP-TEE OS revision from secure world for both SMC and FF-A
> > > ABIs, store it in the OP-TEE driver, and expose it through the
> > > generic get_tee_revision() callback.
> > >
> > > Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> > > ---
> > >  drivers/tee/optee/core.c          | 23 +++++++++++++
> > >  drivers/tee/optee/ffa_abi.c       | 57 ++++++++++++++++++++++++-------
> > >  drivers/tee/optee/optee_private.h | 19 +++++++++++
> > >  drivers/tee/optee/smc_abi.c       | 15 ++++++--
> > >  4 files changed, 99 insertions(+), 15 deletions(-)
> > >
> > > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> > > index 5b62139714ce..2d807bc748bc 100644
> > > --- a/drivers/tee/optee/core.c
> > > +++ b/drivers/tee/optee/core.c
> > > @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
> > >       return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
> > >  }
> > >
> > > +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> > > +{
> > > +     struct optee *optee = tee_get_drvdata(teedev);
> > > +     u64 build_id;
> > > +
> > > +     if (!optee)
> > > +             return -ENODEV;
> > > +     if (!buf || !len)
> > > +             return -EINVAL;
> > > +
> > > +     build_id = optee->revision.os_build_id;
> > > +     if (build_id)
> > > +             scnprintf(buf, len, "%u.%u (%016llx)",
> > > +                       optee->revision.os_major,
> > > +                       optee->revision.os_minor,
> > > +                       (unsigned long long)build_id);
> > > +     else
> > > +             scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> > > +                       optee->revision.os_minor);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > >  static void optee_bus_scan(struct work_struct *work)
> > >  {
> > >       WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> > > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> > > index bf8390789ecf..82dbed1c87e5 100644
> > > --- a/drivers/tee/optee/ffa_abi.c
> > > +++ b/drivers/tee/optee/ffa_abi.c
> > > @@ -775,6 +775,42 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
> > >   * with a matching configuration.
> > >   */
> > >
> > > +static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
> > > +                                     const struct ffa_ops *ops,
> > > +                                     struct optee_revision *revision,
> > > +                                     bool log)
> > > +{
> > > +     const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> > > +     struct ffa_send_direct_data data = {
> > > +             .data0 = OPTEE_FFA_GET_OS_VERSION,
> > > +     };
> > > +     int rc;
> > > +
> > > +     msg_ops->mode_32bit_set(ffa_dev);
> > > +
> > > +     rc = msg_ops->sync_send_receive(ffa_dev, &data);
> > > +     if (rc) {
> > > +             pr_err("Unexpected error %d\n", rc);
> > > +             return false;
> > > +     }
> > > +
> > > +     if (revision) {
> > > +             revision->os_major = data.data0;
> > > +             revision->os_minor = data.data1;
> > > +             revision->os_build_id = data.data2;
> > > +     }
> > > +
> > > +     if (log) {
> > > +             if (data.data2)
> > > +                     pr_info("revision %lu.%lu (%08lx)",
> > > +                             data.data0, data.data1, data.data2);
> > > +             else
> > > +                     pr_info("revision %lu.%lu", data.data0, data.data1);
> > > +     }
> > > +
> > > +     return true;
> > > +}
> > > +
> > >  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > >                                       const struct ffa_ops *ops)
> > >  {
> > > @@ -798,19 +834,8 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
> > >               return false;
> > >       }
> > >
> > > -     data = (struct ffa_send_direct_data){
> > > -             .data0 = OPTEE_FFA_GET_OS_VERSION,
> > > -     };
> > > -     rc = msg_ops->sync_send_receive(ffa_dev, &data);
> > > -     if (rc) {
> > > -             pr_err("Unexpected error %d\n", rc);
> > > +     if (!optee_ffa_get_os_revision(ffa_dev, ops, NULL, true))
> >
> > Why do you need to invoke optee_ffa_get_os_revision() here?
> 
> I’m calling optee_ffa_get_os_revision() here to avoid duplicating the
> GET_OS_VERSION call/printing logic. The original code in
> optee_ffa_api_is_compatible() already did the OS version query and
> printed it; after factoring it out, the helper keeps that behavior in one
> place. If we don’t call it there, we’d either lose the existing dmesg log
> or re‑implement the same OS‑version query/print block again, which I’m
> trying to avoid.
> 
> If you’d rather avoid the extra call at this stage, maybe we can always
> print the log in the optee_ffa_get_os_revision() and remove the call
> from optee_ffa_api_is_compatible() entirely.

Yeah move the print to optee_ffa_get_os_revision() and drop the extra
call.

-Sumit

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

* [PATCH v7 1/2] tee: add revision sysfs attribute
  2026-01-08  6:45         ` [PATCH v6 " Aristo Chen
                             ` (2 preceding siblings ...)
  2026-01-12  9:50           ` Jens Wiklander
@ 2026-01-12 15:48           ` Aristo Chen
  2026-01-12 15:48             ` [PATCH v7 2/2] tee: optee: store OS revision for TEE core Aristo Chen
  2026-01-14 15:42             ` [PATCH v7 1/2] tee: add revision sysfs attribute Jens Wiklander
  3 siblings, 2 replies; 42+ messages in thread
From: Aristo Chen @ 2026-01-12 15:48 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen, Sumit Garg

Add a generic TEE revision sysfs attribute backed by a new
optional get_tee_revision() callback. The revision string is
diagnostic-only and must not be used to infer feature support.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
 Documentation/ABI/testing/sysfs-class-tee | 10 +++++
 drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
 include/linux/tee_core.h                  |  9 ++++
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
index c9144d16003e..1a0a3050aaa9 100644
--- a/Documentation/ABI/testing/sysfs-class-tee
+++ b/Documentation/ABI/testing/sysfs-class-tee
@@ -13,3 +13,13 @@ Description:
 		space if the variable is absent. The primary purpose
 		of this variable is to let systemd know whether
 		tee-supplicant is needed in the early boot with initramfs.
+
+What:		/sys/class/tee/tee{,priv}X/revision
+Date:		Jan 2026
+KernelVersion:	6.19
+Contact:	op-tee@lists.trustedfirmware.org
+Description:
+		Read-only revision string reported by the TEE driver. This is
+		for diagnostics only and must not be used to infer feature
+		support. Use TEE_IOC_VERSION for capability and compatibility
+		checks.
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index d65d47cc154e..0a00499811c1 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
 	NULL
 };
 
-ATTRIBUTE_GROUPS(tee_dev);
+static const struct attribute_group tee_dev_group = {
+	.attrs = tee_dev_attrs,
+};
+
+static ssize_t revision_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+	char version[TEE_REVISION_STR_SIZE];
+	int ret;
+
+	if (!teedev->desc->ops->get_tee_revision)
+		return -ENODEV;
+
+	ret = teedev->desc->ops->get_tee_revision(teedev, version,
+						  sizeof(version));
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%s\n", version);
+}
+static DEVICE_ATTR_RO(revision);
+
+static struct attribute *tee_revision_attrs[] = {
+	&dev_attr_revision.attr,
+	NULL
+};
+
+static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
+					    struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+	if (teedev->desc->ops->get_tee_revision)
+		return attr->mode;
+
+	return 0;
+}
+
+static const struct attribute_group tee_revision_group = {
+	.attrs = tee_revision_attrs,
+	.is_visible = tee_revision_attr_is_visible,
+};
+
+static const struct attribute_group *tee_dev_groups[] = {
+	&tee_dev_group,
+	&tee_revision_group,
+	NULL
+};
 
 static const struct class tee_class = {
 	.name = "tee",
diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
index 1f3e5dad6d0d..ee5f0bd41f43 100644
--- a/include/linux/tee_core.h
+++ b/include/linux/tee_core.h
@@ -76,6 +76,9 @@ struct tee_device {
 /**
  * struct tee_driver_ops - driver operations vtable
  * @get_version:	returns version of driver
+ * @get_tee_revision:	returns revision string (diagnostic only);
+ *			do not infer feature support from this, use
+ *			TEE_IOC_VERSION instead
  * @open:		called for a context when the device file is opened
  * @close_context:	called when the device file is closed
  * @release:		called to release the context
@@ -95,9 +98,12 @@ struct tee_device {
  * client closes the device file, even if there are existing references to the
  * context. The TEE driver can use @close_context to start cleaning up.
  */
+
 struct tee_driver_ops {
 	void (*get_version)(struct tee_device *teedev,
 			    struct tee_ioctl_version_data *vers);
+	int (*get_tee_revision)(struct tee_device *teedev,
+				char *buf, size_t len);
 	int (*open)(struct tee_context *ctx);
 	void (*close_context)(struct tee_context *ctx);
 	void (*release)(struct tee_context *ctx);
@@ -123,6 +129,9 @@ struct tee_driver_ops {
 	int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
 };
 
+/* Size for TEE revision string buffer used by get_tee_revision(). */
+#define TEE_REVISION_STR_SIZE	128
+
 /**
  * struct tee_desc - Describes the TEE driver to the subsystem
  * @name:	name of driver
-- 
2.43.0


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

* [PATCH v7 2/2] tee: optee: store OS revision for TEE core
  2026-01-12 15:48           ` [PATCH v7 " Aristo Chen
@ 2026-01-12 15:48             ` Aristo Chen
  2026-01-14 15:43               ` Jens Wiklander
  2026-01-15  6:18               ` Sumit Garg
  2026-01-14 15:42             ` [PATCH v7 1/2] tee: add revision sysfs attribute Jens Wiklander
  1 sibling, 2 replies; 42+ messages in thread
From: Aristo Chen @ 2026-01-12 15:48 UTC (permalink / raw)
  To: linux-kernel
  Cc: jens.wiklander, sumit.garg, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi,
	Aristo Chen

Collect OP-TEE OS revision from secure world for both SMC and FF-A
ABIs, store it in the OP-TEE driver, and expose it through the
generic get_tee_revision() callback.

Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
---
 drivers/tee/optee/core.c          | 23 +++++++++++++
 drivers/tee/optee/ffa_abi.c       | 54 +++++++++++++++++++++++--------
 drivers/tee/optee/optee_private.h | 19 +++++++++++
 drivers/tee/optee/smc_abi.c       | 15 +++++++--
 4 files changed, 94 insertions(+), 17 deletions(-)

diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index 5b62139714ce..2d807bc748bc 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
 	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
 }
 
+int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
+{
+	struct optee *optee = tee_get_drvdata(teedev);
+	u64 build_id;
+
+	if (!optee)
+		return -ENODEV;
+	if (!buf || !len)
+		return -EINVAL;
+
+	build_id = optee->revision.os_build_id;
+	if (build_id)
+		scnprintf(buf, len, "%u.%u (%016llx)",
+			  optee->revision.os_major,
+			  optee->revision.os_minor,
+			  (unsigned long long)build_id);
+	else
+		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
+			  optee->revision.os_minor);
+
+	return 0;
+}
+
 static void optee_bus_scan(struct work_struct *work)
 {
 	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index bf8390789ecf..8fc72aa95722 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -775,6 +775,39 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
  * with a matching configuration.
  */
 
+static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
+				      const struct ffa_ops *ops,
+				      struct optee_revision *revision)
+{
+	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
+	struct ffa_send_direct_data data = {
+		.data0 = OPTEE_FFA_GET_OS_VERSION,
+	};
+	int rc;
+
+	msg_ops->mode_32bit_set(ffa_dev);
+
+	rc = msg_ops->sync_send_receive(ffa_dev, &data);
+	if (rc) {
+		pr_err("Unexpected error %d\n", rc);
+		return false;
+	}
+
+	if (revision) {
+		revision->os_major = data.data0;
+		revision->os_minor = data.data1;
+		revision->os_build_id = data.data2;
+	}
+
+	if (data.data2)
+		pr_info("revision %lu.%lu (%08lx)",
+			data.data0, data.data1, data.data2);
+	else
+		pr_info("revision %lu.%lu", data.data0, data.data1);
+
+	return true;
+}
+
 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 					const struct ffa_ops *ops)
 {
@@ -798,20 +831,6 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
 		return false;
 	}
 
-	data = (struct ffa_send_direct_data){
-		.data0 = OPTEE_FFA_GET_OS_VERSION,
-	};
-	rc = msg_ops->sync_send_receive(ffa_dev, &data);
-	if (rc) {
-		pr_err("Unexpected error %d\n", rc);
-		return false;
-	}
-	if (data.data2)
-		pr_info("revision %lu.%lu (%08lx)",
-			data.data0, data.data1, data.data2);
-	else
-		pr_info("revision %lu.%lu", data.data0, data.data1);
-
 	return true;
 }
 
@@ -900,6 +919,7 @@ static int optee_ffa_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_ffa_clnt_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_ffa_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -918,6 +938,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
 
 static const struct tee_driver_ops optee_ffa_supp_ops = {
 	.get_version = optee_ffa_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_ffa_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1060,6 +1081,11 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 	if (!optee)
 		return -ENOMEM;
 
+	if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision)) {
+		rc = -EINVAL;
+		goto err_free_optee;
+	}
+
 	pool = optee_ffa_shm_pool_alloc_pages();
 	if (IS_ERR(pool)) {
 		rc = PTR_ERR(pool);
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index db9ea673fbca..acd3051c4879 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -171,6 +171,24 @@ struct optee_ffa {
 
 struct optee;
 
+/**
+ * struct optee_revision - OP-TEE OS revision reported by secure world
+ * @os_major:		OP-TEE OS major version
+ * @os_minor:		OP-TEE OS minor version
+ * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
+ *
+ * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
+ * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
+ * FF-A ABI version.
+ */
+struct optee_revision {
+	u32 os_major;
+	u32 os_minor;
+	u64 os_build_id;
+};
+
+int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
+
 /**
  * struct optee_ops - OP-TEE driver internal operations
  * @do_call_with_arg:	enters OP-TEE in secure world
@@ -249,6 +267,7 @@ struct optee {
 	bool in_kernel_rpmb_routing;
 	struct work_struct scan_bus_work;
 	struct work_struct rpmb_scan_bus_work;
+	struct optee_revision revision;
 };
 
 struct optee_session {
diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
index 0be663fcd52b..51fae1ab8ef8 100644
--- a/drivers/tee/optee/smc_abi.c
+++ b/drivers/tee/optee/smc_abi.c
@@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_clnt_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_smc_open,
 	.release = optee_release,
 	.open_session = optee_open_session,
@@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
 
 static const struct tee_driver_ops optee_supp_ops = {
 	.get_version = optee_get_version,
+	.get_tee_revision = optee_get_revision,
 	.open = optee_smc_open,
 	.release = optee_release_supp,
 	.supp_recv = optee_supp_recv,
@@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
 }
 #endif
 
-static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
+static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
+				      struct optee_revision *revision)
 {
 	union {
 		struct arm_smccc_res smccc;
@@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
 		  &res.smccc);
 
+	if (revision) {
+		revision->os_major = res.result.major;
+		revision->os_minor = res.result.minor;
+		revision->os_build_id = res.result.build_id;
+	}
+
 	if (res.result.build_id)
 		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
 			res.result.minor, (int)sizeof(res.result.build_id) * 2,
@@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	optee_msg_get_os_revision(invoke_fn);
-
 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
 		pr_warn("api revision mismatch\n");
 		return -EINVAL;
@@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
 		goto err_free_shm_pool;
 	}
 
+	optee_msg_get_os_revision(invoke_fn, &optee->revision);
+
 	optee->ops = &optee_ops;
 	optee->smc.invoke_fn = invoke_fn;
 	optee->smc.sec_caps = sec_caps;
-- 
2.43.0


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

* Re: [PATCH v7 1/2] tee: add revision sysfs attribute
  2026-01-12 15:48           ` [PATCH v7 " Aristo Chen
  2026-01-12 15:48             ` [PATCH v7 2/2] tee: optee: store OS revision for TEE core Aristo Chen
@ 2026-01-14 15:42             ` Jens Wiklander
  1 sibling, 0 replies; 42+ messages in thread
From: Jens Wiklander @ 2026-01-14 15:42 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, sumit.garg, op-tee, harshal.dev, mario.limonciello,
	Rijo-john.Thomas, amirreza.zarrabi, Sumit Garg

On Mon, Jan 12, 2026 at 4:48 PM Aristo Chen <aristo.chen@canonical.com> wrote:
>
> Add a generic TEE revision sysfs attribute backed by a new
> optional get_tee_revision() callback. The revision string is
> diagnostic-only and must not be used to infer feature support.
>
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> ---
>  Documentation/ABI/testing/sysfs-class-tee | 10 +++++
>  drivers/tee/tee_core.c                    | 51 ++++++++++++++++++++++-
>  include/linux/tee_core.h                  |  9 ++++
>  3 files changed, 69 insertions(+), 1 deletion(-)

Looks good, I'm picking up this.

Thanks,
Jens

>
> diff --git a/Documentation/ABI/testing/sysfs-class-tee b/Documentation/ABI/testing/sysfs-class-tee
> index c9144d16003e..1a0a3050aaa9 100644
> --- a/Documentation/ABI/testing/sysfs-class-tee
> +++ b/Documentation/ABI/testing/sysfs-class-tee
> @@ -13,3 +13,13 @@ Description:
>                 space if the variable is absent. The primary purpose
>                 of this variable is to let systemd know whether
>                 tee-supplicant is needed in the early boot with initramfs.
> +
> +What:          /sys/class/tee/tee{,priv}X/revision
> +Date:          Jan 2026
> +KernelVersion: 6.19
> +Contact:       op-tee@lists.trustedfirmware.org
> +Description:
> +               Read-only revision string reported by the TEE driver. This is
> +               for diagnostics only and must not be used to infer feature
> +               support. Use TEE_IOC_VERSION for capability and compatibility
> +               checks.
> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
> index d65d47cc154e..0a00499811c1 100644
> --- a/drivers/tee/tee_core.c
> +++ b/drivers/tee/tee_core.c
> @@ -1146,7 +1146,56 @@ static struct attribute *tee_dev_attrs[] = {
>         NULL
>  };
>
> -ATTRIBUTE_GROUPS(tee_dev);
> +static const struct attribute_group tee_dev_group = {
> +       .attrs = tee_dev_attrs,
> +};
> +
> +static ssize_t revision_show(struct device *dev,
> +                            struct device_attribute *attr, char *buf)
> +{
> +       struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +       char version[TEE_REVISION_STR_SIZE];
> +       int ret;
> +
> +       if (!teedev->desc->ops->get_tee_revision)
> +               return -ENODEV;
> +
> +       ret = teedev->desc->ops->get_tee_revision(teedev, version,
> +                                                 sizeof(version));
> +       if (ret)
> +               return ret;
> +
> +       return sysfs_emit(buf, "%s\n", version);
> +}
> +static DEVICE_ATTR_RO(revision);
> +
> +static struct attribute *tee_revision_attrs[] = {
> +       &dev_attr_revision.attr,
> +       NULL
> +};
> +
> +static umode_t tee_revision_attr_is_visible(struct kobject *kobj,
> +                                           struct attribute *attr, int n)
> +{
> +       struct device *dev = kobj_to_dev(kobj);
> +       struct tee_device *teedev = container_of(dev, struct tee_device, dev);
> +
> +       if (teedev->desc->ops->get_tee_revision)
> +               return attr->mode;
> +
> +       return 0;
> +}
> +
> +static const struct attribute_group tee_revision_group = {
> +       .attrs = tee_revision_attrs,
> +       .is_visible = tee_revision_attr_is_visible,
> +};
> +
> +static const struct attribute_group *tee_dev_groups[] = {
> +       &tee_dev_group,
> +       &tee_revision_group,
> +       NULL
> +};
>
>  static const struct class tee_class = {
>         .name = "tee",
> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h
> index 1f3e5dad6d0d..ee5f0bd41f43 100644
> --- a/include/linux/tee_core.h
> +++ b/include/linux/tee_core.h
> @@ -76,6 +76,9 @@ struct tee_device {
>  /**
>   * struct tee_driver_ops - driver operations vtable
>   * @get_version:       returns version of driver
> + * @get_tee_revision:  returns revision string (diagnostic only);
> + *                     do not infer feature support from this, use
> + *                     TEE_IOC_VERSION instead
>   * @open:              called for a context when the device file is opened
>   * @close_context:     called when the device file is closed
>   * @release:           called to release the context
> @@ -95,9 +98,12 @@ struct tee_device {
>   * client closes the device file, even if there are existing references to the
>   * context. The TEE driver can use @close_context to start cleaning up.
>   */
> +
>  struct tee_driver_ops {
>         void (*get_version)(struct tee_device *teedev,
>                             struct tee_ioctl_version_data *vers);
> +       int (*get_tee_revision)(struct tee_device *teedev,
> +                               char *buf, size_t len);
>         int (*open)(struct tee_context *ctx);
>         void (*close_context)(struct tee_context *ctx);
>         void (*release)(struct tee_context *ctx);
> @@ -123,6 +129,9 @@ struct tee_driver_ops {
>         int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
>  };
>
> +/* Size for TEE revision string buffer used by get_tee_revision(). */
> +#define TEE_REVISION_STR_SIZE  128
> +
>  /**
>   * struct tee_desc - Describes the TEE driver to the subsystem
>   * @name:      name of driver
> --
> 2.43.0
>

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

* Re: [PATCH v7 2/2] tee: optee: store OS revision for TEE core
  2026-01-12 15:48             ` [PATCH v7 2/2] tee: optee: store OS revision for TEE core Aristo Chen
@ 2026-01-14 15:43               ` Jens Wiklander
  2026-01-15  6:18               ` Sumit Garg
  1 sibling, 0 replies; 42+ messages in thread
From: Jens Wiklander @ 2026-01-14 15:43 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, sumit.garg, op-tee, harshal.dev, mario.limonciello,
	Rijo-john.Thomas, amirreza.zarrabi

On Mon, Jan 12, 2026 at 4:48 PM Aristo Chen <aristo.chen@canonical.com> wrote:
>
> Collect OP-TEE OS revision from secure world for both SMC and FF-A
> ABIs, store it in the OP-TEE driver, and expose it through the
> generic get_tee_revision() callback.
>
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  drivers/tee/optee/core.c          | 23 +++++++++++++
>  drivers/tee/optee/ffa_abi.c       | 54 +++++++++++++++++++++++--------
>  drivers/tee/optee/optee_private.h | 19 +++++++++++
>  drivers/tee/optee/smc_abi.c       | 15 +++++++--
>  4 files changed, 94 insertions(+), 17 deletions(-)

Looks good, I'm picking up this.

Thanks,
Jens

>
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index 5b62139714ce..2d807bc748bc 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
>         return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
>  }
>
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> +{
> +       struct optee *optee = tee_get_drvdata(teedev);
> +       u64 build_id;
> +
> +       if (!optee)
> +               return -ENODEV;
> +       if (!buf || !len)
> +               return -EINVAL;
> +
> +       build_id = optee->revision.os_build_id;
> +       if (build_id)
> +               scnprintf(buf, len, "%u.%u (%016llx)",
> +                         optee->revision.os_major,
> +                         optee->revision.os_minor,
> +                         (unsigned long long)build_id);
> +       else
> +               scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> +                         optee->revision.os_minor);
> +
> +       return 0;
> +}
> +
>  static void optee_bus_scan(struct work_struct *work)
>  {
>         WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> index bf8390789ecf..8fc72aa95722 100644
> --- a/drivers/tee/optee/ffa_abi.c
> +++ b/drivers/tee/optee/ffa_abi.c
> @@ -775,6 +775,39 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
>   * with a matching configuration.
>   */
>
> +static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
> +                                     const struct ffa_ops *ops,
> +                                     struct optee_revision *revision)
> +{
> +       const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> +       struct ffa_send_direct_data data = {
> +               .data0 = OPTEE_FFA_GET_OS_VERSION,
> +       };
> +       int rc;
> +
> +       msg_ops->mode_32bit_set(ffa_dev);
> +
> +       rc = msg_ops->sync_send_receive(ffa_dev, &data);
> +       if (rc) {
> +               pr_err("Unexpected error %d\n", rc);
> +               return false;
> +       }
> +
> +       if (revision) {
> +               revision->os_major = data.data0;
> +               revision->os_minor = data.data1;
> +               revision->os_build_id = data.data2;
> +       }
> +
> +       if (data.data2)
> +               pr_info("revision %lu.%lu (%08lx)",
> +                       data.data0, data.data1, data.data2);
> +       else
> +               pr_info("revision %lu.%lu", data.data0, data.data1);
> +
> +       return true;
> +}
> +
>  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>                                         const struct ffa_ops *ops)
>  {
> @@ -798,20 +831,6 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>                 return false;
>         }
>
> -       data = (struct ffa_send_direct_data){
> -               .data0 = OPTEE_FFA_GET_OS_VERSION,
> -       };
> -       rc = msg_ops->sync_send_receive(ffa_dev, &data);
> -       if (rc) {
> -               pr_err("Unexpected error %d\n", rc);
> -               return false;
> -       }
> -       if (data.data2)
> -               pr_info("revision %lu.%lu (%08lx)",
> -                       data.data0, data.data1, data.data2);
> -       else
> -               pr_info("revision %lu.%lu", data.data0, data.data1);
> -
>         return true;
>  }
>
> @@ -900,6 +919,7 @@ static int optee_ffa_open(struct tee_context *ctx)
>
>  static const struct tee_driver_ops optee_ffa_clnt_ops = {
>         .get_version = optee_ffa_get_version,
> +       .get_tee_revision = optee_get_revision,
>         .open = optee_ffa_open,
>         .release = optee_release,
>         .open_session = optee_open_session,
> @@ -918,6 +938,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
>
>  static const struct tee_driver_ops optee_ffa_supp_ops = {
>         .get_version = optee_ffa_get_version,
> +       .get_tee_revision = optee_get_revision,
>         .open = optee_ffa_open,
>         .release = optee_release_supp,
>         .supp_recv = optee_supp_recv,
> @@ -1060,6 +1081,11 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>         if (!optee)
>                 return -ENOMEM;
>
> +       if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision)) {
> +               rc = -EINVAL;
> +               goto err_free_optee;
> +       }
> +
>         pool = optee_ffa_shm_pool_alloc_pages();
>         if (IS_ERR(pool)) {
>                 rc = PTR_ERR(pool);
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index db9ea673fbca..acd3051c4879 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -171,6 +171,24 @@ struct optee_ffa {
>
>  struct optee;
>
> +/**
> + * struct optee_revision - OP-TEE OS revision reported by secure world
> + * @os_major:          OP-TEE OS major version
> + * @os_minor:          OP-TEE OS minor version
> + * @os_build_id:       OP-TEE OS build identifier (0 if unspecified)
> + *
> + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> + * FF-A ABI version.
> + */
> +struct optee_revision {
> +       u32 os_major;
> +       u32 os_minor;
> +       u64 os_build_id;
> +};
> +
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> +
>  /**
>   * struct optee_ops - OP-TEE driver internal operations
>   * @do_call_with_arg:  enters OP-TEE in secure world
> @@ -249,6 +267,7 @@ struct optee {
>         bool in_kernel_rpmb_routing;
>         struct work_struct scan_bus_work;
>         struct work_struct rpmb_scan_bus_work;
> +       struct optee_revision revision;
>  };
>
>  struct optee_session {
> diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> index 0be663fcd52b..51fae1ab8ef8 100644
> --- a/drivers/tee/optee/smc_abi.c
> +++ b/drivers/tee/optee/smc_abi.c
> @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
>
>  static const struct tee_driver_ops optee_clnt_ops = {
>         .get_version = optee_get_version,
> +       .get_tee_revision = optee_get_revision,
>         .open = optee_smc_open,
>         .release = optee_release,
>         .open_session = optee_open_session,
> @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
>
>  static const struct tee_driver_ops optee_supp_ops = {
>         .get_version = optee_get_version,
> +       .get_tee_revision = optee_get_revision,
>         .open = optee_smc_open,
>         .release = optee_release_supp,
>         .supp_recv = optee_supp_recv,
> @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
>  }
>  #endif
>
> -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> +                                     struct optee_revision *revision)
>  {
>         union {
>                 struct arm_smccc_res smccc;
> @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
>         invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
>                   &res.smccc);
>
> +       if (revision) {
> +               revision->os_major = res.result.major;
> +               revision->os_minor = res.result.minor;
> +               revision->os_build_id = res.result.build_id;
> +       }
> +
>         if (res.result.build_id)
>                 pr_info("revision %lu.%lu (%0*lx)", res.result.major,
>                         res.result.minor, (int)sizeof(res.result.build_id) * 2,
> @@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
>                 return -EINVAL;
>         }
>
> -       optee_msg_get_os_revision(invoke_fn);
> -
>         if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
>                 pr_warn("api revision mismatch\n");
>                 return -EINVAL;
> @@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
>                 goto err_free_shm_pool;
>         }
>
> +       optee_msg_get_os_revision(invoke_fn, &optee->revision);
> +
>         optee->ops = &optee_ops;
>         optee->smc.invoke_fn = invoke_fn;
>         optee->smc.sec_caps = sec_caps;
> --
> 2.43.0
>

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

* Re: [PATCH v7 2/2] tee: optee: store OS revision for TEE core
  2026-01-12 15:48             ` [PATCH v7 2/2] tee: optee: store OS revision for TEE core Aristo Chen
  2026-01-14 15:43               ` Jens Wiklander
@ 2026-01-15  6:18               ` Sumit Garg
  1 sibling, 0 replies; 42+ messages in thread
From: Sumit Garg @ 2026-01-15  6:18 UTC (permalink / raw)
  To: Aristo Chen
  Cc: linux-kernel, jens.wiklander, op-tee, harshal.dev,
	mario.limonciello, Rijo-john.Thomas, amirreza.zarrabi

On Mon, Jan 12, 2026 at 11:48:30PM +0800, Aristo Chen wrote:
> Collect OP-TEE OS revision from secure world for both SMC and FF-A
> ABIs, store it in the OP-TEE driver, and expose it through the
> generic get_tee_revision() callback.
> 
> Signed-off-by: Aristo Chen <aristo.chen@canonical.com>
> ---
>  drivers/tee/optee/core.c          | 23 +++++++++++++
>  drivers/tee/optee/ffa_abi.c       | 54 +++++++++++++++++++++++--------
>  drivers/tee/optee/optee_private.h | 19 +++++++++++
>  drivers/tee/optee/smc_abi.c       | 15 +++++++--
>  4 files changed, 94 insertions(+), 17 deletions(-)

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

-Sumit

> 
> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
> index 5b62139714ce..2d807bc748bc 100644
> --- a/drivers/tee/optee/core.c
> +++ b/drivers/tee/optee/core.c
> @@ -63,6 +63,29 @@ int optee_set_dma_mask(struct optee *optee, u_int pa_width)
>  	return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask);
>  }
>  
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len)
> +{
> +	struct optee *optee = tee_get_drvdata(teedev);
> +	u64 build_id;
> +
> +	if (!optee)
> +		return -ENODEV;
> +	if (!buf || !len)
> +		return -EINVAL;
> +
> +	build_id = optee->revision.os_build_id;
> +	if (build_id)
> +		scnprintf(buf, len, "%u.%u (%016llx)",
> +			  optee->revision.os_major,
> +			  optee->revision.os_minor,
> +			  (unsigned long long)build_id);
> +	else
> +		scnprintf(buf, len, "%u.%u", optee->revision.os_major,
> +			  optee->revision.os_minor);
> +
> +	return 0;
> +}
> +
>  static void optee_bus_scan(struct work_struct *work)
>  {
>  	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
> diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
> index bf8390789ecf..8fc72aa95722 100644
> --- a/drivers/tee/optee/ffa_abi.c
> +++ b/drivers/tee/optee/ffa_abi.c
> @@ -775,6 +775,39 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
>   * with a matching configuration.
>   */
>  
> +static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
> +				      const struct ffa_ops *ops,
> +				      struct optee_revision *revision)
> +{
> +	const struct ffa_msg_ops *msg_ops = ops->msg_ops;
> +	struct ffa_send_direct_data data = {
> +		.data0 = OPTEE_FFA_GET_OS_VERSION,
> +	};
> +	int rc;
> +
> +	msg_ops->mode_32bit_set(ffa_dev);
> +
> +	rc = msg_ops->sync_send_receive(ffa_dev, &data);
> +	if (rc) {
> +		pr_err("Unexpected error %d\n", rc);
> +		return false;
> +	}
> +
> +	if (revision) {
> +		revision->os_major = data.data0;
> +		revision->os_minor = data.data1;
> +		revision->os_build_id = data.data2;
> +	}
> +
> +	if (data.data2)
> +		pr_info("revision %lu.%lu (%08lx)",
> +			data.data0, data.data1, data.data2);
> +	else
> +		pr_info("revision %lu.%lu", data.data0, data.data1);
> +
> +	return true;
> +}
> +
>  static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>  					const struct ffa_ops *ops)
>  {
> @@ -798,20 +831,6 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
>  		return false;
>  	}
>  
> -	data = (struct ffa_send_direct_data){
> -		.data0 = OPTEE_FFA_GET_OS_VERSION,
> -	};
> -	rc = msg_ops->sync_send_receive(ffa_dev, &data);
> -	if (rc) {
> -		pr_err("Unexpected error %d\n", rc);
> -		return false;
> -	}
> -	if (data.data2)
> -		pr_info("revision %lu.%lu (%08lx)",
> -			data.data0, data.data1, data.data2);
> -	else
> -		pr_info("revision %lu.%lu", data.data0, data.data1);
> -
>  	return true;
>  }
>  
> @@ -900,6 +919,7 @@ static int optee_ffa_open(struct tee_context *ctx)
>  
>  static const struct tee_driver_ops optee_ffa_clnt_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_ffa_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -918,6 +938,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_ffa_supp_ops = {
>  	.get_version = optee_ffa_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_ffa_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1060,6 +1081,11 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
>  	if (!optee)
>  		return -ENOMEM;
>  
> +	if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision)) {
> +		rc = -EINVAL;
> +		goto err_free_optee;
> +	}
> +
>  	pool = optee_ffa_shm_pool_alloc_pages();
>  	if (IS_ERR(pool)) {
>  		rc = PTR_ERR(pool);
> diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
> index db9ea673fbca..acd3051c4879 100644
> --- a/drivers/tee/optee/optee_private.h
> +++ b/drivers/tee/optee/optee_private.h
> @@ -171,6 +171,24 @@ struct optee_ffa {
>  
>  struct optee;
>  
> +/**
> + * struct optee_revision - OP-TEE OS revision reported by secure world
> + * @os_major:		OP-TEE OS major version
> + * @os_minor:		OP-TEE OS minor version
> + * @os_build_id:	OP-TEE OS build identifier (0 if unspecified)
> + *
> + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or
> + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an
> + * FF-A ABI version.
> + */
> +struct optee_revision {
> +	u32 os_major;
> +	u32 os_minor;
> +	u64 os_build_id;
> +};
> +
> +int optee_get_revision(struct tee_device *teedev, char *buf, size_t len);
> +
>  /**
>   * struct optee_ops - OP-TEE driver internal operations
>   * @do_call_with_arg:	enters OP-TEE in secure world
> @@ -249,6 +267,7 @@ struct optee {
>  	bool in_kernel_rpmb_routing;
>  	struct work_struct scan_bus_work;
>  	struct work_struct rpmb_scan_bus_work;
> +	struct optee_revision revision;
>  };
>  
>  struct optee_session {
> diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c
> index 0be663fcd52b..51fae1ab8ef8 100644
> --- a/drivers/tee/optee/smc_abi.c
> +++ b/drivers/tee/optee/smc_abi.c
> @@ -1242,6 +1242,7 @@ static int optee_smc_open(struct tee_context *ctx)
>  
>  static const struct tee_driver_ops optee_clnt_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release,
>  	.open_session = optee_open_session,
> @@ -1261,6 +1262,7 @@ static const struct tee_desc optee_clnt_desc = {
>  
>  static const struct tee_driver_ops optee_supp_ops = {
>  	.get_version = optee_get_version,
> +	.get_tee_revision = optee_get_revision,
>  	.open = optee_smc_open,
>  	.release = optee_release_supp,
>  	.supp_recv = optee_supp_recv,
> @@ -1323,7 +1325,8 @@ static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
>  }
>  #endif
>  
> -static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
> +static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn,
> +				      struct optee_revision *revision)
>  {
>  	union {
>  		struct arm_smccc_res smccc;
> @@ -1337,6 +1340,12 @@ static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
>  	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
>  		  &res.smccc);
>  
> +	if (revision) {
> +		revision->os_major = res.result.major;
> +		revision->os_minor = res.result.minor;
> +		revision->os_build_id = res.result.build_id;
> +	}
> +
>  	if (res.result.build_id)
>  		pr_info("revision %lu.%lu (%0*lx)", res.result.major,
>  			res.result.minor, (int)sizeof(res.result.build_id) * 2,
> @@ -1745,8 +1754,6 @@ static int optee_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> -	optee_msg_get_os_revision(invoke_fn);
> -
>  	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
>  		pr_warn("api revision mismatch\n");
>  		return -EINVAL;
> @@ -1815,6 +1822,8 @@ static int optee_probe(struct platform_device *pdev)
>  		goto err_free_shm_pool;
>  	}
>  
> +	optee_msg_get_os_revision(invoke_fn, &optee->revision);
> +
>  	optee->ops = &optee_ops;
>  	optee->smc.invoke_fn = invoke_fn;
>  	optee->smc.sec_caps = sec_caps;
> -- 
> 2.43.0
> 

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

end of thread, other threads:[~2026-01-15  6:18 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-21 14:12 [PATCH v1 1/1] tee: optee: expose OS revision via sysfs Wei Ming Chen
2025-11-22  7:36 ` Harshal Dev
2025-11-22 14:59 ` [PATCH v2 " Wei Ming Chen
2025-11-24  7:15   ` Jens Wiklander
2025-11-25  7:53     ` Sumit Garg
2025-11-25  7:55       ` Sumit Garg
2025-12-01 11:47         ` Aristo Chen
2025-12-01 13:06           ` Jens Wiklander
2025-12-02  9:54             ` Aristo Chen
2025-12-03  7:50               ` Jens Wiklander
2025-12-07 14:01                 ` Aristo Chen
2025-12-09  8:30                   ` Jens Wiklander
2025-12-19 15:38                     ` Aristo Chen
2025-12-22  8:34                       ` Jens Wiklander
2025-12-22 10:07                         ` Sumit Garg
2025-12-26 13:19   ` [PATCH v3 " Aristo Chen
2025-12-29  4:59     ` Sumit Garg
2025-12-30  5:17     ` [PATCH v4 1/2] tee: add revision sysfs attribute Aristo Chen
2025-12-30  5:17       ` [PATCH v4 2/2] tee: optee: store OS revision for TEE core Aristo Chen
2026-01-05  5:20         ` Sumit Garg
2026-01-05  8:13           ` Aristo Chen
2026-01-05  8:48             ` Sumit Garg
2026-01-05  4:53       ` [PATCH v4 1/2] tee: add revision sysfs attribute Sumit Garg
2026-01-07 15:26       ` [PATCH v5 " Aristo Chen
2026-01-07 15:26         ` [PATCH v5 2/2] tee: optee: store OS revision for TEE core Aristo Chen
2026-01-07 15:28         ` [PATCH v5 1/2] tee: add revision sysfs attribute Mario Limonciello
2026-01-08  2:55           ` Aristo Chen
2026-01-08  3:01             ` Mario Limonciello (AMD) (kernel.org)
2026-01-08  6:45         ` [PATCH v6 " Aristo Chen
2026-01-08  6:45           ` [PATCH v6 2/2] tee: optee: store OS revision for TEE core Aristo Chen
2026-01-09 11:50             ` Sumit Garg
2026-01-09 15:07               ` Aristo Chen
2026-01-12 11:22                 ` Sumit Garg
2026-01-12  9:55             ` Jens Wiklander
2026-01-12 10:43               ` Aristo Chen
2026-01-09 11:48           ` [PATCH v6 1/2] tee: add revision sysfs attribute Sumit Garg
2026-01-12  9:50           ` Jens Wiklander
2026-01-12 15:48           ` [PATCH v7 " Aristo Chen
2026-01-12 15:48             ` [PATCH v7 2/2] tee: optee: store OS revision for TEE core Aristo Chen
2026-01-14 15:43               ` Jens Wiklander
2026-01-15  6:18               ` Sumit Garg
2026-01-14 15:42             ` [PATCH v7 1/2] tee: add revision sysfs attribute Jens Wiklander

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