diff options
Diffstat (limited to 'hw/tpm/tpm_tis.c')
-rw-r--r-- | hw/tpm/tpm_tis.c | 119 |
1 files changed, 110 insertions, 9 deletions
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index b8235d5c9f..0806b5f82e 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -17,6 +17,9 @@ * supports version 1.3, 21 March 2013 * In the developers menu choose the PC Client section then find the TIS * specification. + * + * TPM TIS for TPM 2 implementation following TCG PC Client Platform + * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 */ #include "sysemu/tpm_backend.h" @@ -29,6 +32,7 @@ #include "tpm_tis.h" #include "qemu-common.h" #include "qemu/main-loop.h" +#include "sysemu/tpm_backend.h" #define DEBUG_TIS 0 @@ -49,6 +53,7 @@ #define TPM_TIS_REG_INTF_CAPABILITY 0x14 #define TPM_TIS_REG_STS 0x18 #define TPM_TIS_REG_DATA_FIFO 0x24 +#define TPM_TIS_REG_INTERFACE_ID 0x30 #define TPM_TIS_REG_DATA_XFIFO 0x80 #define TPM_TIS_REG_DATA_XFIFO_END 0xbc #define TPM_TIS_REG_DID_VID 0xf00 @@ -57,6 +62,12 @@ /* vendor-specific registers */ #define TPM_TIS_REG_DEBUG 0xf90 +#define TPM_TIS_STS_TPM_FAMILY_MASK (0x3 << 26)/* TPM 2.0 */ +#define TPM_TIS_STS_TPM_FAMILY1_2 (0 << 26) /* TPM 2.0 */ +#define TPM_TIS_STS_TPM_FAMILY2_0 (1 << 26) /* TPM 2.0 */ +#define TPM_TIS_STS_RESET_ESTABLISHMENT_BIT (1 << 25) /* TPM 2.0 */ +#define TPM_TIS_STS_COMMAND_CANCEL (1 << 24) /* TPM 2.0 */ + #define TPM_TIS_STS_VALID (1 << 7) #define TPM_TIS_STS_COMMAND_READY (1 << 6) #define TPM_TIS_STS_TPM_GO (1 << 5) @@ -102,15 +113,42 @@ #endif #define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28) +#define TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 (3 << 28) #define TPM_TIS_CAP_DATA_TRANSFER_64B (3 << 9) #define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9) #define TPM_TIS_CAP_BURST_COUNT_DYNAMIC (0 << 8) #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */ -#define TPM_TIS_CAPABILITIES_SUPPORTED (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \ - TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \ - TPM_TIS_CAP_DATA_TRANSFER_64B | \ - TPM_TIS_CAP_INTERFACE_VERSION1_3 | \ - TPM_TIS_INTERRUPTS_SUPPORTED) +#define TPM_TIS_CAPABILITIES_SUPPORTED1_3 \ + (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \ + TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \ + TPM_TIS_CAP_DATA_TRANSFER_64B | \ + TPM_TIS_CAP_INTERFACE_VERSION1_3 | \ + TPM_TIS_INTERRUPTS_SUPPORTED) + +#define TPM_TIS_CAPABILITIES_SUPPORTED2_0 \ + (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \ + TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \ + TPM_TIS_CAP_DATA_TRANSFER_64B | \ + TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 | \ + TPM_TIS_INTERRUPTS_SUPPORTED) + +#define TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 (0xf) /* TPM 2.0 */ +#define TPM_TIS_IFACE_ID_INTERFACE_FIFO (0x0) /* TPM 2.0 */ +#define TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO (0 << 4) /* TPM 2.0 */ +#define TPM_TIS_IFACE_ID_CAP_5_LOCALITIES (1 << 8) /* TPM 2.0 */ +#define TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED (1 << 13) /* TPM 2.0 */ +#define TPM_TIS_IFACE_ID_INT_SEL_LOCK (1 << 19) /* TPM 2.0 */ + +#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3 \ + (TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 | \ + (~0 << 4)/* all of it is don't care */) + +/* if backend was a TPM 2.0: */ +#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0 \ + (TPM_TIS_IFACE_ID_INTERFACE_FIFO | \ + TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO | \ + TPM_TIS_IFACE_ID_CAP_5_LOCALITIES | \ + TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED) #define TPM_TIS_TPM_DID 0x0001 #define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM @@ -154,7 +192,8 @@ static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string) /* * Set the given flags in the STS register by clearing the register but - * preserving the SELFTEST_DONE flag and then setting the new flags. + * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting + * the new flags. * * The SELFTEST_DONE flag is acquired from the backend that determines it by * peeking into TPM commands. @@ -166,7 +205,7 @@ static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string) */ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) { - l->sts &= TPM_TIS_STS_SELFTEST_DONE; + l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK; l->sts |= flags; } @@ -489,7 +528,17 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, val = tis->loc[locty].ints; break; case TPM_TIS_REG_INTF_CAPABILITY: - val = TPM_TIS_CAPABILITIES_SUPPORTED; + switch (s->be_tpm_version) { + case TPM_VERSION_UNSPEC: + val = 0; + break; + case TPM_VERSION_1_2: + val = TPM_TIS_CAPABILITIES_SUPPORTED1_3; + break; + case TPM_VERSION_2_0: + val = TPM_TIS_CAPABILITIES_SUPPORTED2_0; + break; + } break; case TPM_TIS_REG_STS: if (tis->active_locty == locty) { @@ -536,6 +585,9 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, shift = 0; /* no more adjustments */ } break; + case TPM_TIS_REG_INTERFACE_ID: + val = tis->loc[locty].iface_id; + break; case TPM_TIS_REG_DID_VID: val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID; break; @@ -736,6 +788,25 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr, break; } + if (s->be_tpm_version == TPM_VERSION_2_0) { + /* some flags that are only supported for TPM 2 */ + if (val & TPM_TIS_STS_COMMAND_CANCEL) { + if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) { + /* + * request the backend to cancel. Some backends may not + * support it + */ + tpm_backend_cancel_cmd(s->be_driver); + } + } + + if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) { + if (locty == 3 || locty == 4) { + tpm_backend_reset_tpm_established_flag(s->be_driver, locty); + } + } + } + val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO | TPM_TIS_STS_RESPONSE_RETRY); @@ -860,6 +931,13 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr, } } break; + case TPM_TIS_REG_INTERFACE_ID: + if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) { + for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { + tis->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK; + } + } + break; } } @@ -885,6 +963,16 @@ static int tpm_tis_do_startup_tpm(TPMState *s) } /* + * Get the TPMVersion of the backend device being used + */ +TPMVersion tpm_tis_get_tpm_version(Object *obj) +{ + TPMState *s = TPM(obj); + + return tpm_backend_get_tpm_version(s->be_driver); +} + +/* * This function is called when the machine starts, resets or due to * S3 resume. */ @@ -894,6 +982,8 @@ static void tpm_tis_reset(DeviceState *dev) TPMTISEmuState *tis = &s->s.tis; int c; + s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); + tpm_backend_reset(s->be_driver); tis->active_locty = TPM_TIS_NO_LOCALITY; @@ -902,7 +992,18 @@ static void tpm_tis_reset(DeviceState *dev) for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) { tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS; - tis->loc[c].sts = 0; + switch (s->be_tpm_version) { + case TPM_VERSION_UNSPEC: + break; + case TPM_VERSION_1_2: + tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2; + tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3; + break; + case TPM_VERSION_2_0: + tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0; + tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0; + break; + } tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL; tis->loc[c].ints = 0; tis->loc[c].state = TPM_TIS_STATE_IDLE; |