]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tee: optee: store OS revision for TEE core
authorAristo Chen <aristo.chen@canonical.com>
Mon, 12 Jan 2026 15:48:30 +0000 (23:48 +0800)
committerJens Wiklander <jens.wiklander@linaro.org>
Thu, 15 Jan 2026 09:35:14 +0000 (10:35 +0100)
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>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
drivers/tee/optee/core.c
drivers/tee/optee/ffa_abi.c
drivers/tee/optee/optee_private.h
drivers/tee/optee/smc_abi.c

index 5b62139714ce973cd0af9f5cebd30fc25b0cbb65..2d807bc748bc496313d3271f2d07b353cd1b0d68 100644 (file)
@@ -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));
index bf8390789ecf8b35a5a01767b4ffe37b56cdf2ee..8fc72aa95722184214feb52d4239168732e12c72 100644 (file)
@@ -775,6 +775,39 @@ static int optee_ffa_reclaim_protmem(struct optee *optee,
  * with a matching configuration.
  */
 
+static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev,
+                                     const struct ffa_ops *ops,
+                                     struct optee_revision *revision)
+{
+       const struct ffa_msg_ops *msg_ops = ops->msg_ops;
+       struct ffa_send_direct_data data = {
+               .data0 = OPTEE_FFA_GET_OS_VERSION,
+       };
+       int rc;
+
+       msg_ops->mode_32bit_set(ffa_dev);
+
+       rc = msg_ops->sync_send_receive(ffa_dev, &data);
+       if (rc) {
+               pr_err("Unexpected error %d\n", rc);
+               return false;
+       }
+
+       if (revision) {
+               revision->os_major = data.data0;
+               revision->os_minor = data.data1;
+               revision->os_build_id = data.data2;
+       }
+
+       if (data.data2)
+               pr_info("revision %lu.%lu (%08lx)",
+                       data.data0, data.data1, data.data2);
+       else
+               pr_info("revision %lu.%lu", data.data0, data.data1);
+
+       return true;
+}
+
 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
                                        const struct ffa_ops *ops)
 {
@@ -798,20 +831,6 @@ static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
                return false;
        }
 
-       data = (struct ffa_send_direct_data){
-               .data0 = OPTEE_FFA_GET_OS_VERSION,
-       };
-       rc = msg_ops->sync_send_receive(ffa_dev, &data);
-       if (rc) {
-               pr_err("Unexpected error %d\n", rc);
-               return false;
-       }
-       if (data.data2)
-               pr_info("revision %lu.%lu (%08lx)",
-                       data.data0, data.data1, data.data2);
-       else
-               pr_info("revision %lu.%lu", data.data0, data.data1);
-
        return true;
 }
 
@@ -900,6 +919,7 @@ static int optee_ffa_open(struct tee_context *ctx)
 
 static const struct tee_driver_ops optee_ffa_clnt_ops = {
        .get_version = optee_ffa_get_version,
+       .get_tee_revision = optee_get_revision,
        .open = optee_ffa_open,
        .release = optee_release,
        .open_session = optee_open_session,
@@ -918,6 +938,7 @@ static const struct tee_desc optee_ffa_clnt_desc = {
 
 static const struct tee_driver_ops optee_ffa_supp_ops = {
        .get_version = optee_ffa_get_version,
+       .get_tee_revision = optee_get_revision,
        .open = optee_ffa_open,
        .release = optee_release_supp,
        .supp_recv = optee_supp_recv,
@@ -1060,6 +1081,11 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
        if (!optee)
                return -ENOMEM;
 
+       if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision)) {
+               rc = -EINVAL;
+               goto err_free_optee;
+       }
+
        pool = optee_ffa_shm_pool_alloc_pages();
        if (IS_ERR(pool)) {
                rc = PTR_ERR(pool);
index db9ea673fbca13f7482529aa0521588f06d352a2..acd3051c4879d941f6110f6170c1cb3861c08b14 100644 (file)
@@ -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 {
index 0be663fcd52b13696fc14060477d2f19a079d533..51fae1ab8ef87582bafda9870c47478335125fe4 100644 (file)
@@ -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;