aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/pcie.txt16
-rw-r--r--hw/acpi/Kconfig4
-rw-r--r--hw/acpi/acpi-x86-stub.c5
-rw-r--r--hw/acpi/acpi_interface.c10
-rw-r--r--hw/acpi/cpu.c3
-rw-r--r--hw/acpi/meson.build4
-rw-r--r--hw/acpi/pci-bridge-stub.c20
-rw-r--r--hw/acpi/pci-bridge.c27
-rw-r--r--hw/acpi/pcihp.c35
-rw-r--r--hw/acpi/piix4.c5
-rw-r--r--hw/arm/smmu-common.c3
-rw-r--r--hw/core/machine.c1
-rw-r--r--hw/i2c/smbus_ich9.c5
-rw-r--r--hw/i386/Kconfig1
-rw-r--r--hw/i386/acpi-build.c281
-rw-r--r--hw/i386/acpi-common.c7
-rw-r--r--hw/i386/acpi-microvm.c3
-rw-r--r--hw/i386/microvm.c15
-rw-r--r--hw/i386/pc_q35.c5
-rw-r--r--hw/i386/x86.c52
-rw-r--r--hw/isa/isa-bus.c10
-rw-r--r--hw/isa/lpc_ich9.c5
-rw-r--r--hw/isa/piix3.c5
-rw-r--r--hw/nvram/fw_cfg.c9
-rw-r--r--hw/pci-bridge/gen_pcie_root_port.c7
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c1
-rw-r--r--hw/pci-host/grackle.c2
-rw-r--r--hw/pci-host/raven.c6
-rw-r--r--hw/pci-host/uninorth.c33
-rw-r--r--hw/pci/pci.c2
-rw-r--r--hw/pci/pci_bridge.c14
-rw-r--r--hw/pci/pcie.c6
-rw-r--r--hw/pci/pcie_port.c3
-rw-r--r--hw/pci/shpc.c7
-rw-r--r--hw/virtio/vhost-user.c104
-rw-r--r--hw/virtio/virtio-iommu.c3
-rw-r--r--include/exec/memory.h26
-rw-r--r--include/hw/acpi/acpi_aml_interface.h3
-rw-r--r--include/hw/acpi/acpi_dev_interface.h3
-rw-r--r--include/hw/acpi/pci.h4
-rw-r--r--include/hw/i386/intel_iommu.h38
-rw-r--r--include/hw/i386/microvm.h5
-rw-r--r--include/hw/i386/pc.h6
-rw-r--r--include/hw/isa/isa.h1
-rw-r--r--include/hw/nvram/fw_cfg.h9
-rw-r--r--include/hw/pci/pci.h2
-rw-r--r--include/hw/pci/pcie_port.h3
-rw-r--r--python/qemu/machine/console_socket.py2
-rw-r--r--python/qemu/machine/machine.py31
-rw-r--r--python/qemu/machine/qtest.py2
-rw-r--r--python/qemu/qmp/legacy.py18
-rw-r--r--python/qemu/qmp/protocol.py27
-rw-r--r--python/qemu/qmp/qmp_client.py4
-rw-r--r--python/qemu/qmp/qmp_tui.py6
-rw-r--r--tests/avocado/avocado_qemu/__init__.py2
-rw-r--r--tests/data/acpi/pc/DSDTbin6458 -> 6360 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.acpierstbin6418 -> 6283 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.acpihmatbin7783 -> 7685 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.bridgebin9532 -> 12487 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.cphpbin6922 -> 6824 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.dimmpxmbin8112 -> 8014 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.hpbridgebin6418 -> 6289 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.hpbrrootbin3064 -> 3081 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.ipmikcsbin6530 -> 6432 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.memhpbin7817 -> 7719 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.nohpetbin6316 -> 6218 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.numamembin6464 -> 6366 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.roothpbin6656 -> 9745 bytes
-rw-r--r--tests/data/acpi/q35/DSDTbin8310 -> 8252 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.acpierstbin8327 -> 8269 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.acpihmatbin9635 -> 9577 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.acpihmat-noinitiatorbin8589 -> 8531 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.applesmcbin8356 -> 8298 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.bridgebin11439 -> 11481 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.core-count2bin32450 -> 32392 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.cphpbin8774 -> 8716 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.cxlbin9636 -> 9578 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.dimmpxmbin9964 -> 9906 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.ipmibtbin8385 -> 8327 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.ipmismbusbin8398 -> 8340 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.ivrsbin8327 -> 8269 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.memhpbin9669 -> 9611 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.mmio64bin9440 -> 9382 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.multi-bridgebin8630 -> 12337 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.nohpetbin8168 -> 8110 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.numamembin8316 -> 8258 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.pvpanic-isabin8411 -> 8353 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.tis.tpm12bin8916 -> 8858 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.tis.tpm2bin8942 -> 8884 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.viotbin9419 -> 9361 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.xapicbin35673 -> 35615 bytes
-rw-r--r--tests/qtest/bios-tables-test.c144
-rw-r--r--tests/qtest/boot-sector.c6
-rw-r--r--tests/qtest/libqtest.c4
94 files changed, 653 insertions, 412 deletions
diff --git a/docs/pcie.txt b/docs/pcie.txt
index 89e3502075..df49178311 100644
--- a/docs/pcie.txt
+++ b/docs/pcie.txt
@@ -48,8 +48,8 @@ Place only the following kinds of devices directly on the Root Complex:
strangely when PCI Express devices are integrated
with the Root Complex.
- (2) PCI Express Root Ports (ioh3420), for starting exclusively PCI Express
- hierarchies.
+ (2) PCI Express Root Ports (pcie-root-port), for starting exclusively
+ PCI Express hierarchies.
(3) PCI Express to PCI Bridge (pcie-pci-bridge), for starting legacy PCI
hierarchies.
@@ -70,7 +70,7 @@ Place only the following kinds of devices directly on the Root Complex:
-device pxb-pcie,id=pcie.1,bus_nr=x[,numa_node=y][,addr=z]
PCI Express Root Ports and PCI Express to PCI bridges can be
connected to the pcie.1 bus:
- -device ioh3420,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \
+ -device pcie-root-port,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \
-device pcie-pci-bridge,id=pcie_pci_bridge1,bus=pcie.1
@@ -112,14 +112,14 @@ Plug only PCI Express devices into PCI Express Ports.
------------
2.2.1 Plugging a PCI Express device into a PCI Express Root Port:
- -device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
+ -device pcie-root-port,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
-device <dev>,bus=root_port1
2.2.2 Using multi-function PCI Express Root Ports:
- -device ioh3420,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \
- -device ioh3420,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \
- -device ioh3420,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \
+ -device pcie-root-port,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \
+ -device pcie-root-port,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \
+ -device pcie-root-port,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \
2.2.3 Plugging a PCI Express device into a Switch:
- -device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
+ -device pcie-root-port,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
-device x3130-upstream,id=upstream_port1,bus=root_port1[,addr=x] \
-device xio3130-downstream,id=downstream_port1,bus=upstream_port1,chassis=x1,slot=y1[,addr=z1]] \
-device <dev>,bus=downstream_port1
diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig
index 1f7803fdab..e07d3204eb 100644
--- a/hw/acpi/Kconfig
+++ b/hw/acpi/Kconfig
@@ -39,6 +39,10 @@ config ACPI_PCIHP
bool
depends on ACPI
+config ACPI_PCI_BRIDGE
+ bool
+ depends on ACPI && PCI && ACPI_PCIHP
+
config ACPI_HMAT
bool
depends on ACPI
diff --git a/hw/acpi/acpi-x86-stub.c b/hw/acpi/acpi-x86-stub.c
index 3df1e090f4..d0d399d26b 100644
--- a/hw/acpi/acpi-x86-stub.c
+++ b/hw/acpi/acpi-x86-stub.c
@@ -2,9 +2,8 @@
#include "hw/i386/pc.h"
#include "hw/i386/acpi-build.h"
-void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
- const CPUArchIdList *apic_ids, GArray *entry,
- bool force_enabled)
+void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids,
+ GArray *entry, bool force_enabled)
{
}
diff --git a/hw/acpi/acpi_interface.c b/hw/acpi/acpi_interface.c
index c668d361f6..8637ff18fc 100644
--- a/hw/acpi/acpi_interface.c
+++ b/hw/acpi/acpi_interface.c
@@ -2,6 +2,7 @@
#include "hw/acpi/acpi_dev_interface.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "qemu/module.h"
+#include "qemu/queue.h"
void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event)
{
@@ -12,6 +13,15 @@ void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event)
}
}
+void qbus_build_aml(BusState *bus, Aml *scope)
+{
+ BusChild *kid;
+
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ call_dev_aml_func(DEVICE(kid->child), scope);
+ }
+}
+
static void register_types(void)
{
static const TypeInfo acpi_dev_if_info = {
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 4e580959a2..19c154d78f 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -355,7 +355,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root);
Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
- AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);
cpu_ctrl_dev = aml_device("%s", cphp_res_path);
{
@@ -666,7 +665,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
/* build _MAT object */
assert(adevc && adevc->madt_cpu);
- adevc->madt_cpu(adev, i, arch_ids, madt_buf,
+ adevc->madt_cpu(i, arch_ids, madt_buf,
true); /* set enabled flag */
aml_append(dev, aml_name_decl("_MAT",
aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data)));
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index 30054a8cdc..50b73129b4 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -19,6 +19,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device
acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c'))
acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PIIX4', if_true: files('piix4.c'))
+acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
@@ -30,9 +31,10 @@ if have_tpm
acpi_ss.add(files('tpm.c'))
endif
softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c'))
+softmmu_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-stub.c'))
softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss)
softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c',
'acpi-x86-stub.c', 'ipmi-stub.c', 'ghes-stub.c',
'acpi-mem-hotplug-stub.c', 'acpi-cpu-hotplug-stub.c',
'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c',
- 'cxl-stub.c'))
+ 'cxl-stub.c', 'pci-bridge-stub.c'))
diff --git a/hw/acpi/pci-bridge-stub.c b/hw/acpi/pci-bridge-stub.c
new file mode 100644
index 0000000000..9d78638c48
--- /dev/null
+++ b/hw/acpi/pci-bridge-stub.c
@@ -0,0 +1,20 @@
+/*
+ * QEMU ACPI PCI bridge stub
+ *
+ * Copyright (c) 2023 Red Hat, Inc.
+ *
+ * Author:
+ * Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * 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 "hw/acpi/pci.h"
+
+void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope)
+{
+}
diff --git a/hw/acpi/pci-bridge.c b/hw/acpi/pci-bridge.c
new file mode 100644
index 0000000000..5f3ee5157f
--- /dev/null
+++ b/hw/acpi/pci-bridge.c
@@ -0,0 +1,27 @@
+/*
+ * QEMU ACPI PCI bridge
+ *
+ * Copyright (c) 2023 Red Hat, Inc.
+ *
+ * Author:
+ * Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * 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 "hw/acpi/pci.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/acpi/pcihp.h"
+
+void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope)
+{
+ PCIBridge *br = PCI_BRIDGE(adev);
+
+ if (object_property_find(OBJECT(&br->sec_bus), ACPI_PCIHP_PROP_BSEL)) {
+ build_append_pci_bus_devices(scope, pci_bridge_get_sec_bus(br));
+ }
+}
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 99a898d9ae..5dc7377411 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -85,31 +85,40 @@ static int acpi_pcihp_get_bsel(PCIBus *bus)
}
}
-/* Assign BSEL property to all buses. In the future, this can be changed
- * to only assign to buses that support hotplug.
- */
+typedef struct {
+ unsigned bsel_alloc;
+ bool has_bridge_hotplug;
+} BSELInfo;
+
+/* Assign BSEL property only to buses that support hotplug. */
static void *acpi_set_bsel(PCIBus *bus, void *opaque)
{
- unsigned *bsel_alloc = opaque;
+ BSELInfo *info = opaque;
unsigned *bus_bsel;
+ DeviceState *br = bus->qbus.parent;
+ bool is_bridge = IS_PCI_BRIDGE(br);
+ /* hotplugged bridges can't be described in ACPI ignore them */
if (qbus_is_hotpluggable(BUS(bus))) {
- bus_bsel = g_malloc(sizeof *bus_bsel);
+ if (!is_bridge || (!br->hotplugged && info->has_bridge_hotplug)) {
+ bus_bsel = g_malloc(sizeof *bus_bsel);
- *bus_bsel = (*bsel_alloc)++;
- object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
- bus_bsel, OBJ_PROP_FLAG_READ);
+ *bus_bsel = info->bsel_alloc++;
+ object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
+ bus_bsel, OBJ_PROP_FLAG_READ);
+ }
}
- return bsel_alloc;
+ return info;
}
-static void acpi_set_pci_info(void)
+static void acpi_set_pci_info(bool has_bridge_hotplug)
{
static bool bsel_is_set;
Object *host = acpi_get_i386_pci_host();
PCIBus *bus;
- unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT;
+ BSELInfo info = { .bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT,
+ .has_bridge_hotplug = has_bridge_hotplug };
if (bsel_is_set) {
return;
@@ -123,7 +132,7 @@ static void acpi_set_pci_info(void)
bus = PCI_HOST_BRIDGE(host)->bus;
if (bus) {
/* Scan all PCI buses. Set property to enable acpi based hotplug. */
- pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc);
+ pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &info);
}
}
@@ -287,7 +296,7 @@ void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off)
if (acpihp_root_off) {
acpi_pcihp_disable_root_bus();
}
- acpi_set_pci_info();
+ acpi_set_pci_info(!s->legacy_piix);
acpi_pcihp_update(s);
}
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 0a81f1ad93..724294b378 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
-#include "hw/southbridge/piix.h"
#include "hw/irq.h"
#include "hw/isa/apm.h"
#include "hw/i2c/pm_smbus.h"
@@ -305,7 +304,9 @@ static void piix4_pm_reset(DeviceState *dev)
acpi_update_sci(&s->ar, s->irq);
pm_io_space_update(s);
- acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug);
+ if (s->use_acpi_hotplug_bridge || s->use_acpi_root_pci_hotplug) {
+ acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug);
+ }
}
static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 54186f31cb..733c964778 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -535,7 +535,8 @@ static void smmu_base_reset_hold(Object *obj)
static Property smmu_dev_properties[] = {
DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0),
- DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, "PCI", PCIBus *),
+ DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus,
+ TYPE_PCI_BUS, PCIBus *),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 616f3a207c..f7761baab5 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -46,6 +46,7 @@ const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2);
GlobalProperty hw_compat_7_1[] = {
{ "virtio-device", "queue_reset", "false" },
+ { "virtio-rng-pci", "vectors", "0" },
};
const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1);
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index ee50ba1f2c..52ba77f3fc 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -97,13 +97,10 @@ static void ich9_smbus_realize(PCIDevice *d, Error **errp)
static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope)
{
- BusChild *kid;
ICH9SMBState *s = ICH9_SMB_DEVICE(adev);
BusState *bus = BUS(s->smb.smbus);
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- call_dev_aml_func(DEVICE(kid->child), scope);
- }
+ qbus_build_aml(bus, scope);
}
static void ich9_smb_class_init(ObjectClass *klass, void *data)
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index c4fb5b49bd..1bf47b0b0b 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -58,6 +58,7 @@ config PC_ACPI
select ACPI_X86
select ACPI_CPU_HOTPLUG
select ACPI_MEMORY_HOTPLUG
+ select ACPI_PCI_BRIDGE
select ACPI_VIOT
select SMBUS_EEPROM
select PFLASH_CFI01
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 127c4e2d50..145389aa58 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -117,8 +117,6 @@ typedef struct AcpiMiscInfo {
#ifdef CONFIG_TPM
TPMVersion tpm_version;
#endif
- const unsigned char *dsdt_code;
- unsigned dsdt_size;
} AcpiMiscInfo;
typedef struct FwCfgTPMConfig {
@@ -385,151 +383,185 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot)
aml_append(method, if_ctx);
}
-static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
- bool pcihp_bridge_en)
+static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus)
{
- Aml *dev, *notify_method = NULL, *method;
- QObject *bsel;
- PCIBus *sec;
- int devfn;
+ const PCIDevice *pdev = bus->devices[devfn];
- bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
- if (bsel) {
- uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
+ if (PCI_FUNC(devfn)) {
+ if (IS_PCI_BRIDGE(pdev)) {
+ /*
+ * Ignore only hotplugged PCI bridges on !0 functions, but
+ * allow describing cold plugged bridges on all functions
+ */
+ if (DEVICE(pdev)->hotplugged) {
+ return true;
+ }
+ } else if (!get_dev_aml_func(DEVICE(pdev))) {
+ /*
+ * Ignore all other devices on !0 functions unless they
+ * have AML description (i.e have get_dev_aml_func() != 0)
+ */
+ return true;
+ }
+ }
+ return false;
+}
- aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
- notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
+static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus)
+{
+ PCIDevice *pdev = bus->devices[devfn];
+ if (pdev) {
+ return is_devfn_ignored_generic(devfn, bus) ||
+ !DEVICE_GET_CLASS(pdev)->hotpluggable ||
+ /* Cold plugged bridges aren't themselves hot-pluggable */
+ (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged);
+ } else { /* non populated slots */
+ /*
+ * hotplug is supported only for non-multifunction device
+ * so generate device description only for function 0
+ */
+ if (PCI_FUNC(devfn) ||
+ (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) {
+ return true;
+ }
}
+ return false;
+}
- for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
- DeviceClass *dc;
- PCIDevice *pdev = bus->devices[devfn];
- int slot = PCI_SLOT(devfn);
- int func = PCI_FUNC(devfn);
- /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
- int adr = slot << 16 | func;
- bool hotpluggbale_slot = false;
- bool bridge_in_acpi = false;
- bool cold_plugged_bridge = false;
+static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus,
+ QObject *bsel)
+{
+ int devfn;
+ Aml *dev, *notify_method = NULL, *method;
+ uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
- if (pdev) {
- dc = DEVICE_GET_CLASS(pdev);
+ aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
+ notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
- /*
- * Cold plugged bridges aren't themselves hot-pluggable.
- * Hotplugged bridges *are* hot-pluggable.
- */
- cold_plugged_bridge = IS_PCI_BRIDGE(pdev) &&
- !DEVICE(pdev)->hotplugged;
- bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
+ for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ int slot = PCI_SLOT(devfn);
+ int adr = slot << 16 | PCI_FUNC(devfn);
- hotpluggbale_slot = bsel && dc->hotpluggable &&
- !cold_plugged_bridge;
+ if (is_devfn_ignored_hotplug(devfn, bus)) {
+ continue;
+ }
- /*
- * allow describing coldplugged bridges in ACPI even if they are not
- * on function 0, as they are not unpluggable, for all other devices
- * generate description only for function 0 per slot, and for other
- * functions if device on function provides its own AML
- */
- if (func && !bridge_in_acpi && !get_dev_aml_func(DEVICE(pdev))) {
- continue;
- }
+ if (bus->devices[devfn]) {
+ dev = aml_scope("S%.02X", devfn);
} else {
- /*
- * hotplug is supported only for non-multifunction device
- * so generate device description only for function 0
- */
- if (bsel && !func) {
- if (pci_bus_is_express(bus) && slot > 0) {
- break;
- }
- /* mark it as empty hotpluggable slot */
- hotpluggbale_slot = true;
- } else {
- continue;
- }
+ dev = aml_device("S%.02X", devfn);
+ aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
}
- /* start to compose PCI device descriptor */
- dev = aml_device("S%.02X", devfn);
- aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
+ /*
+ * Can't declare _SUN here for every device as it changes 'slot'
+ * enumeration order in linux kernel, so use another variable for it
+ */
+ aml_append(dev, aml_name_decl("ASUN", aml_int(slot)));
+ aml_append(dev, aml_pci_device_dsm());
- if (bsel) {
- /*
- * Can't declare _SUN here for every device as it changes 'slot'
- * enumeration order in linux kernel, so use another variable for it
- */
- aml_append(dev, aml_name_decl("ASUN", aml_int(slot)));
- aml_append(dev, aml_pci_device_dsm());
- }
+ aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
+ /* add _EJ0 to make slot hotpluggable */
+ method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
+ aml_append(method,
+ aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
+ );
+ aml_append(dev, method);
- call_dev_aml_func(DEVICE(pdev), dev);
+ build_append_pcihp_notify_entry(notify_method, slot);
- bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
- if (bridge_in_acpi) {
- /*
- * device is coldplugged bridge,
- * add child device descriptions into its scope
- */
- PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
+ /* device descriptor has been composed, add it into parent context */
+ aml_append(parent_scope, dev);
+ }
+ aml_append(parent_scope, notify_method);
+}
- build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en);
- }
+void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus)
+{
+ QObject *bsel;
+ int devfn;
+ Aml *dev;
- if (hotpluggbale_slot) {
- aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
- /* add _EJ0 to make slot hotpluggable */
- method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
- aml_append(method,
- aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
- );
- aml_append(dev, method);
+ bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
- build_append_pcihp_notify_entry(notify_method, slot);
+ for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
+ int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn);
+ PCIDevice *pdev = bus->devices[devfn];
+
+ if (!pdev || is_devfn_ignored_generic(devfn, bus)) {
+ continue;
}
+ /* start to compose PCI device descriptor */
+ dev = aml_device("S%.02X", devfn);
+ aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
+
+ call_dev_aml_func(DEVICE(bus->devices[devfn]), dev);
+
/* device descriptor has been composed, add it into parent context */
aml_append(parent_scope, dev);
}
if (bsel) {
- aml_append(parent_scope, notify_method);
+ build_append_pcihp_slots(parent_scope, bus, bsel);
}
- /* Append PCNT method to notify about events on local and child buses.
- * Add this method for root bus only when hotplug is enabled since DSDT
- * expects it.
- */
- if (bsel || pcihp_bridge_en) {
- method = aml_method("PCNT", 0, AML_NOTSERIALIZED);
-
- /* If bus supports hotplug select it and notify about local events */
- if (bsel) {
- uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
-
- aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
- aml_append(method, aml_call2("DVNT", aml_name("PCIU"),
- aml_int(1))); /* Device Check */
- aml_append(method, aml_call2("DVNT", aml_name("PCID"),
- aml_int(3))); /* Eject Request */
+ qobject_unref(bsel);
+}
+
+static bool build_append_notfication_callback(Aml *parent_scope,
+ const PCIBus *bus)
+{
+ Aml *method;
+ PCIBus *sec;
+ QObject *bsel;
+ int nr_notifiers = 0;
+
+ QLIST_FOREACH(sec, &bus->child, sibling) {
+ Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn);
+ if (pci_bus_is_root(sec) ||
+ !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) {
+ continue;
}
+ nr_notifiers = nr_notifiers +
+ build_append_notfication_callback(br_scope, sec);
+ aml_append(parent_scope, br_scope);
+ }
- /* Notify about child bus events in any case */
- if (pcihp_bridge_en) {
- QLIST_FOREACH(sec, &bus->child, sibling) {
- if (pci_bus_is_root(sec)) {
- continue;
- }
+ /*
+ * Append PCNT method to notify about events on local and child buses.
+ * ps: hostbridge might not have hotplug (bsel) enabled but might have
+ * child bridges that do have bsel.
+ */
+ method = aml_method("PCNT", 0, AML_NOTSERIALIZED);
- aml_append(method, aml_name("^S%.02X.PCNT",
- sec->parent_dev->devfn));
- }
+ /* If bus supports hotplug select it and notify about local events */
+ bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
+ if (bsel) {
+ uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
+
+ aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
+ aml_append(method, aml_call2("DVNT", aml_name("PCIU"),
+ aml_int(1))); /* Device Check */
+ aml_append(method, aml_call2("DVNT", aml_name("PCID"),
+ aml_int(3))); /* Eject Request */
+ nr_notifiers++;
+ }
+
+ /* Notify about child bus events in any case */
+ QLIST_FOREACH(sec, &bus->child, sibling) {
+ if (pci_bus_is_root(sec) ||
+ !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) {
+ continue;
}
- aml_append(parent_scope, method);
+ aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn));
}
+
+ aml_append(parent_scope, method);
qobject_unref(bsel);
+ return !!nr_notifiers;
}
static Aml *aml_pci_pdsm(void)
@@ -1678,7 +1710,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus;
Aml *scope = aml_scope("PCI0");
/* Scan all PCI buses. Generate tables to support hotplug. */
- build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
+ build_append_pci_bus_devices(scope, bus);
aml_append(sb_scope, scope);
}
}
@@ -1728,13 +1760,26 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dsdt, sb_scope);
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
+ bool has_pcnt;
+
+ Object *pci_host = acpi_get_i386_pci_host();
+ PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus;
+
+ scope = aml_scope("\\_SB.PCI0");
+ has_pcnt = build_append_notfication_callback(scope, bus);
+ if (has_pcnt) {
+ aml_append(dsdt, scope);
+ }
+
scope = aml_scope("_GPE");
{
method = aml_method("_E01", 0, AML_NOTSERIALIZED);
- aml_append(method,
- aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
- aml_append(method, aml_call0("\\_SB.PCI0.PCNT"));
- aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK")));
+ if (has_pcnt) {
+ aml_append(method,
+ aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
+ aml_append(method, aml_call0("\\_SB.PCI0.PCNT"));
+ aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK")));
+ }
aml_append(scope, method);
}
aml_append(dsdt, scope);
diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c
index 4aaafbdd7b..52e5c1439a 100644
--- a/hw/i386/acpi-common.c
+++ b/hw/i386/acpi-common.c
@@ -33,9 +33,8 @@
#include "acpi-build.h"
#include "acpi-common.h"
-void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
- const CPUArchIdList *apic_ids, GArray *entry,
- bool force_enabled)
+void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids,
+ GArray *entry, bool force_enabled)
{
uint32_t apic_id = apic_ids->cpus[uid].arch_id;
/* Flags – Local APIC Flags */
@@ -112,7 +111,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
for (i = 0; i < apic_ids->len; i++) {
- adevc->madt_cpu(adev, i, apic_ids, table_data, false);
+ adevc->madt_cpu(i, apic_ids, table_data, false);
if (apic_ids->cpus[i].arch_id > 254) {
x2apic_mode = true;
}
diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
index fb09185cbd..a075360d85 100644
--- a/hw/i386/acpi-microvm.c
+++ b/hw/i386/acpi-microvm.c
@@ -26,6 +26,7 @@
#include "exec/memory.h"
#include "hw/acpi/acpi.h"
+#include "hw/acpi/acpi_aml_interface.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/bios-linker-loader.h"
#include "hw/acpi/generic_event_device.h"
@@ -129,7 +130,7 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
sb_scope = aml_scope("_SB");
fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg);
- isa_build_aml(ISA_BUS(isabus), sb_scope);
+ qbus_build_aml(BUS(isabus), sb_scope);
build_ged_aml(sb_scope, GED_DEVICE, x86ms->acpi_dev,
GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE);
acpi_dsdt_add_power_button(sb_scope);
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 170a331e3f..29f30dd6d3 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -378,7 +378,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
MicrovmMachineState *mms = MICROVM_MACHINE(machine);
BusState *bus;
BusChild *kid;
- char *cmdline;
+ char *cmdline, *existing_cmdline;
+ size_t len;
/*
* Find MMIO transports with attached devices, and add them to the kernel
@@ -387,7 +388,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
* Yes, this is a hack, but one that heavily improves the UX without
* introducing any significant issues.
*/
- cmdline = g_strdup(machine->kernel_cmdline);
+ existing_cmdline = fw_cfg_read_bytes_ptr(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA);
+ cmdline = g_strdup(existing_cmdline);
bus = sysbus_get_default();
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
@@ -411,9 +413,12 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
}
}
- fw_cfg_modify_i32(x86ms->fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(cmdline) + 1);
- fw_cfg_modify_string(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA, cmdline);
-
+ len = strlen(cmdline);
+ if (len > VIRTIO_CMDLINE_TOTAL_MAX_LEN + strlen(existing_cmdline)) {
+ fprintf(stderr, "qemu: virtio mmio cmdline too large, skipping\n");
+ } else {
+ memcpy(existing_cmdline, cmdline, len + 1);
+ }
g_free(cmdline);
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 83c57c6eb1..66cd718b70 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -257,8 +257,9 @@ static void pc_q35_init(MachineState *machine)
NULL);
if (!keep_pci_slot_hpc && acpi_pcihp) {
- object_register_sugar_prop(TYPE_PCIE_SLOT, "x-native-hotplug",
- "false", true);
+ object_register_sugar_prop(TYPE_PCIE_SLOT,
+ "x-do-not-expose-native-hotplug-cap",
+ "true", true);
}
/* irq lines */
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 78cc131926..eaff4227bd 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -50,6 +50,7 @@
#include "hw/intc/i8259.h"
#include "hw/rtc/mc146818rtc.h"
#include "target/i386/sev.h"
+#include "hw/i386/microvm.h"
#include "hw/acpi/cpu_hotplug.h"
#include "hw/irq.h"
@@ -813,12 +814,18 @@ void x86_load_linux(X86MachineState *x86ms,
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
const char *dtb_filename = machine->dtb;
- const char *kernel_cmdline = machine->kernel_cmdline;
+ char *kernel_cmdline;
SevKernelLoaderContext sev_load_ctx = {};
enum { RNG_SEED_LENGTH = 32 };
- /* Align to 16 bytes as a paranoia measure */
- cmdline_size = (strlen(kernel_cmdline) + 16) & ~15;
+ /*
+ * Add the NUL terminator, some padding for the microvm cmdline fiddling
+ * hack, and then align to 16 bytes as a paranoia measure
+ */
+ cmdline_size = (strlen(machine->kernel_cmdline) + 1 +
+ VIRTIO_CMDLINE_TOTAL_MAX_LEN + 16) & ~15;
+ /* Make a copy, since we might append arbitrary bytes to it later. */
+ kernel_cmdline = g_strndup(machine->kernel_cmdline, cmdline_size);
/* load the kernel header */
f = fopen(kernel_filename, "rb");
@@ -959,12 +966,6 @@ void x86_load_linux(X86MachineState *x86ms,
initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1;
}
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1);
- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
- sev_load_ctx.cmdline_data = (char *)kernel_cmdline;
- sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1;
-
if (protocol >= 0x202) {
stl_p(header + 0x228, cmdline_addr);
} else {
@@ -1091,27 +1092,24 @@ void x86_load_linux(X86MachineState *x86ms,
exit(1);
}
- setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16);
- kernel_size = setup_data_offset + sizeof(SetupData) + dtb_size;
- kernel = g_realloc(kernel, kernel_size);
-
-
- setup_data = (SetupData *)(kernel + setup_data_offset);
+ setup_data_offset = cmdline_size;
+ cmdline_size += sizeof(SetupData) + dtb_size;
+ kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size);
+ setup_data = (void *)kernel_cmdline + setup_data_offset;
setup_data->next = cpu_to_le64(first_setup_data);
- first_setup_data = prot_addr + setup_data_offset;
+ first_setup_data = cmdline_addr + setup_data_offset;
setup_data->type = cpu_to_le32(SETUP_DTB);
setup_data->len = cpu_to_le32(dtb_size);
-
load_image_size(dtb_filename, setup_data->data, dtb_size);
}
- if (!legacy_no_rng_seed) {
- setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16);
- kernel_size = setup_data_offset + sizeof(SetupData) + RNG_SEED_LENGTH;
- kernel = g_realloc(kernel, kernel_size);
- setup_data = (SetupData *)(kernel + setup_data_offset);
+ if (!legacy_no_rng_seed && protocol >= 0x209) {
+ setup_data_offset = cmdline_size;
+ cmdline_size += sizeof(SetupData) + RNG_SEED_LENGTH;
+ kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size);
+ setup_data = (void *)kernel_cmdline + setup_data_offset;
setup_data->next = cpu_to_le64(first_setup_data);
- first_setup_data = prot_addr + setup_data_offset;
+ first_setup_data = cmdline_addr + setup_data_offset;
setup_data->type = cpu_to_le32(SETUP_RNG_SEED);
setup_data->len = cpu_to_le32(RNG_SEED_LENGTH);
qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH);
@@ -1122,6 +1120,12 @@ void x86_load_linux(X86MachineState *x86ms,
fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
}
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, cmdline_size);
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline, cmdline_size);
+ sev_load_ctx.cmdline_data = (char *)kernel_cmdline;
+ sev_load_ctx.cmdline_size = cmdline_size;
+
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
sev_load_ctx.kernel_data = (char *)kernel;
@@ -1134,7 +1138,7 @@ void x86_load_linux(X86MachineState *x86ms,
* kernel on the other side of the fw_cfg interface matches the hash of the
* file the user passed in.
*/
- if (!sev_enabled()) {
+ if (!sev_enabled() && first_setup_data) {
SetupDataFixup *fixup = g_malloc(sizeof(*fixup));
memcpy(setup, header, MIN(sizeof(header), setup_size));
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index 1bee1a47f1..f155b80010 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -24,7 +24,6 @@
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "hw/isa/isa.h"
-#include "hw/acpi/acpi_aml_interface.h"
static ISABus *isabus;
@@ -188,15 +187,6 @@ ISADevice *isa_vga_init(ISABus *bus)
}
}
-void isa_build_aml(ISABus *bus, Aml *scope)
-{
- BusChild *kid;
-
- QTAILQ_FOREACH(kid, &bus->parent_obj.children, sibling) {
- call_dev_aml_func(DEVICE(kid->child), scope);
- }
-}
-
static void isabus_bridge_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 8d541e2b54..1fba3c210c 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -813,7 +813,6 @@ static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *field;
- BusChild *kid;
ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
BusState *bus = BUS(s->isa_bus);
Aml *sb_scope = aml_scope("\\_SB");
@@ -835,9 +834,7 @@ static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(sb_scope, field);
aml_append(scope, sb_scope);
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- call_dev_aml_func(DEVICE(kid->child), scope);
- }
+ qbus_build_aml(bus, scope);
}
static void ich9_lpc_class_init(ObjectClass *klass, void *data)
diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c
index 283b971ec4..a9cb39bf21 100644
--- a/hw/isa/piix3.c
+++ b/hw/isa/piix3.c
@@ -306,7 +306,6 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp)
static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *field;
- BusChild *kid;
Aml *sb_scope = aml_scope("\\_SB");
BusState *bus = qdev_get_child_bus(DEVICE(adev), "isa.0");
@@ -322,9 +321,7 @@ static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(sb_scope, field);
aml_append(scope, sb_scope);
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- call_dev_aml_func(DEVICE(kid->child), scope);
- }
+ qbus_build_aml(bus, scope);
}
static void pci_piix3_class_init(ObjectClass *klass, void *data)
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index a00881bc64..432754eda4 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -741,6 +741,15 @@ void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
fw_cfg_add_bytes_callback(s, key, NULL, NULL, NULL, data, len, true);
}
+void *fw_cfg_read_bytes_ptr(FWCfgState *s, uint16_t key)
+{
+ int arch = !!(key & FW_CFG_ARCH_LOCAL);
+
+ key &= FW_CFG_ENTRY_MASK;
+ assert(key < fw_cfg_max_entry(s));
+ return s->entries[arch][key].data;
+}
+
void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
{
size_t sz = strlen(value) + 1;
diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c
index 20099a8ae3..1ce4e7beba 100644
--- a/hw/pci-bridge/gen_pcie_root_port.c
+++ b/hw/pci-bridge/gen_pcie_root_port.c
@@ -87,7 +87,12 @@ static void gen_rp_realize(DeviceState *dev, Error **errp)
return;
}
- if (grp->res_reserve.io == -1 && s->hotplug && !s->native_hotplug) {
+ /*
+ * reserving IO space led to worse issues in 6.1, when this hunk was
+ * introduced. (see commit: 211afe5c69b59). Keep this broken for 6.1
+ * machine type ABI compatibility only
+ */
+ if (s->hide_native_hotplug_cap && grp->res_reserve.io == -1 && s->hotplug) {
grp->res_reserve.io = GEN_PCIE_ROOT_DEFAULT_IO_RANGE;
}
int rc = pci_bridge_qemu_reserve_cap_init(d, 0,
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 3435df8d73..4b2696ea7f 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -186,7 +186,6 @@ static Property pci_bridge_dev_properties[] = {
res_reserve.mem_pref_32, -1),
DEFINE_PROP_SIZE("pref64-reserve", PCIBridgeDev,
res_reserve.mem_pref_64, -1),
-
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c
index 8cf318cb80..8e589ff2c9 100644
--- a/hw/pci-host/grackle.c
+++ b/hw/pci-host/grackle.c
@@ -91,7 +91,7 @@ static void grackle_init(Object *obj)
static void grackle_pci_realize(PCIDevice *d, Error **errp)
{
- d->config[0x09] = 0x01;
+ d->config[PCI_CLASS_PROG] = 0x01;
}
static void grackle_pci_class_init(ObjectClass *klass, void *data)
diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c
index 5b00b4e462..cdfb62ac2e 100644
--- a/hw/pci-host/raven.c
+++ b/hw/pci-host/raven.c
@@ -330,9 +330,9 @@ static void raven_realize(PCIDevice *d, Error **errp)
char *filename;
int bios_size = -1;
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x34] = 0x00; // capabilities_pointer
+ d->config[PCI_CACHE_LINE_SIZE] = 0x08;
+ d->config[PCI_LATENCY_TIMER] = 0x10;
+ d->config[PCI_CAPABILITY_LIST] = 0x00;
memory_region_init_rom_nomigrate(&s->bios, OBJECT(s), "bios", BIOS_SIZE,
&error_fatal);
diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c
index e3abe3c0f9..e4c1abd871 100644
--- a/hw/pci-host/uninorth.c
+++ b/hw/pci-host/uninorth.c
@@ -276,12 +276,9 @@ static void pci_unin_internal_init(Object *obj)
static void unin_main_pci_host_realize(PCIDevice *d, Error **errp)
{
- /* cache_line_size */
- d->config[0x0C] = 0x08;
- /* latency_timer */
- d->config[0x0D] = 0x10;
- /* capabilities_pointer */
- d->config[0x34] = 0x00;
+ d->config[PCI_CACHE_LINE_SIZE] = 0x08;
+ d->config[PCI_LATENCY_TIMER] = 0x10;
+ d->config[PCI_CAPABILITY_LIST] = 0x00;
/*
* Set kMacRISCPCIAddressSelect (0x48) register to indicate PCI
@@ -296,30 +293,22 @@ static void unin_main_pci_host_realize(PCIDevice *d, Error **errp)
static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp)
{
- /* cache_line_size */
- d->config[0x0C] = 0x08;
- /* latency_timer */
- d->config[0x0D] = 0x10;
- /* capabilities_pointer
- d->config[0x34] = 0x80; */
+ d->config[PCI_CACHE_LINE_SIZE] = 0x08;
+ d->config[PCI_LATENCY_TIMER] = 0x10;
+ /* d->config[PCI_CAPABILITY_LIST] = 0x80; */
}
static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp)
{
- /* cache line size */
- d->config[0x0C] = 0x08;
- /* latency timer */
- d->config[0x0D] = 0x10;
+ d->config[PCI_CACHE_LINE_SIZE] = 0x08;
+ d->config[PCI_LATENCY_TIMER] = 0x10;
}
static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp)
{
- /* cache_line_size */
- d->config[0x0C] = 0x08;
- /* latency_timer */
- d->config[0x0D] = 0x10;
- /* capabilities_pointer */
- d->config[0x34] = 0x00;
+ d->config[PCI_CACHE_LINE_SIZE] = 0x08;
+ d->config[PCI_LATENCY_TIMER] = 0x10;
+ d->config[PCI_CAPABILITY_LIST] = 0x00;
}
static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 39a7bb32aa..208c16f450 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -483,7 +483,7 @@ static void pci_bus_uninit(PCIBus *bus)
pci_host_bus_unregister(BUS(bus)->parent);
}
-bool pci_bus_is_express(PCIBus *bus)
+bool pci_bus_is_express(const PCIBus *bus)
{
return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
}
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index b2b180edd6..dd5af508f9 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -36,6 +36,8 @@
#include "qemu/module.h"
#include "qemu/range.h"
#include "qapi/error.h"
+#include "hw/acpi/acpi_aml_interface.h"
+#include "hw/acpi/pci.h"
/* PCI bridge subsystem vendor ID helper functions */
#define PCI_SSVID_SIZEOF 8
@@ -467,11 +469,23 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
return 0;
}
+static void pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+ AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
+
+ adevc->build_dev_aml = build_pci_bridge_aml;
+}
+
static const TypeInfo pci_bridge_type_info = {
.name = TYPE_PCI_BRIDGE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBridge),
+ .class_init = pci_bridge_class_init,
.abstract = true,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_ACPI_DEV_AML_IF },
+ { },
+ },
};
static void pci_bridge_register_types(void)
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 68a62da0b5..924fdabd15 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -611,11 +611,11 @@ void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s)
PCI_EXP_SLTCAP_ABP);
/*
- * Enable native hot-plug on all hot-plugged bridges unless
- * hot-plug is disabled on the slot.
+ * Expose native hot-plug on all bridges if hot-plug is enabled on the slot.
+ * (unless broken 6.1 ABI is enforced for compat reasons)
*/
if (s->hotplug &&
- (s->native_hotplug || DEVICE(dev)->hotplugged)) {
+ (!s->hide_native_hotplug_cap || DEVICE(dev)->hotplugged)) {
pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
PCI_EXP_SLTCAP_HPS |
PCI_EXP_SLTCAP_HPC);
diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
index 687e4e763a..65a397ad23 100644
--- a/hw/pci/pcie_port.c
+++ b/hw/pci/pcie_port.c
@@ -173,7 +173,8 @@ static Property pcie_slot_props[] = {
DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true),
- DEFINE_PROP_BOOL("x-native-hotplug", PCIESlot, native_hotplug, true),
+ DEFINE_PROP_BOOL("x-do-not-expose-native-hotplug-cap", PCIESlot,
+ hide_native_hotplug_cap, false),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
index e71f3a7483..fca7f6691a 100644
--- a/hw/pci/shpc.c
+++ b/hw/pci/shpc.c
@@ -568,6 +568,13 @@ void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
+
+ if (led == SHPC_LED_BLINK) {
+ error_setg(errp, "Hot-unplug failed: "
+ "guest is busy (power indicator blinking)");
+ return;
+ }
+
if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
shpc_free_devices_in_slot(shpc, slot);
shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index d9ce0501b2..e68daa35d4 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -48,7 +48,7 @@
* hardware plaform.
*/
#if defined(TARGET_X86) || defined(TARGET_X86_64) || \
- defined(TARGET_ARM) || defined(TARGET_ARM_64)
+ defined(TARGET_ARM) || defined(TARGET_AARCH64)
#include "hw/acpi/acpi.h"
#define VHOST_USER_MAX_RAM_SLOTS ACPI_MAX_RAM_SLOTS
@@ -305,19 +305,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg)
return 0;
}
-struct vhost_user_read_cb_data {
- struct vhost_dev *dev;
- VhostUserMsg *msg;
- GMainLoop *loop;
- int ret;
-};
-
-static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
- gpointer opaque)
+static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
{
- struct vhost_user_read_cb_data *data = opaque;
- struct vhost_dev *dev = data->dev;
- VhostUserMsg *msg = data->msg;
struct vhost_user *u = dev->opaque;
CharBackend *chr = u->user->chr;
uint8_t *p = (uint8_t *) msg;
@@ -325,8 +314,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
r = vhost_user_read_header(dev, msg);
if (r < 0) {
- data->ret = r;
- goto end;
+ return r;
}
/* validate message size is sane */
@@ -334,8 +322,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
error_report("Failed to read msg header."
" Size %d exceeds the maximum %zu.", msg->hdr.size,
VHOST_USER_PAYLOAD_SIZE);
- data->ret = -EPROTO;
- goto end;
+ return -EPROTO;
}
if (msg->hdr.size) {
@@ -346,84 +333,11 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
int saved_errno = errno;
error_report("Failed to read msg payload."
" Read %d instead of %d.", r, msg->hdr.size);
- data->ret = r < 0 ? -saved_errno : -EIO;
- goto end;
+ return r < 0 ? -saved_errno : -EIO;
}
}
-end:
- g_main_loop_quit(data->loop);
- return G_SOURCE_REMOVE;
-}
-
-static gboolean slave_read(QIOChannel *ioc, GIOCondition condition,
- gpointer opaque);
-
-/*
- * This updates the read handler to use a new event loop context.
- * Event sources are removed from the previous context : this ensures
- * that events detected in the previous context are purged. They will
- * be re-detected and processed in the new context.
- */
-static void slave_update_read_handler(struct vhost_dev *dev,
- GMainContext *ctxt)
-{
- struct vhost_user *u = dev->opaque;
-
- if (!u->slave_ioc) {
- return;
- }
-
- if (u->slave_src) {
- g_source_destroy(u->slave_src);
- g_source_unref(u->slave_src);
- }
-
- u->slave_src = qio_channel_add_watch_source(u->slave_ioc,
- G_IO_IN | G_IO_HUP,
- slave_read, dev, NULL,
- ctxt);
-}
-
-static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
-{
- struct vhost_user *u = dev->opaque;
- CharBackend *chr = u->user->chr;
- GMainContext *prev_ctxt = chr->chr->gcontext;
- GMainContext *ctxt = g_main_context_new();
- GMainLoop *loop = g_main_loop_new(ctxt, FALSE);
- struct vhost_user_read_cb_data data = {
- .dev = dev,
- .loop = loop,
- .msg = msg,
- .ret = 0
- };
-
- /*
- * We want to be able to monitor the slave channel fd while waiting
- * for chr I/O. This requires an event loop, but we can't nest the
- * one to which chr is currently attached : its fd handlers might not
- * be prepared for re-entrancy. So we create a new one and switch chr
- * to use it.
- */
- slave_update_read_handler(dev, ctxt);
- qemu_chr_be_update_read_handlers(chr->chr, ctxt);
- qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data);
-
- g_main_loop_run(loop);
-
- /*
- * Restore the previous event loop context. This also destroys/recreates
- * event sources : this guarantees that all pending events in the original
- * context that have been processed by the nested loop are purged.
- */
- qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt);
- slave_update_read_handler(dev, NULL);
-
- g_main_loop_unref(loop);
- g_main_context_unref(ctxt);
-
- return data.ret;
+ return 0;
}
static int process_message_reply(struct vhost_dev *dev,
@@ -459,6 +373,8 @@ static bool vhost_user_one_time_request(VhostUserRequest request)
case VHOST_USER_SET_MEM_TABLE:
case VHOST_USER_GET_QUEUE_NUM:
case VHOST_USER_NET_SET_MTU:
+ case VHOST_USER_ADD_MEM_REG:
+ case VHOST_USER_REM_MEM_REG:
return true;
default:
return false;
@@ -1807,7 +1723,9 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
return -ECONNREFUSED;
}
u->slave_ioc = ioc;
- slave_update_read_handler(dev, NULL);
+ u->slave_src = qio_channel_add_watch_source(u->slave_ioc,
+ G_IO_IN | G_IO_HUP,
+ slave_read, dev, NULL, NULL);
if (reply_supported) {
msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 23c470977e..1cd258135d 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -1366,7 +1366,8 @@ static const VMStateDescription vmstate_virtio_iommu = {
};
static Property virtio_iommu_properties[] = {
- DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *),
+ DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus,
+ TYPE_PCI_BUS, PCIBus *),
DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/include/exec/memory.h b/include/exec/memory.h
index c37ffdbcd1..2e602a2fad 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -129,6 +129,32 @@ struct IOMMUTLBEntry {
/*
* Bitmap for different IOMMUNotifier capabilities. Each notifier can
* register with one or multiple IOMMU Notifier capability bit(s).
+ *
+ * Normally there're two use cases for the notifiers:
+ *
+ * (1) When the device needs accurate synchronizations of the vIOMMU page
+ * tables, it needs to register with both MAP|UNMAP notifies (which
+ * is defined as IOMMU_NOTIFIER_IOTLB_EVENTS below).
+ *
+ * Regarding to accurate synchronization, it's when the notified
+ * device maintains a shadow page table and must be notified on each
+ * guest MAP (page table entry creation) and UNMAP (invalidation)
+ * events (e.g. VFIO). Both notifications must be accurate so that
+ * the shadow page table is fully in sync with the guest view.
+ *
+ * (2) When the device doesn't need accurate synchronizations of the
+ * vIOMMU page tables, it needs to register only with UNMAP or
+ * DEVIOTLB_UNMAP notifies.
+ *
+ * It's when the device maintains a cache of IOMMU translations
+ * (IOTLB) and is able to fill that cache by requesting translations
+ * from the vIOMMU through a protocol similar to ATS (Address
+ * Translation Service).
+ *
+ * Note that in this mode the vIOMMU will not maintain a shadowed
+ * page table for the address space, and the UNMAP messages can cover
+ * more than the pages that used to get mapped. The IOMMU notifiee
+ * should be able to take care of over-sized invalidations.
*/
typedef enum {
IOMMU_NOTIFIER_NONE = 0,
diff --git a/include/hw/acpi/acpi_aml_interface.h b/include/hw/acpi/acpi_aml_interface.h
index 436da069d6..11748a8866 100644
--- a/include/hw/acpi/acpi_aml_interface.h
+++ b/include/hw/acpi/acpi_aml_interface.h
@@ -3,6 +3,7 @@
#include "qom/object.h"
#include "hw/acpi/aml-build.h"
+#include "hw/qdev-core.h"
#define TYPE_ACPI_DEV_AML_IF "acpi-dev-aml-interface"
typedef struct AcpiDevAmlIfClass AcpiDevAmlIfClass;
@@ -46,4 +47,6 @@ static inline void call_dev_aml_func(DeviceState *dev, Aml *scope)
}
}
+void qbus_build_aml(BusState *bus, Aml *scope);
+
#endif
diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
index ea6056ab92..a1648220ff 100644
--- a/include/hw/acpi/acpi_dev_interface.h
+++ b/include/hw/acpi/acpi_dev_interface.h
@@ -52,8 +52,7 @@ struct AcpiDeviceIfClass {
/* <public> */
void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list);
void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev);
- void (*madt_cpu)(AcpiDeviceIf *adev, int uid,
- const CPUArchIdList *apic_ids, GArray *entry,
+ void (*madt_cpu)(int uid, const CPUArchIdList *apic_ids, GArray *entry,
bool force_enabled);
};
#endif
diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h
index b5deee0a9d..467a99461c 100644
--- a/include/hw/acpi/pci.h
+++ b/include/hw/acpi/pci.h
@@ -27,6 +27,7 @@
#define HW_ACPI_PCI_H
#include "hw/acpi/bios-linker-loader.h"
+#include "hw/acpi/acpi_aml_interface.h"
typedef struct AcpiMcfgInfo {
uint64_t base;
@@ -36,4 +37,7 @@ typedef struct AcpiMcfgInfo {
void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
const char *oem_id, const char *oem_table_id);
Aml *aml_pci_device_dsm(void);
+
+void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus);
+void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope);
#endif
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index 46d973e629..89dcbc5e1e 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -109,7 +109,43 @@ struct VTDAddressSpace {
QLIST_ENTRY(VTDAddressSpace) next;
/* Superset of notifier flags that this address space has */
IOMMUNotifierFlag notifier_flags;
- IOVATree *iova_tree; /* Traces mapped IOVA ranges */
+ /*
+ * @iova_tree traces mapped IOVA ranges.
+ *
+ * The tree is not needed if no MAP notifier is registered with current
+ * VTD address space, because all guest invalidate commands can be
+ * directly passed to the IOMMU UNMAP notifiers without any further
+ * reshuffling.
+ *
+ * The tree OTOH is required for MAP typed iommu notifiers for a few
+ * reasons.
+ *
+ * Firstly, there's no way to identify whether an PSI (Page Selective
+ * Invalidations) or DSI (Domain Selective Invalidations) event is an
+ * MAP or UNMAP event within the message itself. Without having prior
+ * knowledge of existing state vIOMMU doesn't know whether it should
+ * notify MAP or UNMAP for a PSI message it received when caching mode
+ * is enabled (for MAP notifiers).
+ *
+ * Secondly, PSI messages received from guest driver can be enlarged in
+ * range, covers but not limited to what the guest driver wanted to
+ * invalidate. When the range to invalidates gets bigger than the
+ * limit of a PSI message, it can even become a DSI which will
+ * invalidate the whole domain. If the vIOMMU directly notifies the
+ * registered device with the unmodified range, it may confuse the
+ * registered drivers (e.g. vfio-pci) on either:
+ *
+ * (1) Trying to map the same region more than once (for
+ * VFIO_IOMMU_MAP_DMA, -EEXIST will trigger), or,
+ *
+ * (2) Trying to UNMAP a range that is still partially mapped.
+ *
+ * That accuracy is not required for UNMAP-only notifiers, but it is a
+ * must-to-have for notifiers registered with MAP events, because the
+ * vIOMMU needs to make sure the shadow page table is always in sync
+ * with the guest IOMMU pgtables for a device.
+ */
+ IOVATree *iova_tree;
};
struct VTDIOTLBEntry {
diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h
index fad97a891d..e8af61f194 100644
--- a/include/hw/i386/microvm.h
+++ b/include/hw/i386/microvm.h
@@ -50,8 +50,9 @@
*/
/* Platform virtio definitions */
-#define VIRTIO_MMIO_BASE 0xfeb00000
-#define VIRTIO_CMDLINE_MAXLEN 64
+#define VIRTIO_MMIO_BASE 0xfeb00000
+#define VIRTIO_CMDLINE_MAXLEN 64
+#define VIRTIO_CMDLINE_TOTAL_MAX_LEN ((VIRTIO_CMDLINE_MAXLEN + 1) * 16)
#define GED_MMIO_BASE 0xfea00000
#define GED_MMIO_BASE_MEMHP (GED_MMIO_BASE + 0x100)
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 88a120bc23..66e3d059ef 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -9,7 +9,6 @@
#include "hw/block/flash.h"
#include "hw/i386/x86.h"
-#include "hw/acpi/acpi_dev_interface.h"
#include "hw/hotplug.h"
#include "qom/object.h"
#include "hw/i386/sgx-epc.h"
@@ -193,9 +192,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size);
/* hw/i386/acpi-common.c */
-void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
- const CPUArchIdList *apic_ids, GArray *entry,
- bool force_enabled);
+void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids,
+ GArray *entry, bool force_enabled);
/* sgx.c */
void pc_machine_init_sgx_epc(PCMachineState *pcms);
diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h
index 6c8a8a92cb..25acd5c34c 100644
--- a/include/hw/isa/isa.h
+++ b/include/hw/isa/isa.h
@@ -86,7 +86,6 @@ bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp);
ISADevice *isa_create_simple(ISABus *bus, const char *name);
ISADevice *isa_vga_init(ISABus *bus);
-void isa_build_aml(ISABus *bus, Aml *scope);
/**
* isa_register_ioport: Install an I/O port region on the ISA bus.
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index 2e503904dc..990dcdbb2e 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -140,6 +140,15 @@ void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
bool read_only);
/**
+ * fw_cfg_read_bytes_ptr:
+ * @s: fw_cfg device being modified
+ * @key: selector key value for new fw_cfg item
+ *
+ * Reads an existing fw_cfg data pointer.
+ */
+void *fw_cfg_read_bytes_ptr(FWCfgState *s, uint16_t key);
+
+/**
* fw_cfg_add_string:
* @s: fw_cfg device being modified
* @key: selector key value for new fw_cfg item
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 85ee458cd2..d5a40cd058 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -270,7 +270,7 @@ typedef void (*pci_bus_dev_fn)(PCIBus *b, PCIDevice *d, void *opaque);
typedef void (*pci_bus_fn)(PCIBus *b, void *opaque);
typedef void *(*pci_bus_ret_fn)(PCIBus *b, void *opaque);
-bool pci_bus_is_express(PCIBus *bus);
+bool pci_bus_is_express(const PCIBus *bus);
void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent,
const char *name,
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
index fd484afb30..6c40e3733f 100644
--- a/include/hw/pci/pcie_port.h
+++ b/include/hw/pci/pcie_port.h
@@ -63,7 +63,8 @@ struct PCIESlot {
/* Indicates whether any type of hot-plug is allowed on the slot */
bool hotplug;
- bool native_hotplug;
+ /* broken ACPI hotplug compat knob to preserve 6.1 ABI intact */
+ bool hide_native_hotplug_cap;
QLIST_ENTRY(PCIESlot) next;
};
diff --git a/python/qemu/machine/console_socket.py b/python/qemu/machine/console_socket.py
index 8c4ff598ad..4e28ba9bb2 100644
--- a/python/qemu/machine/console_socket.py
+++ b/python/qemu/machine/console_socket.py
@@ -68,7 +68,7 @@ class ConsoleSocket(socket.socket):
"""Kick off a thread to drain the socket."""
# Configure socket to not block and timeout.
# This allows our drain thread to not block
- # on recieve and exit smoothly.
+ # on receive and exit smoothly.
socket.socket.setblocking(self, False)
socket.socket.settimeout(self, 1)
drain_thread = threading.Thread(target=self._drain_fn)
diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py
index 748a0d807c..e57c254484 100644
--- a/python/qemu/machine/machine.py
+++ b/python/qemu/machine/machine.py
@@ -131,7 +131,7 @@ class QEMUMachine:
drain_console: bool = False,
console_log: Optional[str] = None,
log_dir: Optional[str] = None,
- qmp_timer: Optional[float] = None):
+ qmp_timer: Optional[float] = 30):
'''
Initialize a QEMUMachine
@@ -157,18 +157,14 @@ class QEMUMachine:
self._wrapper = wrapper
self._qmp_timer = qmp_timer
- self._name = name or f"qemu-{os.getpid()}-{id(self):02x}"
+ self._name = name or f"{id(self):x}"
+ self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None
self._temp_dir: Optional[str] = None
self._base_temp_dir = base_temp_dir
self._sock_dir = sock_dir
self._log_dir = log_dir
- if monitor_address is not None:
- self._monitor_address = monitor_address
- else:
- self._monitor_address = os.path.join(
- self.sock_dir, f"{self._name}-monitor.sock"
- )
+ self._monitor_address = monitor_address
self._console_log_path = console_log
if self._console_log_path:
@@ -192,7 +188,7 @@ class QEMUMachine:
self._console_set = False
self._console_device_type: Optional[str] = None
self._console_address = os.path.join(
- self.sock_dir, f"{self._name}-console.sock"
+ self.sock_dir, f"{self._name}.con"
)
self._console_socket: Optional[socket.socket] = None
self._remove_files: List[str] = []
@@ -303,7 +299,11 @@ class QEMUMachine:
args = ['-display', 'none', '-vga', 'none']
if self._qmp_set:
- if isinstance(self._monitor_address, tuple):
+ if self._sock_pair:
+ fd = self._sock_pair[0].fileno()
+ os.set_inheritable(fd, True)
+ moncdev = f"socket,id=mon,fd={fd}"
+ elif isinstance(self._monitor_address, tuple):
moncdev = "socket,id=mon,host={},port={}".format(
*self._monitor_address
)
@@ -337,10 +337,17 @@ class QEMUMachine:
self._remove_files.append(self._console_address)
if self._qmp_set:
+ monitor_address = None
+ sock = None
+ if self._monitor_address is None:
+ self._sock_pair = socket.socketpair()
+ sock = self._sock_pair[1]
if isinstance(self._monitor_address, str):
self._remove_files.append(self._monitor_address)
+ monitor_address = self._monitor_address
self._qmp_connection = QEMUMonitorProtocol(
- self._monitor_address,
+ address=monitor_address,
+ sock=sock,
server=True,
nickname=self._name
)
@@ -360,6 +367,8 @@ class QEMUMachine:
))
def _post_launch(self) -> None:
+ if self._sock_pair:
+ self._sock_pair[0].close()
if self._qmp_connection:
self._qmp.accept(self._qmp_timer)
diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py
index 1a1fc6c9b0..1c46138bd0 100644
--- a/python/qemu/machine/qtest.py
+++ b/python/qemu/machine/qtest.py
@@ -42,7 +42,7 @@ class QEMUQtestProtocol:
:raise socket.error: on socket connection errors
.. note::
- No conection is estabalished by __init__(), this is done
+ No connection is established by __init__(), this is done
by the connect() or accept() methods.
"""
def __init__(self, address: SocketAddrT,
diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py
index 1951754455..8b09ee7dbb 100644
--- a/python/qemu/qmp/legacy.py
+++ b/python/qemu/qmp/legacy.py
@@ -22,6 +22,7 @@ old interface.
#
import asyncio
+import socket
from types import TracebackType
from typing import (
Any,
@@ -69,22 +70,32 @@ class QEMUMonitorProtocol:
:param address: QEMU address, can be either a unix socket path (string)
or a tuple in the form ( address, port ) for a TCP
- connection
+ connection or None
+ :param sock: a socket or None
:param server: Act as the socket server. (See 'accept')
:param nickname: Optional nickname used for logging.
"""
- def __init__(self, address: SocketAddrT,
+ def __init__(self,
+ address: Optional[SocketAddrT] = None,
+ sock: Optional[socket.socket] = None,
server: bool = False,
nickname: Optional[str] = None):
+ assert address or sock
self._qmp = QMPClient(nickname)
self._aloop = asyncio.get_event_loop()
self._address = address
+ self._sock = sock
self._timeout: Optional[float] = None
if server:
- self._sync(self._qmp.start_server(self._address))
+ if sock:
+ assert self._sock is not None
+ self._sync(self._qmp.open_with_socket(self._sock))
+ else:
+ assert self._address is not None
+ self._sync(self._qmp.start_server(self._address))
_T = TypeVar('_T')
@@ -139,6 +150,7 @@ class QEMUMonitorProtocol:
:return: QMP greeting dict, or None if negotiate is false
:raise ConnectError: on connection errors
"""
+ assert self._address is not None
self._qmp.await_greeting = negotiate
self._qmp.negotiate = negotiate
diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py
index 6ea86650ad..6d3d739daa 100644
--- a/python/qemu/qmp/protocol.py
+++ b/python/qemu/qmp/protocol.py
@@ -18,6 +18,7 @@ from asyncio import StreamReader, StreamWriter
from enum import Enum
from functools import wraps
import logging
+import socket
from ssl import SSLContext
from typing import (
Any,
@@ -298,6 +299,19 @@ class AsyncProtocol(Generic[T]):
@upper_half
@require(Runstate.IDLE)
+ async def open_with_socket(self, sock: socket.socket) -> None:
+ """
+ Start connection with given socket.
+
+ :param sock: A socket.
+
+ :raise StateError: When the `Runstate` is not `IDLE`.
+ """
+ self._reader, self._writer = await asyncio.open_connection(sock=sock)
+ self._set_state(Runstate.CONNECTING)
+
+ @upper_half
+ @require(Runstate.IDLE)
async def start_server(self, address: SocketAddrT,
ssl: Optional[SSLContext] = None) -> None:
"""
@@ -343,11 +357,12 @@ class AsyncProtocol(Generic[T]):
protocol-level failure occurs while establishing a new
session, the wrapped error may also be an `QMPError`.
"""
- if self._accepted is None:
- raise QMPError("Cannot call accept() before start_server().")
- await self._session_guard(
- self._do_accept(),
- 'Failed to establish connection')
+ if not self._reader:
+ if self._accepted is None:
+ raise QMPError("Cannot call accept() before start_server().")
+ await self._session_guard(
+ self._do_accept(),
+ 'Failed to establish connection')
await self._session_guard(
self._establish_session(),
'Failed to establish session')
@@ -812,7 +827,7 @@ class AsyncProtocol(Generic[T]):
@bottom_half
async def _bh_close_stream(self, error_pathway: bool = False) -> None:
- # NB: Closing the writer also implcitly closes the reader.
+ # NB: Closing the writer also implicitly closes the reader.
if not self._writer:
return
diff --git a/python/qemu/qmp/qmp_client.py b/python/qemu/qmp/qmp_client.py
index 5dcda04a75..b5772e7f32 100644
--- a/python/qemu/qmp/qmp_client.py
+++ b/python/qemu/qmp/qmp_client.py
@@ -197,8 +197,8 @@ class QMPClient(AsyncProtocol[Message], Events):
#: Logger object used for debugging messages.
logger = logging.getLogger(__name__)
- # Read buffer limit; large enough to accept query-qmp-schema
- _limit = (256 * 1024)
+ # Read buffer limit; 10MB like libvirt default
+ _limit = (10 * 1024 * 1024)
# Type alias for pending execute() result items
_PendingT = Union[Message, ExecInterruptedError]
diff --git a/python/qemu/qmp/qmp_tui.py b/python/qemu/qmp/qmp_tui.py
index ce239d8979..8369144723 100644
--- a/python/qemu/qmp/qmp_tui.py
+++ b/python/qemu/qmp/qmp_tui.py
@@ -71,7 +71,7 @@ def format_json(msg: str) -> str:
due to an decoding error then a simple string manipulation is done to
achieve a single line JSON string.
- Converting into single line is more asthetically pleasing when looking
+ Converting into single line is more aesthetically pleasing when looking
along with error messages.
Eg:
@@ -91,7 +91,7 @@ def format_json(msg: str) -> str:
[1, true, 3]: QMP message is not a JSON object.
- The single line mode is more asthetically pleasing.
+ The single line mode is more aesthetically pleasing.
:param msg:
The message to formatted into single line.
@@ -498,7 +498,7 @@ class EditorWidget(urwid.Filler):
class HistoryBox(urwid.ListBox):
"""
This widget is modelled using the ListBox widget, contains the list of
- all messages both QMP messages and log messsages to be shown in the TUI.
+ all messages both QMP messages and log messages to be shown in the TUI.
The messages are urwid.Text widgets. On every append of a message, the
focus is shifted to the last appended message.
diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py
index 910f3ba1ea..25a546842f 100644
--- a/tests/avocado/avocado_qemu/__init__.py
+++ b/tests/avocado/avocado_qemu/__init__.py
@@ -306,7 +306,7 @@ class QemuSystemTest(QemuBaseTest):
self.cancel('no support for user networking')
def _new_vm(self, name, *args):
- self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_")
+ self._sd = tempfile.TemporaryDirectory(prefix="qemu_")
vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir,
sock_dir=self._sd.name, log_dir=self.logdir)
self.log.debug('QEMUMachine "%s" created', name)
diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT
index b688686dc3..0b475fb5a9 100644
--- a/tests/data/acpi/pc/DSDT
+++ b/tests/data/acpi/pc/DSDT
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst
index 86259be9d1..17ef7caeb6 100644
--- a/tests/data/acpi/pc/DSDT.acpierst
+++ b/tests/data/acpi/pc/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat
index e2cc2a6fc9..675b674eaa 100644
--- a/tests/data/acpi/pc/DSDT.acpihmat
+++ b/tests/data/acpi/pc/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge
index 75016fd4b7..c1ce061366 100644
--- a/tests/data/acpi/pc/DSDT.bridge
+++ b/tests/data/acpi/pc/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp
index 53eb0dd7d4..754ab854dc 100644
--- a/tests/data/acpi/pc/DSDT.cphp
+++ b/tests/data/acpi/pc/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm
index 9089d994e0..170503336b 100644
--- a/tests/data/acpi/pc/DSDT.dimmpxm
+++ b/tests/data/acpi/pc/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.hpbridge b/tests/data/acpi/pc/DSDT.hpbridge
index 86259be9d1..834c27002e 100644
--- a/tests/data/acpi/pc/DSDT.hpbridge
+++ b/tests/data/acpi/pc/DSDT.hpbridge
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.hpbrroot b/tests/data/acpi/pc/DSDT.hpbrroot
index 578468f4f0..a71ed4fbaa 100644
--- a/tests/data/acpi/pc/DSDT.hpbrroot
+++ b/tests/data/acpi/pc/DSDT.hpbrroot
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs
index 39427103aa..dd71356027 100644
--- a/tests/data/acpi/pc/DSDT.ipmikcs
+++ b/tests/data/acpi/pc/DSDT.ipmikcs
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp
index 987a263339..2f895e9b38 100644
--- a/tests/data/acpi/pc/DSDT.memhp
+++ b/tests/data/acpi/pc/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.nohpet b/tests/data/acpi/pc/DSDT.nohpet
index fc7598b762..c012b63ace 100644
--- a/tests/data/acpi/pc/DSDT.nohpet
+++ b/tests/data/acpi/pc/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem
index 85af400cdb..f2ef4b9729 100644
--- a/tests/data/acpi/pc/DSDT.numamem
+++ b/tests/data/acpi/pc/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp
index 545512adfa..657c8263f0 100644
--- a/tests/data/acpi/pc/DSDT.roothp
+++ b/tests/data/acpi/pc/DSDT.roothp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT
index 2771bcea89..d68c472b46 100644
--- a/tests/data/acpi/q35/DSDT
+++ b/tests/data/acpi/q35/DSDT
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst
index b45abca7c2..de7ae27125 100644
--- a/tests/data/acpi/q35/DSDT.acpierst
+++ b/tests/data/acpi/q35/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.acpihmat b/tests/data/acpi/q35/DSDT.acpihmat
index d90fd4723a..48e2862257 100644
--- a/tests/data/acpi/q35/DSDT.acpihmat
+++ b/tests/data/acpi/q35/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.acpihmat-noinitiator b/tests/data/acpi/q35/DSDT.acpihmat-noinitiator
index 279fafa821..30a4aa2ec8 100644
--- a/tests/data/acpi/q35/DSDT.acpihmat-noinitiator
+++ b/tests/data/acpi/q35/DSDT.acpihmat-noinitiator
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.applesmc b/tests/data/acpi/q35/DSDT.applesmc
index fdf6d14428..84e2b5cbc4 100644
--- a/tests/data/acpi/q35/DSDT.applesmc
+++ b/tests/data/acpi/q35/DSDT.applesmc
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge
index b41a4dddc0..e411d40fd1 100644
--- a/tests/data/acpi/q35/DSDT.bridge
+++ b/tests/data/acpi/q35/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.core-count2 b/tests/data/acpi/q35/DSDT.core-count2
index 375aceed6b..0603db8cc6 100644
--- a/tests/data/acpi/q35/DSDT.core-count2
+++ b/tests/data/acpi/q35/DSDT.core-count2
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp
index a0ecafc36c..beeb83c33b 100644
--- a/tests/data/acpi/q35/DSDT.cphp
+++ b/tests/data/acpi/q35/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.cxl b/tests/data/acpi/q35/DSDT.cxl
index f9c6dd4ee0..3d18b9672d 100644
--- a/tests/data/acpi/q35/DSDT.cxl
+++ b/tests/data/acpi/q35/DSDT.cxl
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm
index f0659716e3..99a93e12a7 100644
--- a/tests/data/acpi/q35/DSDT.dimmpxm
+++ b/tests/data/acpi/q35/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt
index 9c52529919..7f7601dbff 100644
--- a/tests/data/acpi/q35/DSDT.ipmibt
+++ b/tests/data/acpi/q35/DSDT.ipmibt
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.ipmismbus b/tests/data/acpi/q35/DSDT.ipmismbus
index 3f32dffdbf..6c5d1afe44 100644
--- a/tests/data/acpi/q35/DSDT.ipmismbus
+++ b/tests/data/acpi/q35/DSDT.ipmismbus
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.ivrs b/tests/data/acpi/q35/DSDT.ivrs
index b45abca7c2..de7ae27125 100644
--- a/tests/data/acpi/q35/DSDT.ivrs
+++ b/tests/data/acpi/q35/DSDT.ivrs
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp
index 28a192c69a..79bce5c8f0 100644
--- a/tests/data/acpi/q35/DSDT.memhp
+++ b/tests/data/acpi/q35/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64
index 8fda921296..c249929add 100644
--- a/tests/data/acpi/q35/DSDT.mmio64
+++ b/tests/data/acpi/q35/DSDT.mmio64
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.multi-bridge b/tests/data/acpi/q35/DSDT.multi-bridge
index 3dba4d8436..66b39be294 100644
--- a/tests/data/acpi/q35/DSDT.multi-bridge
+++ b/tests/data/acpi/q35/DSDT.multi-bridge
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.nohpet b/tests/data/acpi/q35/DSDT.nohpet
index b116947dac..9ff9983a80 100644
--- a/tests/data/acpi/q35/DSDT.nohpet
+++ b/tests/data/acpi/q35/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.numamem b/tests/data/acpi/q35/DSDT.numamem
index 5eb6159d5f..1e7c45ef3c 100644
--- a/tests/data/acpi/q35/DSDT.numamem
+++ b/tests/data/acpi/q35/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.pvpanic-isa b/tests/data/acpi/q35/DSDT.pvpanic-isa
index 908e7b6606..ed47451c44 100644
--- a/tests/data/acpi/q35/DSDT.pvpanic-isa
+++ b/tests/data/acpi/q35/DSDT.pvpanic-isa
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.tis.tpm12 b/tests/data/acpi/q35/DSDT.tis.tpm12
index ce2c2c29c2..efc2efc19f 100644
--- a/tests/data/acpi/q35/DSDT.tis.tpm12
+++ b/tests/data/acpi/q35/DSDT.tis.tpm12
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.tis.tpm2 b/tests/data/acpi/q35/DSDT.tis.tpm2
index e9e4b7f6ed..675339715f 100644
--- a/tests/data/acpi/q35/DSDT.tis.tpm2
+++ b/tests/data/acpi/q35/DSDT.tis.tpm2
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.viot b/tests/data/acpi/q35/DSDT.viot
index 6b436f9cd9..eeb40b360f 100644
--- a/tests/data/acpi/q35/DSDT.viot
+++ b/tests/data/acpi/q35/DSDT.viot
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.xapic b/tests/data/acpi/q35/DSDT.xapic
index f47f091222..3aa86f0724 100644
--- a/tests/data/acpi/q35/DSDT.xapic
+++ b/tests/data/acpi/q35/DSDT.xapic
Binary files differ
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 355d0c3d56..d8c8cda58e 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -750,9 +750,9 @@ static void test_smbios_structs(test_data *data, SmbiosEntryPointType ep_type)
}
}
-static void test_acpi_load_tables(test_data *data, bool use_uefi)
+static void test_acpi_load_tables(test_data *data)
{
- if (use_uefi) {
+ if (data->uefi_fl1 && data->uefi_fl2) { /* use UEFI */
g_assert(data->scan_len);
data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts,
data->ram_start, data->scan_len);
@@ -768,12 +768,11 @@ static void test_acpi_load_tables(test_data *data, bool use_uefi)
test_acpi_fadt_table(data);
}
-static char *test_acpi_create_args(test_data *data, const char *params,
- bool use_uefi)
+static char *test_acpi_create_args(test_data *data, const char *params)
{
char *args;
- if (use_uefi) {
+ if (data->uefi_fl1 && data->uefi_fl2) { /* use UEFI */
/*
* TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3)
* when arm/virt boad starts to support it.
@@ -808,14 +807,16 @@ static char *test_acpi_create_args(test_data *data, const char *params,
return args;
}
-static void test_acpi_one(const char *params, test_data *data)
+static void test_vm_prepare(const char *params, test_data *data)
{
- char *args;
- bool use_uefi = data->uefi_fl1 && data->uefi_fl2;
-
- args = test_acpi_create_args(data, params, use_uefi);
+ char *args = test_acpi_create_args(data, params);
data->qts = qtest_init(args);
- test_acpi_load_tables(data, use_uefi);
+ g_free(args);
+}
+
+static void process_acpi_tables_noexit(test_data *data)
+{
+ test_acpi_load_tables(data);
if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
dump_aml_files(data, true);
@@ -828,13 +829,22 @@ static void test_acpi_one(const char *params, test_data *data)
* Bug on uefi-test-tools to provide entry point:
* https://bugs.launchpad.net/qemu/+bug/1821884
*/
- if (!use_uefi) {
+ if (!(data->uefi_fl1 && data->uefi_fl2)) {
SmbiosEntryPointType ep_type = test_smbios_entry_point(data);
test_smbios_structs(data, ep_type);
}
+}
+static void process_acpi_tables(test_data *data)
+{
+ process_acpi_tables_noexit(data);
qtest_quit(data->qts);
- g_free(args);
+}
+
+static void test_acpi_one(const char *params, test_data *data)
+{
+ test_vm_prepare(params, data);
+ process_acpi_tables(data);
}
static uint8_t base_required_struct_types[] = {
@@ -865,7 +875,32 @@ static void test_acpi_piix4_tcg_bridge(void)
data.variant = ".bridge";
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
- test_acpi_one("-device pci-bridge,chassis_nr=1", &data);
+ test_vm_prepare("-S"
+ " -device pci-bridge,chassis_nr=1"
+ " -device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2"
+ " -device pci-testdev,bus=pci.0,addr=5.0"
+ " -device pci-testdev,bus=pci.1", &data);
+
+ /* hotplugged bridges section */
+ qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr",
+ "{'bus': 'pci.1', 'addr': '2.0', 'chassis_nr': 3 }");
+ qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr_multifunc",
+ "{'bus': 'pci.1', 'addr': '0xf.1', 'chassis_nr': 4 }");
+ qtest_qmp_device_add(data.qts, "pci-bridge", "hpbrhost",
+ "{'bus': 'pci.0', 'addr': '4.0', 'chassis_nr': 5 }");
+ qtest_qmp_device_add(data.qts, "pci-testdev", "d1", "{'bus': 'pci.0' }");
+ qtest_qmp_device_add(data.qts, "pci-testdev", "d2", "{'bus': 'pci.1' }");
+ qtest_qmp_device_add(data.qts, "pci-testdev", "d3", "{'bus': 'hpbr', "
+ "'addr': '1.0' }");
+ qtest_qmp_send(data.qts, "{'execute':'cont' }");
+ qtest_qmp_eventwait(data.qts, "RESUME");
+
+ process_acpi_tables_noexit(&data);
+ free_test_data(&data);
+
+ /* check that reboot/reset doesn't change any ACPI tables */
+ qtest_qmp_send(data.qts, "{'execute':'system_reset' }");
+ process_acpi_tables(&data);
free_test_data(&data);
}
@@ -879,7 +914,10 @@ static void test_acpi_piix4_no_root_hotplug(void)
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off "
- "-device pci-bridge,chassis_nr=1", &data);
+ "-device pci-bridge,chassis_nr=1 "
+ "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 "
+ "-device pci-testdev,bus=pci.0 "
+ "-device pci-testdev,bus=pci.1", &data);
free_test_data(&data);
}
@@ -893,7 +931,10 @@ static void test_acpi_piix4_no_bridge_hotplug(void)
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off "
- "-device pci-bridge,chassis_nr=1", &data);
+ "-device pci-bridge,chassis_nr=1 "
+ "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 "
+ "-device pci-testdev,bus=pci.0 "
+ "-device pci-testdev,bus=pci.1,addr=2.0", &data);
free_test_data(&data);
}
@@ -908,7 +949,9 @@ static void test_acpi_piix4_no_acpi_pci_hotplug(void)
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off "
"-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off "
- "-device pci-bridge,chassis_nr=1", &data);
+ "-device pci-bridge,chassis_nr=1 "
+ "-device pci-testdev,bus=pci.0 "
+ "-device pci-testdev,bus=pci.1", &data);
free_test_data(&data);
}
@@ -953,8 +996,9 @@ static void test_acpi_q35_tcg_bridge(void)
data.variant = ".bridge";
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
- test_acpi_one("-device pci-bridge,chassis_nr=1",
- &data);
+ test_acpi_one("-device pci-bridge,chassis_nr=1,id=br1"
+ " -device pci-testdev,bus=pcie.0"
+ " -device pci-testdev,bus=br1", &data);
free_test_data(&data);
}
@@ -964,14 +1008,41 @@ static void test_acpi_q35_multif_bridge(void)
.machine = MACHINE_Q35,
.variant = ".multi-bridge",
};
- test_acpi_one("-device pcie-root-port,id=pcie-root-port-0,"
- "multifunction=on,"
- "port=0x0,chassis=1,addr=0x2,bus=pcie.0 "
- "-device pcie-root-port,id=pcie-root-port-1,"
- "port=0x1,chassis=2,addr=0x3.0x1,bus=pcie.0 "
- "-device virtio-balloon,id=balloon0,"
- "bus=pcie.0,addr=0x4.0x2",
- &data);
+ test_vm_prepare("-S"
+ " -device virtio-balloon,id=balloon0,addr=0x4.0x2"
+ " -device pcie-root-port,id=rp0,multifunction=on,"
+ "port=0x0,chassis=1,addr=0x2"
+ " -device pcie-root-port,id=rp1,port=0x1,chassis=2,addr=0x3.0x1"
+ " -device pcie-root-port,id=rp2,port=0x0,chassis=3,bus=rp1,addr=0.0"
+ " -device pci-bridge,bus=rp2,chassis_nr=4,id=br1"
+ " -device pcie-root-port,id=rphptgt1,port=0x0,chassis=5,addr=2.1"
+ " -device pcie-root-port,id=rphptgt2,port=0x0,chassis=6,addr=2.2"
+ " -device pcie-root-port,id=rphptgt3,port=0x0,chassis=7,addr=2.3"
+ " -device pci-testdev,bus=pcie.0,addr=2.4"
+ " -device pci-testdev,bus=pcie.0,addr=5.0"
+ " -device pci-testdev,bus=rp0,addr=0.0"
+ " -device pci-testdev,bus=br1", &data);
+
+ /* hotplugged bridges section */
+ qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr1",
+ "{'bus': 'br1', 'addr': '6.0', 'chassis_nr': 128 }");
+ qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr2-multiif",
+ "{ 'bus': 'br1', 'addr': '2.2', 'chassis_nr': 129 }");
+ qtest_qmp_device_add(data.qts, "pcie-pci-bridge", "hpbr3",
+ "{'bus': 'rphptgt1', 'addr': '0.0' }");
+ qtest_qmp_device_add(data.qts, "pcie-root-port", "hprp",
+ "{'bus': 'rphptgt2', 'addr': '0.0' }");
+ qtest_qmp_device_add(data.qts, "pci-testdev", "hpnic",
+ "{'bus': 'rphptgt3', 'addr': '0.0' }");
+ qtest_qmp_send(data.qts, "{'execute':'cont' }");
+ qtest_qmp_eventwait(data.qts, "RESUME");
+
+ process_acpi_tables_noexit(&data);
+ free_test_data(&data);
+
+ /* check that reboot/reset doesn't change any ACPI tables */
+ qtest_qmp_send(data.qts, "{'execute':'system_reset' }");
+ process_acpi_tables(&data);
free_test_data(&data);
}
@@ -1900,10 +1971,9 @@ static void test_acpi_piix4_oem_fields(void)
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
- args = test_acpi_create_args(&data,
- OEM_TEST_ARGS, false);
+ args = test_acpi_create_args(&data, OEM_TEST_ARGS);
data.qts = qtest_init(args);
- test_acpi_load_tables(&data, false);
+ test_acpi_load_tables(&data);
test_oem_fields(&data);
qtest_quit(data.qts);
free_test_data(&data);
@@ -1920,10 +1990,9 @@ static void test_acpi_q35_oem_fields(void)
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
- args = test_acpi_create_args(&data,
- OEM_TEST_ARGS, false);
+ args = test_acpi_create_args(&data, OEM_TEST_ARGS);
data.qts = qtest_init(args);
- test_acpi_load_tables(&data, false);
+ test_acpi_load_tables(&data);
test_oem_fields(&data);
qtest_quit(data.qts);
free_test_data(&data);
@@ -1938,9 +2007,9 @@ static void test_acpi_microvm_oem_fields(void)
test_acpi_microvm_prepare(&data);
args = test_acpi_create_args(&data,
- OEM_TEST_ARGS",acpi=on", false);
+ OEM_TEST_ARGS",acpi=on");
data.qts = qtest_init(args);
- test_acpi_load_tables(&data, false);
+ test_acpi_load_tables(&data);
test_oem_fields(&data);
qtest_quit(data.qts);
free_test_data(&data);
@@ -1960,10 +2029,9 @@ static void test_acpi_virt_oem_fields(void)
};
char *args;
- args = test_acpi_create_args(&data,
- "-cpu cortex-a57 "OEM_TEST_ARGS, true);
+ args = test_acpi_create_args(&data, "-cpu cortex-a57 "OEM_TEST_ARGS);
data.qts = qtest_init(args);
- test_acpi_load_tables(&data, true);
+ test_acpi_load_tables(&data);
test_oem_fields(&data);
qtest_quit(data.qts);
free_test_data(&data);
diff --git a/tests/qtest/boot-sector.c b/tests/qtest/boot-sector.c
index 44a109abd8..679ee17e2a 100644
--- a/tests/qtest/boot-sector.c
+++ b/tests/qtest/boot-sector.c
@@ -153,6 +153,8 @@ void boot_sector_test(QTestState *qts)
signature_high = qtest_readb(qts, SIGNATURE_ADDR + 1);
signature = (signature_high << 8) | signature_low;
if (signature == SIGNATURE) {
+ /* wipe signature */
+ qtest_writeb(qts, SIGNATURE_ADDR, 0x00);
break;
}
@@ -160,7 +162,9 @@ void boot_sector_test(QTestState *qts)
qrsp = qtest_qmp(qts, "{ 'execute': 'query-status' }");
qret = qdict_get_qdict(qrsp, "return");
g_assert_nonnull(qret);
- g_assert_cmpstr(qdict_get_try_str(qret, "status"), ==, "running");
+ if (qdict_get_try_str(qret, "status")) {
+ g_assert_cmpstr(qdict_get_try_str(qret, "status"), ==, "running");
+ }
qobject_unref(qrsp);
g_usleep(TEST_DELAY);
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 6b2216cb20..d658222a19 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -1435,6 +1435,10 @@ void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv,
resp = qtest_qmp(qts, "{'execute': 'device_add', 'arguments': %p}", args);
g_assert(resp);
g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */
+ if (qdict_haskey(resp, "error")) {
+ fprintf(stderr, "error: %s\n",
+ qdict_get_str(qdict_get_qdict(resp, "error"), "desc"));
+ }
g_assert(!qdict_haskey(resp, "error"));
qobject_unref(resp);
}