diff --git a/backends/tpm.c b/backends/tpm.c index 36c5d46f0a..f3ab3b30bd 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -96,6 +96,20 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s) return k->ops->get_tpm_established_flag(s); } +int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->reset_tpm_established_flag(s, locty); +} + +TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->get_tpm_version(s); +} + static bool tpm_backend_prop_get_opened(Object *obj, Error **errp) { TPMBackend *s = TPM_BACKEND(obj); diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h index 2b35fe21ec..9866c7962a 100644 --- a/hw/tpm/tpm_int.h +++ b/hw/tpm/tpm_int.h @@ -29,6 +29,7 @@ struct TPMState { char *backend; TPMBackend *be_driver; + TPMVersion be_tpm_version; }; #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 73ca906282..f1361d2cb6 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -267,6 +267,13 @@ static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb) return false; } +static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb, + uint8_t locty) +{ + /* only a TPM 2.0 will support this */ + return 0; +} + static bool tpm_passthrough_get_startup_error(TPMBackend *tb) { TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); @@ -324,6 +331,11 @@ static const char *tpm_passthrough_create_desc(void) return "Passthrough TPM backend driver"; } +static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb) +{ + return TPM_VERSION_1_2; +} + /* * A basic test of a TPM device. We expect a well formatted response header * (error response is fine) within one second. @@ -540,6 +552,8 @@ static const TPMDriverOps tpm_passthrough_driver = { .deliver_request = tpm_passthrough_deliver_request, .cancel_cmd = tpm_passthrough_cancel_cmd, .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, + .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag, + .get_tpm_version = tpm_passthrough_get_tpm_version, }; static void tpm_passthrough_inst_init(Object *obj) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index b8235d5c9f..e8047571c1 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" @@ -49,6 +52,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 +61,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 +112,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 +191,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 +204,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 +527,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 +584,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 +787,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 +930,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; } } @@ -894,6 +971,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 +981,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; diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h index db78d51e4f..a1df41fa21 100644 --- a/hw/tpm/tpm_tis.h +++ b/hw/tpm/tpm_tis.h @@ -42,6 +42,7 @@ typedef struct TPMLocality { TPMTISState state; uint8_t access; uint32_t sts; + uint32_t iface_id; uint32_t inte; uint32_t ints; diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 9b81ce9189..848df412db 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -20,6 +20,12 @@ int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); int tpm_init(void); void tpm_cleanup(void); +typedef enum TPMVersion { + TPM_VERSION_UNSPEC = 0, + TPM_VERSION_1_2 = 1, + TPM_VERSION_2_0 = 2, +} TPMVersion; + #define TYPE_TPM_TIS "tpm-tis" static inline bool tpm_find(void) diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 540ee25477..0a366be0f2 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -88,6 +88,10 @@ struct TPMDriverOps { void (*cancel_cmd)(TPMBackend *t); bool (*get_tpm_established_flag)(TPMBackend *t); + + int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty); + + TPMVersion (*get_tpm_version)(TPMBackend *t); }; @@ -191,6 +195,15 @@ void tpm_backend_cancel_cmd(TPMBackend *s); */ bool tpm_backend_get_tpm_established_flag(TPMBackend *s); +/** + * tpm_backend_reset_tpm_established_flag: + * @s: the backend + * @locty: the locality number + * + * Reset the TPM establishment flag. + */ +int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty); + /** * tpm_backend_open: * @s: the backend to open @@ -201,6 +214,16 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s); */ void tpm_backend_open(TPMBackend *s, Error **errp); +/** + * tpm_backend_get_tpm_version: + * @s: the backend to call into + * + * Get the TPM Version that is emulated at the backend. + * + * Returns TPMVersion. + */ +TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); + TPMBackend *qemu_find_tpm(const char *id); const TPMDriverOps *tpm_get_backend_driver(const char *type);