mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-24 03:59:52 +00:00
Merge tpm 2020/03/04 v2
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEuBi5yt+QicLVzsZrda1lgCoLQhEFAl5hNQEACgkQda1lgCoL QhH7Egf/esr+B1d6kfD8bfy3byplFu3fnNTJRino2c6ElaRLXKG6kl1ODb7oQZ0g 37aVL+UVtVyTIkuTKT6Xx4xNq4TbrXB6hcNqoB/J9DaTVVYCLLQWrHRRmA8VrtLM 6H7hdmi7zPEOm6BDtDJzUyDmWsuZEwGcsToUixfMlG+rCbc3bC4rGQwVg2/t5Y55 LvP8SF6NngmL099ZtZbHsvaVxprZZ5fxx7NzjX6tW19TBg0PqtIV2Ro0VnCliaIN L5xv5amlghIdBbkZKmc6hNERJ/U37lF3AxyY4dxCLn0waMN+DgYvfjr2ZSrB9PQ/ 8yts/x5pIThCffvE0DSir2kQz8yUNg== =MeFg -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanberger/tags/pull-tpm-2020-03-04-2' into staging Merge tpm 2020/03/04 v2 # gpg: Signature made Thu 05 Mar 2020 17:21:05 GMT # gpg: using RSA key B818B9CADF9089C2D5CEC66B75AD65802A0B4211 # gpg: Good signature from "Stefan Berger <stefanb@linux.vnet.ibm.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: B818 B9CA DF90 89C2 D5CE C66B 75AD 6580 2A0B 4211 * remotes/stefanberger/tags/pull-tpm-2020-03-04-2: test: tpm-tis: Add Sysbus TPM-TIS device test test: tpm-tis: Get prepared to share tests between ISA and sysbus devices test: tpm: pass optional machine options to swtpm test functions docs/specs/tpm: Document TPM_TIS sysbus device for ARM hw/arm/virt: vTPM support tpm: Add the SysBus TPM TIS device tpm: Separate TPM_TIS and TPM_TIS_ISA configs tpm: Separate tpm_tis common functions from isa code tpm: Use TPMState as a common struct tpm: rename TPM_TIS into TPM_TIS_ISA Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ef9f8fcbec
@ -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:
|
||||
|
@ -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'.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
};
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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())) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
91
hw/tpm/tpm_tis.h
Normal file
91
hw/tpm/tpm_tis.h
Normal file
@ -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 */
|
@ -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)
|
170
hw/tpm/tpm_tis_isa.c
Normal file
170
hw/tpm/tpm_tis_isa.c
Normal file
@ -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)
|
159
hw/tpm/tpm_tis_sysbus.c
Normal file
159
hw/tpm/tpm_tis_sysbus.c
Normal file
@ -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)
|
@ -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) \
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
76
tests/qtest/tpm-tis-device-swtpm-test.c
Normal file
76
tests/qtest/tpm-tis-device-swtpm-test.c
Normal file
@ -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;
|
||||
}
|
87
tests/qtest/tpm-tis-device-test.c
Normal file
87
tests/qtest/tpm-tis-device-test.c
Normal file
@ -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;
|
||||
}
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
451
tests/qtest/tpm-tis-util.c
Normal file
451
tests/qtest/tpm-tis-util.c
Normal file
@ -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));
|
||||
}
|
23
tests/qtest/tpm-tis-util.h
Normal file
23
tests/qtest/tpm-tis-util.h
Normal file
@ -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 */
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user