[SeaBIOS] FW: [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine

Xu, Quan quan.xu at intel.com
Tue Mar 10 18:23:52 CET 2015



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




More information about the SeaBIOS mailing list