diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hw/tpm_drivers.c | 196 | ||||
-rw-r--r-- | src/hw/tpm_drivers.h | 26 |
2 files changed, 221 insertions, 1 deletions
diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c index 5cee9d85..1fd05e1a 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,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 > 0xffffffff) + 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 = (*len < expected) ? *len : expected; + + 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 +534,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 56fd9e81..adf18396 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 |