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
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
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;
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
[AMD Official Use Only - AMD Internal Distribution Only]
+Deva,
I am on sick leave at present.
Thanks, Rijo
Get Outlook for iOShttps://aka.ms/o0ukef ________________________________ From: Jens Wiklander jens.wiklander@linaro.org Sent: Monday, November 24, 2025 12:45 PM To: Wei Ming Chen jj251510319013@gmail.com Cc: linux-kernel@vger.kernel.org linux-kernel@vger.kernel.org; sumit.garg@kernel.org sumit.garg@kernel.org; op-tee@lists.trustedfirmware.org op-tee@lists.trustedfirmware.org; harshal.dev@oss.qualcomm.com harshal.dev@oss.qualcomm.com; Aristo Chen aristo.chen@canonical.com; Limonciello, Mario Mario.Limonciello@amd.com; Balint Dobszay balint.dobszay@arm.com; Thomas, Rijo-john Rijo-john.Thomas@amd.com; Amirreza Zarrabi amirreza.zarrabi@oss.qualcomm.com Subject: Re: [PATCH v2 1/1] tee: optee: expose OS revision via sysfs
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
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
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
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
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
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
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
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
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
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
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
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
Hi Jens and Sumit,
On Mon, Dec 22, 2025 at 6:07 PM Sumit Garg sumit.garg@kernel.org wrote:
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.
Thanks for the feedback! I will prepare V3 patch
-Sumit
Best regards, Aristo
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*/
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 isfor diagnostics only and must not be used to infer featuresupport. Use TEE_IOC_VERSION for capability and compatibilitychecks.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,
int (*open)(struct tee_context *ctx); void (*close_context)(struct tee_context *ctx); void (*release)(struct tee_context *ctx);char *buf, size_t len);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
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
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);
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
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);elsescnprintf(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
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);elsescnprintf(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
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 isfor diagnostics only and must not be used to infer featuresupport. Use TEE_IOC_VERSION for capability and compatibilitychecks.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,
int (*open)(struct tee_context *ctx); void (*close_context)(struct tee_context *ctx); void (*release)(struct tee_context *ctx);char *buf, size_t len);@@ -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
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
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;
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 isfor diagnostics only and must not be used to infer featuresupport. Use TEE_IOC_VERSION for capability and compatibilitychecks.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,
int (*open)(struct tee_context *ctx); void (*close_context)(struct tee_context *ctx); void (*release)(struct tee_context *ctx);char *buf, size_t len);@@ -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
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 isfor diagnostics only and must not be used to infer featuresupport. Use TEE_IOC_VERSION for capability and compatibilitychecks.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
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 isfor diagnostics only and must not be used to infer featuresupport. Use TEE_IOC_VERSION for capability and compatibilitychecks.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
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
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;
op-tee@lists.trustedfirmware.org