The OTP fuses for secure boot are only accessible from the secure world.
Therefore, burning the fuses has to be delegated to the Rockchip Secure
Boot PTA running in the secure world.

The alternative to burn the fuses while barebox is still in the secure
world prevents user interaction and costs a lot of flexibility.

Signed-off-by: Michael Tretter <[email protected]>
---
 drivers/tee/optee/Kconfig              |   7 ++
 drivers/tee/optee/Makefile             |   1 +
 drivers/tee/optee/pta_rk_secure_boot.h |  48 ++++++++
 drivers/tee/optee/rksecure.c           | 196 +++++++++++++++++++++++++++++++++
 include/rk_secure_boot.h               |  21 ++++
 5 files changed, 273 insertions(+)

diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig
index 805aba65edb7..fcaca29a5df7 100644
--- a/drivers/tee/optee/Kconfig
+++ b/drivers/tee/optee/Kconfig
@@ -40,6 +40,13 @@ config OPTEE_AVB_PERSISTENT_VALUES
          pairs. AVB itself is not implemented in barebox, but enabling this 
option
          allows barebox to use the AVB persistent value store.
 
+config OPTEE_RKSECURE
+       bool "Rockchip Secure Boot PTA support"
+       depends on OPTEE
+       help
+         Enable this option to use the Rockchip Secure Boot PTA to read or
+         write the secure boot OTP fuses of an rk3588 SoC.
+
 endif
 
 config OF_FIXUP_OPTEE
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
index 1fbeb39fb8ba..e89edc876d6f 100644
--- a/drivers/tee/optee/Makefile
+++ b/drivers/tee/optee/Makefile
@@ -8,3 +8,4 @@ optee-objs += device.o
 optee-objs += smc_abi.o
 obj-$(CONFIG_MCI_MMC_RPMB) += rpmb.o
 obj-$(CONFIG_OPTEE_AVB_PERSISTENT_VALUES) += avb.o
+obj-$(CONFIG_OPTEE_RKSECURE) += rksecure.o
diff --git a/drivers/tee/optee/pta_rk_secure_boot.h 
b/drivers/tee/optee/pta_rk_secure_boot.h
new file mode 100644
index 000000000000..13fa59d9908a
--- /dev/null
+++ b/drivers/tee/optee/pta_rk_secure_boot.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2025, Pengutronix, Michael Tretter 
<[email protected]>
+ */
+
+#ifndef __PTA_RK_SECURE_BOOT_H
+#define __PTA_RK_SECURE_BOOT_H
+
+#include <types.h>
+
+#define PTA_RK_SECURE_BOOT_UUID \
+       UUID_INIT(0x5cfa57f6, 0x1a4c, 0x407f, \
+                 0x94, 0xa7, 0xa5, 0x6c, 0x8c, 0x47, 0x01, 0x9d)
+
+struct pta_rk_secure_boot_hash {
+       /* sha256 has 256 bit */
+       uint8_t value[32];
+};
+
+struct pta_rk_secure_boot_info {
+       uint8_t enabled;
+       uint8_t simulation;
+       struct pta_rk_secure_boot_hash hash;
+};
+
+/*
+ * PTA_RK_SECURE_BOOT_GET_INFO - Get secure boot status info
+ *
+ * [out]    memref[0]   buffer memory reference containing a struct
+ *                      pta_rk_secure_boot_info
+ */
+#define PTA_RK_SECURE_BOOT_GET_INFO            0x0
+
+/*
+ * PTA_RK_SECURE_BOOT_BURN_HASH - Burn the RSA key hash to fuses
+ *
+ * [in]    memref[0]   buffer memory reference containing a struct
+ *                     pta_rk_secure_boot_hash
+ * [in]    value[1].a  bit length of signing key
+ */
+#define PTA_RK_SECURE_BOOT_BURN_HASH           0x1
+
+/*
+ * PTA_RK_SECURE_BOOT_LOCKDOWN_DEVICE - Lockdown the device with secure boot
+ */
+#define PTA_RK_SECURE_BOOT_LOCKDOWN_DEVICE     0x2
+
+#endif /* __PTA_ROCKCHIP_OTP_H */
diff --git a/drivers/tee/optee/rksecure.c b/drivers/tee/optee/rksecure.c
new file mode 100644
index 000000000000..6bc9a61571c2
--- /dev/null
+++ b/drivers/tee/optee/rksecure.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Pengutronix, Michael Tretter <[email protected]>
+ */
+
+#include <linux/tee_drv.h>
+#include <linux/uuid.h>
+#include <uapi/linux/tee.h>
+
+#include <rk_secure_boot.h>
+
+#include "optee_private.h"
+#include "pta_rk_secure_boot.h"
+
+const uuid_t ta_uuid = PTA_RK_SECURE_BOOT_UUID;
+
+static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void 
*data)
+{
+       return ver->impl_id == TEE_IMPL_ID_OPTEE ? 1 : 0;
+}
+
+static int rk_secure_open_session(struct tee_context *ctx, __u32 *session)
+{
+       struct tee_ioctl_open_session_arg sess_arg = {};
+       int res = 0;
+
+       export_uuid(sess_arg.uuid, &ta_uuid);
+       sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+       sess_arg.num_params = 0;
+
+       res = tee_client_open_session(ctx, &sess_arg, NULL);
+       if (res < 0)
+               return res;
+       switch (sess_arg.ret) {
+       case TEEC_SUCCESS:
+               res = 0;
+               break;
+       case TEEC_ERROR_ITEM_NOT_FOUND:
+               pr_err("cannot find TA %pU\n", &sess_arg.uuid);
+               return -ENOENT;
+       default:
+               pr_err("TA %pU: error 0x%x\n", &sess_arg.uuid, sess_arg.ret);
+               return -EINVAL;
+       }
+
+       *session = sess_arg.session;
+       return res;
+}
+
+int rk_secure_boot_get_info(struct rk_secure_boot_info *out)
+{
+       struct tee_context *ctx = NULL;
+       struct tee_ioctl_invoke_arg inv_arg;
+       struct tee_param param[1];
+       struct tee_shm *info_shm;
+       struct pta_rk_secure_boot_info *info;
+       __u32 session = 0;
+       int res = 0;
+
+       ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+       if (IS_ERR(ctx))
+               return -ENODEV;
+
+       res = rk_secure_open_session(ctx, &session);
+       if (res < 0)
+               goto out_ctx;
+
+       info_shm = tee_shm_alloc_kernel_buf(ctx, sizeof(*info));
+       if (IS_ERR(info_shm)) {
+               res = -ENOMEM;
+               goto close_session;
+       }
+       info = info_shm->kaddr;
+
+       memset(param, 0, sizeof(param));
+       param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+       param[0].u.memref.shm = info_shm;
+       param[0].u.memref.size = sizeof(*info);
+
+       inv_arg.func = PTA_RK_SECURE_BOOT_GET_INFO;
+       inv_arg.session = session;
+       inv_arg.num_params = ARRAY_SIZE(param);
+
+       res = tee_client_invoke_func(ctx, &inv_arg, param);
+       if (res)
+               goto out;
+       if (inv_arg.ret) {
+               pr_err("invoke func failed with 0x%08x\n", inv_arg.ret);
+               res = -EIO;
+       }
+
+       memcpy(out->hash, info->hash.value, sizeof(out->hash));
+       out->lockdown = info->enabled;
+       out->simulation = info->simulation;
+
+out:
+       tee_shm_free(info_shm);
+close_session:
+       tee_client_close_session(ctx, session);
+out_ctx:
+       tee_client_close_context(ctx);
+
+       return res;
+}
+
+int rk_secure_boot_burn_hash(const u8 *hash, u32 key_size_bits)
+{
+       struct tee_context *ctx = NULL;
+       struct tee_ioctl_invoke_arg inv_arg;
+       struct tee_param param[2];
+       struct tee_shm *shm_hash;
+       struct pta_rk_secure_boot_hash *pta_hash;
+       __u32 session = 0;
+       int res = 0;
+
+       ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+       if (IS_ERR(ctx))
+               return -ENODEV;
+
+       res = rk_secure_open_session(ctx, &session);
+       if (res < 0)
+               goto out_ctx;
+
+       shm_hash = tee_shm_alloc_kernel_buf(ctx, sizeof(*pta_hash));
+       if (IS_ERR(shm_hash)) {
+               res = -ENOMEM;
+               goto close_session;
+       }
+       pta_hash = shm_hash->kaddr;
+
+       memcpy(pta_hash->value, hash, sizeof(pta_hash->value));
+
+       memset(param, 0, sizeof(param));
+       param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+       param[0].u.memref.shm = shm_hash;
+       param[0].u.memref.size = sizeof(*pta_hash);
+
+       param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+       param[1].u.value.a = key_size_bits;
+
+       inv_arg.func = PTA_RK_SECURE_BOOT_BURN_HASH;
+       inv_arg.session = session;
+       inv_arg.num_params = ARRAY_SIZE(param);
+
+       res = tee_client_invoke_func(ctx, &inv_arg, param);
+       if (res)
+               goto out;
+       if (inv_arg.ret) {
+               pr_err("invoke func failed with 0x%08x\n", inv_arg.ret);
+               res = -EIO;
+       }
+
+out:
+       tee_shm_free(shm_hash);
+close_session:
+       tee_client_close_session(ctx, session);
+out_ctx:
+       tee_client_close_context(ctx);
+
+       return res;
+}
+
+int rk_secure_boot_lockdown_device(void)
+{
+       struct tee_context *ctx = NULL;
+       struct tee_ioctl_invoke_arg inv_arg;
+       __u32 session = 0;
+       int res = 0;
+
+       ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+       if (IS_ERR(ctx))
+               return -ENODEV;
+
+       res = rk_secure_open_session(ctx, &session);
+       if (res < 0)
+               goto out_ctx;
+
+       inv_arg.func = PTA_RK_SECURE_BOOT_LOCKDOWN_DEVICE;
+       inv_arg.session = session;
+       inv_arg.num_params = 0;
+
+       res = tee_client_invoke_func(ctx, &inv_arg, NULL);
+       if (res)
+               goto close_session;
+       if (inv_arg.ret) {
+               pr_err("invoke func failed with 0x%08x\n", inv_arg.ret);
+               res = -EIO;
+       }
+
+close_session:
+       tee_client_close_session(ctx, session);
+out_ctx:
+       tee_client_close_context(ctx);
+
+       return res;
+}
diff --git a/include/rk_secure_boot.h b/include/rk_secure_boot.h
new file mode 100644
index 000000000000..6e247aa7eef3
--- /dev/null
+++ b/include/rk_secure_boot.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2025 Pengutronix, Michael Tretter <[email protected]>
+ */
+
+#ifndef __RK_SECURE_BOOT_H
+#define __RK_SECURE_BOOT_H
+
+#include <linux/types.h>
+
+struct rk_secure_boot_info {
+       bool lockdown;
+       bool simulation;
+       u8 hash[32];
+};
+
+int rk_secure_boot_get_info(struct rk_secure_boot_info *info);
+int rk_secure_boot_burn_hash(const u8 *hash, u32 key_size_bits);
+int rk_secure_boot_lockdown_device(void);
+
+#endif /* __RK_SECURE_BOOT_H */

-- 
2.47.3


Reply via email to