virtio,pc,pci: features, cleanups, fixes

lots of fixes, cleanups
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmPYJdcPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRp08cIAMYq0y++RtepDpLnPjybR0v1G4cPgZS4DXFz
 8uc/2nkAHe1Q2lJNmk9p3YjLLloSO8yC1bmuuhUpmry9BJokYzY1r7rfXc8jd/Za
 z2FjC9LuYX+sk26NTGUxPq9mhT0p14HXyoxpnQlCweuVL0DJg1Tip6HI4oOG2LJj
 Au6Rl9keMQNqf9qVtsR1djO+8nO4ywbx6D9d2CYSKkQ3pK3uLvNds9vqU16x8wq7
 mNPqV8BIoDgW4zEOL478h6rJcL7pDQo6kAT1wfg7q1JcMMHJfW36VcBeFfskfJFg
 Pej3TEP2rg1LsGfh5XVw5Rp6FZ4K2TEyTK9cPZ9F7CzKdUrgBHU=
 =S0zd
 -----END PGP SIGNATURE-----

Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging

virtio,pc,pci: features, cleanups, fixes

lots of fixes, cleanups

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# -----BEGIN PGP SIGNATURE-----
#
# iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmPYJdcPHG1zdEByZWRo
# YXQuY29tAAoJECgfDbjSjVRp08cIAMYq0y++RtepDpLnPjybR0v1G4cPgZS4DXFz
# 8uc/2nkAHe1Q2lJNmk9p3YjLLloSO8yC1bmuuhUpmry9BJokYzY1r7rfXc8jd/Za
# z2FjC9LuYX+sk26NTGUxPq9mhT0p14HXyoxpnQlCweuVL0DJg1Tip6HI4oOG2LJj
# Au6Rl9keMQNqf9qVtsR1djO+8nO4ywbx6D9d2CYSKkQ3pK3uLvNds9vqU16x8wq7
# mNPqV8BIoDgW4zEOL478h6rJcL7pDQo6kAT1wfg7q1JcMMHJfW36VcBeFfskfJFg
# Pej3TEP2rg1LsGfh5XVw5Rp6FZ4K2TEyTK9cPZ9F7CzKdUrgBHU=
# =S0zd
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 30 Jan 2023 20:17:27 GMT
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (56 commits)
  docs/pcie.txt: Replace ioh3420 with pcie-root-port
  Revert "vhost-user: Introduce nested event loop in vhost_user_read()"
  Revert "vhost-user: Monitor slave channel in vhost_user_read()"
  tests/qtest/bios-tables-test: Make the test less verbose by default
  hw: Use TYPE_PCI_BUS definition where appropriate
  vhost-user: Skip unnecessary duplicated VHOST_USER_ADD/REM_MEM_REG requests
  tests: acpi: update expected blobs
  pcihp: generate populated non-hotpluggble slot descriptions on non-hotplug path
  tests: acpi: whitelist DSDT before moving non-hotpluggble slots description from hotplug path
  tests: acpi: update expected blobs
  pcihp: acpi: ignore coldplugged bridges when composing hotpluggable slots
  tests: acpi: whitelist DSDT blobs before removing dynamic _DSM on coldplugged bridges
  tests: acpi: update expected blobs
  pcihp: acpi: decouple hotplug and generic slots description
  tests: acpi: whitelist DSDT before decoupling PCI hotplug code from basic slots description
  pcihp: isolate rule whether slot should be described in DSDT
  pci: make sure pci_bus_is_express() won't error out with "discards ‘const’ qualifier"
  pcihp: make bridge describe itself using AcpiDevAmlIfClass:build_dev_aml
  pci: acpi: wire up AcpiDevAmlIf interface to generic bridge
  x86: pcihp: acpi: prepare slot ignore rule to work with self describing bridges
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-02-02 10:10:07 +00:00
commit deabea6e88
86 changed files with 611 additions and 399 deletions

View file

@ -48,8 +48,8 @@ Place only the following kinds of devices directly on the Root Complex:
strangely when PCI Express devices are integrated
with the Root Complex.
(2) PCI Express Root Ports (ioh3420), for starting exclusively PCI Express
hierarchies.
(2) PCI Express Root Ports (pcie-root-port), for starting exclusively
PCI Express hierarchies.
(3) PCI Express to PCI Bridge (pcie-pci-bridge), for starting legacy PCI
hierarchies.
@ -70,7 +70,7 @@ Place only the following kinds of devices directly on the Root Complex:
-device pxb-pcie,id=pcie.1,bus_nr=x[,numa_node=y][,addr=z]
PCI Express Root Ports and PCI Express to PCI bridges can be
connected to the pcie.1 bus:
-device ioh3420,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \
-device pcie-root-port,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \
-device pcie-pci-bridge,id=pcie_pci_bridge1,bus=pcie.1
@ -112,14 +112,14 @@ Plug only PCI Express devices into PCI Express Ports.
------------
2.2.1 Plugging a PCI Express device into a PCI Express Root Port:
-device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
-device pcie-root-port,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
-device <dev>,bus=root_port1
2.2.2 Using multi-function PCI Express Root Ports:
-device ioh3420,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \
-device ioh3420,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \
-device ioh3420,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \
-device pcie-root-port,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \
-device pcie-root-port,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \
-device pcie-root-port,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \
2.2.3 Plugging a PCI Express device into a Switch:
-device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
-device pcie-root-port,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
-device x3130-upstream,id=upstream_port1,bus=root_port1[,addr=x] \
-device xio3130-downstream,id=downstream_port1,bus=upstream_port1,chassis=x1,slot=y1[,addr=z1]] \
-device <dev>,bus=downstream_port1

View file

@ -39,6 +39,10 @@ config ACPI_PCIHP
bool
depends on ACPI
config ACPI_PCI_BRIDGE
bool
depends on ACPI && PCI && ACPI_PCIHP
config ACPI_HMAT
bool
depends on ACPI

View file

@ -2,9 +2,8 @@
#include "hw/i386/pc.h"
#include "hw/i386/acpi-build.h"
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *apic_ids, GArray *entry,
bool force_enabled)
void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids,
GArray *entry, bool force_enabled)
{
}

View file

@ -2,6 +2,7 @@
#include "hw/acpi/acpi_dev_interface.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "qemu/module.h"
#include "qemu/queue.h"
void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event)
{
@ -12,6 +13,15 @@ void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event)
}
}
void qbus_build_aml(BusState *bus, Aml *scope)
{
BusChild *kid;
QTAILQ_FOREACH(kid, &bus->children, sibling) {
call_dev_aml_func(DEVICE(kid->child), scope);
}
}
static void register_types(void)
{
static const TypeInfo acpi_dev_if_info = {

View file

@ -355,7 +355,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root);
Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL);
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj);
cpu_ctrl_dev = aml_device("%s", cphp_res_path);
{
@ -666,7 +665,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
/* build _MAT object */
assert(adevc && adevc->madt_cpu);
adevc->madt_cpu(adev, i, arch_ids, madt_buf,
adevc->madt_cpu(i, arch_ids, madt_buf,
true); /* set enabled flag */
aml_append(dev, aml_name_decl("_MAT",
aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data)));

View file

@ -19,6 +19,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device
acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c'))
acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PIIX4', if_true: files('piix4.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
@ -30,9 +31,10 @@ if have_tpm
acpi_ss.add(files('tpm.c'))
endif
softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c'))
softmmu_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-stub.c'))
softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss)
softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c',
'acpi-x86-stub.c', 'ipmi-stub.c', 'ghes-stub.c',
'acpi-mem-hotplug-stub.c', 'acpi-cpu-hotplug-stub.c',
'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c',
'cxl-stub.c'))
'cxl-stub.c', 'pci-bridge-stub.c'))

20
hw/acpi/pci-bridge-stub.c Normal file
View file

@ -0,0 +1,20 @@
/*
* QEMU ACPI PCI bridge stub
*
* Copyright (c) 2023 Red Hat, Inc.
*
* Author:
* Igor Mammedov <imammedo@redhat.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/acpi/pci.h"
void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope)
{
}

27
hw/acpi/pci-bridge.c Normal file
View file

@ -0,0 +1,27 @@
/*
* QEMU ACPI PCI bridge
*
* Copyright (c) 2023 Red Hat, Inc.
*
* Author:
* Igor Mammedov <imammedo@redhat.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/acpi/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/acpi/pcihp.h"
void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope)
{
PCIBridge *br = PCI_BRIDGE(adev);
if (object_property_find(OBJECT(&br->sec_bus), ACPI_PCIHP_PROP_BSEL)) {
build_append_pci_bus_devices(scope, pci_bridge_get_sec_bus(br));
}
}

View file

@ -85,31 +85,40 @@ static int acpi_pcihp_get_bsel(PCIBus *bus)
}
}
/* Assign BSEL property to all buses. In the future, this can be changed
* to only assign to buses that support hotplug.
*/
typedef struct {
unsigned bsel_alloc;
bool has_bridge_hotplug;
} BSELInfo;
/* Assign BSEL property only to buses that support hotplug. */
static void *acpi_set_bsel(PCIBus *bus, void *opaque)
{
unsigned *bsel_alloc = opaque;
BSELInfo *info = opaque;
unsigned *bus_bsel;
DeviceState *br = bus->qbus.parent;
bool is_bridge = IS_PCI_BRIDGE(br);
/* hotplugged bridges can't be described in ACPI ignore them */
if (qbus_is_hotpluggable(BUS(bus))) {
bus_bsel = g_malloc(sizeof *bus_bsel);
if (!is_bridge || (!br->hotplugged && info->has_bridge_hotplug)) {
bus_bsel = g_malloc(sizeof *bus_bsel);
*bus_bsel = (*bsel_alloc)++;
object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
bus_bsel, OBJ_PROP_FLAG_READ);
*bus_bsel = info->bsel_alloc++;
object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL,
bus_bsel, OBJ_PROP_FLAG_READ);
}
}
return bsel_alloc;
return info;
}
static void acpi_set_pci_info(void)
static void acpi_set_pci_info(bool has_bridge_hotplug)
{
static bool bsel_is_set;
Object *host = acpi_get_i386_pci_host();
PCIBus *bus;
unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT;
BSELInfo info = { .bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT,
.has_bridge_hotplug = has_bridge_hotplug };
if (bsel_is_set) {
return;
@ -123,7 +132,7 @@ static void acpi_set_pci_info(void)
bus = PCI_HOST_BRIDGE(host)->bus;
if (bus) {
/* Scan all PCI buses. Set property to enable acpi based hotplug. */
pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc);
pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &info);
}
}
@ -287,7 +296,7 @@ void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off)
if (acpihp_root_off) {
acpi_pcihp_disable_root_bus();
}
acpi_set_pci_info();
acpi_set_pci_info(!s->legacy_piix);
acpi_pcihp_update(s);
}

View file

@ -21,7 +21,6 @@
#include "qemu/osdep.h"
#include "hw/i386/pc.h"
#include "hw/southbridge/piix.h"
#include "hw/irq.h"
#include "hw/isa/apm.h"
#include "hw/i2c/pm_smbus.h"
@ -305,7 +304,9 @@ static void piix4_pm_reset(DeviceState *dev)
acpi_update_sci(&s->ar, s->irq);
pm_io_space_update(s);
acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug);
if (s->use_acpi_hotplug_bridge || s->use_acpi_root_pci_hotplug) {
acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug);
}
}
static void piix4_pm_powerdown_req(Notifier *n, void *opaque)

View file

@ -535,7 +535,8 @@ static void smmu_base_reset_hold(Object *obj)
static Property smmu_dev_properties[] = {
DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0),
DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, "PCI", PCIBus *),
DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus,
TYPE_PCI_BUS, PCIBus *),
DEFINE_PROP_END_OF_LIST(),
};

View file

@ -46,6 +46,7 @@ const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2);
GlobalProperty hw_compat_7_1[] = {
{ "virtio-device", "queue_reset", "false" },
{ "virtio-rng-pci", "vectors", "0" },
};
const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1);

View file

@ -97,13 +97,10 @@ static void ich9_smbus_realize(PCIDevice *d, Error **errp)
static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope)
{
BusChild *kid;
ICH9SMBState *s = ICH9_SMB_DEVICE(adev);
BusState *bus = BUS(s->smb.smbus);
QTAILQ_FOREACH(kid, &bus->children, sibling) {
call_dev_aml_func(DEVICE(kid->child), scope);
}
qbus_build_aml(bus, scope);
}
static void ich9_smb_class_init(ObjectClass *klass, void *data)

View file

@ -58,6 +58,7 @@ config PC_ACPI
select ACPI_X86
select ACPI_CPU_HOTPLUG
select ACPI_MEMORY_HOTPLUG
select ACPI_PCI_BRIDGE
select ACPI_VIOT
select SMBUS_EEPROM
select PFLASH_CFI01

View file

@ -117,8 +117,6 @@ typedef struct AcpiMiscInfo {
#ifdef CONFIG_TPM
TPMVersion tpm_version;
#endif
const unsigned char *dsdt_code;
unsigned dsdt_size;
} AcpiMiscInfo;
typedef struct FwCfgTPMConfig {
@ -385,153 +383,187 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot)
aml_append(method, if_ctx);
}
static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
bool pcihp_bridge_en)
static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus)
{
Aml *dev, *notify_method = NULL, *method;
QObject *bsel;
PCIBus *sec;
int devfn;
const PCIDevice *pdev = bus->devices[devfn];
bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
if (bsel) {
uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
if (PCI_FUNC(devfn)) {
if (IS_PCI_BRIDGE(pdev)) {
/*
* Ignore only hotplugged PCI bridges on !0 functions, but
* allow describing cold plugged bridges on all functions
*/
if (DEVICE(pdev)->hotplugged) {
return true;
}
} else if (!get_dev_aml_func(DEVICE(pdev))) {
/*
* Ignore all other devices on !0 functions unless they
* have AML description (i.e have get_dev_aml_func() != 0)
*/
return true;
}
}
return false;
}
static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus)
{
PCIDevice *pdev = bus->devices[devfn];
if (pdev) {
return is_devfn_ignored_generic(devfn, bus) ||
!DEVICE_GET_CLASS(pdev)->hotpluggable ||
/* Cold plugged bridges aren't themselves hot-pluggable */
(IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged);
} else { /* non populated slots */
/*
* hotplug is supported only for non-multifunction device
* so generate device description only for function 0
*/
if (PCI_FUNC(devfn) ||
(pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) {
return true;
}
}
return false;
}
static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus,
QObject *bsel)
{
int devfn;
Aml *dev, *notify_method = NULL, *method;
uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
DeviceClass *dc;
PCIDevice *pdev = bus->devices[devfn];
int slot = PCI_SLOT(devfn);
int func = PCI_FUNC(devfn);
/* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
int adr = slot << 16 | func;
bool hotpluggbale_slot = false;
bool bridge_in_acpi = false;
bool cold_plugged_bridge = false;
int adr = slot << 16 | PCI_FUNC(devfn);
if (pdev) {
dc = DEVICE_GET_CLASS(pdev);
if (is_devfn_ignored_hotplug(devfn, bus)) {
continue;
}
/*
* Cold plugged bridges aren't themselves hot-pluggable.
* Hotplugged bridges *are* hot-pluggable.
*/
cold_plugged_bridge = IS_PCI_BRIDGE(pdev) &&
!DEVICE(pdev)->hotplugged;
bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
hotpluggbale_slot = bsel && dc->hotpluggable &&
!cold_plugged_bridge;
/*
* allow describing coldplugged bridges in ACPI even if they are not
* on function 0, as they are not unpluggable, for all other devices
* generate description only for function 0 per slot, and for other
* functions if device on function provides its own AML
*/
if (func && !bridge_in_acpi && !get_dev_aml_func(DEVICE(pdev))) {
continue;
}
if (bus->devices[devfn]) {
dev = aml_scope("S%.02X", devfn);
} else {
/*
* hotplug is supported only for non-multifunction device
* so generate device description only for function 0
*/
if (bsel && !func) {
if (pci_bus_is_express(bus) && slot > 0) {
break;
}
/* mark it as empty hotpluggable slot */
hotpluggbale_slot = true;
} else {
continue;
}
dev = aml_device("S%.02X", devfn);
aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
}
/*
* Can't declare _SUN here for every device as it changes 'slot'
* enumeration order in linux kernel, so use another variable for it
*/
aml_append(dev, aml_name_decl("ASUN", aml_int(slot)));
aml_append(dev, aml_pci_device_dsm());
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
/* add _EJ0 to make slot hotpluggable */
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
build_append_pcihp_notify_entry(notify_method, slot);
/* device descriptor has been composed, add it into parent context */
aml_append(parent_scope, dev);
}
aml_append(parent_scope, notify_method);
}
void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus)
{
QObject *bsel;
int devfn;
Aml *dev;
bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
/* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn);
PCIDevice *pdev = bus->devices[devfn];
if (!pdev || is_devfn_ignored_generic(devfn, bus)) {
continue;
}
/* start to compose PCI device descriptor */
dev = aml_device("S%.02X", devfn);
aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
if (bsel) {
/*
* Can't declare _SUN here for every device as it changes 'slot'
* enumeration order in linux kernel, so use another variable for it
*/
aml_append(dev, aml_name_decl("ASUN", aml_int(slot)));
aml_append(dev, aml_pci_device_dsm());
}
call_dev_aml_func(DEVICE(pdev), dev);
bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
if (bridge_in_acpi) {
/*
* device is coldplugged bridge,
* add child device descriptions into its scope
*/
PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en);
}
if (hotpluggbale_slot) {
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
/* add _EJ0 to make slot hotpluggable */
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
build_append_pcihp_notify_entry(notify_method, slot);
}
call_dev_aml_func(DEVICE(bus->devices[devfn]), dev);
/* device descriptor has been composed, add it into parent context */
aml_append(parent_scope, dev);
}
if (bsel) {
aml_append(parent_scope, notify_method);
build_append_pcihp_slots(parent_scope, bus, bsel);
}
/* Append PCNT method to notify about events on local and child buses.
* Add this method for root bus only when hotplug is enabled since DSDT
* expects it.
*/
if (bsel || pcihp_bridge_en) {
method = aml_method("PCNT", 0, AML_NOTSERIALIZED);
/* If bus supports hotplug select it and notify about local events */
if (bsel) {
uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
aml_append(method, aml_call2("DVNT", aml_name("PCIU"),
aml_int(1))); /* Device Check */
aml_append(method, aml_call2("DVNT", aml_name("PCID"),
aml_int(3))); /* Eject Request */
}
/* Notify about child bus events in any case */
if (pcihp_bridge_en) {
QLIST_FOREACH(sec, &bus->child, sibling) {
if (pci_bus_is_root(sec)) {
continue;
}
aml_append(method, aml_name("^S%.02X.PCNT",
sec->parent_dev->devfn));
}
}
aml_append(parent_scope, method);
}
qobject_unref(bsel);
}
static bool build_append_notfication_callback(Aml *parent_scope,
const PCIBus *bus)
{
Aml *method;
PCIBus *sec;
QObject *bsel;
int nr_notifiers = 0;
QLIST_FOREACH(sec, &bus->child, sibling) {
Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn);
if (pci_bus_is_root(sec) ||
!object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) {
continue;
}
nr_notifiers = nr_notifiers +
build_append_notfication_callback(br_scope, sec);
aml_append(parent_scope, br_scope);
}
/*
* Append PCNT method to notify about events on local and child buses.
* ps: hostbridge might not have hotplug (bsel) enabled but might have
* child bridges that do have bsel.
*/
method = aml_method("PCNT", 0, AML_NOTSERIALIZED);
/* If bus supports hotplug select it and notify about local events */
bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
if (bsel) {
uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM")));
aml_append(method, aml_call2("DVNT", aml_name("PCIU"),
aml_int(1))); /* Device Check */
aml_append(method, aml_call2("DVNT", aml_name("PCID"),
aml_int(3))); /* Eject Request */
nr_notifiers++;
}
/* Notify about child bus events in any case */
QLIST_FOREACH(sec, &bus->child, sibling) {
if (pci_bus_is_root(sec) ||
!object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) {
continue;
}
aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn));
}
aml_append(parent_scope, method);
qobject_unref(bsel);
return !!nr_notifiers;
}
static Aml *aml_pci_pdsm(void)
{
Aml *method, *UUID, *ifctx, *ifctx1;
@ -1678,7 +1710,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus;
Aml *scope = aml_scope("PCI0");
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
build_append_pci_bus_devices(scope, bus);
aml_append(sb_scope, scope);
}
}
@ -1728,13 +1760,26 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dsdt, sb_scope);
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
bool has_pcnt;
Object *pci_host = acpi_get_i386_pci_host();
PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus;
scope = aml_scope("\\_SB.PCI0");
has_pcnt = build_append_notfication_callback(scope, bus);
if (has_pcnt) {
aml_append(dsdt, scope);
}
scope = aml_scope("_GPE");
{
method = aml_method("_E01", 0, AML_NOTSERIALIZED);
aml_append(method,
aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
aml_append(method, aml_call0("\\_SB.PCI0.PCNT"));
aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK")));
if (has_pcnt) {
aml_append(method,
aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
aml_append(method, aml_call0("\\_SB.PCI0.PCNT"));
aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK")));
}
aml_append(scope, method);
}
aml_append(dsdt, scope);

View file

@ -33,9 +33,8 @@
#include "acpi-build.h"
#include "acpi-common.h"
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *apic_ids, GArray *entry,
bool force_enabled)
void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids,
GArray *entry, bool force_enabled)
{
uint32_t apic_id = apic_ids->cpus[uid].arch_id;
/* Flags Local APIC Flags */
@ -112,7 +111,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker,
build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
for (i = 0; i < apic_ids->len; i++) {
adevc->madt_cpu(adev, i, apic_ids, table_data, false);
adevc->madt_cpu(i, apic_ids, table_data, false);
if (apic_ids->cpus[i].arch_id > 254) {
x2apic_mode = true;
}

View file

@ -26,6 +26,7 @@
#include "exec/memory.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/bios-linker-loader.h"
#include "hw/acpi/generic_event_device.h"
@ -129,7 +130,7 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
sb_scope = aml_scope("_SB");
fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg);
isa_build_aml(ISA_BUS(isabus), sb_scope);
qbus_build_aml(BUS(isabus), sb_scope);
build_ged_aml(sb_scope, GED_DEVICE, x86ms->acpi_dev,
GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE);
acpi_dsdt_add_power_button(sb_scope);

View file

@ -378,7 +378,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
MicrovmMachineState *mms = MICROVM_MACHINE(machine);
BusState *bus;
BusChild *kid;
char *cmdline;
char *cmdline, *existing_cmdline;
size_t len;
/*
* Find MMIO transports with attached devices, and add them to the kernel
@ -387,7 +388,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
* Yes, this is a hack, but one that heavily improves the UX without
* introducing any significant issues.
*/
cmdline = g_strdup(machine->kernel_cmdline);
existing_cmdline = fw_cfg_read_bytes_ptr(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA);
cmdline = g_strdup(existing_cmdline);
bus = sysbus_get_default();
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
@ -411,9 +413,12 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
}
}
fw_cfg_modify_i32(x86ms->fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(cmdline) + 1);
fw_cfg_modify_string(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA, cmdline);
len = strlen(cmdline);
if (len > VIRTIO_CMDLINE_TOTAL_MAX_LEN + strlen(existing_cmdline)) {
fprintf(stderr, "qemu: virtio mmio cmdline too large, skipping\n");
} else {
memcpy(existing_cmdline, cmdline, len + 1);
}
g_free(cmdline);
}

View file

@ -257,8 +257,9 @@ static void pc_q35_init(MachineState *machine)
NULL);
if (!keep_pci_slot_hpc && acpi_pcihp) {
object_register_sugar_prop(TYPE_PCIE_SLOT, "x-native-hotplug",
"false", true);
object_register_sugar_prop(TYPE_PCIE_SLOT,
"x-do-not-expose-native-hotplug-cap",
"true", true);
}
/* irq lines */

View file

@ -50,6 +50,7 @@
#include "hw/intc/i8259.h"
#include "hw/rtc/mc146818rtc.h"
#include "target/i386/sev.h"
#include "hw/i386/microvm.h"
#include "hw/acpi/cpu_hotplug.h"
#include "hw/irq.h"
@ -813,12 +814,18 @@ void x86_load_linux(X86MachineState *x86ms,
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
const char *dtb_filename = machine->dtb;
const char *kernel_cmdline = machine->kernel_cmdline;
char *kernel_cmdline;
SevKernelLoaderContext sev_load_ctx = {};
enum { RNG_SEED_LENGTH = 32 };
/* Align to 16 bytes as a paranoia measure */
cmdline_size = (strlen(kernel_cmdline) + 16) & ~15;
/*
* Add the NUL terminator, some padding for the microvm cmdline fiddling
* hack, and then align to 16 bytes as a paranoia measure
*/
cmdline_size = (strlen(machine->kernel_cmdline) + 1 +
VIRTIO_CMDLINE_TOTAL_MAX_LEN + 16) & ~15;
/* Make a copy, since we might append arbitrary bytes to it later. */
kernel_cmdline = g_strndup(machine->kernel_cmdline, cmdline_size);
/* load the kernel header */
f = fopen(kernel_filename, "rb");
@ -959,12 +966,6 @@ void x86_load_linux(X86MachineState *x86ms,
initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1;
}
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1);
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
sev_load_ctx.cmdline_data = (char *)kernel_cmdline;
sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1;
if (protocol >= 0x202) {
stl_p(header + 0x228, cmdline_addr);
} else {
@ -1091,27 +1092,24 @@ void x86_load_linux(X86MachineState *x86ms,
exit(1);
}
setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16);
kernel_size = setup_data_offset + sizeof(SetupData) + dtb_size;
kernel = g_realloc(kernel, kernel_size);
setup_data = (SetupData *)(kernel + setup_data_offset);
setup_data_offset = cmdline_size;
cmdline_size += sizeof(SetupData) + dtb_size;
kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size);
setup_data = (void *)kernel_cmdline + setup_data_offset;
setup_data->next = cpu_to_le64(first_setup_data);
first_setup_data = prot_addr + setup_data_offset;
first_setup_data = cmdline_addr + setup_data_offset;
setup_data->type = cpu_to_le32(SETUP_DTB);
setup_data->len = cpu_to_le32(dtb_size);
load_image_size(dtb_filename, setup_data->data, dtb_size);
}
if (!legacy_no_rng_seed) {
setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16);
kernel_size = setup_data_offset + sizeof(SetupData) + RNG_SEED_LENGTH;
kernel = g_realloc(kernel, kernel_size);
setup_data = (SetupData *)(kernel + setup_data_offset);
if (!legacy_no_rng_seed && protocol >= 0x209) {
setup_data_offset = cmdline_size;
cmdline_size += sizeof(SetupData) + RNG_SEED_LENGTH;
kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size);
setup_data = (void *)kernel_cmdline + setup_data_offset;
setup_data->next = cpu_to_le64(first_setup_data);
first_setup_data = prot_addr + setup_data_offset;
first_setup_data = cmdline_addr + setup_data_offset;
setup_data->type = cpu_to_le32(SETUP_RNG_SEED);
setup_data->len = cpu_to_le32(RNG_SEED_LENGTH);
qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH);
@ -1122,6 +1120,12 @@ void x86_load_linux(X86MachineState *x86ms,
fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
}
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, cmdline_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline, cmdline_size);
sev_load_ctx.cmdline_data = (char *)kernel_cmdline;
sev_load_ctx.cmdline_size = cmdline_size;
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
sev_load_ctx.kernel_data = (char *)kernel;
@ -1134,7 +1138,7 @@ void x86_load_linux(X86MachineState *x86ms,
* kernel on the other side of the fw_cfg interface matches the hash of the
* file the user passed in.
*/
if (!sev_enabled()) {
if (!sev_enabled() && first_setup_data) {
SetupDataFixup *fixup = g_malloc(sizeof(*fixup));
memcpy(setup, header, MIN(sizeof(header), setup_size));

View file

@ -24,7 +24,6 @@
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "hw/isa/isa.h"
#include "hw/acpi/acpi_aml_interface.h"
static ISABus *isabus;
@ -188,15 +187,6 @@ ISADevice *isa_vga_init(ISABus *bus)
}
}
void isa_build_aml(ISABus *bus, Aml *scope)
{
BusChild *kid;
QTAILQ_FOREACH(kid, &bus->parent_obj.children, sibling) {
call_dev_aml_func(DEVICE(kid->child), scope);
}
}
static void isabus_bridge_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);

View file

@ -813,7 +813,6 @@ static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *field;
BusChild *kid;
ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
BusState *bus = BUS(s->isa_bus);
Aml *sb_scope = aml_scope("\\_SB");
@ -835,9 +834,7 @@ static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(sb_scope, field);
aml_append(scope, sb_scope);
QTAILQ_FOREACH(kid, &bus->children, sibling) {
call_dev_aml_func(DEVICE(kid->child), scope);
}
qbus_build_aml(bus, scope);
}
static void ich9_lpc_class_init(ObjectClass *klass, void *data)

View file

@ -306,7 +306,6 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp)
static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *field;
BusChild *kid;
Aml *sb_scope = aml_scope("\\_SB");
BusState *bus = qdev_get_child_bus(DEVICE(adev), "isa.0");
@ -322,9 +321,7 @@ static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(sb_scope, field);
aml_append(scope, sb_scope);
QTAILQ_FOREACH(kid, &bus->children, sibling) {
call_dev_aml_func(DEVICE(kid->child), scope);
}
qbus_build_aml(bus, scope);
}
static void pci_piix3_class_init(ObjectClass *klass, void *data)

View file

@ -741,6 +741,15 @@ void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
fw_cfg_add_bytes_callback(s, key, NULL, NULL, NULL, data, len, true);
}
void *fw_cfg_read_bytes_ptr(FWCfgState *s, uint16_t key)
{
int arch = !!(key & FW_CFG_ARCH_LOCAL);
key &= FW_CFG_ENTRY_MASK;
assert(key < fw_cfg_max_entry(s));
return s->entries[arch][key].data;
}
void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
{
size_t sz = strlen(value) + 1;

View file

@ -87,7 +87,12 @@ static void gen_rp_realize(DeviceState *dev, Error **errp)
return;
}
if (grp->res_reserve.io == -1 && s->hotplug && !s->native_hotplug) {
/*
* reserving IO space led to worse issues in 6.1, when this hunk was
* introduced. (see commit: 211afe5c69b59). Keep this broken for 6.1
* machine type ABI compatibility only
*/
if (s->hide_native_hotplug_cap && grp->res_reserve.io == -1 && s->hotplug) {
grp->res_reserve.io = GEN_PCIE_ROOT_DEFAULT_IO_RANGE;
}
int rc = pci_bridge_qemu_reserve_cap_init(d, 0,

View file

@ -186,7 +186,6 @@ static Property pci_bridge_dev_properties[] = {
res_reserve.mem_pref_32, -1),
DEFINE_PROP_SIZE("pref64-reserve", PCIBridgeDev,
res_reserve.mem_pref_64, -1),
DEFINE_PROP_END_OF_LIST(),
};

View file

@ -91,7 +91,7 @@ static void grackle_init(Object *obj)
static void grackle_pci_realize(PCIDevice *d, Error **errp)
{
d->config[0x09] = 0x01;
d->config[PCI_CLASS_PROG] = 0x01;
}
static void grackle_pci_class_init(ObjectClass *klass, void *data)

View file

@ -330,9 +330,9 @@ static void raven_realize(PCIDevice *d, Error **errp)
char *filename;
int bios_size = -1;
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x34] = 0x00; // capabilities_pointer
d->config[PCI_CACHE_LINE_SIZE] = 0x08;
d->config[PCI_LATENCY_TIMER] = 0x10;
d->config[PCI_CAPABILITY_LIST] = 0x00;
memory_region_init_rom_nomigrate(&s->bios, OBJECT(s), "bios", BIOS_SIZE,
&error_fatal);

View file

@ -276,12 +276,9 @@ static void pci_unin_internal_init(Object *obj)
static void unin_main_pci_host_realize(PCIDevice *d, Error **errp)
{
/* cache_line_size */
d->config[0x0C] = 0x08;
/* latency_timer */
d->config[0x0D] = 0x10;
/* capabilities_pointer */
d->config[0x34] = 0x00;
d->config[PCI_CACHE_LINE_SIZE] = 0x08;
d->config[PCI_LATENCY_TIMER] = 0x10;
d->config[PCI_CAPABILITY_LIST] = 0x00;
/*
* Set kMacRISCPCIAddressSelect (0x48) register to indicate PCI
@ -296,30 +293,22 @@ static void unin_main_pci_host_realize(PCIDevice *d, Error **errp)
static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp)
{
/* cache_line_size */
d->config[0x0C] = 0x08;
/* latency_timer */
d->config[0x0D] = 0x10;
/* capabilities_pointer
d->config[0x34] = 0x80; */
d->config[PCI_CACHE_LINE_SIZE] = 0x08;
d->config[PCI_LATENCY_TIMER] = 0x10;
/* d->config[PCI_CAPABILITY_LIST] = 0x80; */
}
static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp)
{
/* cache line size */
d->config[0x0C] = 0x08;
/* latency timer */
d->config[0x0D] = 0x10;
d->config[PCI_CACHE_LINE_SIZE] = 0x08;
d->config[PCI_LATENCY_TIMER] = 0x10;
}
static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp)
{
/* cache_line_size */
d->config[0x0C] = 0x08;
/* latency_timer */
d->config[0x0D] = 0x10;
/* capabilities_pointer */
d->config[0x34] = 0x00;
d->config[PCI_CACHE_LINE_SIZE] = 0x08;
d->config[PCI_LATENCY_TIMER] = 0x10;
d->config[PCI_CAPABILITY_LIST] = 0x00;
}
static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)

View file

@ -483,7 +483,7 @@ static void pci_bus_uninit(PCIBus *bus)
pci_host_bus_unregister(BUS(bus)->parent);
}
bool pci_bus_is_express(PCIBus *bus)
bool pci_bus_is_express(const PCIBus *bus)
{
return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
}

View file

@ -36,6 +36,8 @@
#include "qemu/module.h"
#include "qemu/range.h"
#include "qapi/error.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/acpi/pci.h"
/* PCI bridge subsystem vendor ID helper functions */
#define PCI_SSVID_SIZEOF 8
@ -467,11 +469,23 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
return 0;
}
static void pci_bridge_class_init(ObjectClass *klass, void *data)
{
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
adevc->build_dev_aml = build_pci_bridge_aml;
}
static const TypeInfo pci_bridge_type_info = {
.name = TYPE_PCI_BRIDGE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBridge),
.class_init = pci_bridge_class_init,
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void pci_bridge_register_types(void)

View file

@ -611,11 +611,11 @@ void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s)
PCI_EXP_SLTCAP_ABP);
/*
* Enable native hot-plug on all hot-plugged bridges unless
* hot-plug is disabled on the slot.
* Expose native hot-plug on all bridges if hot-plug is enabled on the slot.
* (unless broken 6.1 ABI is enforced for compat reasons)
*/
if (s->hotplug &&
(s->native_hotplug || DEVICE(dev)->hotplugged)) {
(!s->hide_native_hotplug_cap || DEVICE(dev)->hotplugged)) {
pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP,
PCI_EXP_SLTCAP_HPS |
PCI_EXP_SLTCAP_HPC);

View file

@ -173,7 +173,8 @@ static Property pcie_slot_props[] = {
DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true),
DEFINE_PROP_BOOL("x-native-hotplug", PCIESlot, native_hotplug, true),
DEFINE_PROP_BOOL("x-do-not-expose-native-hotplug-cap", PCIESlot,
hide_native_hotplug_cap, false),
DEFINE_PROP_END_OF_LIST()
};

View file

@ -568,6 +568,13 @@ void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
if (led == SHPC_LED_BLINK) {
error_setg(errp, "Hot-unplug failed: "
"guest is busy (power indicator blinking)");
return;
}
if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
shpc_free_devices_in_slot(shpc, slot);
shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);

View file

@ -48,7 +48,7 @@
* hardware plaform.
*/
#if defined(TARGET_X86) || defined(TARGET_X86_64) || \
defined(TARGET_ARM) || defined(TARGET_ARM_64)
defined(TARGET_ARM) || defined(TARGET_AARCH64)
#include "hw/acpi/acpi.h"
#define VHOST_USER_MAX_RAM_SLOTS ACPI_MAX_RAM_SLOTS
@ -305,19 +305,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg)
return 0;
}
struct vhost_user_read_cb_data {
struct vhost_dev *dev;
VhostUserMsg *msg;
GMainLoop *loop;
int ret;
};
static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
gpointer opaque)
static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
{
struct vhost_user_read_cb_data *data = opaque;
struct vhost_dev *dev = data->dev;
VhostUserMsg *msg = data->msg;
struct vhost_user *u = dev->opaque;
CharBackend *chr = u->user->chr;
uint8_t *p = (uint8_t *) msg;
@ -325,8 +314,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
r = vhost_user_read_header(dev, msg);
if (r < 0) {
data->ret = r;
goto end;
return r;
}
/* validate message size is sane */
@ -334,8 +322,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
error_report("Failed to read msg header."
" Size %d exceeds the maximum %zu.", msg->hdr.size,
VHOST_USER_PAYLOAD_SIZE);
data->ret = -EPROTO;
goto end;
return -EPROTO;
}
if (msg->hdr.size) {
@ -346,84 +333,11 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
int saved_errno = errno;
error_report("Failed to read msg payload."
" Read %d instead of %d.", r, msg->hdr.size);
data->ret = r < 0 ? -saved_errno : -EIO;
goto end;
return r < 0 ? -saved_errno : -EIO;
}
}
end:
g_main_loop_quit(data->loop);
return G_SOURCE_REMOVE;
}
static gboolean slave_read(QIOChannel *ioc, GIOCondition condition,
gpointer opaque);
/*
* This updates the read handler to use a new event loop context.
* Event sources are removed from the previous context : this ensures
* that events detected in the previous context are purged. They will
* be re-detected and processed in the new context.
*/
static void slave_update_read_handler(struct vhost_dev *dev,
GMainContext *ctxt)
{
struct vhost_user *u = dev->opaque;
if (!u->slave_ioc) {
return;
}
if (u->slave_src) {
g_source_destroy(u->slave_src);
g_source_unref(u->slave_src);
}
u->slave_src = qio_channel_add_watch_source(u->slave_ioc,
G_IO_IN | G_IO_HUP,
slave_read, dev, NULL,
ctxt);
}
static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
{
struct vhost_user *u = dev->opaque;
CharBackend *chr = u->user->chr;
GMainContext *prev_ctxt = chr->chr->gcontext;
GMainContext *ctxt = g_main_context_new();
GMainLoop *loop = g_main_loop_new(ctxt, FALSE);
struct vhost_user_read_cb_data data = {
.dev = dev,
.loop = loop,
.msg = msg,
.ret = 0
};
/*
* We want to be able to monitor the slave channel fd while waiting
* for chr I/O. This requires an event loop, but we can't nest the
* one to which chr is currently attached : its fd handlers might not
* be prepared for re-entrancy. So we create a new one and switch chr
* to use it.
*/
slave_update_read_handler(dev, ctxt);
qemu_chr_be_update_read_handlers(chr->chr, ctxt);
qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data);
g_main_loop_run(loop);
/*
* Restore the previous event loop context. This also destroys/recreates
* event sources : this guarantees that all pending events in the original
* context that have been processed by the nested loop are purged.
*/
qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt);
slave_update_read_handler(dev, NULL);
g_main_loop_unref(loop);
g_main_context_unref(ctxt);
return data.ret;
return 0;
}
static int process_message_reply(struct vhost_dev *dev,
@ -459,6 +373,8 @@ static bool vhost_user_one_time_request(VhostUserRequest request)
case VHOST_USER_SET_MEM_TABLE:
case VHOST_USER_GET_QUEUE_NUM:
case VHOST_USER_NET_SET_MTU:
case VHOST_USER_ADD_MEM_REG:
case VHOST_USER_REM_MEM_REG:
return true;
default:
return false;
@ -1807,7 +1723,9 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
return -ECONNREFUSED;
}
u->slave_ioc = ioc;
slave_update_read_handler(dev, NULL);
u->slave_src = qio_channel_add_watch_source(u->slave_ioc,
G_IO_IN | G_IO_HUP,
slave_read, dev, NULL, NULL);
if (reply_supported) {
msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;

View file

@ -1366,7 +1366,8 @@ static const VMStateDescription vmstate_virtio_iommu = {
};
static Property virtio_iommu_properties[] = {
DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *),
DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus,
TYPE_PCI_BUS, PCIBus *),
DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true),
DEFINE_PROP_END_OF_LIST(),
};

View file

@ -129,6 +129,32 @@ struct IOMMUTLBEntry {
/*
* Bitmap for different IOMMUNotifier capabilities. Each notifier can
* register with one or multiple IOMMU Notifier capability bit(s).
*
* Normally there're two use cases for the notifiers:
*
* (1) When the device needs accurate synchronizations of the vIOMMU page
* tables, it needs to register with both MAP|UNMAP notifies (which
* is defined as IOMMU_NOTIFIER_IOTLB_EVENTS below).
*
* Regarding to accurate synchronization, it's when the notified
* device maintains a shadow page table and must be notified on each
* guest MAP (page table entry creation) and UNMAP (invalidation)
* events (e.g. VFIO). Both notifications must be accurate so that
* the shadow page table is fully in sync with the guest view.
*
* (2) When the device doesn't need accurate synchronizations of the
* vIOMMU page tables, it needs to register only with UNMAP or
* DEVIOTLB_UNMAP notifies.
*
* It's when the device maintains a cache of IOMMU translations
* (IOTLB) and is able to fill that cache by requesting translations
* from the vIOMMU through a protocol similar to ATS (Address
* Translation Service).
*
* Note that in this mode the vIOMMU will not maintain a shadowed
* page table for the address space, and the UNMAP messages can cover
* more than the pages that used to get mapped. The IOMMU notifiee
* should be able to take care of over-sized invalidations.
*/
typedef enum {
IOMMU_NOTIFIER_NONE = 0,

View file

@ -3,6 +3,7 @@
#include "qom/object.h"
#include "hw/acpi/aml-build.h"
#include "hw/qdev-core.h"
#define TYPE_ACPI_DEV_AML_IF "acpi-dev-aml-interface"
typedef struct AcpiDevAmlIfClass AcpiDevAmlIfClass;
@ -46,4 +47,6 @@ static inline void call_dev_aml_func(DeviceState *dev, Aml *scope)
}
}
void qbus_build_aml(BusState *bus, Aml *scope);
#endif

View file

@ -52,8 +52,7 @@ struct AcpiDeviceIfClass {
/* <public> */
void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list);
void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev);
void (*madt_cpu)(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *apic_ids, GArray *entry,
void (*madt_cpu)(int uid, const CPUArchIdList *apic_ids, GArray *entry,
bool force_enabled);
};
#endif

View file

@ -27,6 +27,7 @@
#define HW_ACPI_PCI_H
#include "hw/acpi/bios-linker-loader.h"
#include "hw/acpi/acpi_aml_interface.h"
typedef struct AcpiMcfgInfo {
uint64_t base;
@ -36,4 +37,7 @@ typedef struct AcpiMcfgInfo {
void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
const char *oem_id, const char *oem_table_id);
Aml *aml_pci_device_dsm(void);
void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus);
void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope);
#endif

View file

@ -109,7 +109,43 @@ struct VTDAddressSpace {
QLIST_ENTRY(VTDAddressSpace) next;
/* Superset of notifier flags that this address space has */
IOMMUNotifierFlag notifier_flags;
IOVATree *iova_tree; /* Traces mapped IOVA ranges */
/*
* @iova_tree traces mapped IOVA ranges.
*
* The tree is not needed if no MAP notifier is registered with current
* VTD address space, because all guest invalidate commands can be
* directly passed to the IOMMU UNMAP notifiers without any further
* reshuffling.
*
* The tree OTOH is required for MAP typed iommu notifiers for a few
* reasons.
*
* Firstly, there's no way to identify whether an PSI (Page Selective
* Invalidations) or DSI (Domain Selective Invalidations) event is an
* MAP or UNMAP event within the message itself. Without having prior
* knowledge of existing state vIOMMU doesn't know whether it should
* notify MAP or UNMAP for a PSI message it received when caching mode
* is enabled (for MAP notifiers).
*
* Secondly, PSI messages received from guest driver can be enlarged in
* range, covers but not limited to what the guest driver wanted to
* invalidate. When the range to invalidates gets bigger than the
* limit of a PSI message, it can even become a DSI which will
* invalidate the whole domain. If the vIOMMU directly notifies the
* registered device with the unmodified range, it may confuse the
* registered drivers (e.g. vfio-pci) on either:
*
* (1) Trying to map the same region more than once (for
* VFIO_IOMMU_MAP_DMA, -EEXIST will trigger), or,
*
* (2) Trying to UNMAP a range that is still partially mapped.
*
* That accuracy is not required for UNMAP-only notifiers, but it is a
* must-to-have for notifiers registered with MAP events, because the
* vIOMMU needs to make sure the shadow page table is always in sync
* with the guest IOMMU pgtables for a device.
*/
IOVATree *iova_tree;
};
struct VTDIOTLBEntry {

View file

@ -50,8 +50,9 @@
*/
/* Platform virtio definitions */
#define VIRTIO_MMIO_BASE 0xfeb00000
#define VIRTIO_CMDLINE_MAXLEN 64
#define VIRTIO_MMIO_BASE 0xfeb00000
#define VIRTIO_CMDLINE_MAXLEN 64
#define VIRTIO_CMDLINE_TOTAL_MAX_LEN ((VIRTIO_CMDLINE_MAXLEN + 1) * 16)
#define GED_MMIO_BASE 0xfea00000
#define GED_MMIO_BASE_MEMHP (GED_MMIO_BASE + 0x100)

View file

@ -9,7 +9,6 @@
#include "hw/block/flash.h"
#include "hw/i386/x86.h"
#include "hw/acpi/acpi_dev_interface.h"
#include "hw/hotplug.h"
#include "qom/object.h"
#include "hw/i386/sgx-epc.h"
@ -193,9 +192,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size);
/* hw/i386/acpi-common.c */
void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
const CPUArchIdList *apic_ids, GArray *entry,
bool force_enabled);
void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids,
GArray *entry, bool force_enabled);
/* sgx.c */
void pc_machine_init_sgx_epc(PCMachineState *pcms);

View file

@ -86,7 +86,6 @@ bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp);
ISADevice *isa_create_simple(ISABus *bus, const char *name);
ISADevice *isa_vga_init(ISABus *bus);
void isa_build_aml(ISABus *bus, Aml *scope);
/**
* isa_register_ioport: Install an I/O port region on the ISA bus.

View file

@ -139,6 +139,15 @@ void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
void *data, size_t len,
bool read_only);
/**
* fw_cfg_read_bytes_ptr:
* @s: fw_cfg device being modified
* @key: selector key value for new fw_cfg item
*
* Reads an existing fw_cfg data pointer.
*/
void *fw_cfg_read_bytes_ptr(FWCfgState *s, uint16_t key);
/**
* fw_cfg_add_string:
* @s: fw_cfg device being modified

View file

@ -270,7 +270,7 @@ typedef void (*pci_bus_dev_fn)(PCIBus *b, PCIDevice *d, void *opaque);
typedef void (*pci_bus_fn)(PCIBus *b, void *opaque);
typedef void *(*pci_bus_ret_fn)(PCIBus *b, void *opaque);
bool pci_bus_is_express(PCIBus *bus);
bool pci_bus_is_express(const PCIBus *bus);
void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent,
const char *name,

View file

@ -63,7 +63,8 @@ struct PCIESlot {
/* Indicates whether any type of hot-plug is allowed on the slot */
bool hotplug;
bool native_hotplug;
/* broken ACPI hotplug compat knob to preserve 6.1 ABI intact */
bool hide_native_hotplug_cap;
QLIST_ENTRY(PCIESlot) next;
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -24,7 +24,7 @@
* You will also notice that tests/qtest/bios-tables-test-allowed-diff.h lists
* a bunch of files. This is your hint that you need to do the below:
* 4. Run
* make check V=1
* make check V=2
* this will produce a bunch of warnings about differences
* beween actual and expected ACPI tables. If you have IASL installed,
* they will also be disassembled so you can look at the disassembled
@ -108,6 +108,8 @@ static const char *iasl = CONFIG_IASL;
static const char *iasl;
#endif
static int verbosity_level;
static bool compare_signature(const AcpiSdtTable *sdt, const char *signature)
{
return !memcmp(sdt->aml, signature, 4);
@ -368,7 +370,7 @@ static GArray *load_expected_aml(test_data *data)
gsize aml_len;
GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
if (getenv("V")) {
if (verbosity_level >= 2) {
fputc('\n', stderr);
}
for (i = 0; i < data->tables->len; ++i) {
@ -383,7 +385,7 @@ static GArray *load_expected_aml(test_data *data)
try_again:
aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
sdt->aml, ext);
if (getenv("V")) {
if (verbosity_level >= 2) {
fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
}
if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
@ -395,7 +397,7 @@ try_again:
goto try_again;
}
g_assert(exp_sdt.aml_file);
if (getenv("V")) {
if (verbosity_level >= 2) {
fprintf(stderr, "Using expected file '%s'\n", aml_file);
}
ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml,
@ -503,7 +505,7 @@ static void test_acpi_asl(test_data *data)
exp_sdt->aml, sdt->asl_file, sdt->aml_file,
exp_sdt->asl_file, exp_sdt->aml_file);
fflush(stderr);
if (getenv("V")) {
if (verbosity_level >= 1) {
const char *diff_env = getenv("DIFF");
const char *diff_cmd = diff_env ? diff_env : "diff -U 16";
char *diff = g_strdup_printf("%s %s %s", diff_cmd,
@ -748,9 +750,9 @@ static void test_smbios_structs(test_data *data, SmbiosEntryPointType ep_type)
}
}
static void test_acpi_load_tables(test_data *data, bool use_uefi)
static void test_acpi_load_tables(test_data *data)
{
if (use_uefi) {
if (data->uefi_fl1 && data->uefi_fl2) { /* use UEFI */
g_assert(data->scan_len);
data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts,
data->ram_start, data->scan_len);
@ -766,12 +768,11 @@ static void test_acpi_load_tables(test_data *data, bool use_uefi)
test_acpi_fadt_table(data);
}
static char *test_acpi_create_args(test_data *data, const char *params,
bool use_uefi)
static char *test_acpi_create_args(test_data *data, const char *params)
{
char *args;
if (use_uefi) {
if (data->uefi_fl1 && data->uefi_fl2) { /* use UEFI */
/*
* TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3)
* when arm/virt boad starts to support it.
@ -806,14 +807,16 @@ static char *test_acpi_create_args(test_data *data, const char *params,
return args;
}
static void test_acpi_one(const char *params, test_data *data)
static void test_vm_prepare(const char *params, test_data *data)
{
char *args;
bool use_uefi = data->uefi_fl1 && data->uefi_fl2;
args = test_acpi_create_args(data, params, use_uefi);
char *args = test_acpi_create_args(data, params);
data->qts = qtest_init(args);
test_acpi_load_tables(data, use_uefi);
g_free(args);
}
static void process_acpi_tables_noexit(test_data *data)
{
test_acpi_load_tables(data);
if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
dump_aml_files(data, true);
@ -826,13 +829,22 @@ static void test_acpi_one(const char *params, test_data *data)
* Bug on uefi-test-tools to provide entry point:
* https://bugs.launchpad.net/qemu/+bug/1821884
*/
if (!use_uefi) {
if (!(data->uefi_fl1 && data->uefi_fl2)) {
SmbiosEntryPointType ep_type = test_smbios_entry_point(data);
test_smbios_structs(data, ep_type);
}
}
static void process_acpi_tables(test_data *data)
{
process_acpi_tables_noexit(data);
qtest_quit(data->qts);
g_free(args);
}
static void test_acpi_one(const char *params, test_data *data)
{
test_vm_prepare(params, data);
process_acpi_tables(data);
}
static uint8_t base_required_struct_types[] = {
@ -863,7 +875,32 @@ static void test_acpi_piix4_tcg_bridge(void)
data.variant = ".bridge";
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-device pci-bridge,chassis_nr=1", &data);
test_vm_prepare("-S"
" -device pci-bridge,chassis_nr=1"
" -device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2"
" -device pci-testdev,bus=pci.0,addr=5.0"
" -device pci-testdev,bus=pci.1", &data);
/* hotplugged bridges section */
qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr",
"{'bus': 'pci.1', 'addr': '2.0', 'chassis_nr': 3 }");
qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr_multifunc",
"{'bus': 'pci.1', 'addr': '0xf.1', 'chassis_nr': 4 }");
qtest_qmp_device_add(data.qts, "pci-bridge", "hpbrhost",
"{'bus': 'pci.0', 'addr': '4.0', 'chassis_nr': 5 }");
qtest_qmp_device_add(data.qts, "pci-testdev", "d1", "{'bus': 'pci.0' }");
qtest_qmp_device_add(data.qts, "pci-testdev", "d2", "{'bus': 'pci.1' }");
qtest_qmp_device_add(data.qts, "pci-testdev", "d3", "{'bus': 'hpbr', "
"'addr': '1.0' }");
qtest_qmp_send(data.qts, "{'execute':'cont' }");
qtest_qmp_eventwait(data.qts, "RESUME");
process_acpi_tables_noexit(&data);
free_test_data(&data);
/* check that reboot/reset doesn't change any ACPI tables */
qtest_qmp_send(data.qts, "{'execute':'system_reset' }");
process_acpi_tables(&data);
free_test_data(&data);
}
@ -877,7 +914,10 @@ static void test_acpi_piix4_no_root_hotplug(void)
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off "
"-device pci-bridge,chassis_nr=1", &data);
"-device pci-bridge,chassis_nr=1 "
"-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 "
"-device pci-testdev,bus=pci.0 "
"-device pci-testdev,bus=pci.1", &data);
free_test_data(&data);
}
@ -891,7 +931,10 @@ static void test_acpi_piix4_no_bridge_hotplug(void)
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off "
"-device pci-bridge,chassis_nr=1", &data);
"-device pci-bridge,chassis_nr=1 "
"-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 "
"-device pci-testdev,bus=pci.0 "
"-device pci-testdev,bus=pci.1,addr=2.0", &data);
free_test_data(&data);
}
@ -906,7 +949,9 @@ static void test_acpi_piix4_no_acpi_pci_hotplug(void)
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off "
"-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off "
"-device pci-bridge,chassis_nr=1", &data);
"-device pci-bridge,chassis_nr=1 "
"-device pci-testdev,bus=pci.0 "
"-device pci-testdev,bus=pci.1", &data);
free_test_data(&data);
}
@ -951,8 +996,9 @@ static void test_acpi_q35_tcg_bridge(void)
data.variant = ".bridge";
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-device pci-bridge,chassis_nr=1",
&data);
test_acpi_one("-device pci-bridge,chassis_nr=1,id=br1"
" -device pci-testdev,bus=pcie.0"
" -device pci-testdev,bus=br1", &data);
free_test_data(&data);
}
@ -962,14 +1008,41 @@ static void test_acpi_q35_multif_bridge(void)
.machine = MACHINE_Q35,
.variant = ".multi-bridge",
};
test_acpi_one("-device pcie-root-port,id=pcie-root-port-0,"
"multifunction=on,"
"port=0x0,chassis=1,addr=0x2,bus=pcie.0 "
"-device pcie-root-port,id=pcie-root-port-1,"
"port=0x1,chassis=2,addr=0x3.0x1,bus=pcie.0 "
"-device virtio-balloon,id=balloon0,"
"bus=pcie.0,addr=0x4.0x2",
&data);
test_vm_prepare("-S"
" -device virtio-balloon,id=balloon0,addr=0x4.0x2"
" -device pcie-root-port,id=rp0,multifunction=on,"
"port=0x0,chassis=1,addr=0x2"
" -device pcie-root-port,id=rp1,port=0x1,chassis=2,addr=0x3.0x1"
" -device pcie-root-port,id=rp2,port=0x0,chassis=3,bus=rp1,addr=0.0"
" -device pci-bridge,bus=rp2,chassis_nr=4,id=br1"
" -device pcie-root-port,id=rphptgt1,port=0x0,chassis=5,addr=2.1"
" -device pcie-root-port,id=rphptgt2,port=0x0,chassis=6,addr=2.2"
" -device pcie-root-port,id=rphptgt3,port=0x0,chassis=7,addr=2.3"
" -device pci-testdev,bus=pcie.0,addr=2.4"
" -device pci-testdev,bus=pcie.0,addr=5.0"
" -device pci-testdev,bus=rp0,addr=0.0"
" -device pci-testdev,bus=br1", &data);
/* hotplugged bridges section */
qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr1",
"{'bus': 'br1', 'addr': '6.0', 'chassis_nr': 128 }");
qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr2-multiif",
"{ 'bus': 'br1', 'addr': '2.2', 'chassis_nr': 129 }");
qtest_qmp_device_add(data.qts, "pcie-pci-bridge", "hpbr3",
"{'bus': 'rphptgt1', 'addr': '0.0' }");
qtest_qmp_device_add(data.qts, "pcie-root-port", "hprp",
"{'bus': 'rphptgt2', 'addr': '0.0' }");
qtest_qmp_device_add(data.qts, "pci-testdev", "hpnic",
"{'bus': 'rphptgt3', 'addr': '0.0' }");
qtest_qmp_send(data.qts, "{'execute':'cont' }");
qtest_qmp_eventwait(data.qts, "RESUME");
process_acpi_tables_noexit(&data);
free_test_data(&data);
/* check that reboot/reset doesn't change any ACPI tables */
qtest_qmp_send(data.qts, "{'execute':'system_reset' }");
process_acpi_tables(&data);
free_test_data(&data);
}
@ -1898,10 +1971,9 @@ static void test_acpi_piix4_oem_fields(void)
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
args = test_acpi_create_args(&data,
OEM_TEST_ARGS, false);
args = test_acpi_create_args(&data, OEM_TEST_ARGS);
data.qts = qtest_init(args);
test_acpi_load_tables(&data, false);
test_acpi_load_tables(&data);
test_oem_fields(&data);
qtest_quit(data.qts);
free_test_data(&data);
@ -1918,10 +1990,9 @@ static void test_acpi_q35_oem_fields(void)
data.required_struct_types = base_required_struct_types;
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
args = test_acpi_create_args(&data,
OEM_TEST_ARGS, false);
args = test_acpi_create_args(&data, OEM_TEST_ARGS);
data.qts = qtest_init(args);
test_acpi_load_tables(&data, false);
test_acpi_load_tables(&data);
test_oem_fields(&data);
qtest_quit(data.qts);
free_test_data(&data);
@ -1936,9 +2007,9 @@ static void test_acpi_microvm_oem_fields(void)
test_acpi_microvm_prepare(&data);
args = test_acpi_create_args(&data,
OEM_TEST_ARGS",acpi=on", false);
OEM_TEST_ARGS",acpi=on");
data.qts = qtest_init(args);
test_acpi_load_tables(&data, false);
test_acpi_load_tables(&data);
test_oem_fields(&data);
qtest_quit(data.qts);
free_test_data(&data);
@ -1958,10 +2029,9 @@ static void test_acpi_virt_oem_fields(void)
};
char *args;
args = test_acpi_create_args(&data,
"-cpu cortex-a57 "OEM_TEST_ARGS, true);
args = test_acpi_create_args(&data, "-cpu cortex-a57 "OEM_TEST_ARGS);
data.qts = qtest_init(args);
test_acpi_load_tables(&data, true);
test_acpi_load_tables(&data);
test_oem_fields(&data);
qtest_quit(data.qts);
free_test_data(&data);
@ -1974,8 +2044,13 @@ int main(int argc, char *argv[])
const char *arch = qtest_get_arch();
const bool has_kvm = qtest_has_accel("kvm");
const bool has_tcg = qtest_has_accel("tcg");
char *v_env = getenv("V");
int ret;
if (v_env) {
verbosity_level = atoi(v_env);
}
g_test_init(&argc, &argv, NULL);
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {

View file

@ -153,6 +153,8 @@ void boot_sector_test(QTestState *qts)
signature_high = qtest_readb(qts, SIGNATURE_ADDR + 1);
signature = (signature_high << 8) | signature_low;
if (signature == SIGNATURE) {
/* wipe signature */
qtest_writeb(qts, SIGNATURE_ADDR, 0x00);
break;
}
@ -160,7 +162,9 @@ void boot_sector_test(QTestState *qts)
qrsp = qtest_qmp(qts, "{ 'execute': 'query-status' }");
qret = qdict_get_qdict(qrsp, "return");
g_assert_nonnull(qret);
g_assert_cmpstr(qdict_get_try_str(qret, "status"), ==, "running");
if (qdict_get_try_str(qret, "status")) {
g_assert_cmpstr(qdict_get_try_str(qret, "status"), ==, "running");
}
qobject_unref(qrsp);
g_usleep(TEST_DELAY);

View file

@ -1435,6 +1435,10 @@ void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv,
resp = qtest_qmp(qts, "{'execute': 'device_add', 'arguments': %p}", args);
g_assert(resp);
g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */
if (qdict_haskey(resp, "error")) {
fprintf(stderr, "error: %s\n",
qdict_get_str(qdict_get_qdict(resp, "error"), "desc"));
}
g_assert(!qdict_haskey(resp, "error"));
qobject_unref(resp);
}