Patchwork [v2,repost,8/9] i386: generate pc guest info

login
register
mail settings
Submitter Michael S. Tsirkin
Date July 10, 2013, 1:51 p.m.
Message ID <1373464153-18979-9-git-send-email-mst@redhat.com>
Download mbox | patch
Permalink /patch/258060/
State New
Headers show

Comments

Michael S. Tsirkin - July 10, 2013, 1:51 p.m.
This fills in guest info table with misc
information of interest to the guest.
Will be used by ACPI table generation code.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/acpi/ich9.c         |  7 ++++++-
 hw/acpi/piix4.c        | 44 +++++++++++++++++++++++++++++++++++++++++++-
 hw/i386/Makefile.objs  |  2 ++
 hw/i386/pc.c           | 41 +++++++++++++++++++++++++++++++++++++++--
 hw/i386/pc_piix.c      | 15 ++++++++++++---
 hw/i386/pc_q35.c       | 10 +++++++---
 hw/isa/lpc_ich9.c      | 11 +++++++++--
 hw/mips/mips_malta.c   |  2 +-
 hw/misc/pvpanic.c      | 12 +++++++-----
 hw/pci-host/q35.c      |  1 +
 include/hw/acpi/ich9.h |  2 +-
 include/hw/i386/ich9.h |  3 ++-
 include/hw/i386/pc.h   | 37 ++++++++++++++++++++++++++++++++++---
 13 files changed, 164 insertions(+), 23 deletions(-)
Laszlo Ersek - July 17, 2013, 3:07 p.m.
On 07/10/13 15:51, Michael S. Tsirkin wrote:
> This fills in guest info table with misc
> information of interest to the guest.
> Will be used by ACPI table generation code.
> 
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>  hw/acpi/ich9.c         |  7 ++++++-
>  hw/acpi/piix4.c        | 44 +++++++++++++++++++++++++++++++++++++++++++-
>  hw/i386/Makefile.objs  |  2 ++
>  hw/i386/pc.c           | 41 +++++++++++++++++++++++++++++++++++++++--
>  hw/i386/pc_piix.c      | 15 ++++++++++++---
>  hw/i386/pc_q35.c       | 10 +++++++---
>  hw/isa/lpc_ich9.c      | 11 +++++++++--
>  hw/mips/mips_malta.c   |  2 +-
>  hw/misc/pvpanic.c      | 12 +++++++-----
>  hw/pci-host/q35.c      |  1 +
>  include/hw/acpi/ich9.h |  2 +-
>  include/hw/i386/ich9.h |  3 ++-
>  include/hw/i386/pc.h   | 37 ++++++++++++++++++++++++++++++++++---
>  13 files changed, 164 insertions(+), 23 deletions(-)

So we won't be fishing in a global pool of information at ACPI table
creation time as I had expected / advertized before. Instead any
required bits are gradually collected into the guest info structure
while creating / configuring the machine.

This is likely a better approach; the set of dependencies for all ACPI
tables together are tracked explicitly in guest info. Also, we don't
collect the bits from the outside, breaching encapsulation of devices;
devices publish the bits.

Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Hu Tao - July 19, 2013, 3:55 a.m.
<...>

> +void ich9_lpc_set_guest_info(PcGuestInfo *guest_info)
> +{
> +    guest_info->sci_int = 9;
> +    guest_info->acpi_enable_cmd = ICH9_APM_ACPI_ENABLE;
> +    guest_info->acpi_disable_cmd = ICH9_APM_ACPI_DISABLE;
> +}
> +

This function has to be called somewhere(ich9_lpc_pm_init?) to setup
acpi_enable_cmd and acpi_disable_cmd, or guest Linux will report:

ACPI Error: No ACPI mode transition supported in this system (enable/disable both zero)

and disable ACPI.
Laszlo Ersek - July 24, 2013, 3:36 p.m.
On 07/17/13 17:07, Laszlo Ersek wrote:
> On 07/10/13 15:51, Michael S. Tsirkin wrote:
>> This fills in guest info table with misc
>> information of interest to the guest.
>> Will be used by ACPI table generation code.
>>
>> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>> ---
>>  hw/acpi/ich9.c         |  7 ++++++-
>>  hw/acpi/piix4.c        | 44 +++++++++++++++++++++++++++++++++++++++++++-
>>  hw/i386/Makefile.objs  |  2 ++
>>  hw/i386/pc.c           | 41 +++++++++++++++++++++++++++++++++++++++--
>>  hw/i386/pc_piix.c      | 15 ++++++++++++---
>>  hw/i386/pc_q35.c       | 10 +++++++---
>>  hw/isa/lpc_ich9.c      | 11 +++++++++--
>>  hw/mips/mips_malta.c   |  2 +-
>>  hw/misc/pvpanic.c      | 12 +++++++-----
>>  hw/pci-host/q35.c      |  1 +
>>  include/hw/acpi/ich9.h |  2 +-
>>  include/hw/i386/ich9.h |  3 ++-
>>  include/hw/i386/pc.h   | 37 ++++++++++++++++++++++++++++++++++---
>>  13 files changed, 164 insertions(+), 23 deletions(-)
> 
> So we won't be fishing in a global pool of information at ACPI table
> creation time as I had expected / advertized before. Instead any
> required bits are gradually collected into the guest info structure
> while creating / configuring the machine.
> 
> This is likely a better approach; the set of dependencies for all ACPI
> tables together are tracked explicitly in guest info. Also, we don't
> collect the bits from the outside, breaching encapsulation of devices;
> devices publish the bits.
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>

If I understand correctly, based on the recent comments you got from
Gerd and Andreas for this series (in the other, non-repost thread),
fishing in the global pool it should be after all, just with a different
fishing rod than what I used in my original patch ("hw/i386: build ACPI
MADT (APIC) for fw_cfg clients").

These U-turns in design have proved that I'm not qualified to review
this work. So I won't; there's no use in my repeated saying "yeah why
not" to both approaches (which are polar opposites). My apologies.

I applaud your perseverance in this matter.

Laszlo
Michael S. Tsirkin - July 24, 2013, 3:47 p.m.
On Wed, Jul 24, 2013 at 05:36:58PM +0200, Laszlo Ersek wrote:
> On 07/17/13 17:07, Laszlo Ersek wrote:
> > On 07/10/13 15:51, Michael S. Tsirkin wrote:
> >> This fills in guest info table with misc
> >> information of interest to the guest.
> >> Will be used by ACPI table generation code.
> >>
> >> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> >> ---
> >>  hw/acpi/ich9.c         |  7 ++++++-
> >>  hw/acpi/piix4.c        | 44 +++++++++++++++++++++++++++++++++++++++++++-
> >>  hw/i386/Makefile.objs  |  2 ++
> >>  hw/i386/pc.c           | 41 +++++++++++++++++++++++++++++++++++++++--
> >>  hw/i386/pc_piix.c      | 15 ++++++++++++---
> >>  hw/i386/pc_q35.c       | 10 +++++++---
> >>  hw/isa/lpc_ich9.c      | 11 +++++++++--
> >>  hw/mips/mips_malta.c   |  2 +-
> >>  hw/misc/pvpanic.c      | 12 +++++++-----
> >>  hw/pci-host/q35.c      |  1 +
> >>  include/hw/acpi/ich9.h |  2 +-
> >>  include/hw/i386/ich9.h |  3 ++-
> >>  include/hw/i386/pc.h   | 37 ++++++++++++++++++++++++++++++++++---
> >>  13 files changed, 164 insertions(+), 23 deletions(-)
> > 
> > So we won't be fishing in a global pool of information at ACPI table
> > creation time as I had expected / advertized before. Instead any
> > required bits are gradually collected into the guest info structure
> > while creating / configuring the machine.
> > 
> > This is likely a better approach; the set of dependencies for all ACPI
> > tables together are tracked explicitly in guest info. Also, we don't
> > collect the bits from the outside, breaching encapsulation of devices;
> > devices publish the bits.
> > 
> > Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> If I understand correctly, based on the recent comments you got from
> Gerd and Andreas for this series (in the other, non-repost thread),
> fishing in the global pool it should be after all, just with a different
> fishing rod than what I used in my original patch ("hw/i386: build ACPI
> MADT (APIC) for fw_cfg clients").
> 
> These U-turns in design have proved that I'm not qualified to review
> this work. So I won't; there's no use in my repeated saying "yeah why
> not" to both approaches (which are polar opposites). My apologies.
> 
> I applaud your perseverance in this matter.
> 
> Laszlo

Thanks for all your comments so far,

Patch

diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index 4a17f32..764e27f 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -203,7 +203,7 @@  static void pm_powerdown_req(Notifier *n, void *opaque)
 }
 
 void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
-                  qemu_irq sci_irq)
+                  qemu_irq sci_irq, PcGuestInfo *guest_info)
 {
     memory_region_init(&pm->io, "ich9-pm", ICH9_PMIO_SIZE);
     memory_region_set_enabled(&pm->io, false);
@@ -219,6 +219,11 @@  void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
                           ICH9_PMIO_GPE0_LEN);
     memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
 
+    guest_info->gpe0_blk = PC_GUEST_PORT_ACPI_PM_BASE + ICH9_PMIO_GPE0_STS;
+    guest_info->gpe0_blk_len = ICH9_PMIO_GPE0_LEN;
+    guest_info->fix_rtc = true;
+    guest_info->platform_timer = false;
+
     memory_region_init_io(&pm->io_smi, &ich9_smi_ops, pm, "apci-smi",
                           8);
     memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 756df3b..c077a7a 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -94,6 +94,8 @@  typedef struct PIIX4PMState {
 
     CPUStatus gpe_cpu;
     Notifier cpu_added_notifier;
+
+    PcGuestInfo *guest_info;
 } PIIX4PMState;
 
 static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
@@ -380,6 +382,27 @@  static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
     acpi_pm1_evt_power_down(&s->ar);
 }
 
+static void piix4_update_guest_info(PIIX4PMState *s)
+{
+    PCIDevice *dev = &s->dev;
+    BusState *bus = qdev_get_parent_bus(&dev->qdev);
+    BusChild *kid, *next;
+
+    memset(s->guest_info->slot_hotplug_enable, 0xff,
+           DIV_ROUND_UP(PCI_SLOT_MAX, BITS_PER_BYTE));
+
+    QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
+        DeviceState *qdev = kid->child;
+        PCIDevice *pdev = PCI_DEVICE(qdev);
+        PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
+        int slot = PCI_SLOT(pdev->devfn);
+
+        if (pc->no_hotplug) {
+            clear_bit(slot, s->guest_info->slot_hotplug_enable);
+        }
+    }
+}
+
 static void piix4_pm_machine_ready(Notifier *n, void *opaque)
 {
     PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
@@ -391,6 +414,9 @@  static void piix4_pm_machine_ready(Notifier *n, void *opaque)
     pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
 	(isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
 
+    if (s->guest_info) {
+        piix4_update_guest_info(s);
+    }
 }
 
 static int piix4_pm_initfn(PCIDevice *dev)
@@ -447,7 +473,8 @@  static int piix4_pm_initfn(PCIDevice *dev)
 
 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                        qemu_irq sci_irq, qemu_irq smi_irq,
-                       int kvm_enabled, FWCfgState *fw_cfg)
+                       int kvm_enabled, FWCfgState *fw_cfg,
+                       PcGuestInfo *guest_info)
 {
     PCIDevice *dev;
     PIIX4PMState *s;
@@ -470,6 +497,21 @@  i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
         fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
     }
 
+    if (guest_info) {
+        s->guest_info = guest_info;
+
+        guest_info->s3_disabled = s->disable_s3;
+        guest_info->s4_disabled = s->disable_s4;
+        guest_info->s4_val = s->s4_val;
+
+        guest_info->acpi_enable_cmd = ACPI_ENABLE;
+        guest_info->acpi_disable_cmd = ACPI_DISABLE;
+        guest_info->gpe0_blk = GPE_BASE;
+        guest_info->gpe0_blk_len = GPE_LEN;
+        guest_info->fix_rtc = false;
+        guest_info->platform_timer = true;
+    }
+
     return s->smb.smbus;
 }
 
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 71be2da..e783050 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -5,6 +5,8 @@  obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o
 
 obj-y += kvmvapic.o
 obj-y += bios-linker-loader.o
+hw/i386/pc_piix.o: hw/i386/pc_piix.c hw/i386/acpi-dsdt.hex
+hw/i386/pc_q35.o: hw/i386/pc_q35.c hw/i386/q35-acpi-dsdt.hex
 
 iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \
     ; then echo "$(2)"; else echo "$(3)"; fi ;)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 4b29685..e5ebfa5 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1012,6 +1012,27 @@  static void pc_fw_cfg_guest_info(PcGuestInfo *guest_info)
     fw_cfg_add_file(guest_info->fw_cfg, "etc/pci-info", info, sizeof *info);
 }
 
+static void pc_set_cpu_guest_info(CPUState *cpu, void *arg)
+{
+    PcGuestInfo *guest_info = arg;
+    CPUClass *klass = CPU_GET_CLASS(cpu);
+    uint64_t apic_id = klass->get_arch_id(cpu);
+    int j;
+
+    assert(apic_id <= MAX_CPUMASK_BITS);
+    assert(apic_id < guest_info->apic_id_limit);
+
+    set_bit(apic_id, guest_info->found_cpus);
+
+    for (j = 0; j < guest_info->numa_nodes; j++) {
+        assert(cpu->cpu_index < max_cpus);
+        if (test_bit(cpu->cpu_index, node_cpumask[j])) {
+            guest_info->node_cpu[apic_id] = cpu_to_le64(j);
+            break;
+        }
+    }
+}
+
 typedef struct PcGuestInfoState {
     PcGuestInfo info;
     Notifier machine_done;
@@ -1032,6 +1053,18 @@  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
     PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
     PcGuestInfo *guest_info = &guest_info_state->info;
 
+    guest_info->ram_size = below_4g_mem_size + above_4g_mem_size;
+    guest_info->apic_id_limit = pc_apic_id_limit(max_cpus);
+    guest_info->apic_xrupt_override = kvm_allows_irq0_override();
+    guest_info->numa_nodes = nb_numa_nodes;
+    guest_info->node_mem = g_memdup(node_mem, guest_info->numa_nodes *
+                                    sizeof *guest_info->node_mem);
+    guest_info->node_cpu = g_malloc0(guest_info->apic_id_limit *
+                                     sizeof *guest_info->node_mem);
+
+    memset(&guest_info->found_cpus, 0, sizeof guest_info->found_cpus);
+    qemu_for_each_cpu(pc_set_cpu_guest_info, guest_info);
+
     guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
     if (sizeof(hwaddr) == 4) {
         guest_info->pci_info.w64.begin = 0;
@@ -1204,7 +1237,8 @@  static const MemoryRegionOps ioportF0_io_ops = {
 void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
                           ISADevice **rtc_state,
                           ISADevice **floppy,
-                          bool no_vmport)
+                          bool no_vmport,
+                          PcGuestInfo *guest_info)
 {
     int i;
     DriveInfo *fd[MAX_FD];
@@ -1230,7 +1264,10 @@  void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
      * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT
      * when the HPET wants to take over. Thus we have to disable the latter.
      */
-    if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
+    guest_info->has_hpet = !no_hpet &&
+        (!kvm_irqchip_in_kernel() || kvm_has_pit_state2());
+
+    if (guest_info->has_hpet) {
         hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
 
         if (hpet) {
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 0276694..bc4765c 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -50,6 +50,8 @@ 
 #  include <xen/hvm/hvm_info_table.h>
 #endif
 
+#include "hw/i386/acpi-dsdt.hex"
+
 #define MAX_IDE_BUS 2
 
 static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
@@ -127,6 +129,10 @@  static void pc_init1(MemoryRegion *system_memory,
     }
 
     guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
+
+    guest_info->dsdt_code = AcpiDsdtAmlCode;
+    guest_info->dsdt_size = sizeof AcpiDsdtAmlCode;
+
     guest_info->has_pci_info = has_pci_info;
 
     /* Set PCI window size the way seabios has always done it. */
@@ -195,7 +201,8 @@  static void pc_init1(MemoryRegion *system_memory,
     pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
 
     /* init basic PC hardware */
-    pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled());
+    pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled(),
+                         guest_info);
 
     pc_nic_init(isa_bus, pci_bus);
 
@@ -234,7 +241,9 @@  static void pc_init1(MemoryRegion *system_memory,
         /* TODO: Populate SPD eeprom data.  */
         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
                               gsi[9], *smi_irq,
-                              kvm_enabled(), fw_cfg);
+                              kvm_enabled(), fw_cfg,
+                              guest_info);
+        guest_info->sci_int = 9;
         smbus_eeprom_init(smbus, 8, NULL, 0);
     }
 
@@ -243,7 +252,7 @@  static void pc_init1(MemoryRegion *system_memory,
     }
 
     if (has_pvpanic) {
-        pvpanic_init(isa_bus);
+        pvpanic_init(isa_bus, guest_info);
     }
 }
 
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 5b92160..50afe7c 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -43,6 +43,8 @@ 
 #include "hw/usb.h"
 #include "hw/cpu/icc_bus.h"
 
+#include "hw/i386/q35-acpi-dsdt.hex"
+
 /* ICH9 AHCI has 6 ports */
 #define MAX_SATA_PORTS     6
 
@@ -109,6 +111,8 @@  static void pc_q35_init(QEMUMachineInitArgs *args)
 
     guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
     guest_info->has_pci_info = has_pci_info;
+    guest_info->dsdt_code = Q35AcpiDsdtAmlCode;
+    guest_info->dsdt_size = sizeof Q35AcpiDsdtAmlCode;
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
@@ -175,10 +179,10 @@  static void pc_q35_init(QEMUMachineInitArgs *args)
     pc_register_ferr_irq(gsi[13]);
 
     /* init basic PC hardware */
-    pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false);
+    pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false, guest_info);
 
     /* connect pm stuff to lpc */
-    ich9_lpc_pm_init(lpc);
+    ich9_lpc_pm_init(lpc, guest_info);
 
     /* ahci and SATA device, for q35 1 ahci controller is built-in */
     ahci = pci_create_simple_multifunction(host_bus,
@@ -210,7 +214,7 @@  static void pc_q35_init(QEMUMachineInitArgs *args)
     }
 
     if (has_pvpanic) {
-        pvpanic_init(isa_bus);
+        pvpanic_init(isa_bus, guest_info);
     }
 }
 
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 667e882..a742fcb 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -312,6 +312,13 @@  PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
     return route;
 }
 
+void ich9_lpc_set_guest_info(PcGuestInfo *guest_info)
+{
+    guest_info->sci_int = 9;
+    guest_info->acpi_enable_cmd = ICH9_APM_ACPI_ENABLE;
+    guest_info->acpi_disable_cmd = ICH9_APM_ACPI_DISABLE;
+}
+
 static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
 {
     switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
@@ -356,13 +363,13 @@  static void ich9_set_sci(void *opaque, int irq_num, int level)
     }
 }
 
-void ich9_lpc_pm_init(PCIDevice *lpc_pci)
+void ich9_lpc_pm_init(PCIDevice *lpc_pci, PcGuestInfo *guest_info)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
     qemu_irq *sci_irq;
 
     sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1);
-    ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0]);
+    ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0], guest_info);
 
     ich9_lpc_reset(&lpc->d.qdev);
 }
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 5843fad..b95597c 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -964,7 +964,7 @@  void mips_malta_init(QEMUMachineInitArgs *args)
     pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
     pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
     smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
-                          isa_get_irq(NULL, 9), NULL, 0, NULL);
+                          isa_get_irq(NULL, 9), NULL, 0, NULL, NULL);
     /* TODO: Populate SPD eeprom data.  */
     smbus_eeprom_init(smbus, 8, NULL, 0);
     pit = pit_init(isa_bus, 0x40, 0, NULL);
diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c
index 792d8e4..7af713a 100644
--- a/hw/misc/pvpanic.c
+++ b/hw/misc/pvpanic.c
@@ -101,25 +101,27 @@  static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
     isa_register_ioport(d, &s->io, s->ioport);
 }
 
-static void pvpanic_fw_cfg(ISADevice *dev, FWCfgState *fw_cfg)
+static void pvpanic_guest_info(ISADevice *dev, PcGuestInfo *guest_info)
 {
     PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
     uint16_t *pvpanic_port = g_malloc(sizeof(*pvpanic_port));
     *pvpanic_port = cpu_to_le16(s->ioport);
 
-    fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
+    fw_cfg_add_file(guest_info->fw_cfg, "etc/pvpanic-port", pvpanic_port,
                     sizeof(*pvpanic_port));
+
+    guest_info->pvpanic_port = s->ioport;
 }
 
-void pvpanic_init(ISABus *bus)
+void pvpanic_init(ISABus *bus, PcGuestInfo *guest_info)
 {
     ISADevice *dev;
-    FWCfgState *fw_cfg = fw_cfg_find();
+    FWCfgState *fw_cfg = guest_info->fw_cfg;
     if (!fw_cfg) {
         return;
     }
     dev = isa_create_simple (bus, TYPE_ISA_PVPANIC_DEVICE);
-    pvpanic_fw_cfg(dev, fw_cfg);
+    pvpanic_guest_info(dev, guest_info);
 }
 
 static Property pvpanic_isa_properties[] = {
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 13148ed..667bd20 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -260,6 +260,7 @@  static int mch_init(PCIDevice *d)
      */
     mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
         MCH_HOST_BRIDGE_PCIEXBAR_MAX;
+    mch->guest_info->mcfg_base = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT;
 
     /* setup pci memory regions */
     memory_region_init_alias(&mch->pci_hole, "pci-hole",
diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h
index b1fe71f..66ab31a 100644
--- a/include/hw/acpi/ich9.h
+++ b/include/hw/acpi/ich9.h
@@ -45,7 +45,7 @@  typedef struct ICH9LPCPMRegs {
 } ICH9LPCPMRegs;
 
 void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
-                  qemu_irq sci_irq);
+                  qemu_irq sci_irq, PcGuestInfo *guest_info);
 void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
 extern const VMStateDescription vmstate_ich9_pm;
 
diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index c5f637b..7428452 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -15,10 +15,11 @@ 
 #include "hw/acpi/ich9.h"
 #include "hw/pci/pci_bus.h"
 
+void ich9_lpc_set_guest_info(PcGuestInfo *guest_info);
 void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
 int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
 PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
-void ich9_lpc_pm_init(PCIDevice *pci_lpc);
+void ich9_lpc_pm_init(PCIDevice *pci_lpc, PcGuestInfo *guest_info);
 PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
 i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
 
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 5949e7e..3f0fb43 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -10,6 +10,9 @@ 
 #include "hw/i386/ioapic.h"
 
 #include "qemu/range.h"
+#include "qemu/bitmap.h"
+#include "sysemu/sysemu.h"
+#include "hw/pci/pci.h"
 
 /* PC-style peripherals (also used by other machines).  */
 
@@ -18,9 +21,35 @@  typedef struct PcPciInfo {
     Range w64;
 } PcPciInfo;
 
+/* Matches the value hard-coded in BIOS */
+#define PC_GUEST_PORT_ACPI_PM_BASE      0xb000
+
 struct PcGuestInfo {
     PcPciInfo pci_info;
     bool has_pci_info;
+    hwaddr ram_size;
+    unsigned apic_id_limit;
+    bool apic_xrupt_override;
+    bool has_hpet;
+    uint64_t numa_nodes;
+    uint64_t *node_mem;
+    uint64_t *node_cpu;
+    DECLARE_BITMAP(found_cpus, MAX_CPUMASK_BITS + 1);
+    bool s3_disabled;
+    bool s4_disabled;
+    uint8_t s4_val;
+    DECLARE_BITMAP(slot_hotplug_enable, PCI_SLOT_MAX);
+    uint16_t sci_int;
+    uint8_t acpi_enable_cmd;
+    uint8_t acpi_disable_cmd;
+    uint32_t gpe0_blk;
+    uint32_t gpe0_blk_len;
+    bool fix_rtc;
+    bool platform_timer;
+    uint64_t mcfg_base;
+    const unsigned char *dsdt_code;
+    unsigned dsdt_size;
+    uint16_t pvpanic_port;
     FWCfgState *fw_cfg;
 };
 
@@ -113,7 +142,8 @@  DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
 void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
                           ISADevice **rtc_state,
                           ISADevice **floppy,
-                          bool no_vmport);
+                          bool no_vmport,
+                          PcGuestInfo *guest_info);
 void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd);
 void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
                   const char *boot_device,
@@ -131,7 +161,8 @@  void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name);
 
 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                        qemu_irq sci_irq, qemu_irq smi_irq,
-                       int kvm_enabled, FWCfgState *fw_cfg);
+                       int kvm_enabled, FWCfgState *fw_cfg,
+                       PcGuestInfo *guest_info);
 void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 
 /* hpet.c */
@@ -193,7 +224,7 @@  static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
 void pc_system_firmware_init(MemoryRegion *rom_memory);
 
 /* pvpanic.c */
-void pvpanic_init(ISABus *bus);
+void pvpanic_init(ISABus *bus, PcGuestInfo *guest_info);
 
 /* e820 types */
 #define E820_RAM        1