mirror of
https://github.com/utmapp/qemu.git
synced 2026-05-26 13:51:06 +00:00
tpm_crb_sysbus: introduce TPM CRB SysBus device
This SysBus variant of the CRB interface supports dynamically locating the MMIO interface so that Virt machines can use it. This interface is currently the only one supported by QEMU that works on Windows 11 ARM64. We largely follow the TPM TIS SysBus device as a template. Signed-off-by: Joelle van Dyne <j@getutm.app>
This commit is contained in:
@@ -42,6 +42,7 @@ operating system.
|
||||
QEMU files related to TPM CRB interface:
|
||||
- ``hw/tpm/tpm_crb.c``
|
||||
- ``hw/tpm/tpm_crb_common.c``
|
||||
- ``hw/tpm/tpm_crb_sysbus.c``
|
||||
|
||||
SPAPR interface
|
||||
---------------
|
||||
|
||||
+6
-1
@@ -31,6 +31,7 @@
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/pci/pci_bridge.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
static GArray *build_alloc_array(void)
|
||||
{
|
||||
@@ -2218,7 +2219,7 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
|
||||
{
|
||||
uint8_t start_method_params[12] = {};
|
||||
unsigned log_addr_offset;
|
||||
uint64_t control_area_start_address;
|
||||
uint64_t baseaddr, control_area_start_address;
|
||||
TPMIf *tpmif = tpm_find();
|
||||
uint32_t start_method;
|
||||
AcpiTable table = { .sig = "TPM2", .rev = 4,
|
||||
@@ -2236,6 +2237,10 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
|
||||
} else if (TPM_IS_CRB(tpmif)) {
|
||||
control_area_start_address = TPM_CRB_ADDR_CTRL;
|
||||
start_method = TPM2_START_METHOD_CRB;
|
||||
} else if (TPM_IS_CRB_SYSBUS(tpmif)) {
|
||||
baseaddr = object_property_get_uint(OBJECT(tpmif), "baseaddr", NULL);
|
||||
control_area_start_address = baseaddr + A_CRB_CTRL_REQ;
|
||||
start_method = TPM2_START_METHOD_CRB;
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ config ARM_VIRT
|
||||
imply VFIO_AMD_XGBE
|
||||
imply VFIO_PLATFORM
|
||||
imply VFIO_XGMAC
|
||||
imply TPM_CRB_SYSBUS
|
||||
imply TPM_TIS_SYSBUS
|
||||
imply NVDIMM
|
||||
select ARM_GIC
|
||||
|
||||
@@ -3045,6 +3045,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM);
|
||||
#ifdef CONFIG_TPM
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_CRB_SYSBUS);
|
||||
#endif
|
||||
mc->block_default_type = IF_VIRTIO;
|
||||
mc->no_cdrom = 1;
|
||||
|
||||
@@ -493,6 +493,7 @@ static const BindingEntry bindings[] = {
|
||||
#endif
|
||||
#ifdef CONFIG_TPM
|
||||
TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
|
||||
TYPE_BINDING(TYPE_TPM_CRB_SYSBUS, no_fdt_node),
|
||||
#endif
|
||||
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
|
||||
TYPE_BINDING("", NULL), /* last element */
|
||||
|
||||
@@ -1083,6 +1083,7 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
|
||||
#ifdef CONFIG_TPM
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_CRB_SYSBUS);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ config RISCV_VIRT
|
||||
imply PCI_DEVICES
|
||||
imply VIRTIO_VGA
|
||||
imply TEST_DEVICES
|
||||
imply TPM_CRB_SYSBUS
|
||||
imply TPM_TIS_SYSBUS
|
||||
select RISCV_NUMA
|
||||
select GOLDFISH_RTC
|
||||
|
||||
@@ -1687,6 +1687,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
|
||||
#ifdef CONFIG_TPM
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_CRB_SYSBUS);
|
||||
#endif
|
||||
|
||||
object_class_property_add_bool(oc, "aclint", virt_get_aclint,
|
||||
|
||||
@@ -18,6 +18,11 @@ config TPM_CRB
|
||||
depends on TPM && ISA_BUS
|
||||
select TPM_BACKEND
|
||||
|
||||
config TPM_CRB_SYSBUS
|
||||
bool
|
||||
depends on TPM
|
||||
select TPM_BACKEND
|
||||
|
||||
config TPM_SPAPR
|
||||
bool
|
||||
default y
|
||||
|
||||
@@ -3,6 +3,8 @@ softmmu_ss.add(when: 'CONFIG_TPM_TIS_ISA', if_true: files('tpm_tis_isa.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_TPM_TIS_SYSBUS', if_true: files('tpm_tis_sysbus.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_crb.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_crb_common.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_TPM_CRB_SYSBUS', if_true: files('tpm_crb_sysbus.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_TPM_CRB_SYSBUS', if_true: files('tpm_crb_common.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_TPM_TIS', if_true: files('tpm_ppi.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_ppi.c'))
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ void tpm_crb_reset(TPMCRBState *s, uint64_t baseaddr)
|
||||
void tpm_crb_init_memory(Object *obj, TPMCRBState *s, Error **errp)
|
||||
{
|
||||
memory_region_init_rom_device(&s->mmio, obj, &tpm_crb_memory_ops, s,
|
||||
"tpm-crb-mmio", TPM_CRB_ADDR_SIZE, errp);
|
||||
"tpm-crb-mmio", ROUND_UP(TPM_CRB_ADDR_SIZE, qemu_host_page_size), errp);
|
||||
if (s->ppi_enabled) {
|
||||
tpm_ppi_init_memory(&s->ppi, obj);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* tpm_crb_sysbus.c - QEMU's TPM CRB interface emulator
|
||||
*
|
||||
* Copyright (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Marc-André Lureau <marcandre.lureau@redhat.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.
|
||||
*
|
||||
* tpm_crb is a device for TPM 2.0 Command Response Buffer (CRB) Interface
|
||||
* as defined in TCG PC Client Platform TPM Profile (PTP) Specification
|
||||
* Family “2.0” Level 00 Revision 01.03 v22
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/acpi/acpi_aml_interface.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "tpm_prop.h"
|
||||
#include "hw/pci/pci_ids.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qom/object.h"
|
||||
#include "sysemu/tpm_util.h"
|
||||
#include "trace.h"
|
||||
#include "tpm_crb.h"
|
||||
|
||||
struct TPMCRBStateSysBus {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
TPMCRBState state;
|
||||
uint64_t baseaddr;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(TPMCRBStateSysBus, TPM_CRB_SYSBUS)
|
||||
|
||||
static void tpm_crb_sysbus_request_completed(TPMIf *ti, int ret)
|
||||
{
|
||||
TPMCRBStateSysBus *s = TPM_CRB_SYSBUS(ti);
|
||||
|
||||
return tpm_crb_request_completed(&s->state, ret);
|
||||
}
|
||||
|
||||
static enum TPMVersion tpm_crb_sysbus_get_tpm_version(TPMIf *ti)
|
||||
{
|
||||
TPMCRBStateSysBus *s = TPM_CRB_SYSBUS(ti);
|
||||
|
||||
return tpm_crb_get_version(&s->state);
|
||||
}
|
||||
|
||||
static int tpm_crb_sysbus_pre_save(void *opaque)
|
||||
{
|
||||
TPMCRBStateSysBus *s = opaque;
|
||||
|
||||
return tpm_crb_pre_save(&s->state);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_tpm_crb_sysbus = {
|
||||
.name = "tpm-crb-sysbus",
|
||||
.pre_save = tpm_crb_sysbus_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static Property tpm_crb_sysbus_properties[] = {
|
||||
DEFINE_PROP_TPMBE("tpmdev", TPMCRBStateSysBus, state.tpmbe),
|
||||
DEFINE_PROP_BOOL("ppi", TPMCRBStateSysBus, state.ppi_enabled, false),
|
||||
DEFINE_PROP_UINT64("baseaddr", TPMCRBStateSysBus,
|
||||
baseaddr, TPM_CRB_ADDR_BASE),
|
||||
DEFINE_PROP_UINT64("size", TPMCRBStateSysBus, size, TPM_CRB_ADDR_SIZE),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void tpm_crb_sysbus_initfn(Object *obj)
|
||||
{
|
||||
TPMCRBStateSysBus *s = TPM_CRB_SYSBUS(obj);
|
||||
|
||||
tpm_crb_init_memory(obj, &s->state, NULL);
|
||||
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->state.mmio);
|
||||
}
|
||||
|
||||
static void tpm_crb_sysbus_reset(DeviceState *dev)
|
||||
{
|
||||
TPMCRBStateSysBus *s = TPM_CRB_SYSBUS(dev);
|
||||
|
||||
return tpm_crb_reset(&s->state, s->baseaddr);
|
||||
}
|
||||
|
||||
static void tpm_crb_sysbus_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
TPMCRBStateSysBus *s = TPM_CRB_SYSBUS(dev);
|
||||
|
||||
if (!tpm_find()) {
|
||||
error_setg(errp, "at most one TPM device is permitted");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->state.tpmbe) {
|
||||
error_setg(errp, "'tpmdev' property is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->state.ppi_enabled) {
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->state.ppi.ram);
|
||||
}
|
||||
}
|
||||
|
||||
static void build_tpm_crb_sysbus_aml(AcpiDevAmlIf *adev, Aml *scope)
|
||||
{
|
||||
Aml *dev, *crs;
|
||||
TPMCRBStateSysBus *s = TPM_CRB_SYSBUS(adev);
|
||||
TPMIf *ti = TPM_IF(s);
|
||||
|
||||
dev = aml_device("TPM");
|
||||
if (tpm_crb_sysbus_get_tpm_version(ti) == TPM_VERSION_2_0) {
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
|
||||
aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device")));
|
||||
} else {
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
|
||||
}
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(s->baseaddr, s->size,
|
||||
AML_READ_WRITE));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
/**
|
||||
* FIXME: PPI needs to also get a dynamic address.
|
||||
*/
|
||||
/* tpm_build_ppi_acpi(ti, dev); */
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
static void tpm_crb_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
TPMIfClass *tc = TPM_IF_CLASS(klass);
|
||||
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
|
||||
|
||||
device_class_set_props(dc, tpm_crb_sysbus_properties);
|
||||
dc->vmsd = &vmstate_tpm_crb_sysbus;
|
||||
tc->model = TPM_MODEL_TPM_CRB;
|
||||
dc->realize = tpm_crb_sysbus_realizefn;
|
||||
dc->user_creatable = true;
|
||||
dc->reset = tpm_crb_sysbus_reset;
|
||||
tc->request_completed = tpm_crb_sysbus_request_completed;
|
||||
tc->get_version = tpm_crb_sysbus_get_tpm_version;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
adevc->build_dev_aml = build_tpm_crb_sysbus_aml;
|
||||
}
|
||||
|
||||
static const TypeInfo tpm_crb_sysbus_info = {
|
||||
.name = TYPE_TPM_CRB_SYSBUS,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(TPMCRBStateSysBus),
|
||||
.instance_init = tpm_crb_sysbus_initfn,
|
||||
.class_init = tpm_crb_sysbus_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_TPM_IF },
|
||||
{ TYPE_ACPI_DEV_AML_IF },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void tpm_crb_sysbus_register(void)
|
||||
{
|
||||
type_register_static(&tpm_crb_sysbus_info);
|
||||
}
|
||||
|
||||
type_init(tpm_crb_sysbus_register)
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
#include "hw/acpi/bios-linker-loader.h"
|
||||
#include "exec/hwaddr.h"
|
||||
|
||||
#define ACPI_BUILD_APPNAME6 "BOCHS "
|
||||
#define ACPI_BUILD_APPNAME8 "BXPC "
|
||||
|
||||
@@ -47,6 +47,7 @@ struct TPMIfClass {
|
||||
#define TYPE_TPM_TIS_ISA "tpm-tis"
|
||||
#define TYPE_TPM_TIS_SYSBUS "tpm-tis-device"
|
||||
#define TYPE_TPM_CRB "tpm-crb"
|
||||
#define TYPE_TPM_CRB_SYSBUS "tpm-crb-device"
|
||||
#define TYPE_TPM_SPAPR "tpm-spapr"
|
||||
|
||||
#define TPM_IS_TIS_ISA(chr) \
|
||||
@@ -55,6 +56,8 @@ struct TPMIfClass {
|
||||
object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_SYSBUS)
|
||||
#define TPM_IS_CRB(chr) \
|
||||
object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB)
|
||||
#define TPM_IS_CRB_SYSBUS(chr) \
|
||||
object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB_SYSBUS)
|
||||
#define TPM_IS_SPAPR(chr) \
|
||||
object_dynamic_cast(OBJECT(chr), TYPE_TPM_SPAPR)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user