[SeaBIOS] [PATCH 4/4] WIP: add TPM CRB device support
Stefan Berger
stefanb at linux.vnet.ibm.com
Fri Oct 6 16:50:33 CEST 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).
This looks all really good to me.
The TPM TIS is supposed to be the most widespread interface, so I am
surprised that Win 10 does not use it.
Regards,
Stefan
> Signed-off-by: Marc-André Lureau <marcandre.lureau at redhat.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..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