-----Original Message----- From: Xu, Quan Sent: Tuesday, March 10, 2015 8:16 PM To: kevin@koconnor.net Cc: stefano.stabellini@eu.citrix.com; stefanb@linux.vnet.ibm.com; qemu-devel@nongnu.org; xen-devel@lists.xen.org; Xu, Quan Subject: [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine
Signed-off-by: Quan Xu quan.xu@intel.com Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
Makefile | 2 +- src/post.c | 3 + src/tpm.c | 309 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tpm.h | 141 ++++++++++++++++++++++++++++ 4 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 src/tpm.c create mode 100644 src/tpm.h
diff --git a/Makefile b/Makefile index eecb8a1..945e997 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \ hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \ hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c SRC16=$(SRCBOTH) -SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \ +SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c tpm.c x86.c +optionroms.c \ pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c \ hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c \ fw/coreboot.c fw/lzmadecode.c fw/csm.c fw/biostables.c \ diff --git a/src/post.c b/src/post.c index 0fdd28e..8cb1abd 100644 --- a/src/post.c +++ b/src/post.c @@ -28,6 +28,7 @@ #include "output.h" // dprintf #include "string.h" // memset #include "util.h" // kbd_init +#include "tpm.h" //vtpm4hvm_setup
/*************************************************************
@@ -151,6 +152,8 @@ device_hardware_setup(void) esp_scsi_setup(); megasas_setup(); pvscsi_setup();
- if (runningOnXen())
vtpm4hvm_setup();
}
static void diff --git a/src/tpm.c b/src/tpm.c new file mode 100644 index 0000000..a834d30 --- /dev/null +++ b/src/tpm.c @@ -0,0 +1,309 @@ +/*
- Implementation of a TPM driver for the TPM TIS interface
- Copyright (C) 2006-2013 IBM Corporation
- Copyright (C) 2015 Intel Corporation
- Authors:
Stefan Berger <stefanb@linux.vnet.ibm.com>
Quan Xu <quan.xu@intel.com>
- This file may be distributed under the terms of the GNU
- LGPLv3 license.
- */
+#include "config.h" +#include "util.h" +#include "tpm.h"
+static u32 tis_default_timeouts[4] = {
- TIS_DEFAULT_TIMEOUT_A,
- TIS_DEFAULT_TIMEOUT_B,
- TIS_DEFAULT_TIMEOUT_C,
- TIS_DEFAULT_TIMEOUT_D,
+};
+static u32 tpm_default_durations[3] = {
- TPM_DEFAULT_DURATION_SHORT,
- TPM_DEFAULT_DURATION_MEDIUM,
- TPM_DEFAULT_DURATION_LONG,
+};
+/* if device is not there, return '0', '1' otherwise */ static u32 +tis_probe(void) {
- u32 rc = 0;
- u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID));
- if ((didvid != 0) && (didvid != 0xffffffff))
rc = 1;
- return rc;
+}
+static u32 tis_init(void) +{
- writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);
- if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) {
u32 *durations = malloc_low(sizeof(tpm_default_durations));
if (durations)
memcpy(durations, tpm_default_durations,
sizeof(tpm_default_durations));
else
durations = tpm_default_durations;
tpm_drivers[TIS_DRIVER_IDX].durations = durations;
- }
- if (tpm_drivers[TIS_DRIVER_IDX].timeouts == NULL) {
u32 *timeouts = malloc_low(sizeof(tis_default_timeouts));
if (timeouts)
memcpy(timeouts, tis_default_timeouts,
sizeof(tis_default_timeouts));
else
timeouts = tis_default_timeouts;
tpm_drivers[TIS_DRIVER_IDX].timeouts = timeouts;
- }
- return 1;
+}
+static void set_timeouts(u32 timeouts[4], u32 durations[3]) {
- u32 *tos = tpm_drivers[TIS_DRIVER_IDX].timeouts;
- u32 *dus = tpm_drivers[TIS_DRIVER_IDX].durations;
- if (tos && tos != tis_default_timeouts && timeouts)
memcpy(tos, timeouts, 4 * sizeof(u32));
- if (dus && dus != tpm_default_durations && durations)
memcpy(dus, durations, 3 * sizeof(u32)); }
+static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect) {
- u32 rc = 1;
- while (time > 0) {
u8 sts = readb(TIS_REG(locty, TIS_REG_STS));
if ((sts & mask) == expect) {
rc = 0;
break;
}
msleep(1);
time--;
- }
- return rc;
+}
+static u32 tis_activate(u8 locty) +{
- u32 rc = 0;
- u8 acc;
- int l;
- u32 timeout_a =
+tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_A];
- if (!(readb(TIS_REG(locty, TIS_REG_ACCESS)) &
TIS_ACCESS_ACTIVE_LOCALITY)) {
/* release locality in use top-downwards */
for (l = 4; l >= 0; l--)
writeb(TIS_REG(l, TIS_REG_ACCESS),
TIS_ACCESS_ACTIVE_LOCALITY);
- }
- /* request access to locality */
- writeb(TIS_REG(locty, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
- acc = readb(TIS_REG(locty, TIS_REG_ACCESS));
- if ((acc & TIS_ACCESS_ACTIVE_LOCALITY)) {
writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
rc = tis_wait_sts(locty, timeout_a,
TIS_STS_COMMAND_READY,
TIS_STS_COMMAND_READY);
- }
- return rc;
+}
+static u32 tis_find_active_locality(void) {
- u8 locty;
- for (locty = 0; locty <= 4; locty++) {
if ((readb(TIS_REG(locty, TIS_REG_ACCESS)) &
TIS_ACCESS_ACTIVE_LOCALITY))
return locty;
- }
- tis_activate(0);
- return 0;
+}
+static u32 tis_ready(void) +{
- u32 rc = 0;
- u8 locty = tis_find_active_locality();
- u32 timeout_b =
+tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_B];
- writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
- rc = tis_wait_sts(locty, timeout_b,
TIS_STS_COMMAND_READY,
TIS_STS_COMMAND_READY);
- return rc;
+}
+static u32 tis_senddata(const u8 *const data, u32 len) {
- u32 rc = 0;
- u32 offset = 0;
- u32 end = 0;
- u16 burst = 0;
- u32 ctr = 0;
- u8 locty = tis_find_active_locality();
- u32 timeout_d =
+tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_D];
- do {
while (burst == 0 && ctr < timeout_d) {
burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8;
if (burst == 0) {
msleep(1);
ctr++;
}
}
if (burst == 0) {
rc = TCG_RESPONSE_TIMEOUT;
break;
}
while (1) {
writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), data[offset++]);
burst--;
if (burst == 0 || offset == len)
break;
}
if (offset == len)
end = 1;
- } while (end == 0);
- return rc;
+}
+static u32 tis_readresp(u8 *buffer, u32 *len) {
- u32 rc = 0;
- u32 offset = 0;
- u32 sts;
- u8 locty = tis_find_active_locality();
- while (offset < *len) {
buffer[offset] = readb(TIS_REG(locty, TIS_REG_DATA_FIFO));
offset++;
sts = readb(TIS_REG(locty, TIS_REG_STS));
/* data left ? */
if ((sts & TIS_STS_DATA_AVAILABLE) == 0)
break;
- }
- *len = offset;
- return rc;
+}
+static u32 tis_waitdatavalid(void) +{
- u32 rc = 0;
- u8 locty = tis_find_active_locality();
- u32 timeout_c =
+tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C];
- if (tis_wait_sts(locty, timeout_c, TIS_STS_VALID, TIS_STS_VALID) != 0)
rc = TCG_NO_RESPONSE;
- return rc;
+}
+static u32 tis_waitrespready(enum tpmDurationType to_t) {
- u32 rc = 0;
- u8 locty = tis_find_active_locality();
- u32 timeout = tpm_drivers[TIS_DRIVER_IDX].durations[to_t];
- writeb(TIS_REG(locty ,TIS_REG_STS), TIS_STS_TPM_GO);
- if (tis_wait_sts(locty, timeout,
TIS_STS_DATA_AVAILABLE,
TIS_STS_DATA_AVAILABLE) != 0)
rc = TCG_NO_RESPONSE;
- return rc;
+}
+struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
- [TIS_DRIVER_IDX] =
{
.timeouts = NULL,
.durations = NULL,
.set_timeouts = set_timeouts,
.probe = tis_probe,
.init = tis_init,
.activate = tis_activate,
.ready = tis_ready,
.senddata = tis_senddata,
.readresp = tis_readresp,
.waitdatavalid = tis_waitdatavalid,
.waitrespready = tis_waitrespready,
.sha1threshold = 100 * 1024,
},
+};
+typedef struct {
- u8 tpm_probed:1;
- u8 tpm_found:1;
- u8 tpm_working:1;
- u8 if_shutdown:1;
- u8 tpm_driver_to_use:4;
+} tcpa_state_t;
+static tcpa_state_t tcpa_state = {
- .tpm_driver_to_use = TPM_INVALID_DRIVER, };
+static u32 +is_tpm_present(void) +{
- u32 rc = 0;
- unsigned int i;
- for (i = 0; i < TPM_NUM_DRIVERS; i++) {
struct tpm_driver *td = &tpm_drivers[i];
if (td->probe() != 0) {
td->init();
tcpa_state.tpm_driver_to_use = i;
rc = 1;
break;
}
- }
- return rc;
+}
+int +vtpm4hvm_setup(void) +{
- if (!tcpa_state.tpm_probed) {
tcpa_state.tpm_probed = 1;
tcpa_state.tpm_found = (is_tpm_present() != 0);
tcpa_state.tpm_working = 1;
- }
- if (!tcpa_state.tpm_working)
return 0;
- return tcpa_state.tpm_found;
+}
diff --git a/src/tpm.h b/src/tpm.h new file mode 100644 index 0000000..cac5cec --- /dev/null +++ b/src/tpm.h @@ -0,0 +1,141 @@ +#ifndef TPM_DRIVERS_H +#define TPM_DRIVERS_H
+#include "types.h" // u32
+enum tpmDurationType {
- TPM_DURATION_TYPE_SHORT = 0,
- TPM_DURATION_TYPE_MEDIUM,
- TPM_DURATION_TYPE_LONG,
+};
+/* low level driver implementation */ +struct tpm_driver {
- u32 *timeouts;
- u32 *durations;
- void (*set_timeouts)(u32 timeouts[4], u32 durations[3]);
- u32 (*probe)(void);
- u32 (*init)(void);
- u32 (*activate)(u8 locty);
- u32 (*ready)(void);
- u32 (*senddata)(const u8 *const data, u32 len);
- u32 (*readresp)(u8 *buffer, u32 *len);
- u32 (*waitdatavalid)(void);
- u32 (*waitrespready)(enum tpmDurationType to_t);
- /* the TPM will be used for buffers of sizes below the sha1threshold
for calculating the hash */
- u32 sha1threshold;
+};
+extern struct tpm_driver tpm_drivers[];
+#define TIS_DRIVER_IDX 0 +#define TPM_NUM_DRIVERS 1
+#define TPM_INVALID_DRIVER -1
+/* TIS driver */ +/* address of locality 0 (TIS) */ +#define TPM_TIS_BASE_ADDRESS 0xfed40000
+#define TIS_REG(LOCTY, REG) \
- (void *)(TPM_TIS_BASE_ADDRESS + (LOCTY << 12) + REG)
+/* hardware registers */ +#define TIS_REG_ACCESS 0x0 +#define TIS_REG_INT_ENABLE 0x8 +#define TIS_REG_INT_VECTOR 0xc +#define TIS_REG_INT_STATUS 0x10 +#define TIS_REG_INTF_CAPABILITY 0x14 +#define TIS_REG_STS 0x18 +#define TIS_REG_DATA_FIFO 0x24 +#define TIS_REG_DID_VID 0xf00 +#define TIS_REG_RID 0xf04
+#define TIS_STS_VALID (1 << 7) /* 0x80 */ +#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */ +#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */ +#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */ +#define TIS_STS_EXPECT (1 << 3) /* 0x08 */ +#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
+#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */ +#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */ +#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */ +#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */ +#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */ +#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */ +#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
+#define SCALER 10
+#define TIS_DEFAULT_TIMEOUT_A (750 * SCALER) +#define TIS_DEFAULT_TIMEOUT_B (2000 * SCALER) +#define TIS_DEFAULT_TIMEOUT_C (750 * SCALER) +#define TIS_DEFAULT_TIMEOUT_D (750 * SCALER)
+enum tisTimeoutType {
- TIS_TIMEOUT_TYPE_A = 0,
- TIS_TIMEOUT_TYPE_B,
- TIS_TIMEOUT_TYPE_C,
- TIS_TIMEOUT_TYPE_D,
+};
+#define TPM_DEFAULT_DURATION_SHORT (2000 * SCALER) +#define TPM_DEFAULT_DURATION_MEDIUM (20000 * SCALER) +#define TPM_DEFAULT_DURATION_LONG (60000 * SCALER)
+/***************************************************
TCG BIOS *
- ***************************************************/
+#define TPM_OK 0x0 +#define TPM_RET_BASE 0x1 +#define TCG_GENERAL_ERROR (TPM_RET_BASE + 0x0) +#define TCG_TPM_IS_LOCKED (TPM_RET_BASE + 0x1) +#define TCG_NO_RESPONSE (TPM_RET_BASE + 0x2) +#define TCG_INVALID_RESPONSE (TPM_RET_BASE + 0x3) +#define TCG_INVALID_ACCESS_REQUEST (TPM_RET_BASE + 0x4) +#define TCG_FIRMWARE_ERROR (TPM_RET_BASE + 0x5) +#define TCG_INTEGRITY_CHECK_FAILED (TPM_RET_BASE + 0x6) +#define TCG_INVALID_DEVICE_ID (TPM_RET_BASE + 0x7) +#define TCG_INVALID_VENDOR_ID (TPM_RET_BASE + 0x8) +#define TCG_UNABLE_TO_OPEN (TPM_RET_BASE + 0x9) +#define TCG_UNABLE_TO_CLOSE (TPM_RET_BASE + 0xa) +#define TCG_RESPONSE_TIMEOUT (TPM_RET_BASE + 0xb) +#define TCG_INVALID_COM_REQUEST (TPM_RET_BASE + 0xc) +#define TCG_INVALID_ADR_REQUEST (TPM_RET_BASE + 0xd) +#define TCG_WRITE_BYTE_ERROR (TPM_RET_BASE + 0xe) +#define TCG_READ_BYTE_ERROR (TPM_RET_BASE + 0xf) +#define TCG_BLOCK_WRITE_TIMEOUT (TPM_RET_BASE + 0x10) +#define TCG_CHAR_WRITE_TIMEOUT (TPM_RET_BASE + 0x11) +#define TCG_CHAR_READ_TIMEOUT (TPM_RET_BASE + 0x12) +#define TCG_BLOCK_READ_TIMEOUT (TPM_RET_BASE + 0x13) +#define TCG_TRANSFER_ABORT (TPM_RET_BASE + 0x14) +#define TCG_INVALID_DRV_FUNCTION (TPM_RET_BASE + 0x15) +#define TCG_OUTPUT_BUFFER_TOO_SHORT (TPM_RET_BASE + 0x16) +#define TCG_FATAL_COM_ERROR (TPM_RET_BASE + 0x17) +#define TCG_INVALID_INPUT_PARA (TPM_RET_BASE + 0x18) +#define TCG_TCG_COMMAND_ERROR (TPM_RET_BASE + 0x19) +#define TCG_INTERFACE_SHUTDOWN (TPM_RET_BASE + 0x20) +#define TCG_PC_TPM_NOT_PRESENT (TPM_RET_BASE + 0x22) +#define TCG_PC_TPM_DEACTIVATED (TPM_RET_BASE + 0x23)
+#define TPM_INVALID_ADR_REQUEST TCG_INVALID_ADR_REQUEST +#define TPM_IS_LOCKED TCG_TPM_IS_LOCKED +#define TPM_INVALID_DEVICE_ID TCG_INVALID_DEVICE_ID +#define TPM_INVALID_VENDOR_ID TCG_INVALID_VENDOR_ID +#define TPM_FIRMWARE_ERROR TCG_FIRMWARE_ERROR +#define TPM_UNABLE_TO_OPEN TCG_UNABLE_TO_OPEN +#define TPM_UNABLE_TO_CLOSE TCG_UNABLE_TO_CLOSE +#define TPM_INVALID_RESPONSE TCG_INVALID_RESPONSE +#define TPM_RESPONSE_TIMEOUT TCG_RESPONSE_TIMEOUT +#define TPM_INVALID_ACCESS_REQUEST TCG_INVALID_ACCESS_REQUEST +#define TPM_TRANSFER_ABORT TCG_TRANSFER_ABORT +#define TPM_GENERAL_ERROR TCG_GENERAL_ERROR
+int vtpm4hvm_setup(void);
+#endif /* TPM_DRIVERS_H */
1.8.1.2