[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine
Signed-off-by: Quan Xu <quan.xu@xxxxxxxxx> Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxxxxxxx> --- 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@xxxxxxxxxxxxxxxxxx> + * Quan Xu <quan.xu@xxxxxxxxx> + * + * 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 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |