Skip to contentSkip to conversation

pc: pass pci window data to guests

PATCH Superseded Michael S. Tsirkin 1 participant 4 messages Jun 18, 2013

lore
Share & tools
lore
#0 lore raw

v3 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.
This will also make it easier to add more chipsets down the road.

Ranges are passed within a generic GuestInfo structure, can add more fields of interest to Guests in the future.

Note: this is on top of my PCI branch,
if no one objects I'd like to merge it through there as there are some trivial dependencies on that.

Changes from v1:
- fix v1.5-v1.6 migration compatibility
- address Peter Maydell's comments on range.h
- make addresses a bit smaller, compatible to what seabios does at the moment. We can increase the windows, carefully, at a later time.

Changes from v2:
- document alignment requirements for 32 bit as suggested by Gerd
- align 64 bit windows as suggested by Gerd
- tweak field name for 1.5 compat support
- smash compat patch into main fw cfg patch,
avoid bisect breakage
- add patch to reduce compat code duplication
Michael S. Tsirkin (5):
range: add Range structure
pci: store PCI hole ranges in guestinfo structure
pc: pass PCI hole ranges to Guests
pc: add 1.6 compat type
pc: pci-info add compat support

 hw/i386/pc.c              | 65 ++++++++++++++++++++++++++++++++++++++++++++++-
 hw/i386/pc_piix.c         | 37 ++++++++++++++++++++++++---
 hw/i386/pc_q35.c          |  6 ++++-
 hw/pci-host/q35.c         |  4 +++
 include/hw/i386/pc.h      | 20 ++++++++++++++-
 include/hw/pci-host/q35.h |  2 ++
 include/qemu/range.h      | 16 ++++++++++++
 include/qemu/typedefs.h   |  1 +
 8 files changed, 145 insertions(+), 6 deletions(-)
Signature · 1 line
MST
#1 lore raw

PATCH v3 1/4 range: add Range structure

Sometimes we need to pass ranges around, add a
handy structure for this purpose.

Note: memory.c defines its own concept of AddrRange structure for working with 128 addresses. It's necessary there for doing range math. This is not needed for most users: struct Range is
much simpler, and is only used for passing the range around.

---
 include/qemu/range.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
include/qemu/range.h +16 -0
index 3502372..b76cc0d 100644
@@ -1,6 +1,22 @@
 #ifndef QEMU_RANGE_H
 #define QEMU_RANGE_H
 
+#include <inttypes.h>
+
+/*
+ * Operations on 64 bit address ranges.
+ * Notes:
+ *   - ranges must not wrap around 0, but can include the last byte ~0x0LL.
+ *   - this can not represent a full 0 to ~0x0LL range.
+ */
+
+/* A structure representing a range of addresses. */
+struct Range {
+    uint64_t begin; /* First byte of the range, or 0 if empty. */
+    uint64_t end;   /* 1 + the last byte. 0 if range empty or ends at ~0x0LL. */
+};
+typedef struct Range Range;
+
 /* 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 v3 3/4 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         | 26 ++++++++++++++++++++++++++
 hw/i386/pc_piix.c    | 16 +++++++++++++++-
 hw/i386/pc_q35.c     | 12 ++++++++++--
 include/hw/i386/pc.h |  1 +
 4 files changed, 52 insertions(+), 3 deletions(-)
hw/i386/pc.c +26 -0
index c685ee8..e1ed760 100644
@@ -990,6 +990,31 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
     }
 }
 
+/* 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;
+
+static void pc_fw_cfg_guest_info(PcGuestInfo *guest_info)
+{
+    PcRomPciInfo *info;
+    if (!guest_info->has_pci_info) {
+        return;
+    }
+
+    info = g_malloc(sizeof *info);
+    info->w32_min = cpu_to_le64(guest_info->pci_info.w32.begin);
+    info->w32_max = cpu_to_le64(guest_info->pci_info.w32.end);
+    info->w64_min = cpu_to_le64(guest_info->pci_info.w64.begin);
+    info->w64_max = cpu_to_le64(guest_info->pci_info.w64.end);
+    /* Pass PCI hole info to guest via a side channel.
+     * Required so guest PCI enumeration does the right thing. */
+    fw_cfg_add_file(guest_info->fw_cfg, "etc/pci-info", info, sizeof *info);
+}
+
 typedef struct PcGuestInfoState {
     PcGuestInfo info;
     Notifier machine_done;
@@ -1001,6 +1026,7 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data)
     PcGuestInfoState *guest_info_state = container_of(notifier,
                                                       PcGuestInfoState,
                                                       machine_done);
+    pc_fw_cfg_guest_info(&guest_info_state->info);
 }
 
 PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
hw/i386/pc_piix.c +15 -1
index a70a0d9..d87da95 100644
@@ -57,6 +57,7 @@ static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
 static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
 
 static bool has_pvpanic = true;
+static bool has_pci_info = true;
 
 /* PC hardware initialisation */
 static void pc_init1(MemoryRegion *system_memory,
@@ -121,6 +122,7 @@ static void pc_init1(MemoryRegion *system_memory,
     }
 
     guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
+    guest_info->has_pci_info = has_pci_info;
 
     /* Set PCI window size the way seabios has always done it. */
     /* Power of 2 so bios can cover it with a single MTRR */
@@ -258,8 +260,15 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
              initrd_filename, cpu_model, 1, 1);
 }
 
+static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
+{
+    has_pci_info = false;
+    pc_init_pci(args);
+}
+
 static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
 {
+    has_pci_info = false;
     has_pvpanic = false;
     x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
     pc_init_pci(args);
@@ -267,6 +276,7 @@ static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
 
 static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
 {
+    has_pci_info = false;
     enable_compat_apic_id_mode();
     has_pvpanic = false;
     pc_init_pci(args);
@@ -275,6 +285,7 @@ static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
 /* PC machine init function for pc-1.1 to pc-1.2 */
 static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
 {
+    has_pci_info = false;
     disable_kvm_pv_eoi();
     enable_compat_apic_id_mode();
     has_pvpanic = false;
@@ -284,6 +295,7 @@ static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
 /* PC machine init function for pc-0.14 to pc-1.0 */
 static void pc_init_pci_1_0(QEMUMachineInitArgs *args)
 {
+    has_pci_info = false;
     disable_kvm_pv_eoi();
     enable_compat_apic_id_mode();
     has_pvpanic = false;
@@ -300,6 +312,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
     const char *initrd_filename = args->initrd_filename;
     const char *boot_device = args->boot_device;
     has_pvpanic = false;
+    has_pci_info = false;
     disable_kvm_pv_eoi();
     enable_compat_apic_id_mode();
     pc_init1(get_system_memory(),
@@ -318,6 +331,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
     const char *initrd_filename = args->initrd_filename;
     const char *boot_device = args->boot_device;
     has_pvpanic = false;
+    has_pci_info = false;
     if (cpu_model == NULL)
         cpu_model = "486";
     disable_kvm_pv_eoi();
@@ -353,7 +367,7 @@ static QEMUMachine pc_i440fx_machine_v1_6 = {
 static QEMUMachine pc_i440fx_machine_v1_5 = {
     .name = "pc-i440fx-1.5",
     .desc = "Standard PC (i440FX + PIIX, 1996)",
-    .init = pc_init_pci,
+    .init = pc_init_pci_1_5,
     .hot_add_cpu = pc_hot_add_cpu,
     .max_cpus = 255,
     .compat_props = (GlobalProperty[]) {
hw/i386/pc_q35.c +10 -2
index a13acf2..5b92160 100644
@@ -47,6 +47,7 @@
 #define MAX_SATA_PORTS     6
 
 static bool has_pvpanic = true;
+static bool has_pci_info = true;
 
 /* PC hardware initialisation */
 static void pc_q35_init(QEMUMachineInitArgs *args)
@@ -107,6 +108,7 @@ 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;
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
@@ -212,11 +214,17 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
     }
 }
 
+static void pc_q35_init_1_5(QEMUMachineInitArgs *args)
+{
+    has_pci_info = false;
+    pc_q35_init(args);
+}
+
 static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
 {
     has_pvpanic = false;
     x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
-    pc_q35_init(args);
+    pc_q35_init_1_5(args);
 }
 
 static QEMUMachine pc_q35_machine_v1_6 = {
@@ -232,7 +240,7 @@ static QEMUMachine pc_q35_machine_v1_6 = {
 static QEMUMachine pc_q35_machine_v1_5 = {
     .name = "pc-q35-1.5",
     .desc = "Standard PC (Q35 + ICH9, 2009)",
-    .init = pc_q35_init,
+    .init = pc_q35_init_1_5,
     .hot_add_cpu = pc_hot_add_cpu,
     .max_cpus = 255,
     .compat_props = (GlobalProperty[]) {
include/hw/i386/pc.h +1 -0
index 6cb06fe..0d45462 100644
@@ -20,6 +20,7 @@ typedef struct PcPciInfo {
 
 struct PcGuestInfo {
     PcPciInfo pci_info;
+    bool has_pci_info_in_fw_cfg;
     FWCfgState *fw_cfg;
 };
 
Signature · 1 line
MST
#3 lore raw

PATCH v3 4/4 pc_piix: cleanup init compat handling

In reply to Michael S. Tsirkin

Make sure 1.4 calls 1.5, 1.3 calls 1.4 etc. This way it's enough to add enough new compat hook in a single place in piix.

---
 hw/i386/pc_piix.c | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)
hw/i386/pc_piix.c +4 -14
index d87da95..234424a 100644
@@ -268,38 +268,28 @@ static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
 
 static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
 {
-    has_pci_info = false;
     has_pvpanic = false;
     x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
-    pc_init_pci(args);
+    pc_init_pci_1_5(args);
 }
 
 static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
 {
-    has_pci_info = false;
     enable_compat_apic_id_mode();
-    has_pvpanic = false;
-    pc_init_pci(args);
+    pc_init_pci_1_4(args);
 }
 
 /* PC machine init function for pc-1.1 to pc-1.2 */
 static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
 {
-    has_pci_info = false;
     disable_kvm_pv_eoi();
-    enable_compat_apic_id_mode();
-    has_pvpanic = false;
-    pc_init_pci(args);
+    pc_init_pci_1_3(args);
 }
 
 /* PC machine init function for pc-0.14 to pc-1.0 */
 static void pc_init_pci_1_0(QEMUMachineInitArgs *args)
 {
-    has_pci_info = false;
-    disable_kvm_pv_eoi();
-    enable_compat_apic_id_mode();
-    has_pvpanic = false;
-    pc_init_pci(args);
+    pc_init_pci_1_2(args);
 }
 
 /* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
Signature · 1 line
MST