[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtu
From: |
Quan Xu |
Subject: |
[Qemu-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine |
Date: |
Tue, 10 Mar 2015 08:16:04 -0400 |
Signed-off-by: Quan Xu <address@hidden>
Signed-off-by: Stefan Berger <address@hidden>
---
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 <address@hidden>
+ * Quan Xu <address@hidden>
+ *
+ * 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
- [Qemu-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Quan Xu, 2015/03/10
- [Qemu-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine,
Quan Xu <=
- Re: [Qemu-devel] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Ian Campbell, 2015/03/19
- Re: [Qemu-devel] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Stefan Berger, 2015/03/20
- Re: [Qemu-devel] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Xu, Quan, 2015/03/22
- Re: [Qemu-devel] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Stefan Berger, 2015/03/23
- Re: [Qemu-devel] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Xu, Quan, 2015/03/23
- Re: [Qemu-devel] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Stefan Berger, 2015/03/23
- Re: [Qemu-devel] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Xu, Quan, 2015/03/23
- Re: [Qemu-devel] [Xen-devel] [PATCH] SeaBios/vTPM: Enable Xen stubdom vTPM for HVM virtual machine, Stefan Berger, 2015/03/24