aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/interop/vhost-user.rst24
-rw-r--r--hw/acpi/acpi_generic_initiator.c148
-rw-r--r--hw/acpi/aml-build.c83
-rw-r--r--hw/acpi/cpu.c53
-rw-r--r--hw/acpi/generic_event_device.c19
-rw-r--r--hw/acpi/meson.build1
-rw-r--r--hw/acpi/pci.c242
-rw-r--r--hw/arm/virt-acpi-build.c3
-rw-r--r--hw/block/vhost-user-blk.c27
-rw-r--r--hw/core/machine.c4
-rw-r--r--hw/cxl/cxl-mailbox-utils.c111
-rw-r--r--hw/i386/acpi-build.c15
-rw-r--r--hw/i386/amd_iommu.c98
-rw-r--r--hw/i386/amd_iommu.h5
-rw-r--r--hw/i386/intel_iommu.c96
-rw-r--r--hw/i386/intel_iommu_internal.h16
-rw-r--r--hw/i386/pc.c1
-rw-r--r--hw/mem/cxl_type3.c21
-rw-r--r--hw/pci-bridge/cxl_downstream.c23
-rw-r--r--hw/pci-bridge/cxl_root_port.c5
-rw-r--r--hw/pci-bridge/cxl_upstream.c6
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c27
-rw-r--r--hw/pci-host/gpex-acpi.c5
-rw-r--r--hw/pci/pci.c16
-rw-r--r--hw/pci/pci_bridge.c5
-rw-r--r--hw/pci/pcie.c113
-rw-r--r--hw/virtio/vhost-user.c59
-rw-r--r--hw/virtio/virtio-pci.c19
-rw-r--r--include/exec/memory.h9
-rw-r--r--include/hw/acpi/acpi_generic_initiator.h47
-rw-r--r--include/hw/acpi/aml-build.h7
-rw-r--r--include/hw/acpi/pci.h3
-rw-r--r--include/hw/core/cpu.h2
-rw-r--r--include/hw/cxl/cxl_device.h40
-rw-r--r--include/hw/i386/intel_iommu.h3
-rw-r--r--include/hw/pci-bridge/cxl_upstream_port.h4
-rw-r--r--include/hw/pci/pci.h4
-rw-r--r--include/hw/pci/pci_bridge.h3
-rw-r--r--include/hw/pci/pci_device.h6
-rw-r--r--include/hw/pci/pcie.h2
-rw-r--r--include/hw/qdev-core.h6
-rw-r--r--include/hw/virtio/vhost-user.h1
-rw-r--r--include/hw/virtio/virtio-pci.h3
-rw-r--r--qapi/qdev.json24
-rw-r--r--qapi/qom.json41
-rw-r--r--system/qdev-monitor.c53
-rwxr-xr-xtests/data/acpi/disassemle-aml.sh2
-rw-r--r--tests/data/acpi/x86/pc/DSDTbin8527 -> 8560 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.acpierstbin8438 -> 8471 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.acpihmatbin9852 -> 9885 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.bridgebin15398 -> 15431 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.cphpbin8991 -> 9024 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.dimmpxmbin10181 -> 10214 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.hpbridgebin8478 -> 8511 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.hpbrrootbin5034 -> 5067 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.ipmikcsbin8599 -> 8632 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.memhpbin9886 -> 9919 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.nohpetbin8385 -> 8418 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.numamembin8533 -> 8566 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.roothpbin12320 -> 12353 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDTbin8355 -> 8389 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.acpierstbin8372 -> 8406 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.acpihmatbin9680 -> 9714 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiatorbin8634 -> 8668 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.applesmcbin8401 -> 8435 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.bridgebin11968 -> 12002 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.core-countbin12913 -> 12947 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.core-count2bin33770 -> 33804 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.cphpbin8819 -> 8853 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.cxlbin13148 -> 13180 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.dimmpxmbin10009 -> 10043 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.ipmibtbin8430 -> 8464 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.ipmismbusbin8443 -> 8477 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.ivrsbin8372 -> 8406 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.memhpbin9714 -> 9748 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.mmio64bin9485 -> 9519 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.multi-bridgebin13208 -> 13242 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.noacpihpbin8235 -> 8269 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.nohpetbin8213 -> 8247 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.numamembin8361 -> 8395 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.pvpanic-isabin8456 -> 8490 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.thread-countbin12913 -> 12947 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.thread-count2bin33770 -> 33804 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.tis.tpm12bin8961 -> 8995 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.tis.tpm2bin8987 -> 9021 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.type4-countbin18589 -> 18623 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.viotbin14615 -> 14646 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.xapicbin35718 -> 35752 bytes
-rw-r--r--tests/qtest/fuzz-virtio-balloon-test.c37
-rw-r--r--tests/qtest/meson.build1
90 files changed, 1117 insertions, 426 deletions
diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index d8419fd2f1..2e50f2ddfa 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -167,6 +167,8 @@ A vring address description
Note that a ring address is an IOVA if ``VIRTIO_F_IOMMU_PLATFORM`` has
been negotiated. Otherwise it is a user address.
+.. _memory_region_description:
+
Memory region description
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -180,7 +182,7 @@ Memory region description
:user address: a 64-bit user address
-:mmap offset: 64-bit offset where region starts in the mapped memory
+:mmap offset: a 64-bit offset where region starts in the mapped memory
When the ``VHOST_USER_PROTOCOL_F_XEN_MMAP`` protocol feature has been
successfully negotiated, the memory region description contains two extra
@@ -190,7 +192,7 @@ fields at the end.
| guest address | size | user address | mmap offset | xen mmap flags | domid |
+---------------+------+--------------+-------------+----------------+-------+
-:xen mmap flags: 32-bit bit field
+:xen mmap flags: a 32-bit bit field
- Bit 0 is set for Xen foreign memory mapping.
- Bit 1 is set for Xen grant memory mapping.
@@ -211,7 +213,7 @@ Single memory region description
:padding: 64-bit
-A region is represented by Memory region description.
+:region: region is represented by :ref:`Memory region description <memory_region_description>`.
Multiple Memory regions description
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -224,7 +226,7 @@ Multiple Memory regions description
:padding: 32-bit
-A region is represented by Memory region description.
+:regions: regions field contains 8 regions of type :ref:`Memory region description <memory_region_description>`.
Log description
^^^^^^^^^^^^^^^
@@ -233,9 +235,9 @@ Log description
| log size | log offset |
+----------+------------+
-:log size: size of area used for logging
+:log size: a 64-bit size of area used for logging
-:log offset: offset from start of supplied file descriptor where
+:log offset: a 64-bit offset from start of supplied file descriptor where
logging starts (i.e. where guest address 0 would be
logged)
@@ -382,7 +384,7 @@ the kernel implementation.
The communication consists of the *front-end* sending message requests and
the *back-end* sending message replies. Most of the requests don't require
-replies. Here is a list of the ones that do:
+replies, except for the following requests:
* ``VHOST_USER_GET_FEATURES``
* ``VHOST_USER_GET_PROTOCOL_FEATURES``
@@ -1239,11 +1241,11 @@ Front-end message types
(*a vring descriptor index for split virtqueues* vs. *vring descriptor
indices for packed virtqueues*).
- When and as long as all of a device’s vrings are stopped, it is
+ When and as long as all of a device's vrings are stopped, it is
*suspended*, see :ref:`Suspended device state
<suspended_device_state>`.
- The request payload’s *num* field is currently reserved and must be
+ The request payload's *num* field is currently reserved and must be
set to 0.
``VHOST_USER_SET_VRING_KICK``
@@ -1662,7 +1664,7 @@ Front-end message types
:reply payload: ``u64``
Front-end and back-end negotiate a channel over which to transfer the
- back-end’s internal state during migration. Either side (front-end or
+ back-end's internal state during migration. Either side (front-end or
back-end) may create the channel. The nature of this channel is not
restricted or defined in this document, but whichever side creates it
must create a file descriptor that is provided to the respectively
@@ -1714,7 +1716,7 @@ Front-end message types
:request payload: N/A
:reply payload: ``u64``
- After transferring the back-end’s internal state during migration (see
+ After transferring the back-end's internal state during migration (see
the :ref:`Migrating back-end state <migrating_backend_state>`
section), check whether the back-end was able to successfully fully
process the state.
diff --git a/hw/acpi/acpi_generic_initiator.c b/hw/acpi/acpi_generic_initiator.c
deleted file mode 100644
index 17b9a052f5..0000000000
--- a/hw/acpi/acpi_generic_initiator.c
+++ /dev/null
@@ -1,148 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved
- */
-
-#include "qemu/osdep.h"
-#include "hw/acpi/acpi_generic_initiator.h"
-#include "hw/acpi/aml-build.h"
-#include "hw/boards.h"
-#include "hw/pci/pci_device.h"
-#include "qemu/error-report.h"
-
-typedef struct AcpiGenericInitiatorClass {
- ObjectClass parent_class;
-} AcpiGenericInitiatorClass;
-
-OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator,
- ACPI_GENERIC_INITIATOR, OBJECT,
- { TYPE_USER_CREATABLE },
- { NULL })
-
-OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR)
-
-static void acpi_generic_initiator_init(Object *obj)
-{
- AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
-
- gi->node = MAX_NODES;
- gi->pci_dev = NULL;
-}
-
-static void acpi_generic_initiator_finalize(Object *obj)
-{
- AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
-
- g_free(gi->pci_dev);
-}
-
-static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val,
- Error **errp)
-{
- AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
-
- gi->pci_dev = g_strdup(val);
-}
-
-static void acpi_generic_initiator_set_node(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
- MachineState *ms = MACHINE(qdev_get_machine());
- uint32_t value;
-
- if (!visit_type_uint32(v, name, &value, errp)) {
- return;
- }
-
- if (value >= MAX_NODES) {
- error_printf("%s: Invalid NUMA node specified\n",
- TYPE_ACPI_GENERIC_INITIATOR);
- exit(1);
- }
-
- gi->node = value;
- ms->numa_state->nodes[gi->node].has_gi = true;
-}
-
-static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data)
-{
- object_class_property_add_str(oc, "pci-dev", NULL,
- acpi_generic_initiator_set_pci_device);
- object_class_property_add(oc, "node", "int", NULL,
- acpi_generic_initiator_set_node, NULL, NULL);
-}
-
-/*
- * ACPI 6.3:
- * Table 5-78 Generic Initiator Affinity Structure
- */
-static void
-build_srat_generic_pci_initiator_affinity(GArray *table_data, int node,
- PCIDeviceHandle *handle)
-{
- uint8_t index;
-
- build_append_int_noprefix(table_data, 5, 1); /* Type */
- build_append_int_noprefix(table_data, 32, 1); /* Length */
- build_append_int_noprefix(table_data, 0, 1); /* Reserved */
- build_append_int_noprefix(table_data, 1, 1); /* Device Handle Type: PCI */
- build_append_int_noprefix(table_data, node, 4); /* Proximity Domain */
-
- /* Device Handle - PCI */
- build_append_int_noprefix(table_data, handle->segment, 2);
- build_append_int_noprefix(table_data, handle->bdf, 2);
- for (index = 0; index < 12; index++) {
- build_append_int_noprefix(table_data, 0, 1);
- }
-
- build_append_int_noprefix(table_data, GEN_AFFINITY_ENABLED, 4); /* Flags */
- build_append_int_noprefix(table_data, 0, 4); /* Reserved */
-}
-
-static int build_all_acpi_generic_initiators(Object *obj, void *opaque)
-{
- MachineState *ms = MACHINE(qdev_get_machine());
- AcpiGenericInitiator *gi;
- GArray *table_data = opaque;
- PCIDeviceHandle dev_handle;
- PCIDevice *pci_dev;
- Object *o;
-
- if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
- return 0;
- }
-
- gi = ACPI_GENERIC_INITIATOR(obj);
- if (gi->node >= ms->numa_state->num_nodes) {
- error_printf("%s: Specified node %d is invalid.\n",
- TYPE_ACPI_GENERIC_INITIATOR, gi->node);
- exit(1);
- }
-
- o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
- if (!o) {
- error_printf("%s: Specified device must be a PCI device.\n",
- TYPE_ACPI_GENERIC_INITIATOR);
- exit(1);
- }
-
- pci_dev = PCI_DEVICE(o);
-
- dev_handle.segment = 0;
- dev_handle.bdf = PCI_BUILD_BDF(pci_bus_num(pci_get_bus(pci_dev)),
- pci_dev->devfn);
-
- build_srat_generic_pci_initiator_affinity(table_data,
- gi->node, &dev_handle);
-
- return 0;
-}
-
-void build_srat_generic_pci_initiator(GArray *table_data)
-{
- object_child_foreach_recursive(object_get_root(),
- build_all_acpi_generic_initiators,
- table_data);
-}
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 34e0ddbde8..6a76626177 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1938,6 +1938,89 @@ void build_srat_memory(GArray *table_data, uint64_t base,
}
/*
+ * ACPI Spec Revision 6.3
+ * Table 5-80 Device Handle - PCI
+ */
+static void build_append_srat_pci_device_handle(GArray *table_data,
+ uint16_t segment,
+ uint8_t bus, uint8_t devfn)
+{
+ /* PCI segment number */
+ build_append_int_noprefix(table_data, segment, 2);
+ /* PCI Bus Device Function */
+ build_append_int_noprefix(table_data, bus, 1);
+ build_append_int_noprefix(table_data, devfn, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 12);
+}
+
+static void build_append_srat_acpi_device_handle(GArray *table_data,
+ const char *hid,
+ uint32_t uid)
+{
+ assert(strlen(hid) == 8);
+ /* Device Handle - ACPI */
+ for (int i = 0; i < sizeof(hid); i++) {
+ build_append_int_noprefix(table_data, hid[i], 1);
+ }
+ build_append_int_noprefix(table_data, uid, 4);
+ build_append_int_noprefix(table_data, 0, 4);
+}
+
+/*
+ * ACPI spec, Revision 6.3
+ * 5.2.16.6 Generic Initiator Affinity Structure
+ * With PCI Device Handle.
+ */
+void build_srat_pci_generic_initiator(GArray *table_data, uint32_t node,
+ uint16_t segment, uint8_t bus,
+ uint8_t devfn)
+{
+ /* Type */
+ build_append_int_noprefix(table_data, 5, 1);
+ /* Length */
+ build_append_int_noprefix(table_data, 32, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 1);
+ /* Device Handle Type: PCI */
+ build_append_int_noprefix(table_data, 1, 1);
+ /* Proximity Domain */
+ build_append_int_noprefix(table_data, node, 4);
+ /* Device Handle */
+ build_append_srat_pci_device_handle(table_data, segment, bus, devfn);
+ /* Flags - GI Enabled */
+ build_append_int_noprefix(table_data, 1, 4);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+}
+
+/*
+ * ACPI spec, Revision 6.5
+ * 5.2.16.7 Generic Port Affinity Structure
+ * With ACPI Device Handle.
+ */
+void build_srat_acpi_generic_port(GArray *table_data, uint32_t node,
+ const char *hid, uint32_t uid)
+{
+ /* Type */
+ build_append_int_noprefix(table_data, 6, 1);
+ /* Length */
+ build_append_int_noprefix(table_data, 32, 1);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 1);
+ /* Device Handle Type: ACPI */
+ build_append_int_noprefix(table_data, 0, 1);
+ /* Proximity Domain */
+ build_append_int_noprefix(table_data, node, 4);
+ /* Device Handle */
+ build_append_srat_acpi_device_handle(table_data, hid, uid);
+ /* Flags - GP Enabled */
+ build_append_int_noprefix(table_data, 1, 4);
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+}
+
+/*
* ACPI spec 5.2.17 System Locality Distance Information Table
* (Revision 2.0 or later)
*/
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 5cb60ca8bc..23443f09a5 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -50,6 +50,18 @@ void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list)
}
}
+static bool check_cpu_enabled_status(DeviceState *dev)
+{
+ CPUClass *k = dev ? CPU_GET_CLASS(dev) : NULL;
+ CPUState *cpu = CPU(dev);
+
+ if (cpu && (!k->cpu_enabled_status || k->cpu_enabled_status(cpu))) {
+ return true;
+ }
+
+ return false;
+}
+
static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
{
uint64_t val = 0;
@@ -63,10 +75,11 @@ static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
cdev = &cpu_st->devs[cpu_st->selector];
switch (addr) {
case ACPI_CPU_FLAGS_OFFSET_RW: /* pack and return is_* fields */
- val |= cdev->cpu ? 1 : 0;
+ val |= check_cpu_enabled_status(DEVICE(cdev->cpu)) ? 1 : 0;
val |= cdev->is_inserting ? 2 : 0;
val |= cdev->is_removing ? 4 : 0;
val |= cdev->fw_remove ? 16 : 0;
+ val |= cdev->cpu ? 32 : 0;
trace_cpuhp_acpi_read_flags(cpu_st->selector, val);
break;
case ACPI_CPU_CMD_DATA_OFFSET_RW:
@@ -233,6 +246,17 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
memory_region_add_subregion(as, base_addr, &state->ctrl_reg);
}
+static bool should_remain_acpi_present(DeviceState *dev)
+{
+ CPUClass *k = CPU_GET_CLASS(dev);
+ /*
+ * A system may contain CPUs that are always present on one die, NUMA node,
+ * or socket, yet may be non-present on another simultaneously. Check from
+ * architecture specific code.
+ */
+ return k->cpu_persistent_status && k->cpu_persistent_status(CPU(dev));
+}
+
static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev)
{
CPUClass *k = CPU_GET_CLASS(dev);
@@ -289,7 +313,9 @@ void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st,
return;
}
- cdev->cpu = NULL;
+ if (!should_remain_acpi_present(dev)) {
+ cdev->cpu = NULL;
+ }
}
static const VMStateDescription vmstate_cpuhp_sts = {
@@ -336,6 +362,7 @@ const VMStateDescription vmstate_cpu_hotplug = {
#define CPU_REMOVE_EVENT "CRMV"
#define CPU_EJECT_EVENT "CEJ0"
#define CPU_FW_EJECT_EVENT "CEJF"
+#define CPU_PRESENT "CPRS"
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
build_madt_cpu_fn build_madt_cpu, hwaddr base_addr,
@@ -396,7 +423,9 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1));
/* tell firmware to do device eject, write only */
aml_append(field, aml_named_field(CPU_FW_EJECT_EVENT, 1));
- aml_append(field, aml_reserved_field(3));
+ /* 1 if present, read only */
+ aml_append(field, aml_named_field(CPU_PRESENT, 1));
+ aml_append(field, aml_reserved_field(2));
aml_append(field, aml_named_field(CPU_COMMAND, 8));
aml_append(cpu_ctrl_dev, field);
@@ -426,6 +455,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK);
Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR);
Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED);
+ Aml *is_present = aml_name("%s.%s", cphp_res_path, CPU_PRESENT);
Aml *cpu_cmd = aml_name("%s.%s", cphp_res_path, CPU_COMMAND);
Aml *cpu_data = aml_name("%s.%s", cphp_res_path, CPU_DATA);
Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT);
@@ -454,13 +484,26 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
{
Aml *idx = aml_arg(0);
Aml *sta = aml_local(0);
+ Aml *ifctx2;
+ Aml *else_ctx;
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
aml_append(method, aml_store(idx, cpu_selector));
aml_append(method, aml_store(zero, sta));
- ifctx = aml_if(aml_equal(is_enabled, one));
+ ifctx = aml_if(aml_equal(is_present, one));
{
- aml_append(ifctx, aml_store(aml_int(0xF), sta));
+ ifctx2 = aml_if(aml_equal(is_enabled, one));
+ {
+ /* cpu is present and enabled */
+ aml_append(ifctx2, aml_store(aml_int(0xF), sta));
+ }
+ aml_append(ifctx, ifctx2);
+ else_ctx = aml_else();
+ {
+ /* cpu is present but disabled */
+ aml_append(else_ctx, aml_store(aml_int(0xD), sta));
+ }
+ aml_append(ifctx, else_ctx);
}
aml_append(method, ifctx);
aml_append(method, aml_release(ctrl_lock));
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index d00f5a6c1c..663d9cb093 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -331,6 +331,24 @@ static const VMStateDescription vmstate_memhp_state = {
}
};
+static bool cpuhp_needed(void *opaque)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+
+ return mc->has_hotpluggable_cpus;
+}
+
+static const VMStateDescription vmstate_cpuhp_state = {
+ .name = "acpi-ged/cpuhp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cpuhp_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_ged_state = {
.name = "acpi-ged-state",
.version_id = 1,
@@ -379,6 +397,7 @@ static const VMStateDescription vmstate_acpi_ged = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_memhp_state,
+ &vmstate_cpuhp_state,
&vmstate_ghes_state,
NULL
}
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index 7f8ccc9b7a..c8854f4d48 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -1,6 +1,5 @@
acpi_ss = ss.source_set()
acpi_ss.add(files(
- 'acpi_generic_initiator.c',
'acpi_interface.c',
'aml-build.c',
'bios-linker-loader.c',
diff --git a/hw/acpi/pci.c b/hw/acpi/pci.c
index 20b70dcd81..f88f450af3 100644
--- a/hw/acpi/pci.c
+++ b/hw/acpi/pci.c
@@ -24,8 +24,14 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qom/object_interfaces.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/pci.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_device.h"
#include "hw/pci/pcie_host.h"
/*
@@ -59,3 +65,239 @@ void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
acpi_table_end(linker, &table);
}
+
+typedef struct AcpiGenericInitiator {
+ /* private */
+ Object parent;
+
+ /* public */
+ char *pci_dev;
+ uint32_t node;
+} AcpiGenericInitiator;
+
+typedef struct AcpiGenericInitiatorClass {
+ ObjectClass parent_class;
+} AcpiGenericInitiatorClass;
+
+#define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator"
+
+OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator,
+ ACPI_GENERIC_INITIATOR, OBJECT,
+ { TYPE_USER_CREATABLE },
+ { NULL })
+
+OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR)
+
+static void acpi_generic_initiator_init(Object *obj)
+{
+ AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
+
+ gi->node = MAX_NODES;
+ gi->pci_dev = NULL;
+}
+
+static void acpi_generic_initiator_finalize(Object *obj)
+{
+ AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
+
+ g_free(gi->pci_dev);
+}
+
+static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val,
+ Error **errp)
+{
+ AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
+
+ gi->pci_dev = g_strdup(val);
+}
+
+static void acpi_generic_initiator_set_node(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
+ MachineState *ms = MACHINE(qdev_get_machine());
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ if (value >= MAX_NODES) {
+ error_printf("%s: Invalid NUMA node specified\n",
+ TYPE_ACPI_GENERIC_INITIATOR);
+ exit(1);
+ }
+
+ gi->node = value;
+ ms->numa_state->nodes[gi->node].has_gi = true;
+}
+
+static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data)
+{
+ object_class_property_add_str(oc, "pci-dev", NULL,
+ acpi_generic_initiator_set_pci_device);
+ object_class_property_set_description(oc, "pci-dev",
+ "PCI device to associate with the node");
+ object_class_property_add(oc, "node", "int", NULL,
+ acpi_generic_initiator_set_node, NULL, NULL);
+ object_class_property_set_description(oc, "node",
+ "NUMA node associated with the PCI device");
+}
+
+static int build_acpi_generic_initiator(Object *obj, void *opaque)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ AcpiGenericInitiator *gi;
+ GArray *table_data = opaque;
+ int32_t devfn;
+ uint8_t bus;
+ Object *o;
+
+ if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
+ return 0;
+ }
+
+ gi = ACPI_GENERIC_INITIATOR(obj);
+ if (gi->node >= ms->numa_state->num_nodes) {
+ error_printf("%s: Specified node %d is invalid.\n",
+ TYPE_ACPI_GENERIC_INITIATOR, gi->node);
+ exit(1);
+ }
+
+ o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
+ if (!o) {
+ error_printf("%s: Specified device must be a PCI device.\n",
+ TYPE_ACPI_GENERIC_INITIATOR);
+ exit(1);
+ }
+
+ bus = object_property_get_uint(o, "busnr", &error_fatal);
+ devfn = object_property_get_uint(o, "addr", &error_fatal);
+ /* devfn is constrained in PCI to be 8 bit but storage is an int32_t */
+ assert(devfn >= 0 && devfn < PCI_DEVFN_MAX);
+
+ build_srat_pci_generic_initiator(table_data, gi->node, 0, bus, devfn);
+
+ return 0;
+}
+
+typedef struct AcpiGenericPort {
+ /* private */
+ Object parent;
+
+ /* public */
+ char *pci_bus;
+ uint32_t node;
+} AcpiGenericPort;
+
+typedef struct AcpiGenericPortClass {
+ ObjectClass parent_class;
+} AcpiGenericPortClass;
+
+#define TYPE_ACPI_GENERIC_PORT "acpi-generic-port"
+
+OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericPort, acpi_generic_port,
+ ACPI_GENERIC_PORT, OBJECT,
+ { TYPE_USER_CREATABLE },
+ { NULL })
+
+OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericPort, ACPI_GENERIC_PORT)
+
+static void acpi_generic_port_init(Object *obj)
+{
+ AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
+
+ gp->node = MAX_NODES;
+ gp->pci_bus = NULL;
+}
+
+static void acpi_generic_port_finalize(Object *obj)
+{
+ AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
+
+ g_free(gp->pci_bus);
+}
+
+static void acpi_generic_port_set_pci_bus(Object *obj, const char *val,
+ Error **errp)
+{
+ AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
+
+ gp->pci_bus = g_strdup(val);
+}
+
+static void acpi_generic_port_set_node(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ if (value >= MAX_NODES) {
+ error_printf("%s: Invalid NUMA node specified\n",
+ TYPE_ACPI_GENERIC_INITIATOR);
+ exit(1);
+ }
+
+ gp->node = value;
+}
+
+static void acpi_generic_port_class_init(ObjectClass *oc, void *data)
+{
+ object_class_property_add_str(oc, "pci-bus", NULL,
+ acpi_generic_port_set_pci_bus);
+ object_class_property_set_description(oc, "pci-bus",
+ "PCI Bus of the host bridge associated with this GP affinity structure");
+ object_class_property_add(oc, "node", "int", NULL,
+ acpi_generic_port_set_node, NULL, NULL);
+ object_class_property_set_description(oc, "node",
+ "The NUMA node like ID to index HMAT/SLIT NUMA properties involving GP");
+}
+
+static int build_acpi_generic_port(Object *obj, void *opaque)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ const char *hid = "ACPI0016";
+ GArray *table_data = opaque;
+ AcpiGenericPort *gp;
+ uint32_t uid;
+ Object *o;
+
+ if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_PORT)) {
+ return 0;
+ }
+
+ gp = ACPI_GENERIC_PORT(obj);
+
+ if (gp->node >= ms->numa_state->num_nodes) {
+ error_printf("%s: node %d is invalid.\n",
+ TYPE_ACPI_GENERIC_PORT, gp->node);
+ exit(1);
+ }
+
+ o = object_resolve_path_type(gp->pci_bus, TYPE_PXB_CXL_BUS, NULL);
+ if (!o) {
+ error_printf("%s: device must be a CXL host bridge.\n",
+ TYPE_ACPI_GENERIC_PORT);
+ exit(1);
+ }
+
+ uid = object_property_get_uint(o, "acpi_uid", &error_fatal);
+ build_srat_acpi_generic_port(table_data, gp->node, hid, uid);
+
+ return 0;
+}
+
+void build_srat_generic_affinity_structures(GArray *table_data)
+{
+ object_child_foreach_recursive(object_get_root(),
+ build_acpi_generic_initiator,
+ table_data);
+ object_child_foreach_recursive(object_get_root(), build_acpi_generic_port,
+ table_data);
+}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f76fb117ad..620992c92c 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -57,7 +57,6 @@
#include "migration/vmstate.h"
#include "hw/acpi/ghes.h"
#include "hw/acpi/viot.h"
-#include "hw/acpi/acpi_generic_initiator.h"
#include "hw/virtio/virtio-acpi.h"
#include "target/arm/multiprocessing.h"
@@ -511,7 +510,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
- build_srat_generic_pci_initiator(table_data);
+ build_srat_generic_affinity_structures(table_data);
if (ms->nvdimms_state->is_enabled) {
nvdimm_build_srat(table_data);
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 5b7f46bbb0..7996e49821 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -90,27 +90,39 @@ static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
s->blkcfg.wce = blkcfg->wce;
}
+static int vhost_user_blk_sync_config(DeviceState *dev, Error **errp)
+{
+ int ret;
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VHostUserBlk *s = VHOST_USER_BLK(vdev);
+
+ ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
+ vdev->config_len, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ memcpy(vdev->config, &s->blkcfg, vdev->config_len);
+ virtio_notify_config(vdev);
+
+ return 0;
+}
+
static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
{
int ret;
- VirtIODevice *vdev = dev->vdev;
- VHostUserBlk *s = VHOST_USER_BLK(dev->vdev);
Error *local_err = NULL;
if (!dev->started) {
return 0;
}
- ret = vhost_dev_get_config(dev, (uint8_t *)&s->blkcfg,
- vdev->config_len, &local_err);
+ ret = vhost_user_blk_sync_config(DEVICE(dev->vdev), &local_err);
if (ret < 0) {
error_report_err(local_err);
return ret;
}
- memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len);
- virtio_notify_config(dev->vdev);
-
return 0;
}
@@ -579,6 +591,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, vhost_user_blk_properties);
dc->vmsd = &vmstate_vhost_user_blk;
+ dc->sync_config = vhost_user_blk_sync_config;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
vdc->realize = vhost_user_blk_device_realize;
vdc->unrealize = vhost_user_blk_device_unrealize;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 901c64b042..c1893fe255 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -34,7 +34,9 @@
#include "hw/virtio/virtio-iommu.h"
#include "audio/audio.h"
-GlobalProperty hw_compat_9_1[] = {};
+GlobalProperty hw_compat_9_1[] = {
+ { TYPE_PCI_DEVICE, "x-pcie-ext-tag", "false" },
+};
const size_t hw_compat_9_1_len = G_N_ELEMENTS(hw_compat_9_1);
GlobalProperty hw_compat_9_0[] = {
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 9258e48f95..2d4d62c454 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -151,6 +151,9 @@ static CXLRetCode cmd_tunnel_management_cmd(const struct cxl_cmd *cmd,
in = (void *)payload_in;
out = (void *)payload_out;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
/* Enough room for minimum sized message - no payload */
if (in->size < sizeof(in->ccimessage)) {
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
@@ -266,6 +269,12 @@ static CXLRetCode cmd_events_clear_records(const struct cxl_cmd *cmd,
CXLClearEventPayload *pl;
pl = (CXLClearEventPayload *)payload_in;
+
+ if (len_in < sizeof(*pl) ||
+ len_in < sizeof(*pl) + sizeof(*pl->handle) * pl->nr_recs) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
*len_out = 0;
return cxl_event_clear_records(cxlds, pl);
}
@@ -374,7 +383,7 @@ static CXLRetCode cmd_infostat_identify(const struct cxl_cmd *cmd,
uint16_t pcie_subsys_vid;
uint16_t pcie_subsys_id;
uint64_t sn;
- uint8_t max_message_size;
+ uint8_t max_message_size;
uint8_t component_type;
} QEMU_PACKED *is_identify;
QEMU_BUILD_BUG_ON(sizeof(*is_identify) != 18);
@@ -521,6 +530,9 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
in = (struct cxl_fmapi_get_phys_port_state_req_pl *)payload_in;
out = (struct cxl_fmapi_get_phys_port_state_resp_pl *)payload_out;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
/* Check if what was requested can fit */
if (sizeof(*out) + sizeof(*out->ports) * in->num_ports > cci->payload_max) {
return CXL_MBOX_INVALID_INPUT;
@@ -649,9 +661,9 @@ static CXLRetCode cmd_firmware_update_get_info(const struct cxl_cmd *cmd,
} QEMU_PACKED *fw_info;
QEMU_BUILD_BUG_ON(sizeof(*fw_info) != 0x50);
- if ((cxl_dstate->vmem_size < CXL_CAPACITY_MULTIPLIER) ||
- (cxl_dstate->pmem_size < CXL_CAPACITY_MULTIPLIER) ||
- (ct3d->dc.total_capacity < CXL_CAPACITY_MULTIPLIER)) {
+ if (!QEMU_IS_ALIGNED(cxl_dstate->vmem_size, CXL_CAPACITY_MULTIPLIER) ||
+ !QEMU_IS_ALIGNED(cxl_dstate->pmem_size, CXL_CAPACITY_MULTIPLIER) ||
+ !QEMU_IS_ALIGNED(ct3d->dc.total_capacity, CXL_CAPACITY_MULTIPLIER)) {
return CXL_MBOX_INTERNAL_ERROR;
}
@@ -699,6 +711,10 @@ static CXLRetCode cmd_firmware_update_transfer(const struct cxl_cmd *cmd,
} QEMU_PACKED *fw_transfer = (void *)payload_in;
size_t offset, length;
+ if (len < sizeof(*fw_transfer)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
if (fw_transfer->action == CXL_FW_XFER_ACTION_ABORT) {
/*
* At this point there aren't any on-going transfers
@@ -927,24 +943,28 @@ static CXLRetCode cmd_logs_get_log(const struct cxl_cmd *cmd,
get_log = (void *)payload_in;
+ if (get_log->length > cci->payload_max) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ if (!qemu_uuid_is_equal(&get_log->uuid, &cel_uuid)) {
+ return CXL_MBOX_INVALID_LOG;
+ }
+
/*
* CXL r3.1 Section 8.2.9.5.2: Get Log (Opcode 0401h)
* The device shall return Invalid Input if the Offset or Length
* fields attempt to access beyond the size of the log as reported by Get
- * Supported Logs.
+ * Supported Log.
*
- * The CEL buffer is large enough to fit all commands in the emulation, so
- * the only possible failure would be if the mailbox itself isn't big
- * enough.
+ * Only valid for there to be one entry per opcode, but the length + offset
+ * may still be greater than that if the inputs are not valid and so access
+ * beyond the end of cci->cel_log.
*/
- if (get_log->offset + get_log->length > cci->payload_max) {
+ if ((uint64_t)get_log->offset + get_log->length >= sizeof(cci->cel_log)) {
return CXL_MBOX_INVALID_INPUT;
}
- if (!qemu_uuid_is_equal(&get_log->uuid, &cel_uuid)) {
- return CXL_MBOX_INVALID_LOG;
- }
-
/* Store off everything to local variables so we can wipe out the payload */
*len_out = get_log->length;
@@ -1133,10 +1153,8 @@ static CXLRetCode cmd_features_get_supported(const struct cxl_cmd *cmd,
(struct CXLSupportedFeatureEntry) {
.uuid = ecs_uuid,
.feat_index = index,
- .get_feat_size = CXL_ECS_NUM_MEDIA_FRUS *
- sizeof(CXLMemECSReadAttrs),
- .set_feat_size = CXL_ECS_NUM_MEDIA_FRUS *
- sizeof(CXLMemECSWriteAttrs),
+ .get_feat_size = sizeof(CXLMemECSReadAttrs),
+ .set_feat_size = sizeof(CXLMemECSWriteAttrs),
.attr_flags = CXL_FEAT_ENTRY_ATTR_FLAG_CHANGABLE,
.get_feat_version = CXL_ECS_GET_FEATURE_VERSION,
.set_feat_version = CXL_ECS_SET_FEATURE_VERSION,
@@ -1204,13 +1222,10 @@ static CXLRetCode cmd_features_get_feature(const struct cxl_cmd *cmd,
(uint8_t *)&ct3d->patrol_scrub_attrs + get_feature->offset,
bytes_to_copy);
} else if (qemu_uuid_is_equal(&get_feature->uuid, &ecs_uuid)) {
- if (get_feature->offset >= CXL_ECS_NUM_MEDIA_FRUS *
- sizeof(CXLMemECSReadAttrs)) {
+ if (get_feature->offset >= sizeof(CXLMemECSReadAttrs)) {
return CXL_MBOX_INVALID_INPUT;
}
- bytes_to_copy = CXL_ECS_NUM_MEDIA_FRUS *
- sizeof(CXLMemECSReadAttrs) -
- get_feature->offset;
+ bytes_to_copy = sizeof(CXLMemECSReadAttrs) - get_feature->offset;
bytes_to_copy = MIN(bytes_to_copy, get_feature->count);
memcpy(payload_out,
(uint8_t *)&ct3d->ecs_attrs + get_feature->offset,
@@ -1243,6 +1258,9 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
CXLType3Dev *ct3d;
uint16_t count;
+ if (len_in < sizeof(*hdr)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
if (!object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_TYPE3)) {
return CXL_MBOX_UNSUPPORTED;
@@ -1277,6 +1295,11 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
ps_set_feature = (void *)payload_in;
ps_write_attrs = &ps_set_feature->feat_data;
+
+ if ((uint32_t)hdr->offset + bytes_to_copy >
+ sizeof(ct3d->patrol_scrub_wr_attrs)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
memcpy((uint8_t *)&ct3d->patrol_scrub_wr_attrs + hdr->offset,
ps_write_attrs,
bytes_to_copy);
@@ -1299,18 +1322,22 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
ecs_set_feature = (void *)payload_in;
ecs_write_attrs = ecs_set_feature->feat_data;
- memcpy((uint8_t *)ct3d->ecs_wr_attrs + hdr->offset,
+
+ if ((uint32_t)hdr->offset + bytes_to_copy >
+ sizeof(ct3d->ecs_wr_attrs)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+ memcpy((uint8_t *)&ct3d->ecs_wr_attrs + hdr->offset,
ecs_write_attrs,
bytes_to_copy);
set_feat_info->data_size += bytes_to_copy;
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
data_transfer_flag == CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER) {
+ ct3d->ecs_attrs.ecs_log_cap = ct3d->ecs_wr_attrs.ecs_log_cap;
for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
- ct3d->ecs_attrs[count].ecs_log_cap =
- ct3d->ecs_wr_attrs[count].ecs_log_cap;
- ct3d->ecs_attrs[count].ecs_config =
- ct3d->ecs_wr_attrs[count].ecs_config & 0x1F;
+ ct3d->ecs_attrs.fru_attrs[count].ecs_config =
+ ct3d->ecs_wr_attrs.fru_attrs[count].ecs_config & 0x1F;
}
}
} else {
@@ -1324,7 +1351,7 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
if (qemu_uuid_is_equal(&hdr->uuid, &patrol_scrub_uuid)) {
memset(&ct3d->patrol_scrub_wr_attrs, 0, set_feat_info->data_size);
} else if (qemu_uuid_is_equal(&hdr->uuid, &ecs_uuid)) {
- memset(ct3d->ecs_wr_attrs, 0, set_feat_info->data_size);
+ memset(&ct3d->ecs_wr_attrs, 0, set_feat_info->data_size);
}
set_feat_info->data_transfer_flag = 0;
set_feat_info->data_saved_across_reset = false;
@@ -1445,7 +1472,7 @@ static CXLRetCode cmd_ccls_get_lsa(const struct cxl_cmd *cmd,
} QEMU_PACKED *get_lsa;
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d);
- uint32_t offset, length;
+ uint64_t offset, length;
get_lsa = (void *)payload_in;
offset = get_lsa->offset;
@@ -1479,8 +1506,8 @@ static CXLRetCode cmd_ccls_set_lsa(const struct cxl_cmd *cmd,
const size_t hdr_len = offsetof(struct set_lsa_pl, data);
*len_out = 0;
- if (!len_in) {
- return CXL_MBOX_SUCCESS;
+ if (len_in < hdr_len) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
}
if (set_lsa_payload->offset + len_in > cvc->get_lsa_size(ct3d) + hdr_len) {
@@ -2233,6 +2260,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd,
stw_le_p(&out_rec->shared_seq, ent->shared_seq);
record_done++;
+ out_rec++;
if (record_done == record_count) {
break;
}
@@ -2470,11 +2498,20 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
uint64_t dpa, len;
CXLRetCode ret;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
if (in->num_entries_updated == 0) {
cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
return CXL_MBOX_SUCCESS;
}
+ if (len_in <
+ sizeof(*in) + sizeof(*in->updated_entries) * in->num_entries_updated) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
/* Adding extents causes exceeding device's extent tracking ability. */
if (in->num_entries_updated + ct3d->dc.total_extent_count >
CXL_NUM_EXTENTS_SUPPORTED) {
@@ -2629,10 +2666,19 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd,
uint32_t updated_list_size;
CXLRetCode ret;
+ if (len_in < sizeof(*in)) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
if (in->num_entries_updated == 0) {
return CXL_MBOX_INVALID_INPUT;
}
+ if (len_in <
+ sizeof(*in) + sizeof(*in->updated_entries) * in->num_entries_updated) {
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
+ }
+
ret = cxl_detect_malformed_extent_list(ct3d, in);
if (ret != CXL_MBOX_SUCCESS) {
return ret;
@@ -2879,7 +2925,8 @@ static void bg_timercb(void *opaque)
}
} else {
/* estimate only */
- cci->bg.complete_pct = 100 * now / total_time;
+ cci->bg.complete_pct =
+ 100 * (now - cci->bg.starttime) / cci->bg.runtime;
timer_mod(cci->bg.timer, now + CXL_MBOX_BG_UPDATE_FREQ);
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 4967aa7459..9fcc2897b8 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -68,7 +68,6 @@
#include "hw/acpi/utils.h"
#include "hw/acpi/pci.h"
#include "hw/acpi/cxl.h"
-#include "hw/acpi/acpi_generic_initiator.h"
#include "qom/qom-qobject.h"
#include "hw/i386/amd_iommu.h"
@@ -741,7 +740,8 @@ static Aml *build_prt(bool is_pci0_prt)
int pin;
method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
- rt_pkg = aml_varpackage(nroutes);
+ assert(nroutes < 256);
+ rt_pkg = aml_package(nroutes);
for (pin = 0; pin < nroutes; pin++) {
Aml *pkg = aml_package(4);
@@ -1476,6 +1476,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
QLIST_FOREACH(bus, &bus->child, sibling) {
uint8_t bus_num = pci_bus_num(bus);
uint8_t numa_node = pci_bus_numa_node(bus);
+ uint32_t uid;
/* look only for expander root buses */
if (!pci_bus_is_root(bus)) {
@@ -1486,6 +1487,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
root_bus_limit = bus_num - 1;
}
+ uid = object_property_get_uint(OBJECT(bus), "acpi_uid",
+ &error_fatal);
scope = aml_scope("\\_SB");
if (pci_bus_is_cxl(bus)) {
@@ -1493,7 +1496,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
} else {
dev = aml_device("PC%.02X", bus_num);
}
- aml_append(dev, aml_name_decl("_UID", aml_int(bus_num)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num)));
if (pci_bus_is_cxl(bus)) {
struct Aml *aml_pkg = aml_package(2);
@@ -1971,7 +1974,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
build_srat_memory(table_data, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
}
- build_srat_generic_pci_initiator(table_data);
+ build_srat_generic_affinity_structures(table_data);
/*
* Entry is required for Windows to enable memory hotplug in OS
@@ -2321,7 +2324,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
/* Capability offset */
build_append_int_noprefix(table_data, s->pci.capab_offset, 2);
/* IOMMU base address */
- build_append_int_noprefix(table_data, s->mmio.addr, 8);
+ build_append_int_noprefix(table_data, s->mr_mmio.addr, 8);
/* PCI Segment Group */
build_append_int_noprefix(table_data, 0, 2);
/* IOMMU info */
@@ -2356,7 +2359,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
/* Capability offset */
build_append_int_noprefix(table_data, s->pci.capab_offset, 2);
/* IOMMU base address */
- build_append_int_noprefix(table_data, s->mmio.addr, 8);
+ build_append_int_noprefix(table_data, s->mr_mmio.addr, 8);
/* PCI Segment Group */
build_append_int_noprefix(table_data, 0, 2);
/* IOMMU info */
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 464f0b666e..13af7211e1 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -32,6 +32,7 @@
#include "trace.h"
#include "hw/i386/apic-msidef.h"
#include "hw/qdev-properties.h"
+#include "kvm/kvm_i386.h"
/* used AMD-Vi MMIO registers */
const char *amdvi_mmio_low[] = {
@@ -60,8 +61,9 @@ struct AMDVIAddressSpace {
uint8_t bus_num; /* bus number */
uint8_t devfn; /* device function */
AMDVIState *iommu_state; /* AMDVI - one per machine */
- MemoryRegion root; /* AMDVI Root memory map region */
+ MemoryRegion root; /* AMDVI Root memory map region */
IOMMUMemoryRegion iommu; /* Device's address translation region */
+ MemoryRegion iommu_nodma; /* Alias of shared nodma memory region */
MemoryRegion iommu_ir; /* Device's interrupt remapping region */
AddressSpace as; /* device's corresponding address space */
};
@@ -430,6 +432,12 @@ static void amdvi_complete_ppr(AMDVIState *s, uint64_t *cmd)
trace_amdvi_ppr_exec();
}
+static void amdvi_intremap_inval_notify_all(AMDVIState *s, bool global,
+ uint32_t index, uint32_t mask)
+{
+ x86_iommu_iec_notify_all(X86_IOMMU_DEVICE(s), global, index, mask);
+}
+
static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd)
{
if (extract64(cmd[0], 0, 60) || cmd[1]) {
@@ -437,6 +445,9 @@ static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd)
s->cmdbuf + s->cmdbuf_head);
}
+ /* Notify global invalidation */
+ amdvi_intremap_inval_notify_all(s, true, 0, 0);
+
amdvi_iotlb_reset(s);
trace_amdvi_all_inval();
}
@@ -485,6 +496,9 @@ static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd)
return;
}
+ /* Notify global invalidation */
+ amdvi_intremap_inval_notify_all(s, true, 0, 0);
+
trace_amdvi_intr_inval();
}
@@ -1412,6 +1426,7 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
AMDVIState *s = opaque;
AMDVIAddressSpace **iommu_as, *amdvi_dev_as;
int bus_num = pci_bus_num(bus);
+ X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
iommu_as = s->address_spaces[bus_num];
@@ -1436,13 +1451,13 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
* Memory region relationships looks like (Address range shows
* only lower 32 bits to make it short in length...):
*
- * |-----------------+-------------------+----------|
- * | Name | Address range | Priority |
- * |-----------------+-------------------+----------+
- * | amdvi_root | 00000000-ffffffff | 0 |
- * | amdvi_iommu | 00000000-ffffffff | 1 |
- * | amdvi_iommu_ir | fee00000-feefffff | 64 |
- * |-----------------+-------------------+----------|
+ * |--------------------+-------------------+----------|
+ * | Name | Address range | Priority |
+ * |--------------------+-------------------+----------+
+ * | amdvi-root | 00000000-ffffffff | 0 |
+ * | amdvi-iommu_nodma | 00000000-ffffffff | 0 |
+ * | amdvi-iommu_ir | fee00000-feefffff | 1 |
+ * |--------------------+-------------------+----------|
*/
memory_region_init_iommu(&amdvi_dev_as->iommu,
sizeof(amdvi_dev_as->iommu),
@@ -1452,16 +1467,34 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
memory_region_init(&amdvi_dev_as->root, OBJECT(s),
"amdvi_root", UINT64_MAX);
address_space_init(&amdvi_dev_as->as, &amdvi_dev_as->root, name);
- memory_region_init_io(&amdvi_dev_as->iommu_ir, OBJECT(s),
- &amdvi_ir_ops, s, "amd_iommu_ir",
- AMDVI_INT_ADDR_SIZE);
- memory_region_add_subregion_overlap(&amdvi_dev_as->root,
- AMDVI_INT_ADDR_FIRST,
- &amdvi_dev_as->iommu_ir,
- 64);
memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0,
MEMORY_REGION(&amdvi_dev_as->iommu),
- 1);
+ 0);
+
+ /* Build the DMA Disabled alias to shared memory */
+ memory_region_init_alias(&amdvi_dev_as->iommu_nodma, OBJECT(s),
+ "amdvi-sys", &s->mr_sys, 0,
+ memory_region_size(&s->mr_sys));
+ memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0,
+ &amdvi_dev_as->iommu_nodma,
+ 0);
+ /* Build the Interrupt Remapping alias to shared memory */
+ memory_region_init_alias(&amdvi_dev_as->iommu_ir, OBJECT(s),
+ "amdvi-ir", &s->mr_ir, 0,
+ memory_region_size(&s->mr_ir));
+ memory_region_add_subregion_overlap(MEMORY_REGION(&amdvi_dev_as->iommu),
+ AMDVI_INT_ADDR_FIRST,
+ &amdvi_dev_as->iommu_ir, 1);
+
+ if (!x86_iommu->pt_supported) {
+ memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false);
+ memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu),
+ true);
+ } else {
+ memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu),
+ false);
+ memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, true);
+ }
}
return &iommu_as[devfn]->as;
}
@@ -1598,10 +1631,37 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
x86ms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID);
/* set up MMIO */
- memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
- AMDVI_MMIO_SIZE);
+ memory_region_init_io(&s->mr_mmio, OBJECT(s), &mmio_mem_ops, s,
+ "amdvi-mmio", AMDVI_MMIO_SIZE);
memory_region_add_subregion(get_system_memory(), AMDVI_BASE_ADDR,
- &s->mmio);
+ &s->mr_mmio);
+
+ /* Create the share memory regions by all devices */
+ memory_region_init(&s->mr_sys, OBJECT(s), "amdvi-sys", UINT64_MAX);
+
+ /* set up the DMA disabled memory region */
+ memory_region_init_alias(&s->mr_nodma, OBJECT(s),
+ "amdvi-nodma", get_system_memory(), 0,
+ memory_region_size(get_system_memory()));
+ memory_region_add_subregion_overlap(&s->mr_sys, 0,
+ &s->mr_nodma, 0);
+
+ /* set up the Interrupt Remapping memory region */
+ memory_region_init_io(&s->mr_ir, OBJECT(s), &amdvi_ir_ops,
+ s, "amdvi-ir", AMDVI_INT_ADDR_SIZE);
+ memory_region_add_subregion_overlap(&s->mr_sys, AMDVI_INT_ADDR_FIRST,
+ &s->mr_ir, 1);
+
+ /* AMD IOMMU with x2APIC mode requires xtsup=on */
+ if (x86ms->apic_id_limit > 255 && !s->xtsup) {
+ error_report("AMD IOMMU with x2APIC confguration requires xtsup=on");
+ exit(EXIT_FAILURE);
+ }
+ if (s->xtsup && kvm_irqchip_is_split() && !kvm_enable_x2apic()) {
+ error_report("AMD IOMMU xtsup=on requires support on the KVM side");
+ exit(EXIT_FAILURE);
+ }
+
pci_setup_iommu(bus, &amdvi_iommu_ops, s);
amdvi_init(s);
}
diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h
index 73619fe9ea..e0dac4d9a9 100644
--- a/hw/i386/amd_iommu.h
+++ b/hw/i386/amd_iommu.h
@@ -353,7 +353,10 @@ struct AMDVIState {
uint32_t pprlog_head; /* ppr log head */
uint32_t pprlog_tail; /* ppr log tail */
- MemoryRegion mmio; /* MMIO region */
+ MemoryRegion mr_mmio; /* MMIO region */
+ MemoryRegion mr_sys;
+ MemoryRegion mr_nodma;
+ MemoryRegion mr_ir;
uint8_t mmior[AMDVI_MMIO_SIZE]; /* read/write MMIO */
uint8_t w1cmask[AMDVI_MMIO_SIZE]; /* read/write 1 clear mask */
uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 08fe218935..4c0d1d7d47 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -2532,15 +2532,51 @@ static bool vtd_get_inv_desc(IntelIOMMUState *s,
return true;
}
+static bool vtd_inv_desc_reserved_check(IntelIOMMUState *s,
+ VTDInvDesc *inv_desc,
+ uint64_t mask[4], bool dw,
+ const char *func_name,
+ const char *desc_type)
+{
+ if (s->iq_dw) {
+ if (inv_desc->val[0] & mask[0] || inv_desc->val[1] & mask[1] ||
+ inv_desc->val[2] & mask[2] || inv_desc->val[3] & mask[3]) {
+ error_report("%s: invalid %s desc val[3]: 0x%"PRIx64
+ " val[2]: 0x%"PRIx64" val[1]=0x%"PRIx64
+ " val[0]=0x%"PRIx64" (reserved nonzero)",
+ func_name, desc_type, inv_desc->val[3],
+ inv_desc->val[2], inv_desc->val[1],
+ inv_desc->val[0]);
+ return false;
+ }
+ } else {
+ if (dw) {
+ error_report("%s: 256-bit %s desc in 128-bit invalidation queue",
+ func_name, desc_type);
+ return false;
+ }
+
+ if (inv_desc->lo & mask[0] || inv_desc->hi & mask[1]) {
+ error_report("%s: invalid %s desc: hi=%"PRIx64", lo=%"PRIx64
+ " (reserved nonzero)", func_name, desc_type,
+ inv_desc->hi, inv_desc->lo);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
{
- if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) ||
- (inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) {
- error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
- " (reserved nonzero)", __func__, inv_desc->hi,
- inv_desc->lo);
+ uint64_t mask[4] = {VTD_INV_DESC_WAIT_RSVD_LO, VTD_INV_DESC_WAIT_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "wait")) {
return false;
}
+
if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) {
/* Status Write */
uint32_t status_data = (uint32_t)(inv_desc->lo >>
@@ -2574,13 +2610,14 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
uint16_t sid, fmask;
+ uint64_t mask[4] = {VTD_INV_DESC_CC_RSVD, VTD_INV_DESC_ALL_ONE,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
- if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) {
- error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64
- " (reserved nonzero)", __func__, inv_desc->hi,
- inv_desc->lo);
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "cc inv")) {
return false;
}
+
switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
case VTD_INV_DESC_CC_DOMAIN:
trace_vtd_inv_desc_cc_domain(
@@ -2610,12 +2647,11 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
uint16_t domain_id;
uint8_t am;
hwaddr addr;
+ uint64_t mask[4] = {VTD_INV_DESC_IOTLB_RSVD_LO, VTD_INV_DESC_IOTLB_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
- if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) ||
- (inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) {
- error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
- ", lo=0x%"PRIx64" (reserved bits unzero)",
- __func__, inv_desc->hi, inv_desc->lo);
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "iotlb inv")) {
return false;
}
@@ -2656,6 +2692,14 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
static bool vtd_process_inv_iec_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
+ uint64_t mask[4] = {VTD_INV_DESC_IEC_RSVD, VTD_INV_DESC_ALL_ONE,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "iec inv")) {
+ return false;
+ }
+
trace_vtd_inv_desc_iec(inv_desc->iec.granularity,
inv_desc->iec.index,
inv_desc->iec.index_mask);
@@ -2705,19 +2749,19 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
hwaddr addr;
uint16_t sid;
bool size;
+ uint64_t mask[4] = {VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO,
+ VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI,
+ VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
+
+ if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
+ __func__, "dev-iotlb inv")) {
+ return false;
+ }
addr = VTD_INV_DESC_DEVICE_IOTLB_ADDR(inv_desc->hi);
sid = VTD_INV_DESC_DEVICE_IOTLB_SID(inv_desc->lo);
size = VTD_INV_DESC_DEVICE_IOTLB_SIZE(inv_desc->hi);
- if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) ||
- (inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) {
- error_report_once("%s: invalid dev-iotlb inv desc: hi=%"PRIx64
- ", lo=%"PRIx64" (reserved nonzero)", __func__,
- inv_desc->hi, inv_desc->lo);
- return false;
- }
-
/*
* Using sid is OK since the guest should have finished the
* initialization of both the bus and device.
@@ -2847,6 +2891,7 @@ static void vtd_handle_iqt_write(IntelIOMMUState *s)
if (s->iq_dw && (val & VTD_IQT_QT_256_RSV_BIT)) {
error_report_once("%s: RSV bit is set: val=0x%"PRIx64,
__func__, val);
+ vtd_handle_inv_queue_error(s);
return;
}
s->iq_tail = VTD_IQT_QT(s->iq_dw, val);
@@ -3372,6 +3417,7 @@ static Property vtd_properties[] = {
DEFINE_PROP_BOOL("x-pasid-mode", IntelIOMMUState, pasid, false),
DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true),
DEFINE_PROP_BOOL("dma-translation", IntelIOMMUState, dma_translation, true),
+ DEFINE_PROP_BOOL("stale-tm", IntelIOMMUState, stale_tm, false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -4138,15 +4184,15 @@ static void vtd_init(IntelIOMMUState *s)
*/
vtd_spte_rsvd[0] = ~0ULL;
vtd_spte_rsvd[1] = VTD_SPTE_PAGE_L1_RSVD_MASK(s->aw_bits,
- x86_iommu->dt_supported);
+ x86_iommu->dt_supported && s->stale_tm);
vtd_spte_rsvd[2] = VTD_SPTE_PAGE_L2_RSVD_MASK(s->aw_bits);
vtd_spte_rsvd[3] = VTD_SPTE_PAGE_L3_RSVD_MASK(s->aw_bits);
vtd_spte_rsvd[4] = VTD_SPTE_PAGE_L4_RSVD_MASK(s->aw_bits);
vtd_spte_rsvd_large[2] = VTD_SPTE_LPAGE_L2_RSVD_MASK(s->aw_bits,
- x86_iommu->dt_supported);
+ x86_iommu->dt_supported && s->stale_tm);
vtd_spte_rsvd_large[3] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits,
- x86_iommu->dt_supported);
+ x86_iommu->dt_supported && s->stale_tm);
if (s->scalable_mode || s->snoop_control) {
vtd_spte_rsvd[1] &= ~VTD_SPTE_SNP;
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index 13d5d129ae..4323fc5d6d 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -356,6 +356,7 @@ union VTDInvDesc {
typedef union VTDInvDesc VTDInvDesc;
/* Masks for struct VTDInvDesc */
+#define VTD_INV_DESC_ALL_ONE -1ULL
#define VTD_INV_DESC_TYPE(val) ((((val) >> 5) & 0x70ULL) | \
((val) & 0xfULL))
#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
@@ -409,11 +410,14 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0f1f0
+/* Masks for Interrupt Entry Invalidate Descriptor */
+#define VTD_INV_DESC_IEC_RSVD 0xffff000007fff1e0ULL
+
/* Rsvd field masks for spte */
#define VTD_SPTE_SNP 0x800ULL
-#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw, dt_supported) \
- dt_supported ? \
+#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw, stale_tm) \
+ stale_tm ? \
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
#define VTD_SPTE_PAGE_L2_RSVD_MASK(aw) \
@@ -423,12 +427,12 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_SPTE_PAGE_L4_RSVD_MASK(aw) \
(0x880ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
-#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw, dt_supported) \
- dt_supported ? \
+#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw, stale_tm) \
+ stale_tm ? \
(0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
(0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
-#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw, dt_supported) \
- dt_supported ? \
+#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw, stale_tm) \
+ stale_tm ? \
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 2047633e4c..830614d930 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -82,6 +82,7 @@
GlobalProperty pc_compat_9_1[] = {
{ "ICH9-LPC", "x-smi-swsmi-timer", "off" },
{ "ICH9-LPC", "x-smi-periodic-timer", "off" },
+ { TYPE_INTEL_IOMMU_DEVICE, "stale-tm", "on" },
};
const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1);
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 235ac40aeb..5cf754b38f 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -17,6 +17,7 @@
#include "hw/mem/pc-dimm.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
@@ -919,16 +920,15 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
ct3d->patrol_scrub_attrs.scrub_flags = CXL_MEMDEV_PS_ENABLE_DEFAULT;
/* Set default value for DDR5 ECS read attributes */
+ ct3d->ecs_attrs.ecs_log_cap = CXL_ECS_LOG_ENTRY_TYPE_DEFAULT;
for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
- ct3d->ecs_attrs[count].ecs_log_cap =
- CXL_ECS_LOG_ENTRY_TYPE_DEFAULT;
- ct3d->ecs_attrs[count].ecs_cap =
+ ct3d->ecs_attrs.fru_attrs[count].ecs_cap =
CXL_ECS_REALTIME_REPORT_CAP_DEFAULT;
- ct3d->ecs_attrs[count].ecs_config =
+ ct3d->ecs_attrs.fru_attrs[count].ecs_config =
CXL_ECS_THRESHOLD_COUNT_DEFAULT |
(CXL_ECS_MODE_DEFAULT << 3);
/* Reserved */
- ct3d->ecs_attrs[count].ecs_flags = 0;
+ ct3d->ecs_attrs.fru_attrs[count].ecs_flags = 0;
}
return;
@@ -1200,6 +1200,7 @@ static void ct3d_reset(DeviceState *dev)
uint32_t *reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
uint32_t *write_msk = ct3d->cxl_cstate.crb.cache_mem_regs_write_mask;
+ pcie_cap_fill_link_ep_usp(PCI_DEVICE(dev), ct3d->width, ct3d->speed);
cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE);
cxl_device_register_init_t3(ct3d);
@@ -1229,6 +1230,10 @@ static Property ct3_props[] = {
DEFINE_PROP_UINT8("num-dc-regions", CXLType3Dev, dc.num_regions, 0),
DEFINE_PROP_LINK("volatile-dc-memdev", CXLType3Dev, dc.host_dc,
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", CXLType3Dev,
+ speed, PCIE_LINK_SPEED_32),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLType3Dev,
+ width, PCIE_LINK_WIDTH_16),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1375,9 +1380,7 @@ void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length,
ct3d = CXL_TYPE3(obj);
QLIST_FOREACH(p, &ct3d->poison_list, node) {
- if (((start >= p->start) && (start < p->start + p->length)) ||
- ((start + length > p->start) &&
- (start + length <= p->start + p->length))) {
+ if ((start < p->start + p->length) && (start + length > p->start)) {
error_setg(errp,
"Overlap with existing poisoned region not supported");
return;
@@ -2060,11 +2063,11 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
stw_le_p(&dCap.host_id, hid);
/* only valid for DC_REGION_CONFIG_UPDATED event */
dCap.updated_region_id = 0;
- dCap.flags = 0;
for (i = 0; i < num_extents; i++) {
memcpy(&dCap.dynamic_capacity_extent, &extents[i],
sizeof(CXLDCExtentRaw));
+ dCap.flags = 0;
if (i < num_extents - 1) {
/* Set "More" flag */
dCap.flags |= BIT(0);
diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
index 4b42984360..c347ac06f3 100644
--- a/hw/pci-bridge/cxl_downstream.c
+++ b/hw/pci-bridge/cxl_downstream.c
@@ -13,6 +13,8 @@
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_port.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/cxl/cxl.h"
#include "qapi/error.h"
@@ -210,24 +212,20 @@ static void cxl_dsp_exitfn(PCIDevice *d)
pci_bridge_exitfn(d);
}
-static void cxl_dsp_instance_post_init(Object *obj)
-{
- PCIESlot *s = PCIE_SLOT(obj);
-
- if (!s->speed) {
- s->speed = QEMU_PCI_EXP_LNK_2_5GT;
- }
-
- if (!s->width) {
- s->width = QEMU_PCI_EXP_LNK_X1;
- }
-}
+static Property cxl_dsp_props[] = {
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
+ speed, PCIE_LINK_SPEED_64),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
+ width, PCIE_LINK_WIDTH_16),
+ DEFINE_PROP_END_OF_LIST()
+};
static void cxl_dsp_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
+ device_class_set_props(dc, cxl_dsp_props);
k->config_write = cxl_dsp_config_write;
k->realize = cxl_dsp_realize;
k->exit = cxl_dsp_exitfn;
@@ -243,7 +241,6 @@ static const TypeInfo cxl_dsp_info = {
.name = TYPE_CXL_DSP,
.instance_size = sizeof(CXLDownstreamPort),
.parent = TYPE_PCIE_SLOT,
- .instance_post_init = cxl_dsp_instance_post_init,
.class_init = cxl_dsp_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c
index 2dd10239bd..5e2156d7ba 100644
--- a/hw/pci-bridge/cxl_root_port.c
+++ b/hw/pci-bridge/cxl_root_port.c
@@ -24,6 +24,7 @@
#include "hw/pci/pcie_port.h"
#include "hw/pci/msi.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
#include "hw/cxl/cxl.h"
@@ -206,6 +207,10 @@ static Property gen_rp_props[] = {
-1),
DEFINE_PROP_SIZE("pref64-reserve", CXLRootPort, res_reserve.mem_pref_64,
-1),
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
+ speed, PCIE_LINK_SPEED_64),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
+ width, PCIE_LINK_WIDTH_32),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
index a5a39cc524..55f8b0053f 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -11,6 +11,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
#include "hw/pci/msi.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_port.h"
@@ -100,6 +101,7 @@ static void cxl_usp_reset(DeviceState *qdev)
pci_bridge_reset(qdev);
pcie_cap_deverr_reset(d);
+ pcie_cap_fill_link_ep_usp(d, usp->width, usp->speed);
latch_registers(usp);
}
@@ -363,6 +365,10 @@ static void cxl_usp_exitfn(PCIDevice *d)
static Property cxl_upstream_props[] = {
DEFINE_PROP_UINT64("sn", CXLUpstreamPort, sn, UI64_NULL),
DEFINE_PROP_STRING("cdat", CXLUpstreamPort, cxl_cstate.cdat.filename),
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", CXLUpstreamPort,
+ speed, PCIE_LINK_SPEED_32),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLUpstreamPort,
+ width, PCIE_LINK_WIDTH_16),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index dfaea6cbf4..07d411cff5 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -38,7 +38,6 @@ DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS,
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS,
TYPE_PXB_PCIE_BUS)
-#define TYPE_PXB_CXL_BUS "pxb-cxl-bus"
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_CXL_BUS,
TYPE_PXB_CXL_BUS)
@@ -85,12 +84,25 @@ static uint16_t pxb_bus_numa_node(PCIBus *bus)
return pxb->numa_node;
}
+static void prop_pxb_uid_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint32_t uid = pci_bus_num(PCI_BUS(obj));
+
+ visit_type_uint32(v, name, &uid, errp);
+}
+
static void pxb_bus_class_init(ObjectClass *class, void *data)
{
PCIBusClass *pbc = PCI_BUS_CLASS(class);
pbc->bus_num = pxb_bus_num;
pbc->numa_node = pxb_bus_numa_node;
+
+ object_class_property_add(class, "acpi_uid", "uint32",
+ prop_pxb_uid_get, NULL, NULL, NULL);
+ object_class_property_set_description(class, "acpi_uid",
+ "ACPI Unique ID used to distinguish this PCI Host Bridge / ACPI00016");
}
static const TypeInfo pxb_bus_info = {
@@ -318,7 +330,7 @@ static gint pxb_compare(gconstpointer a, gconstpointer b)
0;
}
-static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
+static bool pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
Error **errp)
{
PXBDev *pxb = PXB_DEV(dev);
@@ -330,13 +342,13 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
if (ms->numa_state == NULL) {
error_setg(errp, "NUMA is not supported by this machine-type");
- return;
+ return false;
}
if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
pxb->numa_node >= ms->numa_state->num_nodes) {
error_setg(errp, "Illegal numa node %d", pxb->numa_node);
- return;
+ return false;
}
if (dev->qdev.id && *dev->qdev.id) {
@@ -382,12 +394,13 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
- return;
+ return true;
err_register_bus:
object_unref(OBJECT(bds));
object_unparent(OBJECT(bus));
object_unref(OBJECT(ds));
+ return false;
}
static void pxb_dev_realize(PCIDevice *dev, Error **errp)
@@ -488,7 +501,9 @@ static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp)
return;
}
- pxb_dev_realize_common(dev, CXL, errp);
+ if (!pxb_dev_realize_common(dev, CXL, errp)) {
+ return;
+ }
pxb_cxl_dev_reset(DEVICE(dev));
}
diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c
index 391fabb8a8..e8b4c64c5f 100644
--- a/hw/pci-host/gpex-acpi.c
+++ b/hw/pci-host/gpex-acpi.c
@@ -141,6 +141,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
QLIST_FOREACH(bus, &bus->child, sibling) {
uint8_t bus_num = pci_bus_num(bus);
uint8_t numa_node = pci_bus_numa_node(bus);
+ uint32_t uid;
bool is_cxl = pci_bus_is_cxl(bus);
if (!pci_bus_is_root(bus)) {
@@ -156,6 +157,8 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
nr_pcie_buses = bus_num;
}
+ uid = object_property_get_uint(OBJECT(bus), "acpi_uid",
+ &error_fatal);
dev = aml_device("PC%.02X", bus_num);
if (is_cxl) {
struct Aml *pkg = aml_package(2);
@@ -168,7 +171,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03")));
}
aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num)));
- aml_append(dev, aml_name_decl("_UID", aml_int(bus_num)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
aml_append(dev, aml_name_decl("_STR", aml_unicode("pxb Device")));
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
if (numa_node != NUMA_NODE_UNASSIGNED) {
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 87da35ca9b..1416ae202c 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -67,6 +67,19 @@ static char *pcibus_get_fw_dev_path(DeviceState *dev);
static void pcibus_reset_hold(Object *obj, ResetType type);
static bool pcie_has_upstream_port(PCIDevice *dev);
+static void prop_pci_busnr_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t busnr = pci_dev_bus_num(PCI_DEVICE(obj));
+
+ visit_type_uint8(v, name, &busnr, errp);
+}
+
+static const PropertyInfo prop_pci_busnr = {
+ .name = "busnr",
+ .get = prop_pci_busnr_get,
+};
+
static Property pci_props[] = {
DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
@@ -87,6 +100,9 @@ static Property pci_props[] = {
QEMU_PCIE_ARI_NEXTFN_1_BITNR, false),
DEFINE_PROP_SIZE32("x-max-bounce-buffer-size", PCIDevice,
max_bounce_buffer_size, DEFAULT_MAX_BOUNCE_BUFFER_SIZE),
+ DEFINE_PROP_BIT("x-pcie-ext-tag", PCIDevice, cap_present,
+ QEMU_PCIE_EXT_TAG_BITNR, true),
+ { .name = "busnr", .info = &prop_pci_busnr },
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index 6a4e38856d..2c7bb1a525 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -380,9 +380,12 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename)
sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn;
sec_bus->address_space_mem = &br->address_space_mem;
memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX);
+ address_space_init(&br->as_mem, &br->address_space_mem,
+ "pci_bridge_pci_mem");
sec_bus->address_space_io = &br->address_space_io;
memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io",
4 * GiB);
+ address_space_init(&br->as_io, &br->address_space_io, "pci_bridge_pci_io");
pci_bridge_region_init(br);
QLIST_INIT(&sec_bus->child);
QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);
@@ -399,6 +402,8 @@ void pci_bridge_exitfn(PCIDevice *pci_dev)
PCIBridge *s = PCI_BRIDGE(pci_dev);
assert(QLIST_EMPTY(&s->sec_bus.child));
QLIST_REMOVE(&s->sec_bus, sibling);
+ address_space_destroy(&s->as_mem);
+ address_space_destroy(&s->as_io);
pci_bridge_region_del(s, &s->windows);
pci_bridge_region_cleanup(s, &s->windows);
/* object_unparent() is called automatically during device deletion */
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 4b2f0805c6..0b455c8654 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -86,7 +86,13 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
* Specification, Revision 1.1., or subsequent PCI Express Base
* Specification revisions.
*/
- pci_set_long(exp_cap + PCI_EXP_DEVCAP, PCI_EXP_DEVCAP_RBER);
+ uint32_t devcap = PCI_EXP_DEVCAP_RBER;
+
+ if (dev->cap_present & QEMU_PCIE_EXT_TAG) {
+ devcap = PCI_EXP_DEVCAP_RBER | PCI_EXP_DEVCAP_EXT_TAG;
+ }
+
+ pci_set_long(exp_cap + PCI_EXP_DEVCAP, devcap);
pci_set_long(exp_cap + PCI_EXP_LNKCAP,
(port << PCI_EXP_LNKCAP_PN_SHIFT) |
@@ -105,46 +111,18 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
}
-static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
+/* Includes setting the target speed default */
+static void pcie_cap_fill_lnk(uint8_t *exp_cap, PCIExpLinkWidth width,
+ PCIExpLinkSpeed speed)
{
- PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
- uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
-
- /* Skip anything that isn't a PCIESlot */
- if (!s) {
- return;
- }
-
/* Clear and fill LNKCAP from what was configured above */
pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- QEMU_PCI_EXP_LNKCAP_MLW(s->width) |
- QEMU_PCI_EXP_LNKCAP_MLS(s->speed));
-
- /*
- * Link bandwidth notification is required for all root ports and
- * downstream ports supporting links wider than x1 or multiple link
- * speeds.
- */
- if (s->width > QEMU_PCI_EXP_LNK_X1 ||
- s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
- pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- PCI_EXP_LNKCAP_LBNC);
- }
-
- if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
- /*
- * Hot-plug capable downstream ports and downstream ports supporting
- * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
- * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
- * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also
- * technically implement this, but it's not done here for compatibility.
- */
- pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- PCI_EXP_LNKCAP_DLLLARC);
- /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */
+ QEMU_PCI_EXP_LNKCAP_MLW(width) |
+ QEMU_PCI_EXP_LNKCAP_MLS(speed));
+ if (speed > QEMU_PCI_EXP_LNK_2_5GT) {
/*
* Target Link Speed defaults to the highest link speed supported by
* the component. 2.5GT/s devices are permitted to hardwire to zero.
@@ -152,7 +130,7 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2,
PCI_EXP_LNKCTL2_TLS);
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2,
- QEMU_PCI_EXP_LNKCAP_MLS(s->speed) &
+ QEMU_PCI_EXP_LNKCAP_MLS(speed) &
PCI_EXP_LNKCTL2_TLS);
}
@@ -161,27 +139,82 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
* actually a reference to the highest bit supported in this register.
* We assume the device supports all link speeds.
*/
- if (s->speed > QEMU_PCI_EXP_LNK_5GT) {
+ if (speed > QEMU_PCI_EXP_LNK_5GT) {
pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U);
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_2_5GB |
PCI_EXP_LNKCAP2_SLS_5_0GB |
PCI_EXP_LNKCAP2_SLS_8_0GB);
- if (s->speed > QEMU_PCI_EXP_LNK_8GT) {
+ if (speed > QEMU_PCI_EXP_LNK_8GT) {
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_16_0GB);
}
- if (s->speed > QEMU_PCI_EXP_LNK_16GT) {
+ if (speed > QEMU_PCI_EXP_LNK_16GT) {
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_32_0GB);
}
- if (s->speed > QEMU_PCI_EXP_LNK_32GT) {
+ if (speed > QEMU_PCI_EXP_LNK_32GT) {
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
PCI_EXP_LNKCAP2_SLS_64_0GB);
}
}
}
+void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
+ PCIExpLinkSpeed speed)
+{
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+
+ /*
+ * For an end point or USP need to set the current status as well
+ * as the capabilities.
+ */
+ pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
+ PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
+ QEMU_PCI_EXP_LNKSTA_NLW(width) |
+ QEMU_PCI_EXP_LNKSTA_CLS(speed));
+
+ pcie_cap_fill_lnk(exp_cap, width, speed);
+}
+
+static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
+{
+ PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+
+ /* Skip anything that isn't a PCIESlot */
+ if (!s) {
+ return;
+ }
+
+ /*
+ * Link bandwidth notification is required for all root ports and
+ * downstream ports supporting links wider than x1 or multiple link
+ * speeds.
+ */
+ if (s->width > QEMU_PCI_EXP_LNK_X1 ||
+ s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
+ PCI_EXP_LNKCAP_LBNC);
+ }
+
+ if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
+ /*
+ * Hot-plug capable downstream ports and downstream ports supporting
+ * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
+ * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
+ * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also
+ * technically implement this, but it's not done here for compatibility.
+ */
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
+ PCI_EXP_LNKCAP_DLLLARC);
+ /* the PCI_EXP_LNKSTA_DLLLA will be set in the hotplug function */
+ }
+
+ pcie_cap_fill_lnk(exp_cap, s->width, s->speed);
+}
+
int pcie_cap_init(PCIDevice *dev, uint8_t offset,
uint8_t type, uint8_t port,
Error **errp)
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 00561daa06..f170f0b25b 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1185,9 +1185,16 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev,
static void vhost_user_host_notifier_free(VhostUserHostNotifier *n)
{
- assert(n && n->unmap_addr);
- munmap(n->unmap_addr, qemu_real_host_page_size());
- n->unmap_addr = NULL;
+ if (n->unmap_addr) {
+ munmap(n->unmap_addr, qemu_real_host_page_size());
+ n->unmap_addr = NULL;
+ }
+ if (n->destroy) {
+ memory_region_transaction_begin();
+ object_unparent(OBJECT(&n->mr));
+ memory_region_transaction_commit();
+ g_free(n);
+ }
}
/*
@@ -1195,17 +1202,28 @@ static void vhost_user_host_notifier_free(VhostUserHostNotifier *n)
* under rcu.
*/
static void vhost_user_host_notifier_remove(VhostUserHostNotifier *n,
- VirtIODevice *vdev)
+ VirtIODevice *vdev, bool destroy)
{
+ /*
+ * if destroy == false and n->addr == NULL, we have nothing to do.
+ * so, just return.
+ */
+ if (!n || (!destroy && !n->addr)) {
+ return;
+ }
+
if (n->addr) {
if (vdev) {
+ memory_region_transaction_begin();
virtio_queue_set_host_notifier_mr(vdev, n->idx, &n->mr, false);
+ memory_region_transaction_commit();
}
assert(!n->unmap_addr);
n->unmap_addr = n->addr;
n->addr = NULL;
- call_rcu(n, vhost_user_host_notifier_free, rcu);
}
+ n->destroy = destroy;
+ call_rcu(n, vhost_user_host_notifier_free, rcu);
}
static int vhost_user_set_vring_base(struct vhost_dev *dev,
@@ -1279,9 +1297,7 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
struct vhost_user *u = dev->opaque;
VhostUserHostNotifier *n = fetch_notifier(u->user, ring->index);
- if (n) {
- vhost_user_host_notifier_remove(n, dev->vdev);
- }
+ vhost_user_host_notifier_remove(n, dev->vdev, false);
ret = vhost_user_write(dev, &msg, NULL, 0);
if (ret < 0) {
@@ -1562,7 +1578,7 @@ static int vhost_user_backend_handle_vring_host_notifier(struct vhost_dev *dev,
* new mapped address.
*/
n = fetch_or_create_notifier(user, queue_idx);
- vhost_user_host_notifier_remove(n, vdev);
+ vhost_user_host_notifier_remove(n, vdev, false);
if (area->u64 & VHOST_USER_VRING_NOFD_MASK) {
return 0;
@@ -1607,9 +1623,14 @@ vhost_user_backend_handle_shared_object_add(struct vhost_dev *dev,
QemuUUID uuid;
memcpy(uuid.data, object->uuid, sizeof(object->uuid));
- return virtio_add_vhost_device(&uuid, dev);
+ return !virtio_add_vhost_device(&uuid, dev);
}
+/*
+ * Handle VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE backend requests.
+ *
+ * Return: 0 on success, 1 on error.
+ */
static int
vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
VhostUserShared *object)
@@ -1623,16 +1644,16 @@ vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
struct vhost_dev *owner = virtio_lookup_vhost_device(&uuid);
if (dev != owner) {
/* Not allowed to remove non-owned entries */
- return 0;
+ return 1;
}
break;
}
default:
/* Not allowed to remove non-owned entries */
- return 0;
+ return 1;
}
- return virtio_remove_resource(&uuid);
+ return !virtio_remove_resource(&uuid);
}
static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
@@ -2736,15 +2757,7 @@ static int vhost_user_set_inflight_fd(struct vhost_dev *dev,
static void vhost_user_state_destroy(gpointer data)
{
VhostUserHostNotifier *n = (VhostUserHostNotifier *) data;
- if (n) {
- vhost_user_host_notifier_remove(n, NULL);
- object_unparent(OBJECT(&n->mr));
- /*
- * We can't free until vhost_user_host_notifier_remove has
- * done it's thing so schedule the free with RCU.
- */
- g_free_rcu(n, rcu);
- }
+ vhost_user_host_notifier_remove(n, NULL, true);
}
bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp)
@@ -2765,9 +2778,7 @@ void vhost_user_cleanup(VhostUserState *user)
if (!user->chr) {
return;
}
- memory_region_transaction_begin();
user->notifiers = (GPtrArray *) g_ptr_array_free(user->notifiers, true);
- memory_region_transaction_commit();
user->chr = NULL;
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 4d832fe845..5a394821da 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -2057,6 +2057,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (modern_pio) {
memory_region_init(&proxy->io_bar, OBJECT(proxy),
"virtio-pci-io", 0x4);
+ address_space_init(&proxy->modern_cfg_io_as, &proxy->io_bar,
+ "virtio-pci-cfg-io-as");
pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar_idx,
PCI_BASE_ADDRESS_SPACE_IO, &proxy->io_bar);
@@ -2180,6 +2182,9 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
/* PCI BAR regions must be powers of 2 */
pow2ceil(proxy->notify.offset + proxy->notify.size));
+ address_space_init(&proxy->modern_cfg_mem_as, &proxy->modern_bar,
+ "virtio-pci-cfg-mem-as");
+
if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) {
proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
}
@@ -2269,12 +2274,17 @@ static void virtio_pci_exit(PCIDevice *pci_dev)
VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
bool pcie_port = pci_bus_is_express(pci_get_bus(pci_dev)) &&
!pci_bus_is_root(pci_get_bus(pci_dev));
+ bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
msix_uninit_exclusive_bar(pci_dev);
if (proxy->flags & VIRTIO_PCI_FLAG_AER && pcie_port &&
pci_is_express(pci_dev)) {
pcie_aer_exit(pci_dev);
}
+ address_space_destroy(&proxy->modern_cfg_mem_as);
+ if (modern_pio) {
+ address_space_destroy(&proxy->modern_cfg_io_as);
+ }
}
static void virtio_pci_reset(DeviceState *qdev)
@@ -2385,6 +2395,14 @@ static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp)
vpciklass->parent_dc_realize(qdev, errp);
}
+static int virtio_pci_sync_config(DeviceState *dev, Error **errp)
+{
+ VirtIOPCIProxy *proxy = VIRTIO_PCI(dev);
+ VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+
+ return qdev_sync_config(DEVICE(vdev), errp);
+}
+
static void virtio_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -2401,6 +2419,7 @@ static void virtio_pci_class_init(ObjectClass *klass, void *data)
device_class_set_parent_realize(dc, virtio_pci_dc_realize,
&vpciklass->parent_dc_realize);
rc->phases.hold = virtio_pci_bus_reset_hold;
+ dc->sync_config = virtio_pci_sync_config;
}
static const TypeInfo virtio_pci_info = {
diff --git a/include/exec/memory.h b/include/exec/memory.h
index e5e865d1a9..9458e2801d 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1104,7 +1104,14 @@ struct AddressSpace {
QTAILQ_HEAD(, MemoryListener) listeners;
QTAILQ_ENTRY(AddressSpace) address_spaces_link;
- /* Maximum DMA bounce buffer size used for indirect memory map requests */
+ /*
+ * Maximum DMA bounce buffer size used for indirect memory map requests.
+ * This limits the total size of bounce buffer allocations made for
+ * DMA requests to indirect memory regions within this AddressSpace. DMA
+ * requests that exceed the limit (e.g. due to overly large requested size
+ * or concurrent DMA requests having claimed too much buffer space) will be
+ * rejected and left to the caller to handle.
+ */
size_t max_bounce_buffer_size;
/* Total size of bounce buffers currently allocated, atomically accessed */
size_t bounce_buffer_size;
diff --git a/include/hw/acpi/acpi_generic_initiator.h b/include/hw/acpi/acpi_generic_initiator.h
deleted file mode 100644
index a304bad73e..0000000000
--- a/include/hw/acpi/acpi_generic_initiator.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved
- */
-
-#ifndef ACPI_GENERIC_INITIATOR_H
-#define ACPI_GENERIC_INITIATOR_H
-
-#include "qom/object_interfaces.h"
-
-#define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator"
-
-typedef struct AcpiGenericInitiator {
- /* private */
- Object parent;
-
- /* public */
- char *pci_dev;
- uint16_t node;
-} AcpiGenericInitiator;
-
-/*
- * ACPI 6.3:
- * Table 5-81 Flags – Generic Initiator Affinity Structure
- */
-typedef enum {
- /*
- * If clear, the OSPM ignores the contents of the Generic
- * Initiator/Port Affinity Structure. This allows system firmware
- * to populate the SRAT with a static number of structures, but only
- * enable them as necessary.
- */
- GEN_AFFINITY_ENABLED = (1 << 0),
-} GenericAffinityFlags;
-
-/*
- * ACPI 6.3:
- * Table 5-80 Device Handle - PCI
- */
-typedef struct PCIDeviceHandle {
- uint16_t segment;
- uint16_t bdf;
-} PCIDeviceHandle;
-
-void build_srat_generic_pci_initiator(GArray *table_data);
-
-#endif
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index a3784155cb..4fd5da49e7 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -486,6 +486,13 @@ Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set, uint32_t io_offset,
void build_srat_memory(GArray *table_data, uint64_t base,
uint64_t len, int node, MemoryAffinityFlags flags);
+void build_srat_pci_generic_initiator(GArray *table_data, uint32_t node,
+ uint16_t segment, uint8_t bus,
+ uint8_t devfn);
+
+void build_srat_acpi_generic_port(GArray *table_data, uint32_t node,
+ const char *hid, uint32_t uid);
+
void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms,
const char *oem_id, const char *oem_table_id);
diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h
index 467a99461c..6359d574fd 100644
--- a/include/hw/acpi/pci.h
+++ b/include/hw/acpi/pci.h
@@ -40,4 +40,7 @@ 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);
+
+void build_srat_generic_affinity_structures(GArray *table_data);
+
#endif
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index c3ca0babcb..db8a6fbc6e 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -158,6 +158,8 @@ struct CPUClass {
void (*dump_state)(CPUState *cpu, FILE *, int flags);
void (*query_cpu_fast)(CPUState *cpu, CpuInfoFast *value);
int64_t (*get_arch_id)(CPUState *cpu);
+ bool (*cpu_persistent_status)(CPUState *cpu);
+ bool (*cpu_enabled_status)(CPUState *cpu);
void (*set_pc)(CPUState *cpu, vaddr value);
vaddr (*get_pc)(CPUState *cpu);
int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg);
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index fdd0f4e62b..561b375dc8 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -463,18 +463,6 @@ typedef struct CXLMemPatrolScrubWriteAttrs {
#define CXL_MEMDEV_PS_ENABLE_DEFAULT 0
/* CXL memory device DDR5 ECS control attributes */
-typedef struct CXLMemECSReadAttrs {
- uint8_t ecs_log_cap;
- uint8_t ecs_cap;
- uint16_t ecs_config;
- uint8_t ecs_flags;
-} QEMU_PACKED CXLMemECSReadAttrs;
-
-typedef struct CXLMemECSWriteAttrs {
- uint8_t ecs_log_cap;
- uint16_t ecs_config;
-} QEMU_PACKED CXLMemECSWriteAttrs;
-
#define CXL_ECS_GET_FEATURE_VERSION 0x01
#define CXL_ECS_SET_FEATURE_VERSION 0x01
#define CXL_ECS_LOG_ENTRY_TYPE_DEFAULT 0x01
@@ -483,6 +471,26 @@ typedef struct CXLMemECSWriteAttrs {
#define CXL_ECS_MODE_DEFAULT 0
#define CXL_ECS_NUM_MEDIA_FRUS 3 /* Default */
+typedef struct CXLMemECSFRUReadAttrs {
+ uint8_t ecs_cap;
+ uint16_t ecs_config;
+ uint8_t ecs_flags;
+} QEMU_PACKED CXLMemECSFRUReadAttrs;
+
+typedef struct CXLMemECSReadAttrs {
+ uint8_t ecs_log_cap;
+ CXLMemECSFRUReadAttrs fru_attrs[CXL_ECS_NUM_MEDIA_FRUS];
+} QEMU_PACKED CXLMemECSReadAttrs;
+
+typedef struct CXLMemECSFRUWriteAttrs {
+ uint16_t ecs_config;
+} QEMU_PACKED CXLMemECSFRUWriteAttrs;
+
+typedef struct CXLMemECSWriteAttrs {
+ uint8_t ecs_log_cap;
+ CXLMemECSFRUWriteAttrs fru_attrs[CXL_ECS_NUM_MEDIA_FRUS];
+} QEMU_PACKED CXLMemECSWriteAttrs;
+
#define DCD_MAX_NUM_REGION 8
typedef struct CXLDCExtentRaw {
@@ -549,6 +557,10 @@ struct CXLType3Dev {
CXLCCI vdm_fm_owned_ld_mctp_cci;
CXLCCI ld0_cci;
+ /* PCIe link characteristics */
+ PCIExpLinkSpeed speed;
+ PCIExpLinkWidth width;
+
/* DOE */
DOECap doe_cdat;
@@ -571,8 +583,8 @@ struct CXLType3Dev {
CXLMemPatrolScrubReadAttrs patrol_scrub_attrs;
CXLMemPatrolScrubWriteAttrs patrol_scrub_wr_attrs;
/* ECS control attributes */
- CXLMemECSReadAttrs ecs_attrs[CXL_ECS_NUM_MEDIA_FRUS];
- CXLMemECSWriteAttrs ecs_wr_attrs[CXL_ECS_NUM_MEDIA_FRUS];
+ CXLMemECSReadAttrs ecs_attrs;
+ CXLMemECSWriteAttrs ecs_wr_attrs;
struct dynamic_capacity {
HostMemoryBackend *host_dc;
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index 1eb05c29fc..d372cd396b 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -306,6 +306,9 @@ struct IntelIOMMUState {
bool dma_translation; /* Whether DMA translation supported */
bool pasid; /* Whether to support PASID */
+ /* Transient Mapping, Reserved(0) since VTD spec revision 3.2 */
+ bool stale_tm;
+
/*
* Protects IOMMU states in general. Currently it protects the
* per-IOMMU IOTLB cache, and context entry cache in VTDAddressSpace.
diff --git a/include/hw/pci-bridge/cxl_upstream_port.h b/include/hw/pci-bridge/cxl_upstream_port.h
index 12635139f6..f208397ffe 100644
--- a/include/hw/pci-bridge/cxl_upstream_port.h
+++ b/include/hw/pci-bridge/cxl_upstream_port.h
@@ -12,6 +12,10 @@ typedef struct CXLUpstreamPort {
/*< public >*/
CXLComponentState cxl_cstate;
CXLCCI swcci;
+
+ PCIExpLinkSpeed speed;
+ PCIExpLinkWidth width;
+
DOECap doe_cdat;
uint64_t sn;
} CXLUpstreamPort;
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 35d4fe0bbf..135695c551 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -16,7 +16,7 @@ extern bool pci_available;
#define PCI_BUS_NUM(x) (((x) >> 8) & 0xff)
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
-#define PCI_BUILD_BDF(bus, devfn) ((bus << 8) | (devfn))
+#define PCI_BUILD_BDF(bus, devfn) (((bus) << 8) | (devfn))
#define PCI_BDF_TO_DEVFN(x) ((x) & 0xff)
#define PCI_BUS_MAX 256
#define PCI_DEVFN_MAX 256
@@ -214,6 +214,8 @@ enum {
QEMU_PCIE_ERR_UNC_MASK = (1 << QEMU_PCIE_ERR_UNC_MASK_BITNR),
#define QEMU_PCIE_ARI_NEXTFN_1_BITNR 12
QEMU_PCIE_ARI_NEXTFN_1 = (1 << QEMU_PCIE_ARI_NEXTFN_1_BITNR),
+#define QEMU_PCIE_EXT_TAG_BITNR 13
+ QEMU_PCIE_EXT_TAG = (1 << QEMU_PCIE_EXT_TAG_BITNR),
};
typedef struct PCIINTxRoute {
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index 5cd452115a..b0f5204d80 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -72,6 +72,8 @@ struct PCIBridge {
*/
MemoryRegion address_space_mem;
MemoryRegion address_space_io;
+ AddressSpace as_mem;
+ AddressSpace as_io;
PCIBridgeWindows windows;
@@ -102,6 +104,7 @@ typedef struct PXBPCIEDev {
PXBDev parent_obj;
} PXBPCIEDev;
+#define TYPE_PXB_CXL_BUS "pxb-cxl-bus"
#define TYPE_PXB_DEV "pxb"
OBJECT_DECLARE_SIMPLE_TYPE(PXBDev, PXB_DEV)
diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
index 91df40f989..8eaf0d58bb 100644
--- a/include/hw/pci/pci_device.h
+++ b/include/hw/pci/pci_device.h
@@ -168,7 +168,11 @@ struct PCIDevice {
char *failover_pair_id;
uint32_t acpi_index;
- /* Maximum DMA bounce buffer size used for indirect memory map requests */
+ /*
+ * Indirect DMA region bounce buffer size as configured for the device. This
+ * is a configuration parameter that is reflected into bus_master_as when
+ * realizing the device.
+ */
uint32_t max_bounce_buffer_size;
};
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
index 5eddb90976..b8d59732bc 100644
--- a/include/hw/pci/pcie.h
+++ b/include/hw/pci/pcie.h
@@ -141,6 +141,8 @@ void pcie_acs_reset(PCIDevice *dev);
void pcie_ari_init(PCIDevice *dev, uint16_t offset);
void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
void pcie_ats_init(PCIDevice *dev, uint16_t offset, bool aligned);
+void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
+ PCIExpLinkSpeed speed);
void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index aa97c34a4b..94914858d8 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -95,6 +95,7 @@ typedef void (*DeviceUnrealize)(DeviceState *dev);
typedef void (*DeviceReset)(DeviceState *dev);
typedef void (*BusRealize)(BusState *bus, Error **errp);
typedef void (*BusUnrealize)(BusState *bus);
+typedef int (*DeviceSyncConfig)(DeviceState *dev, Error **errp);
/**
* struct DeviceClass - The base class for all devices.
@@ -103,6 +104,9 @@ typedef void (*BusUnrealize)(BusState *bus);
* property is changed to %true.
* @unrealize: Callback function invoked when the #DeviceState:realized
* property is changed to %false.
+ * @sync_config: Callback function invoked when QMP command device-sync-config
+ * is called. Should synchronize device configuration from host to guest part
+ * and notify the guest about the change.
* @hotpluggable: indicates if #DeviceClass is hotpluggable, available
* as readonly "hotpluggable" property of #DeviceState instance
*
@@ -162,6 +166,7 @@ struct DeviceClass {
DeviceReset legacy_reset;
DeviceRealize realize;
DeviceUnrealize unrealize;
+ DeviceSyncConfig sync_config;
/**
* @vmsd: device state serialisation description for
@@ -547,6 +552,7 @@ bool qdev_hotplug_allowed(DeviceState *dev, Error **errp);
*/
HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
void qdev_unplug(DeviceState *dev, Error **errp);
+int qdev_sync_config(DeviceState *dev, Error **errp);
void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
void qdev_machine_creation_done(void);
diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
index 324cd8663a..9a3f238b43 100644
--- a/include/hw/virtio/vhost-user.h
+++ b/include/hw/virtio/vhost-user.h
@@ -54,6 +54,7 @@ typedef struct VhostUserHostNotifier {
void *addr;
void *unmap_addr;
int idx;
+ bool destroy;
} VhostUserHostNotifier;
/**
diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h
index 9e67ba38c7..971c5fabd4 100644
--- a/include/hw/virtio/virtio-pci.h
+++ b/include/hw/virtio/virtio-pci.h
@@ -147,6 +147,9 @@ struct VirtIOPCIProxy {
};
MemoryRegion modern_bar;
MemoryRegion io_bar;
+ /* address space for VirtIOPCIRegions */
+ AddressSpace modern_cfg_mem_as;
+ AddressSpace modern_cfg_io_as;
uint32_t legacy_io_bar_idx;
uint32_t msix_bar_idx;
uint32_t modern_io_bar_idx;
diff --git a/qapi/qdev.json b/qapi/qdev.json
index 53d147c7b4..2a581129c9 100644
--- a/qapi/qdev.json
+++ b/qapi/qdev.json
@@ -163,3 +163,27 @@
##
{ 'event': 'DEVICE_UNPLUG_GUEST_ERROR',
'data': { '*device': 'str', 'path': 'str' } }
+
+##
+# @device-sync-config:
+#
+# Synchronize device configuration from host to guest part. First,
+# copy the configuration from the host part (backend) to the guest
+# part (frontend). Then notify guest software that device
+# configuration changed.
+#
+# The command may be used to notify the guest about block device
+# capcity change. Currently only vhost-user-blk device supports
+# this.
+#
+# @id: the device's ID or QOM path
+#
+# Features:
+#
+# @unstable: The command is experimental.
+#
+# Since: 9.1
+##
+{ 'command': 'device-sync-config',
+ 'features': [ 'unstable' ],
+ 'data': {'id': 'str'} }
diff --git a/qapi/qom.json b/qapi/qom.json
index 321ccd708a..a8beeabf1f 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -845,6 +845,45 @@
'node': 'uint32' } }
##
+# @AcpiGenericPortProperties:
+#
+# Properties for acpi-generic-port objects.
+#
+# @pci-bus: QOM path of the PCI bus of the hostbridge associated with
+# this SRAT Generic Port Affinity Structure. This is the same as
+# the bus parameter for the root ports attached to this host
+# bridge. The resulting SRAT Generic Port Affinity Structure will
+# refer to the ACPI object in DSDT that represents the host bridge
+# (e.g. ACPI0016 for CXL host bridges). See ACPI 6.5 Section
+# 5.2.16.7 for more information.
+#
+# @node: Similar to a NUMA node ID, but instead of providing a
+# reference point used for defining NUMA distances and access
+# characteristics to memory or from an initiator (e.g. CPU), this
+# node defines the boundary point between non-discoverable system
+# buses which must be described by firmware, and a discoverable
+# bus. NUMA distances and access characteristics are defined to
+# and from that point. For system software to establish full
+# initiator to target characteristics this information must be
+# combined with information retrieved from the discoverable part
+# of the path. An example would use CDAT (see UEFI.org)
+# information read from devices and switches in conjunction with
+# link characteristics read from PCIe Configuration space.
+# To get the full path latency from CPU to CXL attached DRAM
+# CXL device: Add the latency from CPU to Generic Port (from
+# HMAT indexed via the the node ID in this SRAT structure) to
+# that for CXL bus links, the latency across intermediate switches
+# and from the EP port to the actual memory. Bandwidth is more
+# complex as there may be interleaving across multiple devices
+# and shared links in the path.
+#
+# Since: 9.1
+##
+{ 'struct': 'AcpiGenericPortProperties',
+ 'data': { 'pci-bus': 'str',
+ 'node': 'uint32' } }
+
+##
# @RngProperties:
#
# Properties for objects of classes derived from rng.
@@ -1043,6 +1082,7 @@
{ 'enum': 'ObjectType',
'data': [
'acpi-generic-initiator',
+ 'acpi-generic-port',
'authz-list',
'authz-listfile',
'authz-pam',
@@ -1118,6 +1158,7 @@
'discriminator': 'qom-type',
'data': {
'acpi-generic-initiator': 'AcpiGenericInitiatorProperties',
+ 'acpi-generic-port': 'AcpiGenericPortProperties',
'authz-list': 'AuthZListProperties',
'authz-listfile': 'AuthZListFileProperties',
'authz-pam': 'AuthZPAMProperties',
diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
index 320c47b72d..d25325c4e3 100644
--- a/system/qdev-monitor.c
+++ b/system/qdev-monitor.c
@@ -23,6 +23,7 @@
#include "monitor/monitor.h"
#include "monitor/qdev.h"
#include "sysemu/arch_init.h"
+#include "sysemu/runstate.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-qdev.h"
#include "qapi/qmp/dispatch.h"
@@ -885,13 +886,20 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp)
object_unref(OBJECT(dev));
}
-static DeviceState *find_device_state(const char *id, Error **errp)
+/*
+ * Note that creating new APIs using error classes other than GenericError is
+ * not recommended. Set use_generic_error=true for new interfaces.
+ */
+static DeviceState *find_device_state(const char *id, bool use_generic_error,
+ Error **errp)
{
Object *obj = object_resolve_path_at(qdev_get_peripheral(), id);
DeviceState *dev;
if (!obj) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ error_set(errp,
+ (use_generic_error ?
+ ERROR_CLASS_GENERIC_ERROR : ERROR_CLASS_DEVICE_NOT_FOUND),
"Device '%s' not found", id);
return NULL;
}
@@ -956,7 +964,7 @@ void qdev_unplug(DeviceState *dev, Error **errp)
void qmp_device_del(const char *id, Error **errp)
{
- DeviceState *dev = find_device_state(id, errp);
+ DeviceState *dev = find_device_state(id, false, errp);
if (dev != NULL) {
if (dev->pending_deleted_event &&
(dev->pending_deleted_expires_ms == 0 ||
@@ -970,6 +978,43 @@ void qmp_device_del(const char *id, Error **errp)
}
}
+int qdev_sync_config(DeviceState *dev, Error **errp)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+ if (!dc->sync_config) {
+ error_setg(errp, "device-sync-config is not supported for '%s'",
+ object_get_typename(OBJECT(dev)));
+ return -ENOTSUP;
+ }
+
+ return dc->sync_config(dev, errp);
+}
+
+void qmp_device_sync_config(const char *id, Error **errp)
+{
+ DeviceState *dev;
+
+ /*
+ * During migration there is a race between syncing`configuration
+ * and migrating it (if migrate first, that target would get
+ * outdated version), so let's just not allow it.
+ */
+
+ if (migration_is_running()) {
+ error_setg(errp, "Config synchronization is not allowed "
+ "during migration");
+ return;
+ }
+
+ dev = find_device_state(id, true, errp);
+ if (!dev) {
+ return;
+ }
+
+ qdev_sync_config(dev, errp);
+}
+
void hmp_device_add(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
@@ -1076,7 +1121,7 @@ BlockBackend *blk_by_qdev_id(const char *id, Error **errp)
GLOBAL_STATE_CODE();
- dev = find_device_state(id, errp);
+ dev = find_device_state(id, false, errp);
if (dev == NULL) {
return NULL;
}
diff --git a/tests/data/acpi/disassemle-aml.sh b/tests/data/acpi/disassemle-aml.sh
index 253b7620a0..89561d233d 100755
--- a/tests/data/acpi/disassemle-aml.sh
+++ b/tests/data/acpi/disassemle-aml.sh
@@ -14,7 +14,7 @@ while getopts "o:" arg; do
esac
done
-for machine in tests/data/acpi/*
+for machine in tests/data/acpi/*/*
do
if [[ ! -d "$machine" ]];
then
diff --git a/tests/data/acpi/x86/pc/DSDT b/tests/data/acpi/x86/pc/DSDT
index 92225236e7..f68a32e606 100644
--- a/tests/data/acpi/x86/pc/DSDT
+++ b/tests/data/acpi/x86/pc/DSDT
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.acpierst b/tests/data/acpi/x86/pc/DSDT.acpierst
index 25b3995505..0fd79699eb 100644
--- a/tests/data/acpi/x86/pc/DSDT.acpierst
+++ b/tests/data/acpi/x86/pc/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.acpihmat b/tests/data/acpi/x86/pc/DSDT.acpihmat
index 73a9ce59e9..a4dd09e5ef 100644
--- a/tests/data/acpi/x86/pc/DSDT.acpihmat
+++ b/tests/data/acpi/x86/pc/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.bridge b/tests/data/acpi/x86/pc/DSDT.bridge
index 4cef454e37..7ef58152d2 100644
--- a/tests/data/acpi/x86/pc/DSDT.bridge
+++ b/tests/data/acpi/x86/pc/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.cphp b/tests/data/acpi/x86/pc/DSDT.cphp
index 1dc928333d..1079ff81c1 100644
--- a/tests/data/acpi/x86/pc/DSDT.cphp
+++ b/tests/data/acpi/x86/pc/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.dimmpxm b/tests/data/acpi/x86/pc/DSDT.dimmpxm
index 9f71d2e58b..34fe3fcad9 100644
--- a/tests/data/acpi/x86/pc/DSDT.dimmpxm
+++ b/tests/data/acpi/x86/pc/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.hpbridge b/tests/data/acpi/x86/pc/DSDT.hpbridge
index db420593a3..33c7529f5c 100644
--- a/tests/data/acpi/x86/pc/DSDT.hpbridge
+++ b/tests/data/acpi/x86/pc/DSDT.hpbridge
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.hpbrroot b/tests/data/acpi/x86/pc/DSDT.hpbrroot
index 31b6adb4eb..2661170c83 100644
--- a/tests/data/acpi/x86/pc/DSDT.hpbrroot
+++ b/tests/data/acpi/x86/pc/DSDT.hpbrroot
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.ipmikcs b/tests/data/acpi/x86/pc/DSDT.ipmikcs
index c2a0330d97..688faf83cb 100644
--- a/tests/data/acpi/x86/pc/DSDT.ipmikcs
+++ b/tests/data/acpi/x86/pc/DSDT.ipmikcs
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.memhp b/tests/data/acpi/x86/pc/DSDT.memhp
index c15a9fae94..6ede4361f4 100644
--- a/tests/data/acpi/x86/pc/DSDT.memhp
+++ b/tests/data/acpi/x86/pc/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.nohpet b/tests/data/acpi/x86/pc/DSDT.nohpet
index dd29f5cb62..9d6040733f 100644
--- a/tests/data/acpi/x86/pc/DSDT.nohpet
+++ b/tests/data/acpi/x86/pc/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.numamem b/tests/data/acpi/x86/pc/DSDT.numamem
index 8a6b56fe7d..aa9986f74b 100644
--- a/tests/data/acpi/x86/pc/DSDT.numamem
+++ b/tests/data/acpi/x86/pc/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.roothp b/tests/data/acpi/x86/pc/DSDT.roothp
index a16b0d9d4b..86c2ae11dc 100644
--- a/tests/data/acpi/x86/pc/DSDT.roothp
+++ b/tests/data/acpi/x86/pc/DSDT.roothp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT b/tests/data/acpi/x86/q35/DSDT
index fb89ae0ac6..b0bbff7686 100644
--- a/tests/data/acpi/x86/q35/DSDT
+++ b/tests/data/acpi/x86/q35/DSDT
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.acpierst b/tests/data/acpi/x86/q35/DSDT.acpierst
index 46fd25400b..f91cbe55fc 100644
--- a/tests/data/acpi/x86/q35/DSDT.acpierst
+++ b/tests/data/acpi/x86/q35/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat b/tests/data/acpi/x86/q35/DSDT.acpihmat
index 61c5bd52a4..0949fb9d67 100644
--- a/tests/data/acpi/x86/q35/DSDT.acpihmat
+++ b/tests/data/acpi/x86/q35/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator
index 3aaa2bbdf5..0fa4daa35c 100644
--- a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator
+++ b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.applesmc b/tests/data/acpi/x86/q35/DSDT.applesmc
index 944209adea..a5d032b7d9 100644
--- a/tests/data/acpi/x86/q35/DSDT.applesmc
+++ b/tests/data/acpi/x86/q35/DSDT.applesmc
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.bridge b/tests/data/acpi/x86/q35/DSDT.bridge
index d9938dba8f..3464f55297 100644
--- a/tests/data/acpi/x86/q35/DSDT.bridge
+++ b/tests/data/acpi/x86/q35/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.core-count b/tests/data/acpi/x86/q35/DSDT.core-count
index a24b04cbdb..08f5d5f54b 100644
--- a/tests/data/acpi/x86/q35/DSDT.core-count
+++ b/tests/data/acpi/x86/q35/DSDT.core-count
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.core-count2 b/tests/data/acpi/x86/q35/DSDT.core-count2
index 3a0cb8c581..d29a7108f8 100644
--- a/tests/data/acpi/x86/q35/DSDT.core-count2
+++ b/tests/data/acpi/x86/q35/DSDT.core-count2
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.cphp b/tests/data/acpi/x86/q35/DSDT.cphp
index 20955d0aa3..7fd59bf670 100644
--- a/tests/data/acpi/x86/q35/DSDT.cphp
+++ b/tests/data/acpi/x86/q35/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.cxl b/tests/data/acpi/x86/q35/DSDT.cxl
index f561750cab..613a40b957 100644
--- a/tests/data/acpi/x86/q35/DSDT.cxl
+++ b/tests/data/acpi/x86/q35/DSDT.cxl
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.dimmpxm b/tests/data/acpi/x86/q35/DSDT.dimmpxm
index 228374b55b..1db0bf454a 100644
--- a/tests/data/acpi/x86/q35/DSDT.dimmpxm
+++ b/tests/data/acpi/x86/q35/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.ipmibt b/tests/data/acpi/x86/q35/DSDT.ipmibt
index 45f911ada5..25f43ae8ef 100644
--- a/tests/data/acpi/x86/q35/DSDT.ipmibt
+++ b/tests/data/acpi/x86/q35/DSDT.ipmibt
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.ipmismbus b/tests/data/acpi/x86/q35/DSDT.ipmismbus
index e5d6811bee..32bcd25bda 100644
--- a/tests/data/acpi/x86/q35/DSDT.ipmismbus
+++ b/tests/data/acpi/x86/q35/DSDT.ipmismbus
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.ivrs b/tests/data/acpi/x86/q35/DSDT.ivrs
index 46fd25400b..f91cbe55fc 100644
--- a/tests/data/acpi/x86/q35/DSDT.ivrs
+++ b/tests/data/acpi/x86/q35/DSDT.ivrs
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.memhp b/tests/data/acpi/x86/q35/DSDT.memhp
index 5ce081187a..be90eb71d8 100644
--- a/tests/data/acpi/x86/q35/DSDT.memhp
+++ b/tests/data/acpi/x86/q35/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.mmio64 b/tests/data/acpi/x86/q35/DSDT.mmio64
index bdf36c4d57..01f276a6af 100644
--- a/tests/data/acpi/x86/q35/DSDT.mmio64
+++ b/tests/data/acpi/x86/q35/DSDT.mmio64
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.multi-bridge b/tests/data/acpi/x86/q35/DSDT.multi-bridge
index 1db43a69e4..1bd2ee8d2e 100644
--- a/tests/data/acpi/x86/q35/DSDT.multi-bridge
+++ b/tests/data/acpi/x86/q35/DSDT.multi-bridge
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.noacpihp b/tests/data/acpi/x86/q35/DSDT.noacpihp
index 8bc16887e1..45cc2bcffa 100644
--- a/tests/data/acpi/x86/q35/DSDT.noacpihp
+++ b/tests/data/acpi/x86/q35/DSDT.noacpihp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.nohpet b/tests/data/acpi/x86/q35/DSDT.nohpet
index c13e45e361..f110504b9c 100644
--- a/tests/data/acpi/x86/q35/DSDT.nohpet
+++ b/tests/data/acpi/x86/q35/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.numamem b/tests/data/acpi/x86/q35/DSDT.numamem
index ba6669437e..6090958f39 100644
--- a/tests/data/acpi/x86/q35/DSDT.numamem
+++ b/tests/data/acpi/x86/q35/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa
index 6ad42873e9..7a8e568315 100644
--- a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa
+++ b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.thread-count b/tests/data/acpi/x86/q35/DSDT.thread-count
index a24b04cbdb..08f5d5f54b 100644
--- a/tests/data/acpi/x86/q35/DSDT.thread-count
+++ b/tests/data/acpi/x86/q35/DSDT.thread-count
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.thread-count2 b/tests/data/acpi/x86/q35/DSDT.thread-count2
index 3a0cb8c581..d29a7108f8 100644
--- a/tests/data/acpi/x86/q35/DSDT.thread-count2
+++ b/tests/data/acpi/x86/q35/DSDT.thread-count2
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm12 b/tests/data/acpi/x86/q35/DSDT.tis.tpm12
index e381ce4cbf..29a416f050 100644
--- a/tests/data/acpi/x86/q35/DSDT.tis.tpm12
+++ b/tests/data/acpi/x86/q35/DSDT.tis.tpm12
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm2 b/tests/data/acpi/x86/q35/DSDT.tis.tpm2
index a09253042c..59288f02c4 100644
--- a/tests/data/acpi/x86/q35/DSDT.tis.tpm2
+++ b/tests/data/acpi/x86/q35/DSDT.tis.tpm2
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.type4-count b/tests/data/acpi/x86/q35/DSDT.type4-count
index edc23198cd..eaca76e8e6 100644
--- a/tests/data/acpi/x86/q35/DSDT.type4-count
+++ b/tests/data/acpi/x86/q35/DSDT.type4-count
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.viot b/tests/data/acpi/x86/q35/DSDT.viot
index 8d98dd8845..de0942a13d 100644
--- a/tests/data/acpi/x86/q35/DSDT.viot
+++ b/tests/data/acpi/x86/q35/DSDT.viot
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.xapic b/tests/data/acpi/x86/q35/DSDT.xapic
index d4acd851c6..9059812b58 100644
--- a/tests/data/acpi/x86/q35/DSDT.xapic
+++ b/tests/data/acpi/x86/q35/DSDT.xapic
Binary files differ
diff --git a/tests/qtest/fuzz-virtio-balloon-test.c b/tests/qtest/fuzz-virtio-balloon-test.c
new file mode 100644
index 0000000000..ecb597fbee
--- /dev/null
+++ b/tests/qtest/fuzz-virtio-balloon-test.c
@@ -0,0 +1,37 @@
+/*
+ * QTest fuzzer-generated testcase for virtio balloon device
+ *
+ * Copyright (c) 2024 Gao Shiyuan <gaoshiyuan@baidu.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+/*
+ * https://gitlab.com/qemu-project/qemu/-/issues/2576
+ * Used to trigger:
+ * virtio_address_space_lookup: Assertion `mrs.mr' failed.
+ */
+static void oss_fuzz_71649(void)
+{
+ QTestState *s = qtest_init("-device virtio-balloon -machine q35"
+ " -nodefaults");
+
+ qtest_outl(s, 0xcf8, 0x80000890);
+ qtest_outl(s, 0xcfc, 0x2);
+ qtest_outl(s, 0xcf8, 0x80000891);
+ qtest_inl(s, 0xcfc);
+ qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("fuzz/virtio/oss_fuzz_71649", oss_fuzz_71649);
+
+ return g_test_run();
+}
+
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 0dbdb59a55..aa93e98418 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -88,6 +88,7 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \
(config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_VIRTIO_BALLOON') ? ['fuzz-virtio-balloon-test'] : []) + \
(config_all_devices.has_key('CONFIG_Q35') ? ['q35-test'] : []) + \
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
(config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \