Extend TPM TIS interface to support TPM 2

Following the recent upgrade to version 1.3, extend the TPM TIS
interface with capabilities introduced for support of a TPM 2.

TPM TIS for TPM 2 introduced the following extensions beyond the
TPM TIS 1.3 (used for TPM 1.2):

- A new 32bit interface Id register was introduced.
- New flags for the status (STS) register were defined.
- New flags for the capability flags were defined.

Support the above if a TPM TIS 1.3 for TPM 2 is used with a TPM 2
on the backend side. Support the old TPM TIS 1.3 configuration if a
TPM 1.2 is being used. A subsequent patch will then determine which
TPM version is being used in the backend.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Stefan Berger 2015-05-26 16:51:05 -04:00 committed by Michael S. Tsirkin
parent 38d40ff10f
commit 116694c34a
7 changed files with 158 additions and 9 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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);