aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--default-configs/i386-softmmu.mak2
-rw-r--r--docs/specs/tpm.rst25
-rw-r--r--hw/arm/Kconfig1
-rw-r--r--hw/arm/sysbus-fdt.c33
-rw-r--r--hw/arm/virt.c7
-rw-r--r--hw/i386/Kconfig2
-rw-r--r--hw/i386/acpi-build.c6
-rw-r--r--hw/tpm/Kconfig12
-rw-r--r--hw/tpm/Makefile.objs4
-rw-r--r--hw/tpm/tpm_tis.h91
-rw-r--r--hw/tpm/tpm_tis_common.c (renamed from hw/tpm/tpm_tis.c)181
-rw-r--r--hw/tpm/tpm_tis_isa.c170
-rw-r--r--hw/tpm/tpm_tis_sysbus.c159
-rw-r--r--include/sysemu/tpm.h7
-rw-r--r--tests/qtest/Makefile.include11
-rw-r--r--tests/qtest/tpm-crb-swtpm-test.c9
-rw-r--r--tests/qtest/tpm-crb-test.c3
-rw-r--r--tests/qtest/tpm-tests.c10
-rw-r--r--tests/qtest/tpm-tests.h5
-rw-r--r--tests/qtest/tpm-tis-device-swtpm-test.c76
-rw-r--r--tests/qtest/tpm-tis-device-test.c87
-rw-r--r--tests/qtest/tpm-tis-swtpm-test.c8
-rw-r--r--tests/qtest/tpm-tis-test.c414
-rw-r--r--tests/qtest/tpm-tis-util.c451
-rw-r--r--tests/qtest/tpm-tis-util.h23
-rw-r--r--tests/qtest/tpm-util.c11
-rw-r--r--tests/qtest/tpm-util.h8
27 files changed, 1207 insertions, 609 deletions
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 4cc64dafa2..84d1a2487c 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -20,7 +20,7 @@
#CONFIG_SGA=n
#CONFIG_TEST_DEVICES=n
#CONFIG_TPM_CRB=n
-#CONFIG_TPM_TIS=n
+#CONFIG_TPM_TIS_ISA=n
#CONFIG_VTD=n
# Boards:
diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst
index 2bdf637f55..da9eb39ca9 100644
--- a/docs/specs/tpm.rst
+++ b/docs/specs/tpm.rst
@@ -18,9 +18,15 @@ The TIS interface makes a memory mapped IO region in the area
0xfed40000-0xfed44fff available to the guest operating system.
QEMU files related to TPM TIS interface:
- - ``hw/tpm/tpm_tis.c``
+ - ``hw/tpm/tpm_tis_common.c``
+ - ``hw/tpm/tpm_tis_isa.c``
+ - ``hw/tpm/tpm_tis_sysbus.c``
- ``hw/tpm/tpm_tis.h``
+Both an ISA device and a sysbus device are available. The former is
+used with pc/q35 machine while the latter can be instantiated in the
+ARM virt machine.
+
CRB interface
-------------
@@ -325,6 +331,23 @@ In case a pSeries machine is emulated, use the following command line:
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \
-drive file=test.img,format=raw,if=none,id=drive-virtio-disk0
+In case an ARM virt machine is emulated, use the following command line:
+
+.. code-block:: console
+
+ qemu-system-aarch64 -machine virt,gic-version=3,accel=kvm \
+ -cpu host -m 4G \
+ -nographic -no-acpi \
+ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \
+ -tpmdev emulator,id=tpm0,chardev=chrtpm \
+ -device tpm-tis-device,tpmdev=tpm0 \
+ -device virtio-blk-pci,drive=drv0 \
+ -drive format=qcow2,file=hda.qcow2,if=none,id=drv0 \
+ -drive if=pflash,format=raw,file=flash0.img,readonly \
+ -drive if=pflash,format=raw,file=flash1.img
+
+ On ARM, ACPI boot with TPM is not yet supported.
+
In case SeaBIOS is used as firmware, it should show the TPM menu item
after entering the menu with 'ESC'.
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 61635f52c4..bc54fd61f9 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -5,6 +5,7 @@ config ARM_VIRT
imply VFIO_AMD_XGBE
imply VFIO_PLATFORM
imply VFIO_XGMAC
+ imply TPM_TIS_SYSBUS
select A15MPCORE
select ACPI
select ARM_SMMUV3
diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c
index 022fc97ecd..6b6906f4cf 100644
--- a/hw/arm/sysbus-fdt.c
+++ b/hw/arm/sysbus-fdt.c
@@ -30,6 +30,7 @@
#include "hw/arm/sysbus-fdt.h"
#include "qemu/error-report.h"
#include "sysemu/device_tree.h"
+#include "sysemu/tpm.h"
#include "hw/platform-bus.h"
#include "hw/vfio/vfio-platform.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
@@ -436,6 +437,37 @@ static bool vfio_platform_match(SysBusDevice *sbdev,
#endif /* CONFIG_LINUX */
+/*
+ * add_tpm_tis_fdt_node: Create a DT node for TPM TIS
+ *
+ * See kernel documentation:
+ * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt
+ * Optional interrupt for command completion is not exposed
+ */
+static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque)
+{
+ PlatformBusFDTData *data = opaque;
+ PlatformBusDevice *pbus = data->pbus;
+ void *fdt = data->fdt;
+ const char *parent_node = data->pbus_node_name;
+ char *nodename;
+ uint32_t reg_attr[2];
+ uint64_t mmio_base;
+
+ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
+ nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base);
+ qemu_fdt_add_subnode(fdt, nodename);
+
+ qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio");
+
+ reg_attr[0] = cpu_to_be32(mmio_base);
+ reg_attr[1] = cpu_to_be32(0x5000);
+ qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t));
+
+ g_free(nodename);
+ return 0;
+}
+
static int no_fdt_node(SysBusDevice *sbdev, void *opaque)
{
return 0;
@@ -456,6 +488,7 @@ static const BindingEntry bindings[] = {
TYPE_BINDING(TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node),
VFIO_PLATFORM_BINDING("amd,xgbe-seattle-v1a", add_amd_xgbe_fdt_node),
#endif
+ TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
TYPE_BINDING("", NULL), /* last element */
};
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 856808599d..32d865a488 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -48,6 +48,7 @@
#include "sysemu/numa.h"
#include "sysemu/runstate.h"
#include "sysemu/sysemu.h"
+#include "sysemu/tpm.h"
#include "sysemu/kvm.h"
#include "hw/loader.h"
#include "exec/address-spaces.h"
@@ -2083,6 +2084,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
mc->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
mc->pci_allow_0_address = true;
@@ -2196,6 +2198,11 @@ type_init(machvirt_machine_init);
static void virt_machine_5_0_options(MachineClass *mc)
{
+ static GlobalProperty compat[] = {
+ { TYPE_TPM_TIS_SYSBUS, "ppi", "false" },
+ };
+
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_VIRT_MACHINE_AS_LATEST(5, 0)
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index cdc851598c..c93f32f657 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -20,7 +20,7 @@ config PC
imply SGA
imply TEST_DEVICES
imply TPM_CRB
- imply TPM_TIS
+ imply TPM_TIS_ISA
imply VGA_PCI
imply VIRTIO_VGA
select FDC
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 9c4e46fa74..26777f8828 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2026,7 +2026,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
}
- if (TPM_IS_TIS(tpm_find())) {
+ if (TPM_IS_TIS_ISA(tpm_find())) {
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
}
@@ -2197,7 +2197,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
- if (TPM_IS_TIS(tpm)) {
+ if (TPM_IS_TIS_ISA(tpm)) {
if (misc->tpm_version == TPM_VERSION_2_0) {
dev = aml_device("TPM");
aml_append(dev, aml_name_decl("_HID",
@@ -2304,7 +2304,7 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog)
(char *)&tpm2_ptr->log_area_start_address - table_data->data;
tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
- if (TPM_IS_TIS(tpm_find())) {
+ if (TPM_IS_TIS_ISA(tpm_find())) {
tpm2_ptr->control_area_address = cpu_to_le64(0);
tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
} else if (TPM_IS_CRB(tpm_find())) {
diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig
index 9e67d990e8..4794e7fe28 100644
--- a/hw/tpm/Kconfig
+++ b/hw/tpm/Kconfig
@@ -2,9 +2,19 @@ config TPMDEV
bool
depends on TPM
-config TPM_TIS
+config TPM_TIS_ISA
bool
depends on TPM && ISA_BUS
+ select TPM_TIS
+
+config TPM_TIS_SYSBUS
+ bool
+ depends on TPM
+ select TPM_TIS
+
+config TPM_TIS
+ bool
+ depends on TPM
select TPMDEV
config TPM_CRB
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 85eb99ae05..f1ec4beb95 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,6 +1,8 @@
common-obj-$(CONFIG_TPM) += tpm_util.o
obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o
-common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
+common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o
+common-obj-$(CONFIG_TPM_TIS_SYSBUS) += tpm_tis_sysbus.o
+common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o
common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o
diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
new file mode 100644
index 0000000000..5554989395
--- /dev/null
+++ b/hw/tpm/tpm_tis.h
@@ -0,0 +1,91 @@
+/*
+ * tpm_tis.h - QEMU's TPM TIS common header
+ *
+ * Copyright (C) 2006,2010-2013 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ * David Safford <safford@us.ibm.com>
+ *
+ * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Implementation of the TIS interface according to specs found at
+ * http://www.trustedcomputinggroup.org. This implementation currently
+ * supports version 1.3, 21 March 2013
+ * In the developers menu choose the PC Client section then find the TIS
+ * specification.
+ *
+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform
+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
+ */
+#ifndef TPM_TPM_TIS_H
+#define TPM_TPM_TIS_H
+
+#include "qemu/osdep.h"
+#include "sysemu/tpm_backend.h"
+#include "tpm_ppi.h"
+
+#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
+#define TPM_TIS_LOCALITY_SHIFT 12
+#define TPM_TIS_NO_LOCALITY 0xff
+
+#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES)
+
+#define TPM_TIS_BUFFER_MAX 4096
+
+typedef enum {
+ TPM_TIS_STATE_IDLE = 0,
+ TPM_TIS_STATE_READY,
+ TPM_TIS_STATE_COMPLETION,
+ TPM_TIS_STATE_EXECUTION,
+ TPM_TIS_STATE_RECEPTION,
+} TPMTISState;
+
+/* locality data -- all fields are persisted */
+typedef struct TPMLocality {
+ TPMTISState state;
+ uint8_t access;
+ uint32_t sts;
+ uint32_t iface_id;
+ uint32_t inte;
+ uint32_t ints;
+} TPMLocality;
+
+typedef struct TPMState {
+ MemoryRegion mmio;
+
+ unsigned char buffer[TPM_TIS_BUFFER_MAX];
+ uint16_t rw_offset;
+
+ uint8_t active_locty;
+ uint8_t aborting_locty;
+ uint8_t next_locty;
+
+ TPMLocality loc[TPM_TIS_NUM_LOCALITIES];
+
+ qemu_irq irq;
+ uint32_t irq_num;
+
+ TPMBackendCmd cmd;
+
+ TPMBackend *be_driver;
+ TPMVersion be_tpm_version;
+
+ size_t be_buffer_size;
+
+ bool ppi_enabled;
+ TPMPPI ppi;
+} TPMState;
+
+extern const VMStateDescription vmstate_locty;
+extern const MemoryRegionOps tpm_tis_memory_ops;
+
+int tpm_tis_pre_save(TPMState *s);
+void tpm_tis_reset(TPMState *s);
+enum TPMVersion tpm_tis_get_tpm_version(TPMState *s);
+void tpm_tis_request_completed(TPMState *s, int ret);
+
+#endif /* TPM_TPM_TIS_H */
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis_common.c
index 31facb896d..9ce64d4836 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis_common.c
@@ -1,5 +1,6 @@
/*
- * tpm_tis.c - QEMU's TPM TIS interface emulator
+ * tpm_tis_common.c - QEMU's TPM TIS interface emulator
+ * device agnostic functions
*
* Copyright (C) 2006,2010-2013 IBM Corporation
*
@@ -21,7 +22,6 @@
* TPM TIS for TPM 2 implementation following TCG PC Client Platform
* TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
*/
-
#include "qemu/osdep.h"
#include "hw/irq.h"
#include "hw/isa/isa.h"
@@ -38,60 +38,7 @@
#include "tpm_ppi.h"
#include "trace.h"
-#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
-#define TPM_TIS_LOCALITY_SHIFT 12
-#define TPM_TIS_NO_LOCALITY 0xff
-
-#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES)
-
-#define TPM_TIS_BUFFER_MAX 4096
-
-typedef enum {
- TPM_TIS_STATE_IDLE = 0,
- TPM_TIS_STATE_READY,
- TPM_TIS_STATE_COMPLETION,
- TPM_TIS_STATE_EXECUTION,
- TPM_TIS_STATE_RECEPTION,
-} TPMTISState;
-
-/* locality data -- all fields are persisted */
-typedef struct TPMLocality {
- TPMTISState state;
- uint8_t access;
- uint32_t sts;
- uint32_t iface_id;
- uint32_t inte;
- uint32_t ints;
-} TPMLocality;
-
-typedef struct TPMState {
- ISADevice busdev;
- MemoryRegion mmio;
-
- unsigned char buffer[TPM_TIS_BUFFER_MAX];
- uint16_t rw_offset;
-
- uint8_t active_locty;
- uint8_t aborting_locty;
- uint8_t next_locty;
-
- TPMLocality loc[TPM_TIS_NUM_LOCALITIES];
-
- qemu_irq irq;
- uint32_t irq_num;
-
- TPMBackendCmd cmd;
-
- TPMBackend *be_driver;
- TPMVersion be_tpm_version;
-
- size_t be_buffer_size;
-
- bool ppi_enabled;
- TPMPPI ppi;
-} TPMState;
-
-#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
+#include "tpm_tis.h"
#define DEBUG_TIS 0
@@ -281,9 +228,8 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
/*
* Callback from the TPM to indicate that the response was received.
*/
-static void tpm_tis_request_completed(TPMIf *ti, int ret)
+void tpm_tis_request_completed(TPMState *s, int ret)
{
- TPMState *s = TPM(ti);
uint8_t locty = s->cmd.locty;
uint8_t l;
@@ -338,7 +284,7 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
}
#ifdef DEBUG_TIS
-static void tpm_tis_dump_state(void *opaque, hwaddr addr)
+static void tpm_tis_dump_state(TPMState *s, hwaddr addr)
{
static const unsigned regs[] = {
TPM_TIS_REG_ACCESS,
@@ -353,7 +299,6 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr)
int idx;
uint8_t locty = tpm_tis_locality_from_addr(addr);
hwaddr base = addr & ~0xfff;
- TPMState *s = opaque;
printf("tpm_tis: active locality : %d\n"
"tpm_tis: state of locality %d : %d\n"
@@ -363,7 +308,7 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr)
for (idx = 0; regs[idx] != 0xfff; idx++) {
printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
- (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
+ (int)tpm_tis_mmio_read(s, base + regs[idx], 4));
}
printf("tpm_tis: r/w offset : %d\n"
@@ -488,7 +433,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
break;
#ifdef DEBUG_TIS
case TPM_TIS_REG_DEBUG:
- tpm_tis_dump_state(opaque, addr);
+ tpm_tis_dump_state(s, addr);
break;
#endif
}
@@ -822,7 +767,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
}
}
-static const MemoryRegionOps tpm_tis_memory_ops = {
+const MemoryRegionOps tpm_tis_memory_ops = {
.read = tpm_tis_mmio_read,
.write = tpm_tis_mmio_write,
.endianness = DEVICE_LITTLE_ENDIAN,
@@ -835,10 +780,8 @@ static const MemoryRegionOps tpm_tis_memory_ops = {
/*
* Get the TPMVersion of the backend device being used
*/
-static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti)
+enum TPMVersion tpm_tis_get_tpm_version(TPMState *s)
{
- TPMState *s = TPM(ti);
-
if (tpm_backend_had_startup_error(s->be_driver)) {
return TPM_VERSION_UNSPEC;
}
@@ -850,9 +793,8 @@ static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti)
* This function is called when the machine starts, resets or due to
* S3 resume.
*/
-static void tpm_tis_reset(DeviceState *dev)
+void tpm_tis_reset(TPMState *s)
{
- TPMState *s = TPM(dev);
int c;
s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
@@ -896,15 +838,14 @@ static void tpm_tis_reset(DeviceState *dev)
/* persistent state handling */
-static int tpm_tis_pre_save(void *opaque)
+int tpm_tis_pre_save(TPMState *s)
{
- TPMState *s = opaque;
uint8_t locty = s->active_locty;
trace_tpm_tis_pre_save(locty, s->rw_offset);
if (DEBUG_TIS) {
- tpm_tis_dump_state(opaque, 0);
+ tpm_tis_dump_state(s, 0);
}
/*
@@ -915,7 +856,7 @@ static int tpm_tis_pre_save(void *opaque)
return 0;
}
-static const VMStateDescription vmstate_locty = {
+const VMStateDescription vmstate_locty = {
.name = "tpm-tis/locty",
.version_id = 0,
.fields = (VMStateField[]) {
@@ -929,99 +870,3 @@ static const VMStateDescription vmstate_locty = {
}
};
-static const VMStateDescription vmstate_tpm_tis = {
- .name = "tpm-tis",
- .version_id = 0,
- .pre_save = tpm_tis_pre_save,
- .fields = (VMStateField[]) {
- VMSTATE_BUFFER(buffer, TPMState),
- VMSTATE_UINT16(rw_offset, TPMState),
- VMSTATE_UINT8(active_locty, TPMState),
- VMSTATE_UINT8(aborting_locty, TPMState),
- VMSTATE_UINT8(next_locty, TPMState),
-
- VMSTATE_STRUCT_ARRAY(loc, TPMState, TPM_TIS_NUM_LOCALITIES, 0,
- vmstate_locty, TPMLocality),
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property tpm_tis_properties[] = {
- DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
- DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
- DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
-{
- TPMState *s = TPM(dev);
-
- if (!tpm_find()) {
- error_setg(errp, "at most one TPM device is permitted");
- return;
- }
-
- if (!s->be_driver) {
- error_setg(errp, "'tpmdev' property is required");
- return;
- }
- if (s->irq_num > 15) {
- error_setg(errp, "IRQ %d is outside valid range of 0 to 15",
- s->irq_num);
- return;
- }
-
- isa_init_irq(&s->busdev, &s->irq, s->irq_num);
-
- memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
- TPM_TIS_ADDR_BASE, &s->mmio);
-
- if (s->ppi_enabled) {
- tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)),
- TPM_PPI_ADDR_BASE, OBJECT(s));
- }
-}
-
-static void tpm_tis_initfn(Object *obj)
-{
- TPMState *s = TPM(obj);
-
- memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
- s, "tpm-tis-mmio",
- TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
-}
-
-static void tpm_tis_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- TPMIfClass *tc = TPM_IF_CLASS(klass);
-
- dc->realize = tpm_tis_realizefn;
- device_class_set_props(dc, tpm_tis_properties);
- dc->reset = tpm_tis_reset;
- dc->vmsd = &vmstate_tpm_tis;
- tc->model = TPM_MODEL_TPM_TIS;
- tc->get_version = tpm_tis_get_tpm_version;
- tc->request_completed = tpm_tis_request_completed;
-}
-
-static const TypeInfo tpm_tis_info = {
- .name = TYPE_TPM_TIS,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(TPMState),
- .instance_init = tpm_tis_initfn,
- .class_init = tpm_tis_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_TPM_IF },
- { }
- }
-};
-
-static void tpm_tis_register(void)
-{
- type_register_static(&tpm_tis_info);
-}
-
-type_init(tpm_tis_register)
diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c
new file mode 100644
index 0000000000..30ba37079d
--- /dev/null
+++ b/hw/tpm/tpm_tis_isa.c
@@ -0,0 +1,170 @@
+/*
+ * tpm_tis_isa.c - QEMU's TPM TIS ISA Device
+ *
+ * Copyright (C) 2006,2010-2013 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ * David Safford <safford@us.ibm.com>
+ *
+ * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Implementation of the TIS interface according to specs found at
+ * http://www.trustedcomputinggroup.org. This implementation currently
+ * supports version 1.3, 21 March 2013
+ * In the developers menu choose the PC Client section then find the TIS
+ * specification.
+ *
+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform
+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
+ */
+
+#include "qemu/osdep.h"
+#include "hw/isa/isa.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "tpm_util.h"
+#include "tpm_tis.h"
+
+typedef struct TPMStateISA {
+ /*< private >*/
+ ISADevice parent_obj;
+
+ /*< public >*/
+ TPMState state; /* not a QOM object */
+} TPMStateISA;
+
+#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA)
+
+static int tpm_tis_pre_save_isa(void *opaque)
+{
+ TPMStateISA *isadev = opaque;
+
+ return tpm_tis_pre_save(&isadev->state);
+}
+
+static const VMStateDescription vmstate_tpm_tis_isa = {
+ .name = "tpm-tis",
+ .version_id = 0,
+ .pre_save = tpm_tis_pre_save_isa,
+ .fields = (VMStateField[]) {
+ VMSTATE_BUFFER(state.buffer, TPMStateISA),
+ VMSTATE_UINT16(state.rw_offset, TPMStateISA),
+ VMSTATE_UINT8(state.active_locty, TPMStateISA),
+ VMSTATE_UINT8(state.aborting_locty, TPMStateISA),
+ VMSTATE_UINT8(state.next_locty, TPMStateISA),
+
+ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0,
+ vmstate_locty, TPMLocality),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void tpm_tis_isa_request_completed(TPMIf *ti, int ret)
+{
+ TPMStateISA *isadev = TPM_TIS_ISA(ti);
+ TPMState *s = &isadev->state;
+
+ tpm_tis_request_completed(s, ret);
+}
+
+static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti)
+{
+ TPMStateISA *isadev = TPM_TIS_ISA(ti);
+ TPMState *s = &isadev->state;
+
+ return tpm_tis_get_tpm_version(s);
+}
+
+static void tpm_tis_isa_reset(DeviceState *dev)
+{
+ TPMStateISA *isadev = TPM_TIS_ISA(dev);
+ TPMState *s = &isadev->state;
+
+ return tpm_tis_reset(s);
+}
+
+static Property tpm_tis_isa_properties[] = {
+ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ),
+ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver),
+ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tpm_tis_isa_initfn(Object *obj)
+{
+ TPMStateISA *isadev = TPM_TIS_ISA(obj);
+ TPMState *s = &isadev->state;
+
+ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops,
+ s, "tpm-tis-mmio",
+ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
+}
+
+static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp)
+{
+ TPMStateISA *isadev = TPM_TIS_ISA(dev);
+ TPMState *s = &isadev->state;
+
+ if (!tpm_find()) {
+ error_setg(errp, "at most one TPM device is permitted");
+ return;
+ }
+
+ if (!s->be_driver) {
+ error_setg(errp, "'tpmdev' property is required");
+ return;
+ }
+ if (s->irq_num > 15) {
+ error_setg(errp, "IRQ %d is outside valid range of 0 to 15",
+ s->irq_num);
+ return;
+ }
+
+ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num);
+
+ memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
+ TPM_TIS_ADDR_BASE, &s->mmio);
+
+ if (s->ppi_enabled) {
+ tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)),
+ TPM_PPI_ADDR_BASE, OBJECT(dev));
+ }
+}
+
+static void tpm_tis_isa_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ TPMIfClass *tc = TPM_IF_CLASS(klass);
+
+ device_class_set_props(dc, tpm_tis_isa_properties);
+ dc->vmsd = &vmstate_tpm_tis_isa;
+ tc->model = TPM_MODEL_TPM_TIS;
+ dc->realize = tpm_tis_isa_realizefn;
+ dc->reset = tpm_tis_isa_reset;
+ tc->request_completed = tpm_tis_isa_request_completed;
+ tc->get_version = tpm_tis_isa_get_tpm_version;
+}
+
+static const TypeInfo tpm_tis_isa_info = {
+ .name = TYPE_TPM_TIS_ISA,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(TPMStateISA),
+ .instance_init = tpm_tis_isa_initfn,
+ .class_init = tpm_tis_isa_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_TPM_IF },
+ { }
+ }
+};
+
+static void tpm_tis_isa_register(void)
+{
+ type_register_static(&tpm_tis_isa_info);
+}
+
+type_init(tpm_tis_isa_register)
diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c
new file mode 100644
index 0000000000..18c02aed67
--- /dev/null
+++ b/hw/tpm/tpm_tis_sysbus.c
@@ -0,0 +1,159 @@
+/*
+ * tpm_tis_sysbus.c - QEMU's TPM TIS SYSBUS Device
+ *
+ * Copyright (C) 2006,2010-2013 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ * David Safford <safford@us.ibm.com>
+ *
+ * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Implementation of the TIS interface according to specs found at
+ * http://www.trustedcomputinggroup.org. This implementation currently
+ * supports version 1.3, 21 March 2013
+ * In the developers menu choose the PC Client section then find the TIS
+ * specification.
+ *
+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform
+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "tpm_util.h"
+#include "hw/sysbus.h"
+#include "tpm_tis.h"
+
+typedef struct TPMStateSysBus {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ TPMState state; /* not a QOM object */
+} TPMStateSysBus;
+
+#define TPM_TIS_SYSBUS(obj) OBJECT_CHECK(TPMStateSysBus, (obj), TYPE_TPM_TIS_SYSBUS)
+
+static int tpm_tis_pre_save_sysbus(void *opaque)
+{
+ TPMStateSysBus *sbdev = opaque;
+
+ return tpm_tis_pre_save(&sbdev->state);
+}
+
+static const VMStateDescription vmstate_tpm_tis_sysbus = {
+ .name = "tpm-tis",
+ .version_id = 0,
+ .pre_save = tpm_tis_pre_save_sysbus,
+ .fields = (VMStateField[]) {
+ VMSTATE_BUFFER(state.buffer, TPMStateSysBus),
+ VMSTATE_UINT16(state.rw_offset, TPMStateSysBus),
+ VMSTATE_UINT8(state.active_locty, TPMStateSysBus),
+ VMSTATE_UINT8(state.aborting_locty, TPMStateSysBus),
+ VMSTATE_UINT8(state.next_locty, TPMStateSysBus),
+
+ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateSysBus, TPM_TIS_NUM_LOCALITIES,
+ 0, vmstate_locty, TPMLocality),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void tpm_tis_sysbus_request_completed(TPMIf *ti, int ret)
+{
+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti);
+ TPMState *s = &sbdev->state;
+
+ tpm_tis_request_completed(s, ret);
+}
+
+static enum TPMVersion tpm_tis_sysbus_get_tpm_version(TPMIf *ti)
+{
+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti);
+ TPMState *s = &sbdev->state;
+
+ return tpm_tis_get_tpm_version(s);
+}
+
+static void tpm_tis_sysbus_reset(DeviceState *dev)
+{
+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev);
+ TPMState *s = &sbdev->state;
+
+ return tpm_tis_reset(s);
+}
+
+static Property tpm_tis_sysbus_properties[] = {
+ DEFINE_PROP_UINT32("irq", TPMStateSysBus, state.irq_num, TPM_TIS_IRQ),
+ DEFINE_PROP_TPMBE("tpmdev", TPMStateSysBus, state.be_driver),
+ DEFINE_PROP_BOOL("ppi", TPMStateSysBus, state.ppi_enabled, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tpm_tis_sysbus_initfn(Object *obj)
+{
+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(obj);
+ TPMState *s = &sbdev->state;
+
+ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops,
+ s, "tpm-tis-mmio",
+ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
+
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+}
+
+static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp)
+{
+ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev);
+ TPMState *s = &sbdev->state;
+
+ if (!tpm_find()) {
+ error_setg(errp, "at most one TPM device is permitted");
+ return;
+ }
+
+ if (!s->be_driver) {
+ error_setg(errp, "'tpmdev' property is required");
+ return;
+ }
+}
+
+static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ TPMIfClass *tc = TPM_IF_CLASS(klass);
+
+ device_class_set_props(dc, tpm_tis_sysbus_properties);
+ dc->vmsd = &vmstate_tpm_tis_sysbus;
+ tc->model = TPM_MODEL_TPM_TIS;
+ dc->realize = tpm_tis_sysbus_realizefn;
+ dc->user_creatable = true;
+ dc->reset = tpm_tis_sysbus_reset;
+ tc->request_completed = tpm_tis_sysbus_request_completed;
+ tc->get_version = tpm_tis_sysbus_get_tpm_version;
+}
+
+static const TypeInfo tpm_tis_sysbus_info = {
+ .name = TYPE_TPM_TIS_SYSBUS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TPMStateSysBus),
+ .instance_init = tpm_tis_sysbus_initfn,
+ .class_init = tpm_tis_sysbus_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_TPM_IF },
+ { }
+ }
+};
+
+static void tpm_tis_sysbus_register(void)
+{
+ type_register_static(&tpm_tis_sysbus_info);
+}
+
+type_init(tpm_tis_sysbus_register)
diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
index 15979a3647..f37851b1aa 100644
--- a/include/sysemu/tpm.h
+++ b/include/sysemu/tpm.h
@@ -43,12 +43,13 @@ typedef struct TPMIfClass {
enum TPMVersion (*get_version)(TPMIf *obj);
} TPMIfClass;
-#define TYPE_TPM_TIS "tpm-tis"
+#define TYPE_TPM_TIS_ISA "tpm-tis"
+#define TYPE_TPM_TIS_SYSBUS "tpm-tis-device"
#define TYPE_TPM_CRB "tpm-crb"
#define TYPE_TPM_SPAPR "tpm-spapr"
-#define TPM_IS_TIS(chr) \
- object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS)
+#define TPM_IS_TIS_ISA(chr) \
+ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_ISA)
#define TPM_IS_CRB(chr) \
object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB)
#define TPM_IS_SPAPR(chr) \
diff --git a/tests/qtest/Makefile.include b/tests/qtest/Makefile.include
index e769c1ad70..383b0ab217 100644
--- a/tests/qtest/Makefile.include
+++ b/tests/qtest/Makefile.include
@@ -54,8 +54,8 @@ check-qtest-i386-y += q35-test
check-qtest-i386-y += vmgenid-test
check-qtest-i386-$(CONFIG_TPM_CRB) += tpm-crb-swtpm-test
check-qtest-i386-$(CONFIG_TPM_CRB) += tpm-crb-test
-check-qtest-i386-$(CONFIG_TPM_TIS) += tpm-tis-swtpm-test
-check-qtest-i386-$(CONFIG_TPM_TIS) += tpm-tis-test
+check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tpm-tis-swtpm-test
+check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tpm-tis-test
check-qtest-i386-$(CONFIG_SLIRP) += test-netfilter
check-qtest-i386-$(CONFIG_POSIX) += test-filter-mirror
check-qtest-i386-$(CONFIG_RTL8139_PCI) += test-filter-redirector
@@ -130,6 +130,8 @@ check-qtest-arm-y += hexloader-test
check-qtest-arm-$(CONFIG_PFLASH_CFI02) += pflash-cfi02-test
check-qtest-aarch64-y += arm-cpu-features
+check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-test
+check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-swtpm-test
check-qtest-aarch64-y += numa-test
check-qtest-aarch64-y += boot-serial-test
check-qtest-aarch64-y += migration-test
@@ -302,7 +304,10 @@ tests/qtest/tpm-crb-swtpm-test$(EXESUF): tests/qtest/tpm-crb-swtpm-test.o tests/
tests/qtest/tpm-crb-test$(EXESUF): tests/qtest/tpm-crb-test.o tests/qtest/tpm-emu.o $(test-io-obj-y)
tests/qtest/tpm-tis-swtpm-test$(EXESUF): tests/qtest/tpm-tis-swtpm-test.o tests/qtest/tpm-emu.o \
tests/qtest/tpm-util.o tests/qtest/tpm-tests.o $(test-io-obj-y)
-tests/qtest/tpm-tis-test$(EXESUF): tests/qtest/tpm-tis-test.o tests/qtest/tpm-emu.o $(test-io-obj-y)
+tests/qtest/tpm-tis-device-swtpm-test$(EXESUF): tests/qtest/tpm-tis-device-swtpm-test.o tests/qtest/tpm-emu.o \
+ tests/qtest/tpm-util.o tests/qtest/tpm-tests.o $(test-io-obj-y)
+tests/qtest/tpm-tis-test$(EXESUF): tests/qtest/tpm-tis-test.o tests/qtest/tpm-tis-util.o tests/qtest/tpm-emu.o $(test-io-obj-y)
+tests/qtest/tpm-tis-device-test$(EXESUF): tests/qtest/tpm-tis-device-test.o tests/qtest/tpm-tis-util.o tests/qtest/tpm-emu.o $(test-io-obj-y)
# QTest rules
diff --git a/tests/qtest/tpm-crb-swtpm-test.c b/tests/qtest/tpm-crb-swtpm-test.c
index 2c4fb8ae29..55fdb5657d 100644
--- a/tests/qtest/tpm-crb-swtpm-test.c
+++ b/tests/qtest/tpm-crb-swtpm-test.c
@@ -18,6 +18,10 @@
#include "libqtest.h"
#include "qemu/module.h"
#include "tpm-tests.h"
+#include "hw/acpi/tpm.h"
+
+/* Not used but needed for linking */
+uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE;
typedef struct TestState {
char *src_tpm_path;
@@ -29,7 +33,8 @@ static void tpm_crb_swtpm_test(const void *data)
{
const TestState *ts = data;
- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, "tpm-crb");
+ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer,
+ "tpm-crb", NULL);
}
static void tpm_crb_swtpm_migration_test(const void *data)
@@ -37,7 +42,7 @@ static void tpm_crb_swtpm_migration_test(const void *data)
const TestState *ts = data;
tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri,
- tpm_util_crb_transfer, "tpm-crb");
+ tpm_util_crb_transfer, "tpm-crb", NULL);
}
int main(int argc, char **argv)
diff --git a/tests/qtest/tpm-crb-test.c b/tests/qtest/tpm-crb-test.c
index 632fb7fbd8..ed533900d1 100644
--- a/tests/qtest/tpm-crb-test.c
+++ b/tests/qtest/tpm-crb-test.c
@@ -19,6 +19,9 @@
#include "qemu/module.h"
#include "tpm-emu.h"
+/* Not used but needed for linking */
+uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE;
+
#define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"
static void tpm_crb_test(const void *data)
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
index 6e45a0ba85..a2f2838e15 100644
--- a/tests/qtest/tpm-tests.c
+++ b/tests/qtest/tpm-tests.c
@@ -30,7 +30,7 @@ tpm_test_swtpm_skip(void)
}
void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
- const char *ifmodel)
+ const char *ifmodel, const char *machine_options)
{
char *args = NULL;
QTestState *s;
@@ -47,10 +47,11 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
g_assert_true(succ);
args = g_strdup_printf(
+ "%s "
"-chardev socket,id=chr,path=%s "
"-tpmdev emulator,id=dev,chardev=chr "
"-device %s,tpmdev=dev",
- addr->u.q_unix.path, ifmodel);
+ machine_options ? : "", addr->u.q_unix.path, ifmodel);
s = qtest_start(args);
g_free(args);
@@ -78,7 +79,8 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
void tpm_test_swtpm_migration_test(const char *src_tpm_path,
const char *dst_tpm_path,
const char *uri, tx_func *tx,
- const char *ifmodel)
+ const char *ifmodel,
+ const char *machine_options)
{
gboolean succ;
GPid src_tpm_pid, dst_tpm_pid;
@@ -100,7 +102,7 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
tpm_util_migration_start_qemu(&src_qemu, &dst_qemu,
src_tpm_addr, dst_tpm_addr, uri,
- ifmodel);
+ ifmodel, machine_options);
tpm_util_startup(src_qemu, tx);
tpm_util_pcrextend(src_qemu, tx);
diff --git a/tests/qtest/tpm-tests.h b/tests/qtest/tpm-tests.h
index b97688fe75..a5df35ab5b 100644
--- a/tests/qtest/tpm-tests.h
+++ b/tests/qtest/tpm-tests.h
@@ -16,11 +16,12 @@
#include "tpm-util.h"
void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
- const char *ifmodel);
+ const char *ifmodel, const char *machine_options);
void tpm_test_swtpm_migration_test(const char *src_tpm_path,
const char *dst_tpm_path,
const char *uri, tx_func *tx,
- const char *ifmodel);
+ const char *ifmodel,
+ const char *machine_options);
#endif /* TESTS_TPM_TESTS_H */
diff --git a/tests/qtest/tpm-tis-device-swtpm-test.c b/tests/qtest/tpm-tis-device-swtpm-test.c
new file mode 100644
index 0000000000..7b20035142
--- /dev/null
+++ b/tests/qtest/tpm-tis-device-swtpm-test.c
@@ -0,0 +1,76 @@
+/*
+ * QTest testcase for Sysbus TPM TIS talking to external swtpm and swtpm
+ * migration
+ *
+ * Copyright (c) 2018 IBM Corporation
+ * with parts borrowed from migration-test.c that is:
+ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include <glib/gstdio.h>
+
+#include "libqtest.h"
+#include "qemu/module.h"
+#include "tpm-tests.h"
+#include "hw/acpi/tpm.h"
+
+uint64_t tpm_tis_base_addr = 0xc000000;
+#define MACHINE_OPTIONS "-machine virt,gic-version=max -accel tcg"
+
+typedef struct TestState {
+ char *src_tpm_path;
+ char *dst_tpm_path;
+ char *uri;
+} TestState;
+
+static void tpm_tis_swtpm_test(const void *data)
+{
+ const TestState *ts = data;
+
+ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer,
+ "tpm-tis-device", MACHINE_OPTIONS);
+}
+
+static void tpm_tis_swtpm_migration_test(const void *data)
+{
+ const TestState *ts = data;
+
+ tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri,
+ tpm_util_tis_transfer, "tpm-tis-device",
+ MACHINE_OPTIONS);
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ TestState ts = { 0 };
+
+ ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX",
+ NULL);
+ ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX",
+ NULL);
+ ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
+
+ module_call_init(MODULE_INIT_QOM);
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test);
+ qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts,
+ tpm_tis_swtpm_migration_test);
+ ret = g_test_run();
+
+ g_rmdir(ts.dst_tpm_path);
+ g_free(ts.dst_tpm_path);
+ g_rmdir(ts.src_tpm_path);
+ g_free(ts.src_tpm_path);
+ g_free(ts.uri);
+
+ return ret;
+}
diff --git a/tests/qtest/tpm-tis-device-test.c b/tests/qtest/tpm-tis-device-test.c
new file mode 100644
index 0000000000..63ed36440f
--- /dev/null
+++ b/tests/qtest/tpm-tis-device-test.c
@@ -0,0 +1,87 @@
+/*
+ * QTest testcase for SYSBUS TPM TIS
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ * Copyright (c) 2018 IBM Corporation
+ *
+ * Authors:
+ * Marc-André Lureau <marcandre.lureau@redhat.com>
+ * Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include <glib/gstdio.h>
+
+#include "io/channel-socket.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "tpm-emu.h"
+#include "tpm-util.h"
+#include "tpm-tis-util.h"
+
+/*
+ * As the Sysbus tpm-tis-device is instantiated on the ARM virt
+ * platform bus and it is the only sysbus device dynamically
+ * instantiated, it gets plugged at its base address
+ */
+uint64_t tpm_tis_base_addr = 0xc000000;
+
+int main(int argc, char **argv)
+{
+ char *tmp_path = g_dir_make_tmp("qemu-tpm-tis-device-test.XXXXXX", NULL);
+ GThread *thread;
+ TestState test;
+ char *args;
+ int ret;
+
+ module_call_init(MODULE_INIT_QOM);
+ g_test_init(&argc, &argv, NULL);
+
+ test.addr = g_new0(SocketAddress, 1);
+ test.addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+ test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL);
+ g_mutex_init(&test.data_mutex);
+ g_cond_init(&test.data_cond);
+ test.data_cond_signal = false;
+
+ thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test);
+ tpm_emu_test_wait_cond(&test);
+
+ args = g_strdup_printf(
+ "-machine virt,gic-version=max -accel tcg "
+ "-chardev socket,id=chr,path=%s "
+ "-tpmdev emulator,id=dev,chardev=chr "
+ "-device tpm-tis-device,tpmdev=dev",
+ test.addr->u.q_unix.path);
+ qtest_start(args);
+
+ qtest_add_data_func("/tpm-tis/test_check_localities", &test,
+ tpm_tis_test_check_localities);
+
+ qtest_add_data_func("/tpm-tis/test_check_access_reg", &test,
+ tpm_tis_test_check_access_reg);
+
+ qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test,
+ tpm_tis_test_check_access_reg_seize);
+
+ qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test,
+ tpm_tis_test_check_access_reg_release);
+
+ qtest_add_data_func("/tpm-tis/test_check_transmit", &test,
+ tpm_tis_test_check_transmit);
+
+ ret = g_test_run();
+
+ qtest_end();
+
+ g_thread_join(thread);
+ g_unlink(test.addr->u.q_unix.path);
+ qapi_free_SocketAddress(test.addr);
+ g_rmdir(tmp_path);
+ g_free(tmp_path);
+ g_free(args);
+ return ret;
+}
diff --git a/tests/qtest/tpm-tis-swtpm-test.c b/tests/qtest/tpm-tis-swtpm-test.c
index 9f58a3a92b..90131cb3c4 100644
--- a/tests/qtest/tpm-tis-swtpm-test.c
+++ b/tests/qtest/tpm-tis-swtpm-test.c
@@ -18,6 +18,9 @@
#include "libqtest.h"
#include "qemu/module.h"
#include "tpm-tests.h"
+#include "hw/acpi/tpm.h"
+
+uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE;
typedef struct TestState {
char *src_tpm_path;
@@ -29,7 +32,8 @@ static void tpm_tis_swtpm_test(const void *data)
{
const TestState *ts = data;
- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, "tpm-tis");
+ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer,
+ "tpm-tis", NULL);
}
static void tpm_tis_swtpm_migration_test(const void *data)
@@ -37,7 +41,7 @@ static void tpm_tis_swtpm_migration_test(const void *data)
const TestState *ts = data;
tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri,
- tpm_util_tis_transfer, "tpm-tis");
+ tpm_util_tis_transfer, "tpm-tis", NULL);
}
int main(int argc, char **argv)
diff --git a/tests/qtest/tpm-tis-test.c b/tests/qtest/tpm-tis-test.c
index dcf30e05b7..79ffbc943e 100644
--- a/tests/qtest/tpm-tis-test.c
+++ b/tests/qtest/tpm-tis-test.c
@@ -1,5 +1,5 @@
/*
- * QTest testcase for TPM TIS
+ * QTest testcase for ISA TPM TIS
*
* Copyright (c) 2018 Red Hat, Inc.
* Copyright (c) 2018 IBM Corporation
@@ -20,417 +20,9 @@
#include "libqtest-single.h"
#include "qemu/module.h"
#include "tpm-emu.h"
+#include "tpm-tis-util.h"
-#define TIS_REG(LOCTY, REG) \
- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
-
-#define DEBUG_TIS_TEST 0
-
-#define DPRINTF(fmt, ...) do { \
- if (DEBUG_TIS_TEST) { \
- printf(fmt, ## __VA_ARGS__); \
- } \
-} while (0)
-
-#define DPRINTF_ACCESS \
- DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \
- __func__, __LINE__, locty, l, access, pending_request_flag)
-
-#define DPRINTF_STS \
- DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts)
-
-static const uint8_t TPM_CMD[12] =
- "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
-
-static void tpm_tis_test_check_localities(const void *data)
-{
- uint8_t locty;
- uint8_t access;
- uint32_t ifaceid;
- uint32_t capability;
- uint32_t didvid;
- uint32_t rid;
-
- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) {
- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY));
- g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0);
-
- ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID));
- g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0);
-
- didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID));
- g_assert_cmpint(didvid, !=, 0);
- g_assert_cmpint(didvid, !=, 0xffffffff);
-
- rid = readl(TIS_REG(locty, TPM_TIS_REG_RID));
- g_assert_cmpint(rid, !=, 0);
- g_assert_cmpint(rid, !=, 0xffffffff);
- }
-}
-
-static void tpm_tis_test_check_access_reg(const void *data)
-{
- uint8_t locty;
- uint8_t access;
-
- /* do not test locality 4 (hw only) */
- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* request use of locality */
- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* release access */
- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
- TPM_TIS_ACCESS_ACTIVE_LOCALITY);
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
- }
-}
-
-/*
- * Test case for seizing access by a higher number locality
- */
-static void tpm_tis_test_check_access_reg_seize(const void *data)
-{
- int locty, l;
- uint8_t access;
- uint8_t pending_request_flag;
-
- /* do not test locality 4 (hw only) */
- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
- pending_request_flag = 0;
-
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* request use of locality */
- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* lower localities cannot seize access */
- for (l = 0; l < locty; l++) {
- /* lower locality is not active */
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* try to request use from 'l' */
- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-
- /* requesting use from 'l' was not possible;
- we must see REQUEST_USE and possibly PENDING_REQUEST */
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_REQUEST_USE |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* locality 'locty' must be unchanged;
- we must see PENDING_REQUEST */
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- TPM_TIS_ACCESS_PENDING_REQUEST |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* try to seize from 'l' */
- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
- /* seize from 'l' was not possible */
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_REQUEST_USE |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* locality 'locty' must be unchanged */
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- TPM_TIS_ACCESS_PENDING_REQUEST |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* on the next loop we will have a PENDING_REQUEST flag
- set for locality 'l' */
- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
- }
-
- /* higher localities can 'seize' access but not 'request use';
- note: this will activate first l+1, then l+2 etc. */
- for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
- /* try to 'request use' from 'l' */
- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
-
- /* requesting use from 'l' was not possible; we should see
- REQUEST_USE and may see PENDING_REQUEST */
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_REQUEST_USE |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* locality 'l-1' must be unchanged; we should always
- see PENDING_REQUEST from 'l' requesting access */
- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- TPM_TIS_ACCESS_PENDING_REQUEST |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* try to seize from 'l' */
- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
-
- /* seize from 'l' was possible */
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* l - 1 should show that it has BEEN_SEIZED */
- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_BEEN_SEIZED |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* clear the BEEN_SEIZED flag and make sure it's gone */
- writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS),
- TPM_TIS_ACCESS_BEEN_SEIZED);
-
- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
- }
-
- /* PENDING_REQUEST will not be set if locty = 0 since all localities
- were active; in case of locty = 1, locality 0 will be active
- but no PENDING_REQUEST anywhere */
- if (locty <= 1) {
- pending_request_flag = 0;
- }
-
- /* release access from l - 1; this activates locty - 1 */
- l--;
-
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
-
- DPRINTF("%s: %d: relinquishing control on l = %d\n",
- __func__, __LINE__, l);
- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
- TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- for (l = locty - 1; l >= 0; l--) {
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* release this locality */
- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
- TPM_TIS_ACCESS_ACTIVE_LOCALITY);
-
- if (l == 1) {
- pending_request_flag = 0;
- }
- }
-
- /* no locality may be active now */
- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
- }
- }
-}
-
-/*
- * Test case for getting access when higher number locality relinquishes access
- */
-static void tpm_tis_test_check_access_reg_release(const void *data)
-{
- int locty, l;
- uint8_t access;
- uint8_t pending_request_flag;
-
- /* do not test locality 4 (hw only) */
- for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) {
- pending_request_flag = 0;
-
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* request use of locality */
- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- /* request use of all other localities */
- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
- if (l == locty) {
- continue;
- }
- /* request use of locality 'l' -- we MUST see REQUEST USE and
- may see PENDING_REQUEST */
- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_REQUEST_USE |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
- }
- /* release locality 'locty' */
- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
- TPM_TIS_ACCESS_ACTIVE_LOCALITY);
- /* highest locality should now be active; release it and make sure the
- next higest locality is active afterwards */
- for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) {
- if (l == locty) {
- continue;
- }
- /* 'l' should be active now */
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
- /* 'l' relinquishes access */
- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
- TPM_TIS_ACCESS_ACTIVE_LOCALITY);
- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
- DPRINTF_ACCESS;
- if (l == 1 || (locty <= 1 && l == 2)) {
- pending_request_flag = 0;
- }
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- pending_request_flag |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
- }
- }
-}
-
-/*
- * Test case for transmitting packets
- */
-static void tpm_tis_test_check_transmit(const void *data)
-{
- const TestState *s = data;
- uint8_t access;
- uint32_t sts;
- uint16_t bcount;
- size_t i;
-
- /* request use of locality 0 */
- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
- TPM_TIS_ACCESS_ACTIVE_LOCALITY |
- TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
-
- sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
- DPRINTF_STS;
-
- g_assert_cmpint(sts & 0xff, ==, 0);
- g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==,
- TPM_TIS_STS_TPM_FAMILY2_0);
-
- bcount = (sts >> 8) & 0xffff;
- g_assert_cmpint(bcount, >=, 128);
-
- writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
- sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
- DPRINTF_STS;
- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY);
-
- /* transmit command */
- for (i = 0; i < sizeof(TPM_CMD); i++) {
- writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]);
- sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
- DPRINTF_STS;
- if (i < sizeof(TPM_CMD) - 1) {
- g_assert_cmpint(sts & 0xff, ==,
- TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
- } else {
- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID);
- }
- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
- }
- /* start processing */
- writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
-
- uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
- do {
- sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
- if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
- break;
- }
- } while (g_get_monotonic_time() < end_time);
-
- sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
- DPRINTF_STS;
- g_assert_cmpint(sts & 0xff, == ,
- TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
- bcount = (sts >> 8) & 0xffff;
-
- /* read response */
- uint8_t tpm_msg[sizeof(struct tpm_hdr)];
- g_assert_cmpint(sizeof(tpm_msg), ==, bcount);
-
- for (i = 0; i < sizeof(tpm_msg); i++) {
- tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
- sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
- DPRINTF_STS;
- if (sts & TPM_TIS_STS_DATA_AVAILABLE) {
- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
- }
- }
- g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg));
-
- /* relinquish use of locality 0 */
- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY);
- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
-}
+uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE;
int main(int argc, char **argv)
{
diff --git a/tests/qtest/tpm-tis-util.c b/tests/qtest/tpm-tis-util.c
new file mode 100644
index 0000000000..9aff503fd8
--- /dev/null
+++ b/tests/qtest/tpm-tis-util.c
@@ -0,0 +1,451 @@
+/*
+ * QTest testcase for TPM TIS: common test functions used for both
+ * the ISA and SYSBUS devices
+ *
+ * Copyright (c) 2018 Red Hat, Inc.
+ * Copyright (c) 2018 IBM Corporation
+ *
+ * Authors:
+ * Marc-André Lureau <marcandre.lureau@redhat.com>
+ * Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include <glib/gstdio.h>
+
+#include "hw/acpi/tpm.h"
+#include "io/channel-socket.h"
+#include "libqtest-single.h"
+#include "qemu/module.h"
+#include "tpm-emu.h"
+#include "tpm-util.h"
+#include "tpm-tis-util.h"
+
+#define DEBUG_TIS_TEST 0
+
+#define DPRINTF(fmt, ...) do { \
+ if (DEBUG_TIS_TEST) { \
+ printf(fmt, ## __VA_ARGS__); \
+ } \
+} while (0)
+
+#define DPRINTF_ACCESS \
+ DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \
+ __func__, __LINE__, locty, l, access, pending_request_flag)
+
+#define DPRINTF_STS \
+ DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts)
+
+static const uint8_t TPM_CMD[12] =
+ "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
+
+void tpm_tis_test_check_localities(const void *data)
+{
+ uint8_t locty;
+ uint8_t access;
+ uint32_t ifaceid;
+ uint32_t capability;
+ uint32_t didvid;
+ uint32_t rid;
+
+ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) {
+ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY));
+ g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0);
+
+ ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID));
+ g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0);
+
+ didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID));
+ g_assert_cmpint(didvid, !=, 0);
+ g_assert_cmpint(didvid, !=, 0xffffffff);
+
+ rid = readl(TIS_REG(locty, TPM_TIS_REG_RID));
+ g_assert_cmpint(rid, !=, 0);
+ g_assert_cmpint(rid, !=, 0xffffffff);
+ }
+}
+
+void tpm_tis_test_check_access_reg(const void *data)
+{
+ uint8_t locty;
+ uint8_t access;
+
+ /* do not test locality 4 (hw only) */
+ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* request use of locality */
+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* release access */
+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+ }
+}
+
+/*
+ * Test case for seizing access by a higher number locality
+ */
+void tpm_tis_test_check_access_reg_seize(const void *data)
+{
+ int locty, l;
+ uint8_t access;
+ uint8_t pending_request_flag;
+
+ /* do not test locality 4 (hw only) */
+ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
+ pending_request_flag = 0;
+
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* request use of locality */
+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* lower localities cannot seize access */
+ for (l = 0; l < locty; l++) {
+ /* lower locality is not active */
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* try to request use from 'l' */
+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+
+ /*
+ * requesting use from 'l' was not possible;
+ * we must see REQUEST_USE and possibly PENDING_REQUEST
+ */
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_REQUEST_USE |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /*
+ * locality 'locty' must be unchanged;
+ * we must see PENDING_REQUEST
+ */
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ TPM_TIS_ACCESS_PENDING_REQUEST |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* try to seize from 'l' */
+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
+ /* seize from 'l' was not possible */
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_REQUEST_USE |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* locality 'locty' must be unchanged */
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ TPM_TIS_ACCESS_PENDING_REQUEST |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /*
+ * on the next loop we will have a PENDING_REQUEST flag
+ * set for locality 'l'
+ */
+ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
+ }
+
+ /*
+ * higher localities can 'seize' access but not 'request use';
+ * note: this will activate first l+1, then l+2 etc.
+ */
+ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
+ /* try to 'request use' from 'l' */
+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+
+ /*
+ * requesting use from 'l' was not possible; we should see
+ * REQUEST_USE and may see PENDING_REQUEST
+ */
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_REQUEST_USE |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /*
+ * locality 'l-1' must be unchanged; we should always
+ * see PENDING_REQUEST from 'l' requesting access
+ */
+ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ TPM_TIS_ACCESS_PENDING_REQUEST |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* try to seize from 'l' */
+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE);
+
+ /* seize from 'l' was possible */
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* l - 1 should show that it has BEEN_SEIZED */
+ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_BEEN_SEIZED |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* clear the BEEN_SEIZED flag and make sure it's gone */
+ writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS),
+ TPM_TIS_ACCESS_BEEN_SEIZED);
+
+ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+ }
+
+ /*
+ * PENDING_REQUEST will not be set if locty = 0 since all localities
+ * were active; in case of locty = 1, locality 0 will be active
+ * but no PENDING_REQUEST anywhere
+ */
+ if (locty <= 1) {
+ pending_request_flag = 0;
+ }
+
+ /* release access from l - 1; this activates locty - 1 */
+ l--;
+
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+
+ DPRINTF("%s: %d: relinquishing control on l = %d\n",
+ __func__, __LINE__, l);
+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ for (l = locty - 1; l >= 0; l--) {
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* release this locality */
+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+
+ if (l == 1) {
+ pending_request_flag = 0;
+ }
+ }
+
+ /* no locality may be active now */
+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+ }
+ }
+}
+
+/*
+ * Test case for getting access when higher number locality relinquishes access
+ */
+void tpm_tis_test_check_access_reg_release(const void *data)
+{
+ int locty, l;
+ uint8_t access;
+ uint8_t pending_request_flag;
+
+ /* do not test locality 4 (hw only) */
+ for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) {
+ pending_request_flag = 0;
+
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* request use of locality */
+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ /* request use of all other localities */
+ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
+ if (l == locty) {
+ continue;
+ }
+ /*
+ * request use of locality 'l' -- we MUST see REQUEST USE and
+ * may see PENDING_REQUEST
+ */
+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_REQUEST_USE |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
+ }
+ /* release locality 'locty' */
+ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS),
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+ /*
+ * highest locality should now be active; release it and make sure the
+ * next higest locality is active afterwards
+ */
+ for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) {
+ if (l == locty) {
+ continue;
+ }
+ /* 'l' should be active now */
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+ /* 'l' relinquishes access */
+ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS),
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS));
+ DPRINTF_ACCESS;
+ if (l == 1 || (locty <= 1 && l == 2)) {
+ pending_request_flag = 0;
+ }
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ pending_request_flag |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+ }
+ }
+}
+
+/*
+ * Test case for transmitting packets
+ */
+void tpm_tis_test_check_transmit(const void *data)
+{
+ const TestState *s = data;
+ uint8_t access;
+ uint32_t sts;
+ uint16_t bcount;
+ size_t i;
+
+ /* request use of locality 0 */
+ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
+ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
+ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
+ TPM_TIS_ACCESS_ACTIVE_LOCALITY |
+ TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
+
+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+ DPRINTF_STS;
+
+ g_assert_cmpint(sts & 0xff, ==, 0);
+ g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==,
+ TPM_TIS_STS_TPM_FAMILY2_0);
+
+ bcount = (sts >> 8) & 0xffff;
+ g_assert_cmpint(bcount, >=, 128);
+
+ writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+ DPRINTF_STS;
+ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY);
+
+ /* transmit command */
+ for (i = 0; i < sizeof(TPM_CMD); i++) {
+ writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]);
+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+ DPRINTF_STS;
+ if (i < sizeof(TPM_CMD) - 1) {
+ g_assert_cmpint(sts & 0xff, ==,
+ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
+ } else {
+ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID);
+ }
+ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
+ }
+ /* start processing */
+ writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO);
+
+ uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
+ do {
+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+ if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
+ break;
+ }
+ } while (g_get_monotonic_time() < end_time);
+
+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+ DPRINTF_STS;
+ g_assert_cmpint(sts & 0xff, == ,
+ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
+ bcount = (sts >> 8) & 0xffff;
+
+ /* read response */
+ uint8_t tpm_msg[sizeof(struct tpm_hdr)];
+ g_assert_cmpint(sizeof(tpm_msg), ==, bcount);
+
+ for (i = 0; i < sizeof(tpm_msg); i++) {
+ tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
+ sts = readl(TIS_REG(0, TPM_TIS_REG_STS));
+ DPRINTF_STS;
+ if (sts & TPM_TIS_STS_DATA_AVAILABLE) {
+ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
+ }
+ }
+ g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg));
+
+ /* relinquish use of locality 0 */
+ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY);
+ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS));
+}
diff --git a/tests/qtest/tpm-tis-util.h b/tests/qtest/tpm-tis-util.h
new file mode 100644
index 0000000000..d10efe86ae
--- /dev/null
+++ b/tests/qtest/tpm-tis-util.h
@@ -0,0 +1,23 @@
+/*
+ * QTest TPM TIS: Common test functions used for both the
+ * ISA and SYSBUS devices
+ *
+ * Copyright (c) 2018 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TESTS_TPM_TIS_UTIL_H
+#define TESTS_TPM_TIS_UTIL_H
+
+void tpm_tis_test_check_localities(const void *data);
+void tpm_tis_test_check_access_reg(const void *data);
+void tpm_tis_test_check_access_reg_seize(const void *data);
+void tpm_tis_test_check_access_reg_release(const void *data);
+void tpm_tis_test_check_transmit(const void *data);
+
+#endif /* TESTS_TPM_TIS_UTIL_H */
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index e08b137651..34efae8f18 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -19,9 +19,6 @@
#include "tpm-util.h"
#include "qapi/qmp/qdict.h"
-#define TIS_REG(LOCTY, REG) \
- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
-
void tpm_util_crb_transfer(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size)
@@ -258,23 +255,27 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu,
SocketAddress *src_tpm_addr,
SocketAddress *dst_tpm_addr,
const char *miguri,
- const char *ifmodel)
+ const char *ifmodel,
+ const char *machine_options)
{
char *src_qemu_args, *dst_qemu_args;
src_qemu_args = g_strdup_printf(
+ "%s "
"-chardev socket,id=chr,path=%s "
"-tpmdev emulator,id=dev,chardev=chr "
"-device %s,tpmdev=dev ",
- src_tpm_addr->u.q_unix.path, ifmodel);
+ machine_options ? : "", src_tpm_addr->u.q_unix.path, ifmodel);
*src_qemu = qtest_init(src_qemu_args);
dst_qemu_args = g_strdup_printf(
+ "%s "
"-chardev socket,id=chr,path=%s "
"-tpmdev emulator,id=dev,chardev=chr "
"-device %s,tpmdev=dev "
"-incoming %s",
+ machine_options ? : "",
dst_tpm_addr->u.q_unix.path,
ifmodel, miguri);
diff --git a/tests/qtest/tpm-util.h b/tests/qtest/tpm-util.h
index 5755698ad2..3b97d69017 100644
--- a/tests/qtest/tpm-util.h
+++ b/tests/qtest/tpm-util.h
@@ -15,6 +15,11 @@
#include "io/channel-socket.h"
+extern uint64_t tpm_tis_base_addr;
+
+#define TIS_REG(LOCTY, REG) \
+ (tpm_tis_base_addr + ((LOCTY) << 12) + REG)
+
typedef void (tx_func)(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size);
@@ -44,7 +49,8 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu,
SocketAddress *src_tpm_addr,
SocketAddress *dst_tpm_addr,
const char *miguri,
- const char *ifmodel);
+ const char *ifmodel,
+ const char *machine_options);
void tpm_util_wait_for_migration_complete(QTestState *who);