> -----Original Message----- > From: Xu, Quan > Sent: Tuesday, March 10, 2015 8:16 PM > To: [email protected] > Cc: [email protected]; [email protected]; > [email protected]; [email protected]; Xu, Quan > Subject: [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual > machine > > Signed-off-by: Quan Xu <[email protected]> > Signed-off-by: Stefan Berger <[email protected]> > --- > 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 <[email protected]> > + * Quan Xu <[email protected]> > + * > + * 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
_______________________________________________ SeaBIOS mailing list [email protected] http://www.seabios.org/mailman/listinfo/seabios
