diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-03-05 19:39:47 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-03-05 19:39:47 +0000 |
commit | ef9f8fcbec6276414921dcd042575129a6331a2d (patch) | |
tree | e8544e26b655528037dccf0f767bc26ddbc6f26e /hw | |
parent | 55afdac3b29e672aad51e953412364127e54268b (diff) | |
parent | fe985ed6837ac6169ab9673547115df2897bcf6d (diff) | |
download | qemu-ef9f8fcbec6276414921dcd042575129a6331a2d.zip |
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>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/Kconfig | 1 | ||||
-rw-r--r-- | hw/arm/sysbus-fdt.c | 33 | ||||
-rw-r--r-- | hw/arm/virt.c | 7 | ||||
-rw-r--r-- | hw/i386/Kconfig | 2 | ||||
-rw-r--r-- | hw/i386/acpi-build.c | 6 | ||||
-rw-r--r-- | hw/tpm/Kconfig | 12 | ||||
-rw-r--r-- | hw/tpm/Makefile.objs | 4 | ||||
-rw-r--r-- | hw/tpm/tpm_tis.h | 91 | ||||
-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.c | 170 | ||||
-rw-r--r-- | hw/tpm/tpm_tis_sysbus.c | 159 |
11 files changed, 492 insertions, 174 deletions
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) |