> -----Original Message-----
> From: Xu, Quan
> Sent: Tuesday, March 10, 2015 8:16 PM
> To: kevin(a)koconnor.net
> Cc: stefano.stabellini(a)eu.citrix.com; stefanb(a)linux.vnet.ibm.com;
> qemu-devel(a)nongnu.org; xen-devel(a)lists.xen.org; Xu, Quan
> Subject: [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual
> machine
>
> Signed-off-by: Quan Xu <quan.xu(a)intel.com>
> Signed-off-by: Stefan Berger <stefanb(a)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(a)linux.vnet.ibm.com>
> + * Quan Xu <quan.xu(a)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