aboutsummaryrefslogtreecommitdiff
path: root/hw/tpm/tpm_tis.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/tpm/tpm_tis.c')
-rw-r--r--hw/tpm/tpm_tis.c119
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;