Older 32-bit Linux VMs (including Ubuntu 16.10) have issues with the
64-bit pci io window, failing during boot with errors like:

virtio_balloon virtio2: virtio: device uses modern interface but does not have 
VIRTIO_F_VERSION_19734-565debf7b362
virtio_net virtio0: virtio: device uses modern interface but does not have 
VIRTIO_F_VERSION_1
Virtio_scsi virtio1: virtio: device uses modern interface but does not have 
VIRTIO_F_VERSION_1
Gave up waiting for root device.  Common problems:
 - Boot args (cat /proc/cmdline)
 - Check rootdelay= (did the system wait long enough?)
 - Check root= (did the system wait for the right device?)
 - Missing modules (cat /proc/modules; ls /dev)
ALERT!  /dev/disk/by-uuid/86859879-3f17-443d-a226-077c435291e2 does not exist.
Dropping to a shell!

Be a bit more conservative, and only enable the window by default when
the ram size extends beyond 64G - a 32-bit guest using PAE cannot
address beyond that anyway. Due to the mmio window this translates
to an effective working configuration limit of 62G/63G, depending on
machine type.

Fixes: 96a8d130 ("be less conservative with the 64bit pci io window")
Signed-off-by: John Levon <john.le...@nutanix.com>
---
 src/fw/paravirt.c | 28 ++++++++++++++++++++++++----
 src/fw/paravirt.h |  1 +
 src/fw/pciinit.c  |  6 +++++-
 3 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c
index 3ad9094b..5b0f191b 100644
--- a/src/fw/paravirt.c
+++ b/src/fw/paravirt.c
@@ -29,11 +29,14 @@
 #include "stacks.h" // yield
 
 #define MEM_4G (0x100000000ULL)
+#define MEM_64G (16 * 0x100000000ULL)
 
 // Amount of continuous ram under 4Gig
 u32 RamSize;
 // Amount of continuous ram >4Gig
 u64 RamSizeOver4G;
+// Amount of continuous ram >64Gig
+u64 RamSizeOver64G;
 // physical address space bits
 u8 CPUPhysBits;
 // 64bit processor
@@ -591,8 +594,12 @@ qemu_cfg_e820(void)
                 | ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24)
                 | ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32));
     RamSizeOver4G = high;
+    RamSizeOver64G = 0;
+    if (high + MEM_4G > MEM_64G)
+        RamSizeOver64G = high + MEM_4G - MEM_64G;
     e820_add(MEM_4G, high, E820_RAM);
     dprintf(1, "RamSizeOver4G: 0x%016llx [cmos]\n", RamSizeOver4G);
+    dprintf(1, "RamSizeOver64G: 0x%016llx [cmos]\n", RamSizeOver64G);
 }
 
 // Populate romfile entries for legacy fw_cfg ports (that predate the
@@ -774,19 +781,32 @@ static int qemu_early_e820(void)
             e820_add(table.address, table.length, table.type);
             dprintf(1, "qemu/e820: addr 0x%016llx len 0x%016llx [RAM]\n",
                     table.address, table.length);
+            // address below 4g?
             if (table.address < MEM_4G) {
-                // below 4g
                 if (RamSize < table.address + table.length)
                     RamSize = table.address + table.length;
             } else {
-                // above 4g
-                if (RamSizeOver4G < table.address + table.length - MEM_4G)
-                    RamSizeOver4G = table.address + table.length - MEM_4G;
+                u64 table_end = table.address + table.length;
+
+                /*
+                 * Note that this would ignore any span that crosses the 4G
+                 * boundary. For RamSizeOver64G, we do account for any spans
+                 * that cross the 64G boundary.
+                 */
+                if (RamSizeOver4G < table_end - MEM_4G)
+                    RamSizeOver4G = table_end - MEM_4G;
+
+                // crosses 64G ?
+                if (table_end > MEM_64G) {
+                    if (RamSizeOver64G < table_end - MEM_64G)
+                        RamSizeOver64G = table_end - MEM_64G;
+                }
             }
         }
     }
 
     dprintf(1, "qemu/e820: RamSize: 0x%08x\n", RamSize);
     dprintf(1, "qemu/e820: RamSizeOver4G: 0x%016llx\n", RamSizeOver4G);
+    dprintf(1, "qemu/e820: RamSizeOver64G: 0x%016llx\n", RamSizeOver64G);
     return 1;
 }
diff --git a/src/fw/paravirt.h b/src/fw/paravirt.h
index 62a2cd07..b56e96e8 100644
--- a/src/fw/paravirt.h
+++ b/src/fw/paravirt.h
@@ -30,6 +30,7 @@ typedef struct QemuCfgDmaAccess {
 
 extern u32 RamSize;
 extern u64 RamSizeOver4G;
+extern u64 RamSizeOver64G;
 extern int PlatformRunningOn;
 extern u8 CPUPhysBits;
 extern u8 CPULongMode;
diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
index 0395fdbf..1247eb12 100644
--- a/src/fw/pciinit.c
+++ b/src/fw/pciinit.c
@@ -1197,7 +1197,11 @@ pci_setup(void)
         }
     }
 
-    if (CPUPhysBits >= 36 && CPULongMode && RamSizeOver4G) {
+    /*
+     * Only enable this if we exceed 64G, as some older 32-bit Linux VMs cannot
+     * handle the 64-bit window correctly.
+     */
+    if (CPUPhysBits >= 36 && CPULongMode && RamSizeOver64G) {
         dprintf(1, "enabling 64-bit pci mmio window\n");
         pci_pad_mem64 = 1;
     }
-- 
2.34.1

_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-le...@seabios.org

Reply via email to