Skip to content

Commit

Permalink
Extend TPM TIS interface to support TPM 2
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
stefanberger authored and mstsirkin committed May 31, 2015
1 parent 38d40ff commit 116694c
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 9 deletions.
14 changes: 14 additions & 0 deletions backends/tpm.c
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions hw/tpm/tpm_int.h
Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions hw/tpm/tpm_passthrough.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down
108 changes: 99 additions & 9 deletions hw/tpm/tpm_tis.c
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions hw/tpm/tpm_tis.h
Expand Up @@ -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;

Expand Down
6 changes: 6 additions & 0 deletions include/sysemu/tpm.h
Expand Up @@ -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)
Expand Down
23 changes: 23 additions & 0 deletions include/sysemu/tpm_backend.h
Expand Up @@ -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);
};


Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down

0 comments on commit 116694c

Please sign in to comment.