diff mbox

[2.1,v7,2/3] pc & q35: Add new machine opt max-ram-below-4g

Message ID 1403228426-7609-3-git-send-email-dslutz@verizon.com
State New
Headers show

Commit Message

Don Slutz June 20, 2014, 1:40 a.m. UTC
This is a pc & q35 only machine opt.

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@verizon.com>
---
v7:
    Drop most of v5 to v6 changes.
    default: max-ram-below-4g=4g
    pc & q35:
       calculate lowmem
       lowmem = MIN(lowmem, max-ram-below-4g)
       calculate above_4g_mem_size and below_4g_mem_size
v6:
    Added setting of .default_machine_opts to include max-ram-below-4g
      for all pc types.
    Removed gigabyte_align
    Added warning on small value.
    "less then" to "less than"

v5:
    Re-work based on:

    https://github.com/imammedo/qemu/commits/memory-hotplug-v11


 hw/i386/pc.c         | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/i386/pc_piix.c    | 22 +++++++++++++++++++++-
 hw/i386/pc_q35.c     | 22 +++++++++++++++++++++-
 include/hw/i386/pc.h |  3 +++
 vl.c                 |  4 ++++
 5 files changed, 96 insertions(+), 2 deletions(-)

Comments

Michael S. Tsirkin June 23, 2014, 2:59 p.m. UTC | #1
On Thu, Jun 19, 2014 at 09:40:25PM -0400, Don Slutz wrote:
> This is a pc & q35 only machine opt.
> 
> 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@verizon.com>
> ---
> v7:
>     Drop most of v5 to v6 changes.
>     default: max-ram-below-4g=4g
>     pc & q35:
>        calculate lowmem
>        lowmem = MIN(lowmem, max-ram-below-4g)
>        calculate above_4g_mem_size and below_4g_mem_size
> v6:
>     Added setting of .default_machine_opts to include max-ram-below-4g
>       for all pc types.
>     Removed gigabyte_align
>     Added warning on small value.
>     "less then" to "less than"
> 
> v5:
>     Re-work based on:
> 
>     https://github.com/imammedo/qemu/commits/memory-hotplug-v11
> 
> 
>  hw/i386/pc.c         | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>  hw/i386/pc_piix.c    | 22 +++++++++++++++++++++-
>  hw/i386/pc_q35.c     | 22 +++++++++++++++++++++-
>  include/hw/i386/pc.h |  3 +++
>  vl.c                 |  4 ++++
>  5 files changed, 96 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index e993b0f..bc15761 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -1647,11 +1647,58 @@ pc_machine_get_hotplug_memory_region_size(Object *obj, Visitor *v, void *opaque,
>      visit_type_int(v, &value, name, errp);
>  }
>  
> +static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v,
> +                                         void *opaque, const char *name,
> +                                         Error **errp)
> +{
> +    PCMachineState *pcms = PC_MACHINE(obj);
> +    uint64_t value = pcms->max_ram_below_4g;
> +
> +    visit_type_size(v, &value, name, errp);
> +}
> +
> +static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v,
> +                                         void *opaque, const char *name,
> +                                         Error **errp)
> +{
> +    PCMachineState *pcms = PC_MACHINE(obj);
> +    Error *error = NULL;
> +    uint64_t value;
> +
> +    visit_type_size(v, &value, name, &error);
> +    if (error) {
> +        error_propagate(errp, error);
> +        return;
> +    }
> +    if (value > (1ULL << 32)) {
> +        error_set(&error, ERROR_CLASS_GENERIC_ERROR,
> +                  "Machine option 'max-ram-below-4g=%"PRIu64
> +                  "' expects size less than or equal to 4G", value);
> +        error_propagate(errp, error);
> +        return;
> +    }
> +
> +    if (value < (1ULL << 20)) {
> +        error_report("Warning: small max_ram_below_4g(%"PRIu64
> +                     ") less than 1M.  BIOS may not work..",
> +                     value);
> +    }
> +
> +    pcms->max_ram_below_4g = value;
> +}
> +
>  static void pc_machine_initfn(Object *obj)
>  {
> +    PCMachineState *pcms = PC_MACHINE(obj);
> +
>      object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int",
>                          pc_machine_get_hotplug_memory_region_size,
>                          NULL, NULL, NULL, NULL);
> +    pcms->max_ram_below_4g = 1UL << 32; /* 4G */

This is a bug: should be 1ULL. Fixed it up locally.

> +    object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
> +                        pc_machine_get_max_ram_below_4g,
> +                        pc_machine_set_max_ram_below_4g,
> +                        NULL, NULL, NULL);
>  }
>  
>  static void pc_machine_class_init(ObjectClass *oc, void *data)
> diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> index 60057f9..b4ce10e 100644
> --- a/hw/i386/pc_piix.c
> +++ b/hw/i386/pc_piix.c
> @@ -48,6 +48,7 @@
>  #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
> @@ -98,6 +99,7 @@ static void pc_init1(MachineState *machine,
>      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.
> @@ -107,7 +109,25 @@ static void pc_init1(MachineState *machine,
>       * breaking migration.
>       */
>      if (machine->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 > pc_machine->max_ram_below_4g) {
> +        lowmem = pc_machine->max_ram_below_4g;
> +        if (machine->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.",
> +                         pc_machine->max_ram_below_4g);
> +        }
> +    }
> +
> +    if (machine->ram_size >= lowmem) {
>          above_4g_mem_size = machine->ram_size - lowmem;
>          below_4g_mem_size = lowmem;
>      } else {
> diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
> index 2cb743c..c6d97ce 100644
> --- a/hw/i386/pc_q35.c
> +++ b/hw/i386/pc_q35.c
> @@ -44,6 +44,7 @@
>  #include "hw/ide/ahci.h"
>  #include "hw/usb.h"
>  #include "hw/cpu/icc_bus.h"
> +#include "qemu/error-report.h"
>  
>  /* ICH9 AHCI has 6 ports */
>  #define MAX_SATA_PORTS     6
> @@ -85,6 +86,7 @@ static void pc_q35_init(MachineState *machine)
>      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
> @@ -96,7 +98,25 @@ static void pc_q35_init(MachineState *machine)
>       * breaking migration.
>       */
>      if (machine->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 > pc_machine->max_ram_below_4g) {
> +        lowmem = pc_machine->max_ram_below_4g;
> +        if (machine->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.",
> +                         pc_machine->max_ram_below_4g);
> +        }
> +    }
> +
> +    if (machine->ram_size >= lowmem) {
>          above_4g_mem_size = machine->ram_size - lowmem;
>          below_4g_mem_size = lowmem;
>      } else {
> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> index 76d4c6e..f5672ee 100644
> --- a/include/hw/i386/pc.h
> +++ b/include/hw/i386/pc.h
> @@ -33,10 +33,13 @@ struct PCMachineState {
>      MemoryRegion hotplug_memory;
>  
>      HotplugHandler *acpi_dev;
> +
> +    uint64_t max_ram_below_4g;
>  };
>  
>  #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"
>  #define PC_MACHINE_MEMHP_REGION_SIZE "hotplug-memory-region-size"
> +#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g"
>  
>  /**
>   * PCMachineClass:
> diff --git a/vl.c b/vl.c
> index 1617013..27c60eb 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -381,6 +381,10 @@ static QemuOptsList qemu_machine_opts = {
>              .name = "kvm-type",
>              .type = QEMU_OPT_STRING,
>              .help = "Specifies the KVM virtualization mode (HV, PR)",
> +        },{
> +            .name = PC_MACHINE_MAX_RAM_BELOW_4G,
> +            .type = QEMU_OPT_SIZE,
> +            .help = "maximum ram below the 4G boundary (32bit boundary)",
>          },
>          { /* End of list */ }
>      },
> -- 
> 1.8.4
Don Slutz June 23, 2014, 5:49 p.m. UTC | #2
On 06/23/14 10:59, Michael S. Tsirkin wrote:
> On Thu, Jun 19, 2014 at 09:40:25PM -0400, Don Slutz wrote:
>> This is a pc & q35 only machine opt.
>>
...
>>
>>   static void pc_machine_initfn(Object *obj)
>>   {
>> +    PCMachineState *pcms = PC_MACHINE(obj);
>> +
>>       object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int",
>>                           pc_machine_get_hotplug_memory_region_size,
>>                           NULL, NULL, NULL, NULL);
>> +    pcms->max_ram_below_4g = 1UL << 32; /* 4G */
> This is a bug: should be 1ULL. Fixed it up locally.

Yes.  Thanks for fixing it.  My 64bit system's gcc:

dcs-xen-54:~/qemu>gcc --version
gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)
Copyright (C) 2012 Free Software Foundation, Inc.

Gets this wrong generating 32bit code :(

     -Don Slutz

>> +    object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
>> +                        pc_machine_get_max_ram_below_4g,
>> +                        pc_machine_set_max_ram_below_4g,
>> +                        NULL, NULL, NULL);
>>   }
diff mbox

Patch

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index e993b0f..bc15761 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1647,11 +1647,58 @@  pc_machine_get_hotplug_memory_region_size(Object *obj, Visitor *v, void *opaque,
     visit_type_int(v, &value, name, errp);
 }
 
+static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v,
+                                         void *opaque, const char *name,
+                                         Error **errp)
+{
+    PCMachineState *pcms = PC_MACHINE(obj);
+    uint64_t value = pcms->max_ram_below_4g;
+
+    visit_type_size(v, &value, name, errp);
+}
+
+static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v,
+                                         void *opaque, const char *name,
+                                         Error **errp)
+{
+    PCMachineState *pcms = PC_MACHINE(obj);
+    Error *error = NULL;
+    uint64_t value;
+
+    visit_type_size(v, &value, name, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
+    if (value > (1ULL << 32)) {
+        error_set(&error, ERROR_CLASS_GENERIC_ERROR,
+                  "Machine option 'max-ram-below-4g=%"PRIu64
+                  "' expects size less than or equal to 4G", value);
+        error_propagate(errp, error);
+        return;
+    }
+
+    if (value < (1ULL << 20)) {
+        error_report("Warning: small max_ram_below_4g(%"PRIu64
+                     ") less than 1M.  BIOS may not work..",
+                     value);
+    }
+
+    pcms->max_ram_below_4g = value;
+}
+
 static void pc_machine_initfn(Object *obj)
 {
+    PCMachineState *pcms = PC_MACHINE(obj);
+
     object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int",
                         pc_machine_get_hotplug_memory_region_size,
                         NULL, NULL, NULL, NULL);
+    pcms->max_ram_below_4g = 1UL << 32; /* 4G */
+    object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
+                        pc_machine_get_max_ram_below_4g,
+                        pc_machine_set_max_ram_below_4g,
+                        NULL, NULL, NULL);
 }
 
 static void pc_machine_class_init(ObjectClass *oc, void *data)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 60057f9..b4ce10e 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -48,6 +48,7 @@ 
 #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
@@ -98,6 +99,7 @@  static void pc_init1(MachineState *machine,
     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.
@@ -107,7 +109,25 @@  static void pc_init1(MachineState *machine,
      * breaking migration.
      */
     if (machine->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 > pc_machine->max_ram_below_4g) {
+        lowmem = pc_machine->max_ram_below_4g;
+        if (machine->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.",
+                         pc_machine->max_ram_below_4g);
+        }
+    }
+
+    if (machine->ram_size >= lowmem) {
         above_4g_mem_size = machine->ram_size - lowmem;
         below_4g_mem_size = lowmem;
     } else {
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 2cb743c..c6d97ce 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -44,6 +44,7 @@ 
 #include "hw/ide/ahci.h"
 #include "hw/usb.h"
 #include "hw/cpu/icc_bus.h"
+#include "qemu/error-report.h"
 
 /* ICH9 AHCI has 6 ports */
 #define MAX_SATA_PORTS     6
@@ -85,6 +86,7 @@  static void pc_q35_init(MachineState *machine)
     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
@@ -96,7 +98,25 @@  static void pc_q35_init(MachineState *machine)
      * breaking migration.
      */
     if (machine->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 > pc_machine->max_ram_below_4g) {
+        lowmem = pc_machine->max_ram_below_4g;
+        if (machine->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.",
+                         pc_machine->max_ram_below_4g);
+        }
+    }
+
+    if (machine->ram_size >= lowmem) {
         above_4g_mem_size = machine->ram_size - lowmem;
         below_4g_mem_size = lowmem;
     } else {
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 76d4c6e..f5672ee 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -33,10 +33,13 @@  struct PCMachineState {
     MemoryRegion hotplug_memory;
 
     HotplugHandler *acpi_dev;
+
+    uint64_t max_ram_below_4g;
 };
 
 #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"
 #define PC_MACHINE_MEMHP_REGION_SIZE "hotplug-memory-region-size"
+#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g"
 
 /**
  * PCMachineClass:
diff --git a/vl.c b/vl.c
index 1617013..27c60eb 100644
--- a/vl.c
+++ b/vl.c
@@ -381,6 +381,10 @@  static QemuOptsList qemu_machine_opts = {
             .name = "kvm-type",
             .type = QEMU_OPT_STRING,
             .help = "Specifies the KVM virtualization mode (HV, PR)",
+        },{
+            .name = PC_MACHINE_MAX_RAM_BELOW_4G,
+            .type = QEMU_OPT_SIZE,
+            .help = "maximum ram below the 4G boundary (32bit boundary)",
         },
         { /* End of list */ }
     },