[SeaBIOS] [PATCH 2/2] pci: load memory window setup from host

Michael S. Tsirkin mst at redhat.com
Mon Apr 29 17:21:40 CEST 2013


Load memory window setup for pci 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.

Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
---
 src/paravirt.c | 25 ++++++++++++++++++++++++-
 src/pciinit.c  | 54 ++++++++++++++++++++++++++++++++++++++++--------------
 src/util.h     |  8 +++++++-
 3 files changed, 71 insertions(+), 16 deletions(-)

diff --git a/src/paravirt.c b/src/paravirt.c
index 85aa423..067a4dc 100644
--- a/src/paravirt.c
+++ b/src/paravirt.c
@@ -91,14 +91,35 @@ qemu_preinit(void)
     dprintf(1, "Ram Size=0x%08x (0x%016llx high)\n", RamSize, RamSizeOver4G);
 }
 
+struct pci_mem *qemu_get_pci_mem(void)
+{
+    int psize;
+    struct pci_mem *mem = romfile_loadfile("etc/pci-info", &psize);
+    if (!mem)
+        return NULL;
+    if (psize < sizeof *mem) {
+        free(mem);
+        return NULL;
+    }
+    mem->start32 = le64_to_cpu(mem->start32);
+    mem->end32 = le64_to_cpu(mem->end32);
+    mem->start64 = le64_to_cpu(mem->start64);
+    mem->end64 = le64_to_cpu(mem->end64);
+    return mem;
+}
+
 void
 qemu_platform_setup(void)
 {
+    struct pci_mem *mem;
+
     if (!CONFIG_QEMU)
         return;
 
     qemu_cfg_init();
 
+    mem = qemu_get_pci_mem();
+
     if (runningOnXen()) {
         pci_probe_devices();
         xen_hypercall_setup();
@@ -107,7 +128,7 @@ qemu_platform_setup(void)
     }
 
     // Initialize pci
-    pci_setup();
+    pci_setup(mem);
     smm_device_setup();
     smm_setup();
 
@@ -120,6 +141,8 @@ qemu_platform_setup(void)
     mptable_setup();
     smbios_setup();
     acpi_setup();
+    if (mem)
+        free(mem);
 }
 
 
diff --git a/src/pciinit.c b/src/pciinit.c
index bb9355f..f3bac02 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -361,6 +361,8 @@ static void pci_enable_default_vga(void)
 
 void i440fx_mem_addr_setup(struct pci_device *dev, void *arg)
 {
+    if (arg)
+	/* use supplied memory */;
     if (RamSize <= 0x80000000)
         pcimem_start = 0x80000000;
     else if (RamSize <= 0xc0000000)
@@ -383,8 +385,9 @@ void mch_mem_addr_setup(struct pci_device *dev, void *arg)
     pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower);
     add_e820(addr, size, E820_RESERVED);
 
-    /* setup pci i/o window (above mmconfig) */
-    pcimem_start = addr + size;
+    /* unless done already, setup pci i/o window (above mmconfig) */
+    if (!arg)
+    	pcimem_start = addr + size;
 
     pci_slot_get_irq = mch_pci_slot_get_irq;
 }
@@ -397,11 +400,11 @@ static const struct pci_device_id pci_platform_tbl[] = {
     PCI_DEVICE_END
 };
 
-static void pci_bios_init_platform(void)
+static void pci_bios_init_platform(struct pci_mem *mem)
 {
     struct pci_device *pci;
     foreachpci(pci) {
-        pci_init_device(pci_platform_tbl, pci, NULL);
+        pci_init_device(pci_platform_tbl, pci, mem);
     }
 }
 
@@ -762,10 +765,14 @@ static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r)
     }
 }
 
-static void pci_bios_map_devices(struct pci_bus *busses)
+static void pci_bios_map_devices(struct pci_bus *busses, struct pci_mem *mem)
 {
     if (pci_bios_init_root_regions(busses)) {
         struct pci_region r64_mem, r64_pref;
+
+        if (mem && mem->start64 <= mem->end64)
+            panic("PCI: out of 32bit address space\n");
+
         r64_mem.list = NULL;
         r64_pref.list = NULL;
         pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_MEM],
@@ -781,14 +788,27 @@ static void pci_bios_map_devices(struct pci_bus *busses)
         u64 align_mem = pci_region_align(&r64_mem);
         u64 align_pref = pci_region_align(&r64_pref);
 
-        r64_mem.base = ALIGN(0x100000000LL + RamSizeOver4G, align_mem);
-        r64_pref.base = ALIGN(r64_mem.base + sum_mem, align_pref);
-        pcimem64_start = r64_mem.base;
-        pcimem64_end = r64_pref.base + sum_pref;
+        if (mem) {
+            /*
+             * Non prefetcheable memory at start of the window,
+             * prefetcheable memory at the end.
+             * This way OS has the maximum flexibility for
+             * allocating the rest of the memory.
+             */
+            r64_mem.base = ALIGN(mem->start64, align_mem);
+            r64_pref.base = ALIGN_DOWN(mem->end64 - sum_pref + 1, align_pref);
+            if (sum_pref && r64_pref.base < r64_mem.base + sum_mem)
+                panic("PCI: out of 64bit address space\n");
+        } else {
+            r64_mem.base = ALIGN(0x100000000LL + RamSizeOver4G, align_mem);
+            r64_pref.base = ALIGN(r64_mem.base + sum_mem, align_pref);
+            pcimem64_start = r64_mem.base;
+            pcimem64_end = r64_pref.base + sum_pref;
+        }
 
         pci_region_map_entries(busses, &r64_mem);
         pci_region_map_entries(busses, &r64_pref);
-    } else {
+    } else if (!mem) {
         // no bars mapped high -> drop 64bit window (see dsdt)
         pcimem64_start = 0;
     }
@@ -807,7 +827,7 @@ static void pci_bios_map_devices(struct pci_bus *busses)
  ****************************************************************/
 
 void
-pci_setup(void)
+pci_setup(struct pci_mem *mem)
 {
     if (!CONFIG_QEMU)
         return;
@@ -823,8 +843,14 @@ pci_setup(void)
     dprintf(1, "=== PCI device probing ===\n");
     pci_probe_devices();
 
-    pcimem_start = RamSize;
-    pci_bios_init_platform();
+    if (mem) {
+        pcimem_start = mem->start32;
+        pcimem_end = mem->end32;
+        pcimem64_start = mem->start64;
+        pcimem64_end = mem->end64;
+    } else
+        pcimem_start = RamSize;
+    pci_bios_init_platform(mem);
 
     dprintf(1, "=== PCI new allocation pass #1 ===\n");
     struct pci_bus *busses = malloc_tmp(sizeof(*busses) * (MaxPCIBus + 1));
@@ -837,7 +863,7 @@ pci_setup(void)
         return;
 
     dprintf(1, "=== PCI new allocation pass #2 ===\n");
-    pci_bios_map_devices(busses);
+    pci_bios_map_devices(busses, mem);
 
     pci_bios_init_devices();
 
diff --git a/src/util.h b/src/util.h
index 7b50c38..03fe60c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -311,7 +311,13 @@ void qemu_prep_reset(void);
 
 // pciinit.c
 extern const u8 pci_irqs[4];
-void pci_setup(void);
+struct pci_mem {
+	u64 start32;
+	u64 end32;
+	u64 start64;
+	u64 end64;
+};
+void pci_setup(struct pci_mem *);
 
 // smm.c
 void smm_device_setup(void);
-- 
MST



More information about the SeaBIOS mailing list