Skip to contentSkip to conversation

pc: pass pci window data to guests

PATCH Superseded Michael S. Tsirkin 1 participant 4 messages Apr 29, 2013

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

cover pc: pass pci window data to guests

This makes it possible for bios to load pci window data from host.

This makes it possible for host to make sure setup matches hardware exactly: especially important for when ACPI tables are loaded from host. This will also make it easier to add more chipsets down the road.

Michael S. Tsirkin (3):
range: add structure to pass ranges around
pc: factor out pci hole math
pc: pass PCI hole ranges to Guests

 hw/i386/pc.c              | 34 +++++++++++++++++++++++++++++++---
 hw/i386/pc_piix.c         | 14 +++++++-------
 hw/i386/pc_q35.c          |  9 ++++++---
 hw/pci-host/q35.c         | 18 ++++++++----------
 include/hw/i386/pc.h      | 25 ++++++++++++++++++++++++-
 include/hw/pci-host/q35.h |  4 ++--
 include/qemu/range.h      | 24 ++++++++++++++++++++++++
 7 files changed, 102 insertions(+), 26 deletions(-)
Signature · 1 line
MST
#1 lore raw

PATCH 1/3 range: add structure to pass ranges around

Convenient structure to pass ranges around, and calculate length avoiding 64 bit overlap issues.

---
 include/qemu/range.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
include/qemu/range.h +24 -0
index 3502372..aeef1fb 100644
@@ -1,6 +1,30 @@
 #ifndef QEMU_RANGE_H
 #define QEMU_RANGE_H
 
+#include <inttypes.h>
+
+struct Range {
+    uint64_t min;
+    uint64_t max;
+};
+typedef struct Range Range;
+
+/* max <= min means not valid */
+static inline bool range_valid(Range *r)
+{
+    return r->max > r->min;
+}
+
+static inline uint64_t range_len(Range *r)
+{
+    return range_valid(r) ? r->max - r->min + 1 : 0;
+}
+
+static inline uint64_t range_start(Range *r)
+{
+    return r->min;
+}
+
 /* Get last byte of a range from offset + length.
  * Undefined for ranges that wrap around 0. */
 static inline uint64_t range_get_last(uint64_t offset, uint64_t len)
Signature · 1 line
MST
#2 lore raw

PATCH 2/3 pc: factor out pci hole math

In reply to Michael S. Tsirkin

Move common code for calculating ranges for 32 and 64 bit pci holes for use by guest to pc.c.
Pass ranges to Q35/PIIX respectively.

Note: ranges are passed within a generic GuestInfo structure, we are going to add more fields of interest to Guests in the future.

---
 hw/i386/pc.c              | 15 +++++++++++++++
 hw/i386/pc_piix.c         | 12 ++++++------
 hw/i386/pc_q35.c          |  7 +++++--
 hw/pci-host/q35.c         | 18 ++++++++----------
 include/hw/i386/pc.h      | 13 +++++++++++++
 include/hw/pci-host/q35.h |  4 ++--
 6 files changed, 49 insertions(+), 20 deletions(-)
hw/i386/pc.c +15 -0
index 0b84aa4..fbea5d0 100644
@@ -922,6 +922,21 @@ void pc_acpi_init(const char *default_dsdt)
     }
 }
 
+void pc_guest_info_init(PcGuestInfo *guest_info,
+                        ram_addr_t below_4g_mem_size,
+                        ram_addr_t above_4g_mem_size)
+{
+    guest_info->pci_info.w32.min = below_4g_mem_size;
+    guest_info->pci_info.w32.max = 0x100000000ULL - 0x1;
+    if (sizeof(hwaddr) == 4) {
+        guest_info->pci_info.w64.min = 0x100000000ULL + above_4g_mem_size;
+        guest_info->pci_info.w64.max =
+            range_get_last(guest_info->pci_info.w64.min, (0x1ULL << 62));
+    } else {
+        guest_info->pci_info.w64.min = guest_info->pci_info.w64.max =  0;
+    }
+}
+
 FWCfgState *pc_memory_init(MemoryRegion *system_memory,
                            const char *kernel_filename,
                            const char *kernel_cmdline,
hw/i386/pc_piix.c +6 -6
index da10e6d..539f72a 100644
@@ -86,6 +86,7 @@ static void pc_init1(MemoryRegion *system_memory,
     MemoryRegion *pci_memory;
     MemoryRegion *rom_memory;
     FWCfgState *fw_cfg = NULL;
+    PcGuestInfo guest_info;
 
     pc_cpus_init(cpu_model);
     pc_acpi_init("acpi-dsdt.aml");
@@ -111,6 +112,7 @@ static void pc_init1(MemoryRegion *system_memory,
         rom_memory = system_memory;
     }
 
+    pc_guest_info_init(&guest_info, below_4g_mem_size, above_4g_mem_size);
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
         fw_cfg = pc_memory_init(system_memory,
@@ -131,12 +133,10 @@ static void pc_init1(MemoryRegion *system_memory,
     if (pci_enabled) {
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
                               system_memory, system_io, ram_size,
-                              below_4g_mem_size,
-                              0x100000000ULL - below_4g_mem_size,
-                              0x100000000ULL + above_4g_mem_size,
-                              (sizeof(hwaddr) == 4
-                               ? 0
-                               : ((uint64_t)1 << 62)),
+                              range_start(&guest_info.pci_info.w32),
+                              range_len(&guest_info.pci_info.w32),
+                              range_start(&guest_info.pci_info.w64),
+                              range_len(&guest_info.pci_info.w64),
                               pci_memory, ram_memory);
     } else {
         pci_bus = NULL;
hw/i386/pc_q35.c +5 -2
index 6ac1a89..50dc14d 100644
@@ -85,6 +85,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
     ICH9LPCState *ich9_lpc;
     PCIDevice *ahci;
     qemu_irq *cmos_s3;
+    PcGuestInfo guest_info;
 
     pc_cpus_init(cpu_model);
     pc_acpi_init("q35-acpi-dsdt.aml");
@@ -109,6 +110,8 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
         rom_memory = get_system_memory();
     }
 
+    pc_guest_info_init(&guest_info, below_4g_mem_size, above_4g_mem_size);
+
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
         pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
@@ -133,8 +136,8 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
     q35_host->mch.pci_address_space = pci_memory;
     q35_host->mch.system_memory = get_system_memory();
     q35_host->mch.address_space_io = get_system_io();;
-    q35_host->mch.below_4g_mem_size = below_4g_mem_size;
-    q35_host->mch.above_4g_mem_size = above_4g_mem_size;
+    q35_host->mch.below_4g_mem_range = guest_info.pci_info.w32;
+    q35_host->mch.above_4g_mem_range = guest_info.pci_info.w64;
     /* pci */
     qdev_init_nofail(DEVICE(q35_host));
     host_bus = q35_host->host.pci.bus;
hw/pci-host/q35.c +8 -10
index 8467f86..c951255 100644
@@ -240,25 +240,23 @@ static void mch_reset(DeviceState *qdev)
 static int mch_init(PCIDevice *d)
 {
     int i;
-    hwaddr pci_hole64_size;
     MCHPCIState *mch = MCH_PCI_DEVICE(d);
 
     /* setup pci memory regions */
     memory_region_init_alias(&mch->pci_hole, "pci-hole",
                              mch->pci_address_space,
-                             mch->below_4g_mem_size,
-                             0x100000000ULL - mch->below_4g_mem_size);
-    memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
+                             range_start(&mch->below_4g_mem_range),
+                             range_len(&mch->below_4g_mem_range));
+    memory_region_add_subregion(mch->system_memory,
+                                range_len(&mch->below_4g_mem_range),
                                 &mch->pci_hole);
-    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
-                       ((uint64_t)1 << 62));
     memory_region_init_alias(&mch->pci_hole_64bit, "pci-hole64",
                              mch->pci_address_space,
-                             0x100000000ULL + mch->above_4g_mem_size,
-                             pci_hole64_size);
-    if (pci_hole64_size) {
+                             range_start(&mch->above_4g_mem_range),
+                             range_len(&mch->above_4g_mem_range));
+    if (range_valid(&mch->above_4g_mem_range)) {
         memory_region_add_subregion(mch->system_memory,
-                                    0x100000000ULL + mch->above_4g_mem_size,
+                                    range_len(&mch->above_4g_mem_range),
                                     &mch->pci_hole_64bit);
     }
     /* smram */
include/hw/i386/pc.h +13 -0
index a65c6a0..cf3b263 100644
@@ -10,9 +10,19 @@
 #include "exec/memory.h"
 #include "hw/i386/ioapic.h"
 #include "hw/nvram/fw_cfg.h"
+#include "qemu/range.h"
 
 /* PC-style peripherals (also used by other machines).  */
 
+typedef struct PciGuestInfo {
+    Range w32;
+    Range w64;
+} PciGuestInfo;
+
+typedef struct PcGuestInfo {
+    PciGuestInfo pci_info;
+} PcGuestInfo;
+
 /* parallel.c */
 static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr)
 {
@@ -81,6 +91,9 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
 
 void pc_cpus_init(const char *cpu_model);
 void pc_acpi_init(const char *default_dsdt);
+void pc_guest_info_init(PcGuestInfo *guest_info,
+                        ram_addr_t below_4g_mem_size,
+                        ram_addr_t above_4g_mem_size);
 FWCfgState *pc_memory_init(MemoryRegion *system_memory,
                            const char *kernel_filename,
                            const char *kernel_cmdline,
include/hw/pci-host/q35.h +2 -2
index e182c82..2766b6a 100644
@@ -53,8 +53,8 @@ typedef struct MCHPCIState {
     MemoryRegion pci_hole;
     MemoryRegion pci_hole_64bit;
     uint8_t smm_enabled;
-    ram_addr_t below_4g_mem_size;
-    ram_addr_t above_4g_mem_size;
+    Range below_4g_mem_range;
+    Range above_4g_mem_range;
 } MCHPCIState;
 
 typedef struct Q35PCIHost {
Signature · 1 line
MST
#3 lore raw

PATCH 3/3 pc: pass PCI hole ranges to Guests

In reply to Michael S. Tsirkin

Guest currently has to jump through lots of
hoops to guess the PCI hole ranges.
It's fragile, and makes us change BIOS each time we add a new chipset. Let's report the window in a ROM file, to make
BIOS do exactly what QEMU intends.

---
 hw/i386/pc.c         | 19 ++++++++++++++++---
 hw/i386/pc_piix.c    |  2 +-
 hw/i386/pc_q35.c     |  2 +-
 include/hw/i386/pc.h | 18 ++++++++++++++----
 4 files changed, 32 insertions(+), 9 deletions(-)
hw/i386/pc.c +16 -3
index fbea5d0..35c0dd9 100644
@@ -567,7 +567,7 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus)
     return x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
 }
 
-static FWCfgState *bochs_bios_init(void)
+static FWCfgState *bochs_bios_init(PcGuestInfo *guest_info)
 {
     FWCfgState *fw_cfg;
     uint8_t *smbios_table;
@@ -629,6 +629,9 @@ static FWCfgState *bochs_bios_init(void)
                      (1 + apic_id_limit + nb_numa_nodes) *
                      sizeof(*numa_fw_cfg));
 
+    fw_cfg_add_file(fw_cfg, "etc/pci-info", guest_info->pci_info_rom,
+                    sizeof *guest_info->pci_info_rom);
+
     return fw_cfg;
 }
 
@@ -926,6 +929,8 @@ void pc_guest_info_init(PcGuestInfo *guest_info,
                         ram_addr_t below_4g_mem_size,
                         ram_addr_t above_4g_mem_size)
 {
+    PcRomPciInfo *pci_info;
+
     guest_info->pci_info.w32.min = below_4g_mem_size;
     guest_info->pci_info.w32.max = 0x100000000ULL - 0x1;
     if (sizeof(hwaddr) == 4) {
@@ -935,6 +940,13 @@ void pc_guest_info_init(PcGuestInfo *guest_info,
     } else {
         guest_info->pci_info.w64.min = guest_info->pci_info.w64.max =  0;
     }
+
+    guest_info->pci_info_rom = pci_info = g_malloc0(sizeof *pci_info);
+    pci_info->w32_min = cpu_to_le64(guest_info->pci_info.w32.min);
+    pci_info->w32_max = cpu_to_le64(MIN(guest_info->pci_info.w32.max,
+                                        IO_APIC_DEFAULT_ADDRESS));
+    pci_info->w64_min = cpu_to_le64(guest_info->pci_info.w64.min);
+    pci_info->w64_max = cpu_to_le64(guest_info->pci_info.w64.max);
 }
 
 FWCfgState *pc_memory_init(MemoryRegion *system_memory,
@@ -944,7 +956,8 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
                            ram_addr_t below_4g_mem_size,
                            ram_addr_t above_4g_mem_size,
                            MemoryRegion *rom_memory,
-                           MemoryRegion **ram_memory)
+                           MemoryRegion **ram_memory,
+                           PcGuestInfo *guest_info)
 {
     int linux_boot, i;
     MemoryRegion *ram, *option_rom_mr;
@@ -986,7 +999,7 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
                                         option_rom_mr,
                                         1);
 
-    fw_cfg = bochs_bios_init();
+    fw_cfg = bochs_bios_init(guest_info);
     rom_set_fw(fw_cfg);
 
     if (linux_boot) {
hw/i386/pc_piix.c +1 -1
index 539f72a..524ce9b 100644
@@ -118,7 +118,7 @@ static void pc_init1(MemoryRegion *system_memory,
         fw_cfg = pc_memory_init(system_memory,
                        kernel_filename, kernel_cmdline, initrd_filename,
                        below_4g_mem_size, above_4g_mem_size,
-                       rom_memory, &ram_memory);
+                       rom_memory, &ram_memory, &guest_info);
     }
 
     gsi_state = g_malloc0(sizeof(*gsi_state));
hw/i386/pc_q35.c +1 -1
index 50dc14d..5ac4f33 100644
@@ -116,7 +116,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
     if (!xen_enabled()) {
         pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
                        initrd_filename, below_4g_mem_size, above_4g_mem_size,
-                       rom_memory, &ram_memory);
+                       rom_memory, &ram_memory, &guest_info);
     }
 
     /* irq lines */
include/hw/i386/pc.h +14 -4
index cf3b263..afd494f 100644
@@ -14,13 +14,22 @@
 
 /* PC-style peripherals (also used by other machines).  */
 
-typedef struct PciGuestInfo {
+typedef struct PcPciInfo {
     Range w32;
     Range w64;
-} PciGuestInfo;
+} PcPciInfo;
+
+/* pci-info ROM file. Little endian format */
+typedef struct PcRomPciInfo {
+    uint64_t w32_min;
+    uint64_t w32_max;
+    uint64_t w64_min;
+    uint64_t w64_max;
+} PcRomPciInfo;
 
 typedef struct PcGuestInfo {
-    PciGuestInfo pci_info;
+    PcPciInfo pci_info;
+    PcRomPciInfo *pci_info_rom;
 } PcGuestInfo;
 
 /* parallel.c */
@@ -101,7 +110,8 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
                            ram_addr_t below_4g_mem_size,
                            ram_addr_t above_4g_mem_size,
                            MemoryRegion *rom_memory,
-                           MemoryRegion **ram_memory);
+                           MemoryRegion **ram_memory,
+                           PcGuestInfo *guest_info);
 qemu_irq *pc_allocate_cpu_irq(void);
 DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
 void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
Signature · 1 line
MST