[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 2/2] Backport pc & q35: Add new machine opt max-ram-below-4g



This is a xen only backport of 2 QEMU 2.1.0 changes:

commit c87b1520726f7ae1e698a41f07043d1b539ac88c
  pc & q35: Add new machine opt max-ram-below-4g
commit c4f5cdc53f181f6fe84a0f1bf99914598934a8a6
  xen-hvm: Handle machine opt max-ram-below-4g

It changes all machine types to have this, not just pc & q35.  But
only pc & q35 machines do anything with it.  I.E. this machine
option will be ignored by other types.

If you add enough PCI devices then all mmio for them will not fit
below 4G which may not be the layout the user wanted. This allows
you to increase the below 4G address space that PCI devices can use
(aka decrease ram below 4G) and therefore in more cases not have any
mmio that is above 4G.

For example using "-machine pc,max-ram-below-4g=2G" on the command
line will limit the amount of ram that is below 4G to 2G.

Note: this machine option cannot be used to increase the amount of
ram below 4G.

Signed-off-by: Don Slutz <dslutz@xxxxxxxxxxx>
---
 hw/i386/pc_piix.c | 24 +++++++++++++++++++++++-
 hw/i386/pc_q35.c  | 24 +++++++++++++++++++++++-
 vl.c              | 28 ++++++++++++++++++++++++++++
 xen-hvm.c         | 35 +++++++++++++++++++++++------------
 4 files changed, 97 insertions(+), 14 deletions(-)

diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index bd52f6e..d506630 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -48,10 +48,13 @@
 #include "exec/address-spaces.h"
 #include "hw/acpi/acpi.h"
 #include "cpu.h"
+#include "qemu/error-report.h"
 #ifdef CONFIG_XEN
 #  include <xen/hvm/hvm_info_table.h>
 #endif
 
+extern uint64_t max_ram_below_4g;
+
 #define MAX_IDE_BUS 2
 
 static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
@@ -95,6 +98,7 @@ static void pc_init1(QEMUMachineInitArgs *args,
     DeviceState *icc_bridge;
     FWCfgState *fw_cfg = NULL;
     PcGuestInfo *guest_info;
+    ram_addr_t lowmem;
 
     /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory).
      * If it doesn't, we need to split it in chunks below and above 4G.
@@ -104,7 +108,25 @@ static void pc_init1(QEMUMachineInitArgs *args,
      * breaking migration.
      */
     if (args->ram_size >= 0xe0000000) {
-        ram_addr_t lowmem = gigabyte_align ? 0xc0000000 : 0xe0000000;
+        lowmem = gigabyte_align ? 0xc0000000 : 0xe0000000;
+    } else {
+        lowmem = 0xe0000000;
+    }
+
+    /* Handle the machine opt max-ram-below-4g.  It is basicly doing
+     * min(qemu limit, user limit).
+     */
+    if (lowmem > max_ram_below_4g) {
+        lowmem = max_ram_below_4g;
+        if (args->ram_size - lowmem > lowmem &&
+            lowmem & ((1ULL << 30) - 1)) {
+            error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64
+                         ") not a multiple of 1G; possible bad performance.",
+                         max_ram_below_4g);
+        }
+    }
+
+    if (args->ram_size >= lowmem) {
         above_4g_mem_size = args->ram_size - lowmem;
         below_4g_mem_size = lowmem;
     } else {
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 6e34fe1..c529e02 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -44,6 +44,9 @@
 #include "hw/ide/ahci.h"
 #include "hw/usb.h"
 #include "hw/cpu/icc_bus.h"
+#include "qemu/error-report.h"
+
+extern uint64_t max_ram_below_4g;
 
 /* ICH9 AHCI has 6 ports */
 #define MAX_SATA_PORTS     6
@@ -82,6 +85,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
     PCIDevice *ahci;
     DeviceState *icc_bridge;
     PcGuestInfo *guest_info;
+    ram_addr_t lowmem;
 
     /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
      * and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
@@ -93,7 +97,25 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
      * breaking migration.
      */
     if (args->ram_size >= 0xb0000000) {
-        ram_addr_t lowmem = gigabyte_align ? 0x80000000 : 0xb0000000;
+        lowmem = gigabyte_align ? 0x80000000 : 0xb0000000;
+    } else {
+        lowmem = 0xb0000000;
+    }
+
+    /* Handle the machine opt max-ram-below-4g.  It is basicly doing
+     * min(qemu limit, user limit).
+     */
+    if (lowmem > max_ram_below_4g) {
+        lowmem = max_ram_below_4g;
+        if (args->ram_size - lowmem > lowmem &&
+            lowmem & ((1ULL << 30) - 1)) {
+            error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64
+                         ") not a multiple of 1G; possible bad performance.",
+                         max_ram_below_4g);
+        }
+    }
+
+    if (args->ram_size >= lowmem) {
         above_4g_mem_size = args->ram_size - lowmem;
         below_4g_mem_size = lowmem;
     } else {
diff --git a/vl.c b/vl.c
index 9975e5a..83927c9 100644
--- a/vl.c
+++ b/vl.c
@@ -212,6 +212,7 @@ static NotifierList machine_init_done_notifiers =
 
 static bool tcg_allowed = true;
 bool xen_allowed;
+uint64_t max_ram_below_4g = 1ULL << 32; /* 4G */
 uint32_t xen_domid;
 enum xen_mode xen_mode = XEN_EMULATE;
 static int tcg_tb_size;
@@ -382,6 +383,10 @@ static QemuOptsList qemu_machine_opts = {
             .name = "kvm-type",
             .type = QEMU_OPT_STRING,
             .help = "Specifies the KVM virtualization mode (HV, PR)",
+        },{
+            .name = "max-ram-below-4g",
+            .type = QEMU_OPT_SIZE,
+            .help = "maximum ram below the 4G boundary (32bit boundary)",
         },
         { /* End of list */ }
     },
@@ -4182,6 +4187,29 @@ int main(int argc, char **argv, char **envp)
     kernel_cmdline = qemu_opt_get(machine_opts, "append");
     bios_name = qemu_opt_get(machine_opts, "firmware");
 
+    max_ram_below_4g = qemu_opt_get_size(machine_opts,
+                                         "max-ram-below-4g",
+                                         max_ram_below_4g);
+
+    if (max_ram_below_4g > (1ULL << 32)) {
+        Error *local_err = NULL;
+        error_set(&local_err, ERROR_CLASS_GENERIC_ERROR,
+                  "Machine option 'max-ram-below-4g=%"PRIu64
+                  "' expects size less than or equal to 4G",
+                  max_ram_below_4g);
+        if (local_err) {
+            error_report("%s", error_get_pretty(local_err));
+            error_free(local_err);
+            exit(1);
+        }
+    }
+
+    if (max_ram_below_4g < (1ULL << 20)) {
+        error_report("Warning: small max_ram_below_4g(%"PRIu64
+                     ") less than 1M.  BIOS may not work..",
+                     max_ram_below_4g);
+    }
+
     boot_order = machine->default_boot_order;
     opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL);
     if (opts) {
diff --git a/xen-hvm.c b/xen-hvm.c
index ad9ee45..a573a20 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -26,6 +26,8 @@
 #include <xen/hvm/params.h>
 #include <xen/hvm/e820.h>
 
+extern uint64_t max_ram_below_4g;
+
 //#define DEBUG_XEN_HVM
 
 #ifdef DEBUG_XEN_HVM
@@ -161,25 +163,34 @@ static void xen_ram_init(ram_addr_t *below_4g_mem_size,
 {
     MemoryRegion *sysmem = get_system_memory();
     ram_addr_t block_len;
+    uint64_t user_lowmem = max_ram_below_4g;
 
-    block_len = ram_size;
-    if (ram_size >= HVM_BELOW_4G_RAM_END) {
-        /* Xen does not allocate the memory continuously, and keep a hole at
-         * HVM_BELOW_4G_MMIO_START of HVM_BELOW_4G_MMIO_LENGTH
-         */
-        block_len += HVM_BELOW_4G_MMIO_LENGTH;
+    /* Handle the machine opt max-ram-below-4g.  It is basically doing
+     * min(xen limit, user limit).
+     */
+    if (HVM_BELOW_4G_RAM_END <= user_lowmem) {
+        user_lowmem = HVM_BELOW_4G_RAM_END;
     }
-    memory_region_init_ram(&ram_memory, NULL, "xen.ram", block_len);
-    *ram_memory_p = &ram_memory;
-    vmstate_register_ram_global(&ram_memory);
 
-    if (ram_size >= HVM_BELOW_4G_RAM_END) {
-        *above_4g_mem_size = ram_size - HVM_BELOW_4G_RAM_END;
-        *below_4g_mem_size = HVM_BELOW_4G_RAM_END;
+    if (ram_size >= user_lowmem) {
+        *above_4g_mem_size = ram_size - user_lowmem;
+        *below_4g_mem_size = user_lowmem;
     } else {
         *above_4g_mem_size = 0;
         *below_4g_mem_size = ram_size;
     }
+    if (!*above_4g_mem_size) {
+        block_len = ram_size;
+    } else {
+        /*
+         * Xen does not allocate the memory continuously, it keeps a
+         * hole of the size computed above or passed in.
+         */
+        block_len = (1ULL << 32) + *above_4g_mem_size;
+    }
+    memory_region_init_ram(&ram_memory, NULL, "xen.ram", block_len);
+    *ram_memory_p = &ram_memory;
+    vmstate_register_ram_global(&ram_memory);
 
     memory_region_init_alias(&ram_640k, NULL, "xen.ram.640k",
                              &ram_memory, 0, 0xa0000);
-- 
1.8.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.