pci: load memory window setup from host

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@redhat.com>
diff --git a/src/pciinit.c b/src/pciinit.c
index ef5e33b..cc12040 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -15,6 +15,7 @@
 #include "paravirt.h" // RamSize
 #include "dev-q35.h" // Q35_HOST_BRIDGE_PCIEXBAR_ADDR
 #include "list.h" // struct hlist_node
+#include "byteorder.h" // le64_to_cpu
 
 #define PCI_DEVICE_MEM_MIN     0x1000
 #define PCI_BRIDGE_IO_MIN      0x1000
@@ -844,15 +845,45 @@
     }
 }
 
+static
+int pci_mem_get(struct pci_mem *mem)
+{
+    int ret;
+    struct romfile_s *file = romfile_find("etc/pci-info");
+    if (!file)
+        return -1;
+
+    ret = file->copy(file, mem, sizeof(*mem));
+    if (ret < (int)sizeof(*mem)) {
+        dprintf(1, "failed to read %d bytes from etc/pci-info: result %d\n",
+                (int)sizeof *mem, ret);
+        return -1;
+    }
+
+    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);
+
+    dprintf(3, "loaded pci setup from etc/pci-info: %llx-%llx %llx-%llx\n",
+            (long long)mem->start32,
+            (long long)mem->end32,
+            (long long)mem->start64,
+            (long long)mem->end64
+           );
+
+    return 0;
+}
+
 
 /****************************************************************
  * Main setup code
  ****************************************************************/
-
 void
 pci_setup(void)
 {
     struct pci_mem mem;
+    int pcimem_is_set;
 
     if (!CONFIG_QEMU)
         return;
@@ -868,7 +899,13 @@
     dprintf(1, "=== PCI device probing ===\n");
     pci_probe_devices();
 
-    pci_bios_init_mem_addr(&mem);
+    if (pci_mem_get(&mem) < 0) {
+        pci_bios_init_mem_addr(&mem);
+        pcimem_is_set = 0;
+    } else {
+        pcimem_is_set = 1;
+    }
+
     pci_bios_init_platform();
 
     dprintf(1, "=== PCI new allocation pass #1 ===\n");
@@ -882,11 +919,20 @@
         return;
 
     dprintf(1, "=== PCI new allocation pass #2 ===\n");
+    if (pcimem_is_set) {
+        pcimem_start = mem.start32;
+        pcimem_end = mem.end32;
+        pcimem64_start = mem.start64;
+        pcimem64_end = mem.end64;
+    }
     pci_bios_map_devices(busses, &mem);
-    pcimem_start = mem.start32;
-    pcimem_end = mem.end32;
-    pcimem64_start = mem.start64;
-    pcimem64_end = mem.end64;
+    /* If memory window is not yet set, set it to result of bus scan */
+    if (!pcimem_is_set) {
+        pcimem_start = mem.start32;
+        pcimem_end = mem.end32;
+        pcimem64_start = mem.start64;
+        pcimem64_end = mem.end64;
+    }
 
     pci_bios_init_devices();