]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
stm32mp: Add OP-TEE support in bsec driver
authorPatrick Delaunay <patrick.delaunay@foss.st.com>
Fri, 6 Jan 2023 12:20:15 +0000 (13:20 +0100)
committerPatrice Chotard <patrice.chotard@foss.st.com>
Thu, 12 Jan 2023 15:37:13 +0000 (16:37 +0100)
When OP-TEE is used, the SMC for BSEC management are not available and
the STM32MP BSEC pseudo TA must be used (it is mandatory for STM32MP13
and it is a new feature for STM32MP15x).

The BSEC driver try to open a session to this PTA BSEC at probe
and use it for OTP read or write access to fuse or to shadow.

This patch also adapts the commands stm32key and stboard to handle
the BSEC_LOCK_PERM lock value instead of 1.

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Reviewed-by: Patrice Chotard <patrice.chotard@foss.st.com>
arch/arm/mach-stm32mp/bsec.c
arch/arm/mach-stm32mp/cmd_stm32key.c
arch/arm/mach-stm32mp/include/mach/bsec.h
board/st/common/cmd_stboard.c
doc/board/st/stm32mp1.rst

index 51ccff9aa56088962b933899d7531e3cc434ea3d..fe79c986f95c62a411f106fe64219d31cf3e49bf 100644 (file)
 #include <dm.h>
 #include <log.h>
 #include <misc.h>
+#include <tee.h>
 #include <asm/io.h>
 #include <asm/arch/bsec.h>
 #include <asm/arch/stm32mp1_smc.h>
+#include <dm/device.h>
 #include <dm/device_compat.h>
 #include <linux/arm-smccc.h>
 #include <linux/iopoll.h>
  */
 #define BSEC_LOCK_PROGRAM              0x04
 
+#define PTA_BSEC_UUID { 0x94cf71ad, 0x80e6, 0x40b5, \
+       { 0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03 } }
+
+/*
+ * Read OTP memory
+ *
+ * [in]                value[0].a              OTP start offset in byte
+ * [in]                value[0].b              Access type (0:shadow, 1:fuse, 2:lock)
+ * [out]       memref[1].buffer        Output buffer to store read values
+ * [out]       memref[1].size          Size of OTP to be read
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller
+ */
+#define PTA_BSEC_READ_MEM              0x0
+
 /*
- * OTP status: bit 0 permanent lock
+ * Write OTP memory
+ *
+ * [in]                value[0].a              OTP start offset in byte
+ * [in]                value[0].b              Access type (0:shadow, 1:fuse, 2:lock)
+ * [in]                memref[1].buffer        Input buffer to read values
+ * [in]                memref[1].size          Size of OTP to be written
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller
  */
-#define BSEC_LOCK_PERM                 BIT(0)
+#define PTA_BSEC_WRITE_MEM             0x1
+
+/* value of PTA_BSEC access type = value[in] b */
+#define SHADOW_ACCESS                  0
+#define FUSE_ACCESS                    1
+#define LOCK_ACCESS                    2
 
 /**
  * bsec_lock() - manage lock for each type SR/SP/SW
@@ -359,6 +394,10 @@ struct stm32mp_bsec_plat {
        u32 base;
 };
 
+struct stm32mp_bsec_priv {
+       struct udevice *tee;
+};
+
 static int stm32mp_bsec_read_otp(struct udevice *dev, u32 *val, u32 otp)
 {
        struct stm32mp_bsec_plat *plat;
@@ -470,14 +509,109 @@ static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp)
        return bsec_permanent_lock_otp(dev, plat->base, otp);
 }
 
+static int bsec_pta_open_session(struct udevice *tee, u32 *tee_session)
+{
+       const struct tee_optee_ta_uuid uuid = PTA_BSEC_UUID;
+       struct tee_open_session_arg arg;
+       int rc;
+
+       memset(&arg, 0, sizeof(arg));
+       tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
+       arg.clnt_login = TEE_LOGIN_REE_KERNEL;
+       rc = tee_open_session(tee, &arg, 0, NULL);
+       if (rc < 0)
+               return -ENODEV;
+
+       *tee_session = arg.session;
+
+       return 0;
+}
+
+static int bsec_optee_open(struct udevice *dev)
+{
+       struct stm32mp_bsec_priv *priv = dev_get_priv(dev);
+       struct udevice *tee;
+       u32 tee_session;
+       int rc;
+
+       tee = tee_find_device(NULL, NULL, NULL, NULL);
+       if (!tee)
+               return -ENODEV;
+
+       /* try to open the STM32 BSEC TA */
+       rc = bsec_pta_open_session(tee, &tee_session);
+       if (rc)
+               return rc;
+
+       tee_close_session(tee, tee_session);
+
+       priv->tee = tee;
+
+       return 0;
+}
+
+static int bsec_optee_pta(struct udevice *dev, int cmd, int type, int offset,
+                         void *buff, ulong size)
+{
+       struct stm32mp_bsec_priv *priv = dev_get_priv(dev);
+       u32 tee_session;
+       struct tee_invoke_arg arg;
+       struct tee_param param[2];
+       struct tee_shm *fw_shm;
+       int rc;
+
+       rc = bsec_pta_open_session(priv->tee, &tee_session);
+       if (rc)
+               return rc;
+
+       rc = tee_shm_register(priv->tee, buff, size, 0, &fw_shm);
+       if (rc)
+               goto close_session;
+
+       memset(&arg, 0, sizeof(arg));
+       arg.func = cmd;
+       arg.session = tee_session;
+
+       memset(param, 0, sizeof(param));
+
+       param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
+       param[0].u.value.a = offset;
+       param[0].u.value.b = type;
+
+       if (cmd == PTA_BSEC_WRITE_MEM)
+               param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
+       else
+               param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+
+       param[1].u.memref.shm = fw_shm;
+       param[1].u.memref.size = size;
+
+       rc = tee_invoke_func(priv->tee, &arg, 2, param);
+       if (rc < 0 || arg.ret != 0) {
+               dev_err(priv->tee,
+                       "PTA_BSEC invoke failed TEE err: %x, err:%x\n",
+                       arg.ret, rc);
+               if (!rc)
+                       rc = -EIO;
+       }
+
+       tee_shm_free(fw_shm);
+
+close_session:
+       tee_close_session(priv->tee, tee_session);
+
+       return rc;
+}
+
 static int stm32mp_bsec_read(struct udevice *dev, int offset,
                             void *buf, int size)
 {
+       struct stm32mp_bsec_priv *priv = dev_get_priv(dev);
        int ret;
        int i;
        bool shadow = true, lock = false;
        int nb_otp = size / sizeof(u32);
-       int otp;
+       int otp, cmd;
        unsigned int offs = offset;
 
        if (offs >= STM32_BSEC_LOCK_OFFSET) {
@@ -491,6 +625,19 @@ static int stm32mp_bsec_read(struct udevice *dev, int offset,
        if ((offs % 4) || (size % 4))
                return -EINVAL;
 
+       if (IS_ENABLED(CONFIG_OPTEE) && priv->tee) {
+               cmd = FUSE_ACCESS;
+               if (shadow)
+                       cmd = SHADOW_ACCESS;
+               if (lock)
+                       cmd = LOCK_ACCESS;
+               ret = bsec_optee_pta(dev, PTA_BSEC_READ_MEM, cmd, offs, buf, size);
+               if (ret)
+                       return ret;
+
+               return size;
+       }
+
        otp = offs / sizeof(u32);
 
        for (i = otp; i < (otp + nb_otp) && i <= BSEC_OTP_MAX_VALUE; i++) {
@@ -515,11 +662,12 @@ static int stm32mp_bsec_read(struct udevice *dev, int offset,
 static int stm32mp_bsec_write(struct udevice *dev, int offset,
                              const void *buf, int size)
 {
+       struct stm32mp_bsec_priv *priv = dev_get_priv(dev);
        int ret = 0;
        int i;
        bool shadow = true, lock = false;
        int nb_otp = size / sizeof(u32);
-       int otp;
+       int otp, cmd;
        unsigned int offs = offset;
 
        if (offs >= STM32_BSEC_LOCK_OFFSET) {
@@ -533,6 +681,19 @@ static int stm32mp_bsec_write(struct udevice *dev, int offset,
        if ((offs % 4) || (size % 4))
                return -EINVAL;
 
+       if (IS_ENABLED(CONFIG_OPTEE) && priv->tee) {
+               cmd = FUSE_ACCESS;
+               if (shadow)
+                       cmd = SHADOW_ACCESS;
+               if (lock)
+                       cmd = LOCK_ACCESS;
+               ret = bsec_optee_pta(dev, PTA_BSEC_WRITE_MEM, cmd, offs, (void *)buf, size);
+               if (ret)
+                       return ret;
+
+               return size;
+       }
+
        otp = offs / sizeof(u32);
 
        for (i = otp; i < otp + nb_otp && i <= BSEC_OTP_MAX_VALUE; i++) {
@@ -581,6 +742,9 @@ static int stm32mp_bsec_probe(struct udevice *dev)
                        return ret;
        }
 
+       if (IS_ENABLED(CONFIG_OPTEE))
+               bsec_optee_open(dev);
+
        /*
         * update unlocked shadow for OTP cleared by the rom code
         * only executed in SPL, it is done in TF-A for TFABOOT
@@ -607,6 +771,7 @@ U_BOOT_DRIVER(stm32mp_bsec) = {
        .of_match = stm32mp_bsec_ids,
        .of_to_plat = stm32mp_bsec_of_to_plat,
        .plat_auto = sizeof(struct stm32mp_bsec_plat),
+       .priv_auto = sizeof(struct stm32mp_bsec_priv),
        .ops = &stm32mp_bsec_ops,
        .probe = stm32mp_bsec_probe,
 };
index 278253e472f5acf9a187264dee6adf5e79611351..85be8e23bdba191f4a919183150baa69bf2f7217 100644 (file)
@@ -8,6 +8,7 @@
 #include <console.h>
 #include <log.h>
 #include <misc.h>
+#include <asm/arch/bsec.h>
 #include <dm/device.h>
 #include <dm/uclass.h>
 
@@ -84,9 +85,6 @@ static u32 get_otp_close_mask(void)
                return STM32_OTP_STM32MP15x_CLOSE_MASK;
 }
 
-#define BSEC_LOCK_ERROR                        (-1)
-#define BSEC_LOCK_PERM                 BIT(0)
-
 static int get_misc_dev(struct udevice **dev)
 {
        int ret;
index 252eac3946a49cf103f778394f6acc84c1fe42cf..10ebc535c4b5bb91ca636a14053199161559a216 100644 (file)
@@ -5,3 +5,10 @@
 
 /* check self hosted debug status = BSEC_DENABLE.DBGSWENABLE */
 bool bsec_dbgswenable(void);
+
+/* Bitfield definition for LOCK status */
+#define BSEC_LOCK_PERM                 BIT(30)
+#define BSEC_LOCK_SHADOW_R             BIT(29)
+#define BSEC_LOCK_SHADOW_W             BIT(28)
+#define BSEC_LOCK_SHADOW_P             BIT(27)
+#define BSEC_LOCK_ERROR                        BIT(26)
index e12669b8628d49947b14d6418375335ac8c3b53a..213fb5d30208b68c8f3b29d66154bacd5333ba2f 100644 (file)
@@ -34,6 +34,7 @@
 #include <command.h>
 #include <console.h>
 #include <misc.h>
+#include <asm/arch/bsec.h>
 #include <dm/device.h>
 #include <dm/uclass.h>
 
@@ -109,7 +110,7 @@ static int do_stboard(struct cmd_tbl *cmdtp, int flag, int argc,
                else
                        display_stboard(otp);
                printf("      OTP %d %s locked !\n", BSEC_OTP_BOARD,
-                      lock == 1 ? "" : "NOT");
+                      lock & BSEC_LOCK_PERM ? "" : "NOT");
                return CMD_RET_SUCCESS;
        }
 
@@ -178,7 +179,7 @@ static int do_stboard(struct cmd_tbl *cmdtp, int flag, int argc,
        }
 
        /* write persistent lock */
-       otp = 1;
+       otp = BSEC_LOCK_PERM;
        ret = misc_write(dev, STM32_BSEC_LOCK(BSEC_OTP_BOARD),
                         &otp, sizeof(otp));
        if (ret != sizeof(otp)) {
index 3759df353ee528a385aacff39c1b8cf1c91048ac..9780ac9768cfdc49dc18f46e9e9eb358e200b724 100644 (file)
@@ -620,7 +620,7 @@ Prerequisite: check if a MAC address isn't yet programmed in OTP
     STM32MP> env print ethaddr
     ## Error: "ethaddr" not defined
 
-3) check lock status of fuse 57 & 58 (at 0x39, 0=unlocked, 1=locked)::
+3) check lock status of fuse 57 & 58 (at 0x39, 0=unlocked, 0x40000000=locked)::
 
     STM32MP> fuse sense 0 0x10000039 2
     Sensing bank 0:
@@ -640,11 +640,11 @@ Example to set mac address "12:34:56:78:9a:bc"
 
 3) Lock OTP::
 
-    STM32MP> fuse prog 0 0x10000039 1 1
+    STM32MP> fuse prog 0 0x10000039 0x40000000 0x40000000
 
     STM32MP> fuse sense 0 0x10000039 2
     Sensing bank 0:
-       Word 0x10000039: 00000001 00000001
+       Word 0x10000039: 40000000 40000000
 
 4) next REBOOT, in the trace::