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

Stefan Berger stefanb at linux.vnet.ibm.com
Wed Nov 1 15:09:17 CET 2017


On 10/06/2017 10:33 AM, marcandre.lureau at redhat.com wrote:
> 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 WIP patch doesn't support locality other than 0. The BIOS doesn't
> seem to require other localities, so that code seems a bit pointless.
>
> In theory, the cmd/resp buffers could be located above 4G, but I
> don't know how seabios could reach it in 32bit mode (my qemu WIP
> allocates next to 0xfed40000).
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau at redhat.com>

Some more changes necessary once we run longer commands from a TPM 2 menu:

diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c
index 3b8f6e1..f12924e 100644
--- a/src/hw/tpm_drivers.c
+++ b/src/hw/tpm_drivers.c
@ -405,7 +405,12 @@ static u32 crb_wait_reg(u8 locty, u8 reg, u32 time, 
u8 mask, u8 expect)
          return 0;

      u32 rc = 1;
-    u32 end = timer_calc_usec(time);
+    u32 end;
+
+    if (time < 1000000)
+        end = timer_calc_usec(time);
+    else
+        end = timer_calc(time / 1000);

      for (;;) {
          u8 sts = readl(CRB_REG(locty, reg));
@@ -512,9 +515,9 @@ static u32 crb_waitrespready(enum tpmDurationType to_t)

      u32 rc = 0;
      u8 locty = crb_find_active_locality();
-    u32 timeout_a = 
tpm_drivers[CRB_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_A];
+    u32 timeout = tpm_drivers[CRB_DRIVER_IDX].durations[to_t];

-    rc = crb_wait_reg(locty, CRB_REG_CTRL_START, timeout_a,
+    rc = crb_wait_reg(locty, CRB_REG_CTRL_START, timeout,
                        CRB_START_INVOKE, 0);

      return rc;


The 1st part fixes what seem to be u32 overflows when using 60s 
durations. The commands immediately time out. I will fix this in the TIS 
driver as well.

The 2nd part uses command duration to wait until a response is ready.

     Stefan

> ---
>   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..3b8f6e1 100644
> --- a/src/hw/tpm_drivers.c
> +++ b/src/hw/tpm_drivers.c
> @@ -36,7 +36,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 +58,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 +344,181 @@ 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;
> +
> +    /* TODO activate locty */
> +
> +    return 0;
> +}
> +
> +static u32 crb_find_active_locality(void)
> +{
> +    if (!CONFIG_TCGBIOS)
> +        return 0;
> +
> +    /* TODO return current locty */
> +
> +    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 = tis_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 = tis_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 > *len || expected < 6)
> +        return 1;
> +
> +    memcpy(buffer + 6, crb_resp + 6, expected - 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_a = tpm_drivers[CRB_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_A];
> +
> +    rc = crb_wait_reg(locty, CRB_REG_CTRL_START, timeout_a,
> +                      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





More information about the SeaBIOS mailing list