[SeaBIOS] [PATCH v2 4/4] tpm: add TPM CRB device support

Stefan Berger stefanb at linux.vnet.ibm.com
Tue Feb 13 17:08:07 CET 2018


From: Marc-André Lureau <marcandre.lureau at redhat.com>

The CRB device was introduced with TPM 2.0 to be physical-bus agnostic
and defined in TCG PC Client Platform TPM Profile (PTP) Specification
Family “2.0” Level 00 Revision 01.03 v22

It seems to be required with Windows 10. It is also a simpler device
than FIFO/TIS.

This patch only support locality 0 since also the CRB device in QEMU
only supports this locality.

Signed-off-by: Marc-André Lureau <marcandre.lureau at redhat.com>
Reviewed-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
Tested-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
---
 src/hw/tpm_drivers.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/hw/tpm_drivers.h |  26 +++++++
 2 files changed, 223 insertions(+), 1 deletion(-)

diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c
index 5cee9d8..24ce9b7 100644
--- a/src/hw/tpm_drivers.c
+++ b/src/hw/tpm_drivers.c
@@ -17,6 +17,8 @@
 #include "util.h" // timer_calc_usec
 #include "x86.h" // readl
 
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
 /* low level driver implementation */
 struct tpm_driver {
     u32 *timeouts;
@@ -36,7 +38,8 @@ struct tpm_driver {
 extern struct tpm_driver tpm_drivers[];
 
 #define TIS_DRIVER_IDX       0
-#define TPM_NUM_DRIVERS      1
+#define CRB_DRIVER_IDX       1
+#define TPM_NUM_DRIVERS      2
 
 #define TPM_INVALID_DRIVER   0xf
 
@@ -57,6 +60,11 @@ static const u32 tpm_default_durations[3] = {
 static u32 tpm_default_dur[3];
 static u32 tpm_default_to[4];
 
+static u32 crb_cmd_size;
+static void *crb_cmd;
+static u32 crb_resp_size;
+static void *crb_resp;
+
 /* if device is not there, return '0', '1' otherwise */
 static u32 tis_probe(void)
 {
@@ -338,6 +346,179 @@ static u32 tis_waitrespready(enum tpmDurationType to_t)
     return rc;
 }
 
+/* if device is not there, return '0', '1' otherwise */
+static u32 crb_probe(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    u32 ifaceid = readl(CRB_REG(0, CRB_REG_INTF_ID));
+
+    if ((ifaceid & 0xf) != 0xf) {
+        if ((ifaceid & 0xf) == 1) {
+            /* CRB is active */
+            return 1;
+        }
+        if ((ifaceid & (1 << 14)) == 0) {
+            /* CRB cannot be selected */
+            return 0;
+        }
+        /* write of 1 to bits 17-18 selects CRB */
+        writel(CRB_REG(0, CRB_REG_INTF_ID), (1 << 17));
+        /* lock it */
+        writel(CRB_REG(0, CRB_REG_INTF_ID), (1 << 19));
+    }
+
+    /* no support for 64 bit addressing yet */
+    if (readl(CRB_REG(0, CRB_REG_CTRL_CMD_HADDR)))
+        return 1;
+
+    u64 addr = readq(CRB_REG(0, CRB_REG_CTRL_RSP_ADDR));
+    if (addr > __UINT32_MAX__)
+        return 1;
+
+    return 0;
+}
+
+static TPMVersion crb_get_tpm_version(void)
+{
+    /* CRB is supposed to be TPM 2.0 only */
+    return TPM_VERSION_2;
+}
+
+static u32 crb_init(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return 1;
+
+    crb_cmd = (void*)readl(CRB_REG(0, CRB_REG_CTRL_CMD_LADDR));
+    crb_cmd_size = readl(CRB_REG(0, CRB_REG_CTRL_CMD_SIZE));
+    crb_resp = (void*)readl(CRB_REG(0, CRB_REG_CTRL_RSP_ADDR));
+    crb_resp_size = readl(CRB_REG(0, CRB_REG_CTRL_RSP_SIZE));
+
+    init_timeout(CRB_DRIVER_IDX);
+
+    return 0;
+}
+
+static u32 crb_wait_reg(u8 locty, u8 reg, u32 time, u8 mask, u8 expect)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    u32 rc = 1;
+    u32 end = timer_calc_usec(time);
+
+    for (;;) {
+        u8 sts = readl(CRB_REG(locty, reg));
+        if ((sts & mask) == expect) {
+            rc = 0;
+            break;
+        }
+        if (timer_check(end)) {
+            warn_timeout();
+            break;
+        }
+        yield();
+    }
+    return rc;
+}
+
+static u32 crb_activate(u8 locty)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    return 0;
+}
+
+static u32 crb_find_active_locality(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    return 0;
+}
+
+#define CRB_CTRL_REQ_CMD_READY 0b1
+#define CRB_START_INVOKE 0b1
+#define CRB_CTRL_STS_ERROR 0b1
+
+static u32 crb_ready(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    u32 rc = 0;
+    u8 locty = crb_find_active_locality();
+    u32 timeout_c = tpm_drivers[CRB_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C];
+
+    writel(CRB_REG(locty, CRB_REG_CTRL_REQ), CRB_CTRL_REQ_CMD_READY);
+    rc = crb_wait_reg(locty, CRB_REG_CTRL_REQ, timeout_c,
+                      CRB_CTRL_REQ_CMD_READY, 0);
+
+    return rc;
+}
+
+static u32 crb_senddata(const u8 *const data, u32 len)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    if (len > crb_cmd_size)
+        return 1;
+
+    u8 locty = crb_find_active_locality();
+    memcpy(crb_cmd, data, len);
+    writel(CRB_REG(locty, CRB_REG_CTRL_START), CRB_START_INVOKE);
+
+    return 0;
+}
+
+static u32 crb_readresp(u8 *buffer, u32 *len)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    u8 locty = crb_find_active_locality();
+    if (readl(CRB_REG(locty, CRB_REG_CTRL_STS)) & CRB_CTRL_STS_ERROR)
+        return 1;
+
+    if (*len < 6)
+        return 1;
+
+    memcpy(buffer, crb_resp, 6);
+    u32 expected = be32_to_cpu(*(u32 *) &buffer[2]);
+    if (expected < 6)
+        return 1;
+
+    *len = MIN(expected, *len);
+
+    memcpy(buffer + 6, crb_resp + 6, *len - 6);
+
+    return 0;
+}
+
+
+static u32 crb_waitdatavalid(void)
+{
+    return 0;
+}
+
+static u32 crb_waitrespready(enum tpmDurationType to_t)
+{
+    if (!CONFIG_TCGBIOS)
+        return 0;
+
+    u32 rc = 0;
+    u8 locty = crb_find_active_locality();
+    u32 timeout = tpm_drivers[CRB_DRIVER_IDX].durations[to_t];
+
+    rc = crb_wait_reg(locty, CRB_REG_CTRL_START, timeout,
+                      CRB_START_INVOKE, 0);
+
+    return rc;
+}
 
 struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
     [TIS_DRIVER_IDX] =
@@ -355,6 +536,21 @@ struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
             .waitdatavalid = tis_waitdatavalid,
             .waitrespready = tis_waitrespready,
         },
+    [CRB_DRIVER_IDX] =
+        {
+            .timeouts      = NULL,
+            .durations     = NULL,
+            .set_timeouts  = set_timeouts,
+            .probe         = crb_probe,
+            .get_tpm_version = crb_get_tpm_version,
+            .init          = crb_init,
+            .activate      = crb_activate,
+            .ready         = crb_ready,
+            .senddata      = crb_senddata,
+            .readresp      = crb_readresp,
+            .waitdatavalid = crb_waitdatavalid,
+            .waitrespready = crb_waitrespready,
+        },
 };
 
 static u8 TPMHW_driver_to_use = TPM_INVALID_DRIVER;
diff --git a/src/hw/tpm_drivers.h b/src/hw/tpm_drivers.h
index 56fd9e8..adf1839 100644
--- a/src/hw/tpm_drivers.h
+++ b/src/hw/tpm_drivers.h
@@ -24,6 +24,32 @@ int tpmhw_transmit(u8 locty, struct tpm_req_header *req,
                    enum tpmDurationType to_t);
 void tpmhw_set_timeouts(u32 timeouts[4], u32 durations[3]);
 
+/* CRB driver */
+/* address of locality 0 (CRB) */
+#define TPM_CRB_BASE_ADDRESS        0xfed40000
+
+#define CRB_REG(LOCTY, REG)                                 \
+    (void *)(TPM_CRB_BASE_ADDRESS + (LOCTY << 12) + REG)
+
+/* hardware registers */
+#define CRB_REG_LOC_STATE              0x0
+#define CRB_REG_LOC_CTRL               0x8
+#define CRB_REG_LOC_STS                0xC
+#define CRB_REG_INTF_ID                0x30
+#define CRB_REG_CTRL_EXT               0x38
+#define CRB_REG_CTRL_REQ               0x40
+#define CRB_REG_CTRL_STS               0x44
+#define CRB_REG_CTRL_CANCEL            0x48
+#define CRB_REG_CTRL_START             0x4C
+#define CRB_REG_INT_ENABLE             0x50
+#define CRB_REG_INT_STS                0x54
+#define CRB_REG_CTRL_CMD_SIZE          0x58
+#define CRB_REG_CTRL_CMD_LADDR         0x5C
+#define CRB_REG_CTRL_CMD_HADDR         0x60
+#define CRB_REG_CTRL_RSP_SIZE          0x64
+#define CRB_REG_CTRL_RSP_ADDR          0x68
+#define CRB_REG_DATA_BUFFER            0x80
+
 /* TIS driver */
 /* address of locality 0 (TIS) */
 #define TPM_TIS_BASE_ADDRESS        0xfed40000
-- 
2.5.5




More information about the SeaBIOS mailing list