All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
@ 2013-07-24  6:01 Michael S. Tsirkin
  2013-07-24  6:50 ` Andreas Färber
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Michael S. Tsirkin @ 2013-07-24  6:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: Anthony Liguori, Eduardo Habkost, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

It turns out that some 32 bit windows guests crash
if 64 bit PCI hole size is >2G.
Limit it to 2G for piix and q35 by default,
add properties to let management override the hole size.

Examples:
-global i440FX-pcihost.pci_hole64_size=137438953472

-global q35-pcihost.pci_hole64_size=137438953472

Reported-by: Igor Mammedov <imammedo@redhat.com>,
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/i386/pc.c              | 35 ++++++++++++++++++++---------------
 hw/i386/pc_piix.c         | 14 +-------------
 hw/pci-host/piix.c        | 42 ++++++++++++++++++++++++++++++++++--------
 hw/pci-host/q35.c         | 29 +++++++++++++++++------------
 include/hw/i386/pc.h      |  7 +++++--
 include/hw/pci-host/q35.h |  1 +
 6 files changed, 78 insertions(+), 50 deletions(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index a7c578f..9cc0fda 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1072,27 +1072,32 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
     memset(&guest_info->found_cpus, 0, sizeof guest_info->found_cpus);
     qemu_for_each_cpu(pc_set_cpu_guest_info, guest_info);
 
-    guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
-    if (sizeof(hwaddr) == 4) {
-        guest_info->pci_info.w64.begin = 0;
-        guest_info->pci_info.w64.end = 0;
-    } else {
+    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
+    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
+    return guest_info;
+}
+
+void pc_init_pci_info(PcPciInfo *pci_info,
+                      uint64_t pci_hole64_start,
+                      uint64_t pci_hole64_size)
+{
+        pci_info->w32.end = IO_APIC_DEFAULT_ADDRESS;
+
+        if (pci_hole64_size & ((0x1 << 30) - 1)) {
+            error_report("Invalid value for pci_hole64_size: "
+                         "must be a multiple of 1G. Rounding up.");
+        }
+        pci_hole64_size = ROUND_UP(pci_hole64_size, 0x1ULL << 30);
+
         /*
          * BIOS does not set MTRR entries for the 64 bit window, so no need to
          * align address to power of two.  Align address at 1G, this makes sure
          * it can be exactly covered with a PAT entry even when using huge
          * pages.
          */
-        guest_info->pci_info.w64.begin =
-            ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL << 30);
-        guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin +
-            (0x1ULL << 31);
-        assert(guest_info->pci_info.w64.begin <= guest_info->pci_info.w64.end);
-    }
-
-    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
-    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
-    return guest_info;
+        pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30);
+        pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
+        assert(pci_info->w64.begin <= pci_info->w64.end);
 }
 
 void pc_acpi_init(const char *default_dsdt)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 76df42b..da61fa3 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -137,15 +137,6 @@ static void pc_init1(MemoryRegion *system_memory,
 
     guest_info->has_pci_info = has_pci_info;
 
-    /* Set PCI window size the way seabios has always done it. */
-    /* Power of 2 so bios can cover it with a single MTRR */
-    if (ram_size <= 0x80000000)
-        guest_info->pci_info.w32.begin = 0x80000000;
-    else if (ram_size <= 0xc0000000)
-        guest_info->pci_info.w32.begin = 0xc0000000;
-    else
-        guest_info->pci_info.w32.begin = 0xe0000000;
-
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
         fw_cfg = pc_memory_init(system_memory,
@@ -169,10 +160,7 @@ static void pc_init1(MemoryRegion *system_memory,
                               below_4g_mem_size,
                               0x100000000ULL - below_4g_mem_size,
                               0x100000000ULL + above_4g_mem_size,
-                              (sizeof(hwaddr) == 4
-                               ? 0
-                               : ((uint64_t)1 << 62)),
-                              pci_memory, ram_memory);
+                              pci_memory, ram_memory, guest_info);
     } else {
         pci_bus = NULL;
         i440fx_state = NULL;
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 7fb2fb1..963b3d8 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -40,6 +41,7 @@
 
 typedef struct I440FXState {
     PCIHostState parent_obj;
+    uint64_t pci_hole64_size;
 } I440FXState;
 
 #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
@@ -234,9 +236,9 @@ static PCIBus *i440fx_common_init(const char *device_name,
                                   hwaddr pci_hole_start,
                                   hwaddr pci_hole_size,
                                   hwaddr pci_hole64_start,
-                                  hwaddr pci_hole64_size,
                                   MemoryRegion *pci_address_space,
-                                  MemoryRegion *ram_memory)
+                                  MemoryRegion *ram_memory,
+                                  PcGuestInfo *guest_info)
 {
     DeviceState *dev;
     PCIBus *b;
@@ -245,15 +247,31 @@ static PCIBus *i440fx_common_init(const char *device_name,
     PIIX3State *piix3;
     PCII440FXState *f;
     unsigned i;
+    I440FXState *i440fx;
 
     dev = qdev_create(NULL, "i440FX-pcihost");
     s = PCI_HOST_BRIDGE(dev);
+    i440fx = OBJECT_CHECK(I440FXState, dev, "i440FX-pcihost");
     b = pci_bus_new(dev, NULL, pci_address_space,
                     address_space_io, 0, TYPE_PCI_BUS);
     s->bus = b;
     object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
     qdev_init_nofail(dev);
 
+    if (guest_info) {
+        /* Set PCI window size the way seabios has always done it. */
+        /* Power of 2 so bios can cover it with a single MTRR */
+        if (ram_size <= 0x80000000)
+            guest_info->pci_info.w32.begin = 0x80000000;
+        else if (ram_size <= 0xc0000000)
+            guest_info->pci_info.w32.begin = 0xc0000000;
+        else
+            guest_info->pci_info.w32.begin = 0xe0000000;
+
+        pc_init_pci_info(&guest_info->pci_info,
+                         pci_hole64_start, i440fx->pci_hole64_size);
+    }
+
     d = pci_create_simple(b, 0, device_name);
     *pi440fx_state = I440FX_PCI_DEVICE(d);
     f = *pi440fx_state;
@@ -265,8 +283,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
     memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
     memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64",
                              f->pci_address_space,
-                             pci_hole64_start, pci_hole64_size);
-    if (pci_hole64_size) {
+                             pci_hole64_start, i440fx->pci_hole64_size);
+    if (i440fx->pci_hole64_size) {
         memory_region_add_subregion(f->system_memory, pci_hole64_start,
                                     &f->pci_hole_64bit);
     }
@@ -322,8 +340,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
                     hwaddr pci_hole_start,
                     hwaddr pci_hole_size,
                     hwaddr pci_hole64_start,
-                    hwaddr pci_hole64_size,
-                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
+                    MemoryRegion *pci_memory, MemoryRegion *ram_memory,
+                    PcGuestInfo *guest_info)
 
 {
     PCIBus *b;
@@ -332,8 +350,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
                            piix3_devfn, isa_bus, pic,
                            address_space_mem, address_space_io, ram_size,
                            pci_hole_start, pci_hole_size,
-                           pci_hole64_start, pci_hole64_size,
-                           pci_memory, ram_memory);
+                           pci_hole64_start,
+                           pci_memory, ram_memory,
+                           guest_info);
     return b;
 }
 
@@ -645,6 +664,12 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
     return "0000";
 }
 
+static Property i440fx_props[] = {
+    DEFINE_PROP_UINT64("pci_hole64_size", I440FXState,
+                       pci_hole64_size, 0x1ULL << 31),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -655,6 +680,7 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
     k->init = i440fx_pcihost_initfn;
     dc->fw_name = "pci";
     dc->no_user = 1;
+    dc->props = i440fx_props;
 }
 
 static const TypeInfo i440fx_pcihost_info = {
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index c761a43..4dd7ca4 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -73,6 +74,8 @@ static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
 static Property mch_props[] = {
     DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
                         MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
+    DEFINE_PROP_UINT64("pci_hole64_size", Q35PCIHost,
+                       mch.pci_hole64_size, 0x1ULL << 31),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -250,16 +253,20 @@ static void mch_reset(DeviceState *qdev)
 static int mch_init(PCIDevice *d)
 {
     int i;
-    hwaddr pci_hole64_size;
     MCHPCIState *mch = MCH_PCI_DEVICE(d);
 
-    /* Leave enough space for the biggest MCFG BAR */
-    /* TODO: this matches current bios behaviour, but
-     * it's not a power of two, which means an MTRR
-     * can't cover it exactly.
-     */
-    mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
-        MCH_HOST_BRIDGE_PCIEXBAR_MAX;
+    if (mch->guest_info) {
+        /* Leave enough space for the biggest MCFG BAR */
+        /* TODO: this matches current bios behaviour, but
+         * it's not a power of two, which means an MTRR
+         * can't cover it exactly.
+         */
+        mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
+            MCH_HOST_BRIDGE_PCIEXBAR_MAX;
+        pc_init_pci_info(&mch->guest_info->pci_info,
+                         0x100000000ULL + mch->above_4g_mem_size,
+                         mch->pci_hole64_size);
+    }
 
     /* setup pci memory regions */
     memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
@@ -268,13 +275,11 @@ static int mch_init(PCIDevice *d)
                              0x100000000ULL - mch->below_4g_mem_size);
     memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
                                 &mch->pci_hole);
-    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
-                       ((uint64_t)1 << 62));
     memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch), "pci-hole64",
                              mch->pci_address_space,
                              0x100000000ULL + mch->above_4g_mem_size,
-                             pci_hole64_size);
-    if (pci_hole64_size) {
+                             mch->pci_hole64_size);
+    if (mch->pci_hole64_size) {
         memory_region_add_subregion(mch->system_memory,
                                     0x100000000ULL + mch->above_4g_mem_size,
                                     &mch->pci_hole_64bit);
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 0e6f519..72b4456 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -132,6 +132,9 @@ void pc_acpi_init(const char *default_dsdt);
 
 PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
                                 ram_addr_t above_4g_mem_size);
+void pc_init_pci_info(PcPciInfo *pci_info,
+                      uint64_t pci_hole64_start,
+                      uint64_t pci_hole64_size);
 
 FWCfgState *pc_memory_init(MemoryRegion *system_memory,
                            const char *kernel_filename,
@@ -183,9 +186,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
                     hwaddr pci_hole_start,
                     hwaddr pci_hole_size,
                     hwaddr pci_hole64_start,
-                    hwaddr pci_hole64_size,
                     MemoryRegion *pci_memory,
-                    MemoryRegion *ram_memory);
+                    MemoryRegion *ram_memory,
+                    PcGuestInfo *guest_info);
 
 PCIBus *find_i440fx(void);
 /* piix4.c */
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index 3d59ae1..869ecb2 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -52,6 +52,7 @@ typedef struct MCHPCIState {
     MemoryRegion smram_region;
     MemoryRegion pci_hole;
     MemoryRegion pci_hole_64bit;
+    uint64_t pci_hole64_size;
     uint8_t smm_enabled;
     ram_addr_t below_4g_mem_size;
     ram_addr_t above_4g_mem_size;
-- 
MST

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24  6:01 [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default Michael S. Tsirkin
@ 2013-07-24  6:50 ` Andreas Färber
  2013-07-24  7:01 ` Gerd Hoffmann
  2013-07-25 13:40 ` Igor Mammedov
  2 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2013-07-24  6:50 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	David Gibson

Hi,

Am 24.07.2013 08:01, schrieb Michael S. Tsirkin:
> It turns out that some 32 bit windows guests crash
> if 64 bit PCI hole size is >2G.
> Limit it to 2G for piix and q35 by default,
> add properties to let management override the hole size.
> 
> Examples:
> -global i440FX-pcihost.pci_hole64_size=137438953472
> 
> -global q35-pcihost.pci_hole64_size=137438953472
> 
> Reported-by: Igor Mammedov <imammedo@redhat.com>,
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>  hw/i386/pc.c              | 35 ++++++++++++++++++++---------------
>  hw/i386/pc_piix.c         | 14 +-------------
>  hw/pci-host/piix.c        | 42 ++++++++++++++++++++++++++++++++++--------
>  hw/pci-host/q35.c         | 29 +++++++++++++++++------------
>  include/hw/i386/pc.h      |  7 +++++--
>  include/hw/pci-host/q35.h |  1 +
>  6 files changed, 78 insertions(+), 50 deletions(-)
[...]
> diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> index 7fb2fb1..963b3d8 100644
> --- a/hw/pci-host/piix.c
> +++ b/hw/pci-host/piix.c
> @@ -40,6 +41,7 @@
>  
>  typedef struct I440FXState {
>      PCIHostState parent_obj;
> +    uint64_t pci_hole64_size;
>  } I440FXState;
>  
>  #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
> @@ -234,9 +236,9 @@ static PCIBus *i440fx_common_init(const char *device_name,
>                                    hwaddr pci_hole_start,
>                                    hwaddr pci_hole_size,
>                                    hwaddr pci_hole64_start,
> -                                  hwaddr pci_hole64_size,
>                                    MemoryRegion *pci_address_space,
> -                                  MemoryRegion *ram_memory)
> +                                  MemoryRegion *ram_memory,
> +                                  PcGuestInfo *guest_info)
>  {
>      DeviceState *dev;
>      PCIBus *b;
> @@ -245,15 +247,31 @@ static PCIBus *i440fx_common_init(const char *device_name,
>      PIIX3State *piix3;
>      PCII440FXState *f;
>      unsigned i;
> +    I440FXState *i440fx;
>  
>      dev = qdev_create(NULL, "i440FX-pcihost");
>      s = PCI_HOST_BRIDGE(dev);
> +    i440fx = OBJECT_CHECK(I440FXState, dev, "i440FX-pcihost");

If we're lacking a macro for this, please define one. E.g.:
#define TYPE_I440FX "i440FX-pcihost"
#define I440FX(obj) OBJECT_CHECK(I440FXState, (obj), TYPE_I440FX)
above I440FXState.

i440fx = I440FX(dev);

So far was unused due to PCI_HOST_BRIDGE(), I guess.

>      b = pci_bus_new(dev, NULL, pci_address_space,
>                      address_space_io, 0, TYPE_PCI_BUS);
>      s->bus = b;
>      object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
>      qdev_init_nofail(dev);
>  
> +    if (guest_info) {
> +        /* Set PCI window size the way seabios has always done it. */
> +        /* Power of 2 so bios can cover it with a single MTRR */
> +        if (ram_size <= 0x80000000)
> +            guest_info->pci_info.w32.begin = 0x80000000;
> +        else if (ram_size <= 0xc0000000)
> +            guest_info->pci_info.w32.begin = 0xc0000000;
> +        else
> +            guest_info->pci_info.w32.begin = 0xe0000000;
> +
> +        pc_init_pci_info(&guest_info->pci_info,
> +                         pci_hole64_start, i440fx->pci_hole64_size);
> +    }
> +
>      d = pci_create_simple(b, 0, device_name);
>      *pi440fx_state = I440FX_PCI_DEVICE(d);
>      f = *pi440fx_state;
> @@ -265,8 +283,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
>      memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
>      memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64",
>                               f->pci_address_space,
> -                             pci_hole64_start, pci_hole64_size);
> -    if (pci_hole64_size) {
> +                             pci_hole64_start, i440fx->pci_hole64_size);
> +    if (i440fx->pci_hole64_size) {
>          memory_region_add_subregion(f->system_memory, pci_hole64_start,
>                                      &f->pci_hole_64bit);
>      }
> @@ -322,8 +340,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
>                      hwaddr pci_hole_start,
>                      hwaddr pci_hole_size,
>                      hwaddr pci_hole64_start,
> -                    hwaddr pci_hole64_size,
> -                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
> +                    MemoryRegion *pci_memory, MemoryRegion *ram_memory,
> +                    PcGuestInfo *guest_info)
>  
>  {
>      PCIBus *b;
> @@ -332,8 +350,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
>                             piix3_devfn, isa_bus, pic,
>                             address_space_mem, address_space_io, ram_size,
>                             pci_hole_start, pci_hole_size,
> -                           pci_hole64_start, pci_hole64_size,
> -                           pci_memory, ram_memory);
> +                           pci_hole64_start,
> +                           pci_memory, ram_memory,
> +                           guest_info);
>      return b;
>  }
>  
> @@ -645,6 +664,12 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
>      return "0000";
>  }
>  
> +static Property i440fx_props[] = {
> +    DEFINE_PROP_UINT64("pci_hole64_size", I440FXState,

"pci-hole64-size"? Same for q35.

> +                       pci_hole64_size, 0x1ULL << 31),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>  static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -655,6 +680,7 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
>      k->init = i440fx_pcihost_initfn;
>      dc->fw_name = "pci";
>      dc->no_user = 1;
> +    dc->props = i440fx_props;
>  }
>  
>  static const TypeInfo i440fx_pcihost_info = {
> diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> index c761a43..4dd7ca4 100644
> --- a/hw/pci-host/q35.c
> +++ b/hw/pci-host/q35.c
> @@ -73,6 +74,8 @@ static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
>  static Property mch_props[] = {
>      DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
>                          MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
> +    DEFINE_PROP_UINT64("pci_hole64_size", Q35PCIHost,
> +                       mch.pci_hole64_size, 0x1ULL << 31),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
[snip]

Do we need compat_props for pc-*-0.15 and earlier?

Regards,
Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24  6:01 [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default Michael S. Tsirkin
  2013-07-24  6:50 ` Andreas Färber
@ 2013-07-24  7:01 ` Gerd Hoffmann
  2013-07-24  9:51   ` Michael S. Tsirkin
  2013-07-25 13:40 ` Igor Mammedov
  2 siblings, 1 reply; 16+ messages in thread
From: Gerd Hoffmann @ 2013-07-24  7:01 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

On 07/24/13 08:01, Michael S. Tsirkin wrote:
> It turns out that some 32 bit windows guests crash
> if 64 bit PCI hole size is >2G.

Ah, *that* is the reason for winxp crashing with a 64bit hole.

Current seabios uses a slightly different approach: the 64bit hole is
present only in case it is actually used to map bars there, and seabios
tries to fit everything into the 32bit hole first.

> Limit it to 2G for piix and q35 by default,
> add properties to let management override the hole size.
> 
> Examples:
> -global i440FX-pcihost.pci_hole64_size=137438953472

Do we really want specify this in bytes?  Using megabytes or gigabytes
instead looks more sane to me.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24  7:01 ` Gerd Hoffmann
@ 2013-07-24  9:51   ` Michael S. Tsirkin
  2013-07-24 10:08     ` Igor Mammedov
                       ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Michael S. Tsirkin @ 2013-07-24  9:51 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

On Wed, Jul 24, 2013 at 09:01:51AM +0200, Gerd Hoffmann wrote:
> On 07/24/13 08:01, Michael S. Tsirkin wrote:
> > It turns out that some 32 bit windows guests crash
> > if 64 bit PCI hole size is >2G.
> 
> Ah, *that* is the reason for winxp crashing with a 64bit hole.
> 
> Current seabios uses a slightly different approach: the 64bit hole is
> present only in case it is actually used to map bars there, and seabios
> tries to fit everything into the 32bit hole first.

Yes. But this doesn't work with device hotplug.

> > Limit it to 2G for piix and q35 by default,
> > add properties to let management override the hole size.
> > 
> > Examples:
> > -global i440FX-pcihost.pci_hole64_size=137438953472
> 
> Do we really want specify this in bytes?  Using megabytes or gigabytes
> instead looks more sane to me.
> 
> cheers,
>   Gerd

I think that arbitrarily saying size is in gigabytes is
confusing to users (in particular because there's no
documentation for properties except their type).
I intend to send a patch to properties that allows writing
"size=1G" instead.
Will this address your comment?

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24  9:51   ` Michael S. Tsirkin
@ 2013-07-24 10:08     ` Igor Mammedov
  2013-07-24 12:59     ` Paolo Bonzini
  2013-07-24 13:00     ` Gerd Hoffmann
  2 siblings, 0 replies; 16+ messages in thread
From: Igor Mammedov @ 2013-07-24 10:08 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

On Wed, 24 Jul 2013 12:51:16 +0300
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Wed, Jul 24, 2013 at 09:01:51AM +0200, Gerd Hoffmann wrote:
> > On 07/24/13 08:01, Michael S. Tsirkin wrote:
> > > It turns out that some 32 bit windows guests crash
> > > if 64 bit PCI hole size is >2G.
> > 
> > Ah, *that* is the reason for winxp crashing with a 64bit hole.
> > 
> > Current seabios uses a slightly different approach: the 64bit hole is
> > present only in case it is actually used to map bars there, and seabios
> > tries to fit everything into the 32bit hole first.
> 
> Yes. But this doesn't work with device hotplug.
> 
> > > Limit it to 2G for piix and q35 by default,
> > > add properties to let management override the hole size.
> > > 
> > > Examples:
> > > -global i440FX-pcihost.pci_hole64_size=137438953472
> > 
> > Do we really want specify this in bytes?  Using megabytes or gigabytes
> > instead looks more sane to me.
> > 
> > cheers,
> >   Gerd
> 
> I think that arbitrarily saying size is in gigabytes is
> confusing to users (in particular because there's no
> documentation for properties except their type).
> I intend to send a patch to properties that allows writing
> "size=1G" instead.
for size property you could take patches:
 [PATCH 04/16] qapi: make visit_type_size fallback to type_int
 [PATCH 05/16] qdev: Add SIZE type to qdev properties
from [PATCH 00/16 RFC v6] ACPI memory hotplug

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24  9:51   ` Michael S. Tsirkin
  2013-07-24 10:08     ` Igor Mammedov
@ 2013-07-24 12:59     ` Paolo Bonzini
  2013-07-24 13:14       ` Michael S. Tsirkin
  2013-07-24 13:00     ` Gerd Hoffmann
  2 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2013-07-24 12:59 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Laszlo Ersek,
	Andreas Färber, David Gibson

Il 24/07/2013 11:51, Michael S. Tsirkin ha scritto:
> > Current seabios uses a slightly different approach: the 64bit hole is
> > present only in case it is actually used to map bars there, and seabios
> > tries to fit everything into the 32bit hole first.
> 
> Yes. But this doesn't work with device hotplug.

Are you preserving that behavior for older machine types?

(Also, what happens if you do -global i440FX-pcihost.pci_hole64_size=0?
 Does that return a _CRS with only the 32-bit hole)?

Paolo

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24  9:51   ` Michael S. Tsirkin
  2013-07-24 10:08     ` Igor Mammedov
  2013-07-24 12:59     ` Paolo Bonzini
@ 2013-07-24 13:00     ` Gerd Hoffmann
  2 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-07-24 13:00 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

On 07/24/13 11:51, Michael S. Tsirkin wrote:
> On Wed, Jul 24, 2013 at 09:01:51AM +0200, Gerd Hoffmann wrote:
>> On 07/24/13 08:01, Michael S. Tsirkin wrote:
>>> It turns out that some 32 bit windows guests crash
>>> if 64 bit PCI hole size is >2G.
>>
>> Ah, *that* is the reason for winxp crashing with a 64bit hole.
>>
>> Current seabios uses a slightly different approach: the 64bit hole is
>> present only in case it is actually used to map bars there, and seabios
>> tries to fit everything into the 32bit hole first.
> 
> Yes. But this doesn't work with device hotplug.

Sure.  This wasn't meant as request to match current seabios behavior.
Just wanted provide some additional background info.

> I intend to send a patch to properties that allows writing
> "size=1G" instead.
> Will this address your comment?

Sounds good.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24 12:59     ` Paolo Bonzini
@ 2013-07-24 13:14       ` Michael S. Tsirkin
  2013-07-24 13:18         ` Paolo Bonzini
  0 siblings, 1 reply; 16+ messages in thread
From: Michael S. Tsirkin @ 2013-07-24 13:14 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Laszlo Ersek,
	Andreas Färber, David Gibson

On Wed, Jul 24, 2013 at 02:59:18PM +0200, Paolo Bonzini wrote:
> Il 24/07/2013 11:51, Michael S. Tsirkin ha scritto:
> > > Current seabios uses a slightly different approach: the 64bit hole is
> > > present only in case it is actually used to map bars there, and seabios
> > > tries to fit everything into the 32bit hole first.
> > 
> > Yes. But this doesn't work with device hotplug.
> 
> Are you preserving that behavior for older machine types?

Older machine types (1.5 and back) don't report PCI hole size to guests
so there's nothing to preserve.
This means there's not much I can do for pc-1.5: as before this
patch, hotplug of devices with large BARs won't work,
and some windows guests will crash if a device with a huge
BAR is added statically.

> (Also, what happens if you do -global i440FX-pcihost.pci_hole64_size=0?
>  Does that return a _CRS with only the 32-bit hole)?
> 
> Paolo

Yes.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24 13:14       ` Michael S. Tsirkin
@ 2013-07-24 13:18         ` Paolo Bonzini
  2013-07-24 14:07           ` Michael S. Tsirkin
  0 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2013-07-24 13:18 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Laszlo Ersek,
	Andreas Färber, David Gibson

Il 24/07/2013 15:14, Michael S. Tsirkin ha scritto:
> On Wed, Jul 24, 2013 at 02:59:18PM +0200, Paolo Bonzini wrote:
>> Il 24/07/2013 11:51, Michael S. Tsirkin ha scritto:
>>>> Current seabios uses a slightly different approach: the 64bit hole is
>>>> present only in case it is actually used to map bars there, and seabios
>>>> tries to fit everything into the 32bit hole first.
>>>
>>> Yes. But this doesn't work with device hotplug.
>>
>> Are you preserving that behavior for older machine types?
> 
> Older machine types (1.5 and back) don't report PCI hole size to guests
> so there's nothing to preserve.

So pc-1.5 and older always use the SeaBIOS ACPI tables, even on new
QEMU?  (I guess I should review your ACPI table patches).

Paolo

> This means there's not much I can do for pc-1.5: as before this
> patch, hotplug of devices with large BARs won't work,
> and some windows guests will crash if a device with a huge
> BAR is added statically.
> 
>> (Also, what happens if you do -global i440FX-pcihost.pci_hole64_size=0?
>>  Does that return a _CRS with only the 32-bit hole)?
>>
>> Paolo
> 
> Yes.
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24 13:18         ` Paolo Bonzini
@ 2013-07-24 14:07           ` Michael S. Tsirkin
  0 siblings, 0 replies; 16+ messages in thread
From: Michael S. Tsirkin @ 2013-07-24 14:07 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Laszlo Ersek,
	Andreas Färber, David Gibson

On Wed, Jul 24, 2013 at 03:18:01PM +0200, Paolo Bonzini wrote:
> Il 24/07/2013 15:14, Michael S. Tsirkin ha scritto:
> > On Wed, Jul 24, 2013 at 02:59:18PM +0200, Paolo Bonzini wrote:
> >> Il 24/07/2013 11:51, Michael S. Tsirkin ha scritto:
> >>>> Current seabios uses a slightly different approach: the 64bit hole is
> >>>> present only in case it is actually used to map bars there, and seabios
> >>>> tries to fit everything into the 32bit hole first.
> >>>
> >>> Yes. But this doesn't work with device hotplug.
> >>
> >> Are you preserving that behavior for older machine types?
> > 
> > Older machine types (1.5 and back) don't report PCI hole size to guests
> > so there's nothing to preserve.
> 
> So pc-1.5 and older always use the SeaBIOS ACPI tables, even on new
> QEMU?  (I guess I should review your ACPI table patches).
> 
> Paolo

Yes.

> > This means there's not much I can do for pc-1.5: as before this
> > patch, hotplug of devices with large BARs won't work,
> > and some windows guests will crash if a device with a huge
> > BAR is added statically.
> > 
> >> (Also, what happens if you do -global i440FX-pcihost.pci_hole64_size=0?
> >>  Does that return a _CRS with only the 32-bit hole)?
> >>
> >> Paolo
> > 
> > Yes.
> > 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-24  6:01 [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default Michael S. Tsirkin
  2013-07-24  6:50 ` Andreas Färber
  2013-07-24  7:01 ` Gerd Hoffmann
@ 2013-07-25 13:40 ` Igor Mammedov
  2013-07-25 15:03   ` Michael S. Tsirkin
  2013-07-25 15:16   ` Igor Mammedov
  2 siblings, 2 replies; 16+ messages in thread
From: Igor Mammedov @ 2013-07-25 13:40 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

On Wed, 24 Jul 2013 09:01:04 +0300
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> It turns out that some 32 bit windows guests crash
> if 64 bit PCI hole size is >2G.
> Limit it to 2G for piix and q35 by default,
> add properties to let management override the hole size.
> 
> Examples:
> -global i440FX-pcihost.pci_hole64_size=137438953472
> 
> -global q35-pcihost.pci_hole64_size=137438953472
> 
> Reported-by: Igor Mammedov <imammedo@redhat.com>,
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>  hw/i386/pc.c              | 35 ++++++++++++++++++++---------------
>  hw/i386/pc_piix.c         | 14 +-------------
>  hw/pci-host/piix.c        | 42 ++++++++++++++++++++++++++++++++++--------
>  hw/pci-host/q35.c         | 29 +++++++++++++++++------------
>  include/hw/i386/pc.h      |  7 +++++--
>  include/hw/pci-host/q35.h |  1 +
>  6 files changed, 78 insertions(+), 50 deletions(-)
> 
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index a7c578f..9cc0fda 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -1072,27 +1072,32 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
>      memset(&guest_info->found_cpus, 0, sizeof guest_info->found_cpus);
>      qemu_for_each_cpu(pc_set_cpu_guest_info, guest_info);
>  
> -    guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
> -    if (sizeof(hwaddr) == 4) {
> -        guest_info->pci_info.w64.begin = 0;
> -        guest_info->pci_info.w64.end = 0;
> -    } else {
> +    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
> +    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> +    return guest_info;
> +}
> +
> +void pc_init_pci_info(PcPciInfo *pci_info,
> +                      uint64_t pci_hole64_start,
> +                      uint64_t pci_hole64_size)
> +{
> +        pci_info->w32.end = IO_APIC_DEFAULT_ADDRESS;
weird ident

> +
> +        if (pci_hole64_size & ((0x1 << 30) - 1)) {
> +            error_report("Invalid value for pci_hole64_size: "
> +                         "must be a multiple of 1G. Rounding up.");
> +        }
> +        pci_hole64_size = ROUND_UP(pci_hole64_size, 0x1ULL << 30);
> +
if pci_hole64_size is a property it would be better to put check,
in property setter (custom one) and error out instead of doing fixup,
lets user fix his wrong cmd line.
 
>          /*
>           * BIOS does not set MTRR entries for the 64 bit window, so no need to
>           * align address to power of two.  Align address at 1G, this makes sure
>           * it can be exactly covered with a PAT entry even when using huge
>           * pages.
>           */
> -        guest_info->pci_info.w64.begin =
> -            ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL << 30);
> -        guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin +
> -            (0x1ULL << 31);
> -        assert(guest_info->pci_info.w64.begin <= guest_info->pci_info.w64.end);
> -    }
> -
> -    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
> -    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> -    return guest_info;
> +        pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30);
> +        pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
> +        assert(pci_info->w64.begin <= pci_info->w64.end);
>  }
>  
>  void pc_acpi_init(const char *default_dsdt)
> diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> index 76df42b..da61fa3 100644
> --- a/hw/i386/pc_piix.c
> +++ b/hw/i386/pc_piix.c
> @@ -137,15 +137,6 @@ static void pc_init1(MemoryRegion *system_memory,
>  
>      guest_info->has_pci_info = has_pci_info;
>  
> -    /* Set PCI window size the way seabios has always done it. */
> -    /* Power of 2 so bios can cover it with a single MTRR */
> -    if (ram_size <= 0x80000000)
> -        guest_info->pci_info.w32.begin = 0x80000000;
> -    else if (ram_size <= 0xc0000000)
> -        guest_info->pci_info.w32.begin = 0xc0000000;
> -    else
> -        guest_info->pci_info.w32.begin = 0xe0000000;
> -
>      /* allocate ram and load rom/bios */
>      if (!xen_enabled()) {
>          fw_cfg = pc_memory_init(system_memory,
> @@ -169,10 +160,7 @@ static void pc_init1(MemoryRegion *system_memory,
>                                below_4g_mem_size,
>                                0x100000000ULL - below_4g_mem_size,
>                                0x100000000ULL + above_4g_mem_size,
> -                              (sizeof(hwaddr) == 4
> -                               ? 0
> -                               : ((uint64_t)1 << 62)),
> -                              pci_memory, ram_memory);
> +                              pci_memory, ram_memory, guest_info);
>      } else {
>          pci_bus = NULL;
>          i440fx_state = NULL;
> diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> index 7fb2fb1..963b3d8 100644
> --- a/hw/pci-host/piix.c
> +++ b/hw/pci-host/piix.c
> @@ -40,6 +41,7 @@
>  
>  typedef struct I440FXState {
>      PCIHostState parent_obj;
> +    uint64_t pci_hole64_size;
>  } I440FXState;
>  
>  #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
> @@ -234,9 +236,9 @@ static PCIBus *i440fx_common_init(const char *device_name,
>                                    hwaddr pci_hole_start,
>                                    hwaddr pci_hole_size,
>                                    hwaddr pci_hole64_start,
^^^ could but to be more consistent if moved to a place where 64 PCI hole is
initialized, replace it with above_4g_memory_size, and let i440fx_common_init()
set it near the place where 64 PCI hole end is set.

> -                                  hwaddr pci_hole64_size,
>                                    MemoryRegion *pci_address_space,
> -                                  MemoryRegion *ram_memory)
> +                                  MemoryRegion *ram_memory,
> +                                  PcGuestInfo *guest_info)
>  {
>      DeviceState *dev;
>      PCIBus *b;
> @@ -245,15 +247,31 @@ static PCIBus *i440fx_common_init(const char *device_name,
>      PIIX3State *piix3;
>      PCII440FXState *f;
>      unsigned i;
> +    I440FXState *i440fx;
>  
>      dev = qdev_create(NULL, "i440FX-pcihost");
>      s = PCI_HOST_BRIDGE(dev);
> +    i440fx = OBJECT_CHECK(I440FXState, dev, "i440FX-pcihost");
>      b = pci_bus_new(dev, NULL, pci_address_space,
>                      address_space_io, 0, TYPE_PCI_BUS);
>      s->bus = b;
>      object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
>      qdev_init_nofail(dev);
>  
> +    if (guest_info) {
> +        /* Set PCI window size the way seabios has always done it. */
> +        /* Power of 2 so bios can cover it with a single MTRR */
> +        if (ram_size <= 0x80000000)
> +            guest_info->pci_info.w32.begin = 0x80000000;
> +        else if (ram_size <= 0xc0000000)
> +            guest_info->pci_info.w32.begin = 0xc0000000;
> +        else
> +            guest_info->pci_info.w32.begin = 0xe0000000;
> +
> +        pc_init_pci_info(&guest_info->pci_info,
> +                         pci_hole64_start, i440fx->pci_hole64_size);
> +    }
split brain init of the same data structure make it ugly, would be more readable
inlined.

Wouldn't it be better/cleaner to put PcPciInfo inside of I440FXState/MCHPCIState
and make QOM based API to access it as in latest ACPI tables series?



>      d = pci_create_simple(b, 0, device_name);
>      *pi440fx_state = I440FX_PCI_DEVICE(d);
>      f = *pi440fx_state;
> @@ -265,8 +283,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
>      memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
>      memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64",
>                               f->pci_address_space,
> -                             pci_hole64_start, pci_hole64_size);
> -    if (pci_hole64_size) {
> +                             pci_hole64_start, i440fx->pci_hole64_size);
> +    if (i440fx->pci_hole64_size) {
>          memory_region_add_subregion(f->system_memory, pci_hole64_start,
>                                      &f->pci_hole_64bit);
>      }
> @@ -322,8 +340,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
>                      hwaddr pci_hole_start,
>                      hwaddr pci_hole_size,
>                      hwaddr pci_hole64_start,
> -                    hwaddr pci_hole64_size,
> -                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
> +                    MemoryRegion *pci_memory, MemoryRegion *ram_memory,
> +                    PcGuestInfo *guest_info)
>  
>  {
>      PCIBus *b;
> @@ -332,8 +350,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
>                             piix3_devfn, isa_bus, pic,
>                             address_space_mem, address_space_io, ram_size,
>                             pci_hole_start, pci_hole_size,
> -                           pci_hole64_start, pci_hole64_size,
> -                           pci_memory, ram_memory);
> +                           pci_hole64_start,
> +                           pci_memory, ram_memory,
> +                           guest_info);
>      return b;
>  }
>  
> @@ -645,6 +664,12 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
>      return "0000";
>  }
>  
> +static Property i440fx_props[] = {
> +    DEFINE_PROP_UINT64("pci_hole64_size", I440FXState,
> +                       pci_hole64_size, 0x1ULL << 31),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>  static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -655,6 +680,7 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
>      k->init = i440fx_pcihost_initfn;
>      dc->fw_name = "pci";
>      dc->no_user = 1;
> +    dc->props = i440fx_props;
>  }
>  
>  static const TypeInfo i440fx_pcihost_info = {
> diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> index c761a43..4dd7ca4 100644
> --- a/hw/pci-host/q35.c
> +++ b/hw/pci-host/q35.c
> @@ -73,6 +74,8 @@ static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
>  static Property mch_props[] = {
>      DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
>                          MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
> +    DEFINE_PROP_UINT64("pci_hole64_size", Q35PCIHost,
> +                       mch.pci_hole64_size, 0x1ULL << 31),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> @@ -250,16 +253,20 @@ static void mch_reset(DeviceState *qdev)
>  static int mch_init(PCIDevice *d)
>  {
>      int i;
> -    hwaddr pci_hole64_size;
>      MCHPCIState *mch = MCH_PCI_DEVICE(d);
>  
> -    /* Leave enough space for the biggest MCFG BAR */
> -    /* TODO: this matches current bios behaviour, but
> -     * it's not a power of two, which means an MTRR
> -     * can't cover it exactly.
> -     */
> -    mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
> -        MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> +    if (mch->guest_info) {
> +        /* Leave enough space for the biggest MCFG BAR */
> +        /* TODO: this matches current bios behaviour, but
> +         * it's not a power of two, which means an MTRR
> +         * can't cover it exactly.
> +         */
> +        mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
> +            MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> +        pc_init_pci_info(&mch->guest_info->pci_info,
> +                         0x100000000ULL + mch->above_4g_mem_size,
> +                         mch->pci_hole64_size);
> +    }
>  
>      /* setup pci memory regions */
>      memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
> @@ -268,13 +275,11 @@ static int mch_init(PCIDevice *d)
>                               0x100000000ULL - mch->below_4g_mem_size);
>      memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
>                                  &mch->pci_hole);
> -    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
> -                       ((uint64_t)1 << 62));
>      memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch), "pci-hole64",
>                               mch->pci_address_space,
>                               0x100000000ULL + mch->above_4g_mem_size,
> -                             pci_hole64_size);
> -    if (pci_hole64_size) {
> +                             mch->pci_hole64_size);
> +    if (mch->pci_hole64_size) {
>          memory_region_add_subregion(mch->system_memory,
>                                      0x100000000ULL + mch->above_4g_mem_size,
>                                      &mch->pci_hole_64bit);
> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> index 0e6f519..72b4456 100644
> --- a/include/hw/i386/pc.h
> +++ b/include/hw/i386/pc.h
> @@ -132,6 +132,9 @@ void pc_acpi_init(const char *default_dsdt);
>  
>  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
>                                  ram_addr_t above_4g_mem_size);
> +void pc_init_pci_info(PcPciInfo *pci_info,
> +                      uint64_t pci_hole64_start,
> +                      uint64_t pci_hole64_size);
>  
>  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
>                             const char *kernel_filename,
> @@ -183,9 +186,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
>                      hwaddr pci_hole_start,
>                      hwaddr pci_hole_size,
>                      hwaddr pci_hole64_start,
> -                    hwaddr pci_hole64_size,
>                      MemoryRegion *pci_memory,
> -                    MemoryRegion *ram_memory);
> +                    MemoryRegion *ram_memory,
> +                    PcGuestInfo *guest_info);
>  
>  PCIBus *find_i440fx(void);
>  /* piix4.c */
> diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
> index 3d59ae1..869ecb2 100644
> --- a/include/hw/pci-host/q35.h
> +++ b/include/hw/pci-host/q35.h
> @@ -52,6 +52,7 @@ typedef struct MCHPCIState {
>      MemoryRegion smram_region;
>      MemoryRegion pci_hole;
>      MemoryRegion pci_hole_64bit;
> +    uint64_t pci_hole64_size;
>      uint8_t smm_enabled;
>      ram_addr_t below_4g_mem_size;
>      ram_addr_t above_4g_mem_size;

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-25 13:40 ` Igor Mammedov
@ 2013-07-25 15:03   ` Michael S. Tsirkin
  2013-07-25 15:16   ` Igor Mammedov
  1 sibling, 0 replies; 16+ messages in thread
From: Michael S. Tsirkin @ 2013-07-25 15:03 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

On Thu, Jul 25, 2013 at 03:40:05PM +0200, Igor Mammedov wrote:
> On Wed, 24 Jul 2013 09:01:04 +0300
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
> > It turns out that some 32 bit windows guests crash
> > if 64 bit PCI hole size is >2G.
> > Limit it to 2G for piix and q35 by default,
> > add properties to let management override the hole size.
> > 
> > Examples:
> > -global i440FX-pcihost.pci_hole64_size=137438953472
> > 
> > -global q35-pcihost.pci_hole64_size=137438953472
> > 
> > Reported-by: Igor Mammedov <imammedo@redhat.com>,
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > ---
> >  hw/i386/pc.c              | 35 ++++++++++++++++++++---------------
> >  hw/i386/pc_piix.c         | 14 +-------------
> >  hw/pci-host/piix.c        | 42 ++++++++++++++++++++++++++++++++++--------
> >  hw/pci-host/q35.c         | 29 +++++++++++++++++------------
> >  include/hw/i386/pc.h      |  7 +++++--
> >  include/hw/pci-host/q35.h |  1 +
> >  6 files changed, 78 insertions(+), 50 deletions(-)
> > 
> > diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> > index a7c578f..9cc0fda 100644
> > --- a/hw/i386/pc.c
> > +++ b/hw/i386/pc.c
> > @@ -1072,27 +1072,32 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> >      memset(&guest_info->found_cpus, 0, sizeof guest_info->found_cpus);
> >      qemu_for_each_cpu(pc_set_cpu_guest_info, guest_info);
> >  
> > -    guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
> > -    if (sizeof(hwaddr) == 4) {
> > -        guest_info->pci_info.w64.begin = 0;
> > -        guest_info->pci_info.w64.end = 0;
> > -    } else {
> > +    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
> > +    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > +    return guest_info;
> > +}
> > +
> > +void pc_init_pci_info(PcPciInfo *pci_info,
> > +                      uint64_t pci_hole64_start,
> > +                      uint64_t pci_hole64_size)
> > +{
> > +        pci_info->w32.end = IO_APIC_DEFAULT_ADDRESS;
> weird ident

Yea, I'm not sure why. I can tweak that.

> > +
> > +        if (pci_hole64_size & ((0x1 << 30) - 1)) {
> > +            error_report("Invalid value for pci_hole64_size: "
> > +                         "must be a multiple of 1G. Rounding up.");
> > +        }
> > +        pci_hole64_size = ROUND_UP(pci_hole64_size, 0x1ULL << 30);
> > +
> if pci_hole64_size is a property it would be better to put check,
> in property setter (custom one) and error out instead of doing fixup,
> lets user fix his wrong cmd line.

It's not a strict requirement to have
it a multiple of 1G - it's an implementation choice.
So I don't think error out is a right choice.

> >          /*
> >           * BIOS does not set MTRR entries for the 64 bit window, so no need to
> >           * align address to power of two.  Align address at 1G, this makes sure
> >           * it can be exactly covered with a PAT entry even when using huge
> >           * pages.
> >           */
> > -        guest_info->pci_info.w64.begin =
> > -            ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL << 30);
> > -        guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin +
> > -            (0x1ULL << 31);
> > -        assert(guest_info->pci_info.w64.begin <= guest_info->pci_info.w64.end);
> > -    }
> > -
> > -    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
> > -    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > -    return guest_info;
> > +        pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30);
> > +        pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
> > +        assert(pci_info->w64.begin <= pci_info->w64.end);
> >  }
> >  
> >  void pc_acpi_init(const char *default_dsdt)
> > diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> > index 76df42b..da61fa3 100644
> > --- a/hw/i386/pc_piix.c
> > +++ b/hw/i386/pc_piix.c
> > @@ -137,15 +137,6 @@ static void pc_init1(MemoryRegion *system_memory,
> >  
> >      guest_info->has_pci_info = has_pci_info;
> >  
> > -    /* Set PCI window size the way seabios has always done it. */
> > -    /* Power of 2 so bios can cover it with a single MTRR */
> > -    if (ram_size <= 0x80000000)
> > -        guest_info->pci_info.w32.begin = 0x80000000;
> > -    else if (ram_size <= 0xc0000000)
> > -        guest_info->pci_info.w32.begin = 0xc0000000;
> > -    else
> > -        guest_info->pci_info.w32.begin = 0xe0000000;
> > -
> >      /* allocate ram and load rom/bios */
> >      if (!xen_enabled()) {
> >          fw_cfg = pc_memory_init(system_memory,
> > @@ -169,10 +160,7 @@ static void pc_init1(MemoryRegion *system_memory,
> >                                below_4g_mem_size,
> >                                0x100000000ULL - below_4g_mem_size,
> >                                0x100000000ULL + above_4g_mem_size,
> > -                              (sizeof(hwaddr) == 4
> > -                               ? 0
> > -                               : ((uint64_t)1 << 62)),
> > -                              pci_memory, ram_memory);
> > +                              pci_memory, ram_memory, guest_info);
> >      } else {
> >          pci_bus = NULL;
> >          i440fx_state = NULL;
> > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > index 7fb2fb1..963b3d8 100644
> > --- a/hw/pci-host/piix.c
> > +++ b/hw/pci-host/piix.c
> > @@ -40,6 +41,7 @@
> >  
> >  typedef struct I440FXState {
> >      PCIHostState parent_obj;
> > +    uint64_t pci_hole64_size;
> >  } I440FXState;
> >  
> >  #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
> > @@ -234,9 +236,9 @@ static PCIBus *i440fx_common_init(const char *device_name,
> >                                    hwaddr pci_hole_start,
> >                                    hwaddr pci_hole_size,
> >                                    hwaddr pci_hole64_start,
> ^^^ could but to be more consistent if moved to a place where 64 PCI hole is
> initialized, replace it with above_4g_memory_size, and let i440fx_common_init()
> set it near the place where 64 PCI hole end is set.

Sounds like a wholesale refactoring of PC init to use QOM.
We'll get there but let's not make it block a bugfix.

> > -                                  hwaddr pci_hole64_size,
> >                                    MemoryRegion *pci_address_space,
> > -                                  MemoryRegion *ram_memory)
> > +                                  MemoryRegion *ram_memory,
> > +                                  PcGuestInfo *guest_info)
> >  {
> >      DeviceState *dev;
> >      PCIBus *b;
> > @@ -245,15 +247,31 @@ static PCIBus *i440fx_common_init(const char *device_name,
> >      PIIX3State *piix3;
> >      PCII440FXState *f;
> >      unsigned i;
> > +    I440FXState *i440fx;
> >  
> >      dev = qdev_create(NULL, "i440FX-pcihost");
> >      s = PCI_HOST_BRIDGE(dev);
> > +    i440fx = OBJECT_CHECK(I440FXState, dev, "i440FX-pcihost");
> >      b = pci_bus_new(dev, NULL, pci_address_space,
> >                      address_space_io, 0, TYPE_PCI_BUS);
> >      s->bus = b;
> >      object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
> >      qdev_init_nofail(dev);
> >  
> > +    if (guest_info) {
> > +        /* Set PCI window size the way seabios has always done it. */
> > +        /* Power of 2 so bios can cover it with a single MTRR */
> > +        if (ram_size <= 0x80000000)
> > +            guest_info->pci_info.w32.begin = 0x80000000;
> > +        else if (ram_size <= 0xc0000000)
> > +            guest_info->pci_info.w32.begin = 0xc0000000;
> > +        else
> > +            guest_info->pci_info.w32.begin = 0xe0000000;
> > +
> > +        pc_init_pci_info(&guest_info->pci_info,
> > +                         pci_hole64_start, i440fx->pci_hole64_size);
> > +    }
> split brain init of the same data structure make it ugly, would be more readable
> inlined.

Code duplication is worse. I'll add some comments.

> 
> Wouldn't it be better/cleaner to put PcPciInfo inside of I440FXState/MCHPCIState
> and make QOM based API to access it as in latest ACPI tables series?

Want to code it up?
I'd like to make windows not crash first (for 1.6)
refactor existing code to use QOM can come after 1.6.


> >      d = pci_create_simple(b, 0, device_name);
> >      *pi440fx_state = I440FX_PCI_DEVICE(d);
> >      f = *pi440fx_state;
> > @@ -265,8 +283,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
> >      memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
> >      memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64",
> >                               f->pci_address_space,
> > -                             pci_hole64_start, pci_hole64_size);
> > -    if (pci_hole64_size) {
> > +                             pci_hole64_start, i440fx->pci_hole64_size);
> > +    if (i440fx->pci_hole64_size) {
> >          memory_region_add_subregion(f->system_memory, pci_hole64_start,
> >                                      &f->pci_hole_64bit);
> >      }
> > @@ -322,8 +340,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
> >                      hwaddr pci_hole_start,
> >                      hwaddr pci_hole_size,
> >                      hwaddr pci_hole64_start,
> > -                    hwaddr pci_hole64_size,
> > -                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
> > +                    MemoryRegion *pci_memory, MemoryRegion *ram_memory,
> > +                    PcGuestInfo *guest_info)
> >  
> >  {
> >      PCIBus *b;
> > @@ -332,8 +350,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
> >                             piix3_devfn, isa_bus, pic,
> >                             address_space_mem, address_space_io, ram_size,
> >                             pci_hole_start, pci_hole_size,
> > -                           pci_hole64_start, pci_hole64_size,
> > -                           pci_memory, ram_memory);
> > +                           pci_hole64_start,
> > +                           pci_memory, ram_memory,
> > +                           guest_info);
> >      return b;
> >  }
> >  
> > @@ -645,6 +664,12 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
> >      return "0000";
> >  }
> >  
> > +static Property i440fx_props[] = {
> > +    DEFINE_PROP_UINT64("pci_hole64_size", I440FXState,
> > +                       pci_hole64_size, 0x1ULL << 31),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> >  static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
> >  {
> >      DeviceClass *dc = DEVICE_CLASS(klass);
> > @@ -655,6 +680,7 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
> >      k->init = i440fx_pcihost_initfn;
> >      dc->fw_name = "pci";
> >      dc->no_user = 1;
> > +    dc->props = i440fx_props;
> >  }
> >  
> >  static const TypeInfo i440fx_pcihost_info = {
> > diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> > index c761a43..4dd7ca4 100644
> > --- a/hw/pci-host/q35.c
> > +++ b/hw/pci-host/q35.c
> > @@ -73,6 +74,8 @@ static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
> >  static Property mch_props[] = {
> >      DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
> >                          MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
> > +    DEFINE_PROP_UINT64("pci_hole64_size", Q35PCIHost,
> > +                       mch.pci_hole64_size, 0x1ULL << 31),
> >      DEFINE_PROP_END_OF_LIST(),
> >  };
> >  
> > @@ -250,16 +253,20 @@ static void mch_reset(DeviceState *qdev)
> >  static int mch_init(PCIDevice *d)
> >  {
> >      int i;
> > -    hwaddr pci_hole64_size;
> >      MCHPCIState *mch = MCH_PCI_DEVICE(d);
> >  
> > -    /* Leave enough space for the biggest MCFG BAR */
> > -    /* TODO: this matches current bios behaviour, but
> > -     * it's not a power of two, which means an MTRR
> > -     * can't cover it exactly.
> > -     */
> > -    mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
> > -        MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > +    if (mch->guest_info) {
> > +        /* Leave enough space for the biggest MCFG BAR */
> > +        /* TODO: this matches current bios behaviour, but
> > +         * it's not a power of two, which means an MTRR
> > +         * can't cover it exactly.
> > +         */
> > +        mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
> > +            MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > +        pc_init_pci_info(&mch->guest_info->pci_info,
> > +                         0x100000000ULL + mch->above_4g_mem_size,
> > +                         mch->pci_hole64_size);
> > +    }
> >  
> >      /* setup pci memory regions */
> >      memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
> > @@ -268,13 +275,11 @@ static int mch_init(PCIDevice *d)
> >                               0x100000000ULL - mch->below_4g_mem_size);
> >      memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
> >                                  &mch->pci_hole);
> > -    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
> > -                       ((uint64_t)1 << 62));
> >      memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch), "pci-hole64",
> >                               mch->pci_address_space,
> >                               0x100000000ULL + mch->above_4g_mem_size,
> > -                             pci_hole64_size);
> > -    if (pci_hole64_size) {
> > +                             mch->pci_hole64_size);
> > +    if (mch->pci_hole64_size) {
> >          memory_region_add_subregion(mch->system_memory,
> >                                      0x100000000ULL + mch->above_4g_mem_size,
> >                                      &mch->pci_hole_64bit);
> > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > index 0e6f519..72b4456 100644
> > --- a/include/hw/i386/pc.h
> > +++ b/include/hw/i386/pc.h
> > @@ -132,6 +132,9 @@ void pc_acpi_init(const char *default_dsdt);
> >  
> >  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> >                                  ram_addr_t above_4g_mem_size);
> > +void pc_init_pci_info(PcPciInfo *pci_info,
> > +                      uint64_t pci_hole64_start,
> > +                      uint64_t pci_hole64_size);
> >  
> >  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
> >                             const char *kernel_filename,
> > @@ -183,9 +186,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
> >                      hwaddr pci_hole_start,
> >                      hwaddr pci_hole_size,
> >                      hwaddr pci_hole64_start,
> > -                    hwaddr pci_hole64_size,
> >                      MemoryRegion *pci_memory,
> > -                    MemoryRegion *ram_memory);
> > +                    MemoryRegion *ram_memory,
> > +                    PcGuestInfo *guest_info);
> >  
> >  PCIBus *find_i440fx(void);
> >  /* piix4.c */
> > diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
> > index 3d59ae1..869ecb2 100644
> > --- a/include/hw/pci-host/q35.h
> > +++ b/include/hw/pci-host/q35.h
> > @@ -52,6 +52,7 @@ typedef struct MCHPCIState {
> >      MemoryRegion smram_region;
> >      MemoryRegion pci_hole;
> >      MemoryRegion pci_hole_64bit;
> > +    uint64_t pci_hole64_size;
> >      uint8_t smm_enabled;
> >      ram_addr_t below_4g_mem_size;
> >      ram_addr_t above_4g_mem_size;

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-25 13:40 ` Igor Mammedov
  2013-07-25 15:03   ` Michael S. Tsirkin
@ 2013-07-25 15:16   ` Igor Mammedov
  2013-07-25 15:23     ` Michael S. Tsirkin
  1 sibling, 1 reply; 16+ messages in thread
From: Igor Mammedov @ 2013-07-25 15:16 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson



----- Original Message -----
> From: "Igor Mammedov" <imammedo@redhat.com>
> To: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: "Anthony Liguori" <aliguori@us.ibm.com>, "Eduardo Habkost" <ehabkost@redhat.com>, qemu-devel@nongnu.org, "Isaku
> Yamahata" <yamahata@valinux.co.jp>, "Alex Williamson" <alex.williamson@redhat.com>, "Gerd Hoffmann"
> <kraxel@redhat.com>, "Paolo Bonzini" <pbonzini@redhat.com>, "Laszlo Ersek" <lersek@redhat.com>, "Andreas Färber"
> <afaerber@suse.de>, "David Gibson" <david@gibson.dropbear.id.au>
> Sent: Thursday, July 25, 2013 3:40:05 PM
> Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
> 
> On Wed, 24 Jul 2013 09:01:04 +0300
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
> > It turns out that some 32 bit windows guests crash
> > if 64 bit PCI hole size is >2G.
> > Limit it to 2G for piix and q35 by default,
> > add properties to let management override the hole size.
> > 
> > Examples:
> > -global i440FX-pcihost.pci_hole64_size=137438953472
> > 
> > -global q35-pcihost.pci_hole64_size=137438953472
> > 
> > Reported-by: Igor Mammedov <imammedo@redhat.com>,
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > ---
> >  hw/i386/pc.c              | 35 ++++++++++++++++++++---------------
> >  hw/i386/pc_piix.c         | 14 +-------------
> >  hw/pci-host/piix.c        | 42 ++++++++++++++++++++++++++++++++++--------
> >  hw/pci-host/q35.c         | 29 +++++++++++++++++------------
> >  include/hw/i386/pc.h      |  7 +++++--
> >  include/hw/pci-host/q35.h |  1 +
> >  6 files changed, 78 insertions(+), 50 deletions(-)
> > 
> > diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> > index a7c578f..9cc0fda 100644
> > --- a/hw/i386/pc.c
> > +++ b/hw/i386/pc.c
> > @@ -1072,27 +1072,32 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t
> > below_4g_mem_size,
> >      memset(&guest_info->found_cpus, 0, sizeof guest_info->found_cpus);
> >      qemu_for_each_cpu(pc_set_cpu_guest_info, guest_info);
> >  
> > -    guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
> > -    if (sizeof(hwaddr) == 4) {
> > -        guest_info->pci_info.w64.begin = 0;
> > -        guest_info->pci_info.w64.end = 0;
> > -    } else {
> > +    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
> > +    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > +    return guest_info;
> > +}
> > +
> > +void pc_init_pci_info(PcPciInfo *pci_info,
> > +                      uint64_t pci_hole64_start,
> > +                      uint64_t pci_hole64_size)
> > +{
> > +        pci_info->w32.end = IO_APIC_DEFAULT_ADDRESS;
> weird ident
> 
> > +
> > +        if (pci_hole64_size & ((0x1 << 30) - 1)) {
> > +            error_report("Invalid value for pci_hole64_size: "
> > +                         "must be a multiple of 1G. Rounding up.");
> > +        }
> > +        pci_hole64_size = ROUND_UP(pci_hole64_size, 0x1ULL << 30);
> > +
> if pci_hole64_size is a property it would be better to put check,
> in property setter (custom one) and error out instead of doing fixup,
> lets user fix his wrong cmd line.
>  
> >          /*
> >           * BIOS does not set MTRR entries for the 64 bit window, so no
> >           need to
> >           * align address to power of two.  Align address at 1G, this makes
> >           sure
> >           * it can be exactly covered with a PAT entry even when using huge
> >           * pages.
> >           */
> > -        guest_info->pci_info.w64.begin =
> > -            ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL << 30);
> > -        guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin +
> > -            (0x1ULL << 31);
> > -        assert(guest_info->pci_info.w64.begin <=
> > guest_info->pci_info.w64.end);
> > -    }
> > -
> > -    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
> > -    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > -    return guest_info;
> > +        pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30);
> > +        pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
> > +        assert(pci_info->w64.begin <= pci_info->w64.end);
> >  }
> >  
> >  void pc_acpi_init(const char *default_dsdt)
> > diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> > index 76df42b..da61fa3 100644
> > --- a/hw/i386/pc_piix.c
> > +++ b/hw/i386/pc_piix.c
> > @@ -137,15 +137,6 @@ static void pc_init1(MemoryRegion *system_memory,
> >  
> >      guest_info->has_pci_info = has_pci_info;
> >  
> > -    /* Set PCI window size the way seabios has always done it. */
> > -    /* Power of 2 so bios can cover it with a single MTRR */
> > -    if (ram_size <= 0x80000000)
> > -        guest_info->pci_info.w32.begin = 0x80000000;
> > -    else if (ram_size <= 0xc0000000)
> > -        guest_info->pci_info.w32.begin = 0xc0000000;
> > -    else
> > -        guest_info->pci_info.w32.begin = 0xe0000000;
> > -
> >      /* allocate ram and load rom/bios */
> >      if (!xen_enabled()) {
> >          fw_cfg = pc_memory_init(system_memory,
> > @@ -169,10 +160,7 @@ static void pc_init1(MemoryRegion *system_memory,
> >                                below_4g_mem_size,
> >                                0x100000000ULL - below_4g_mem_size,
> >                                0x100000000ULL + above_4g_mem_size,
> > -                              (sizeof(hwaddr) == 4
> > -                               ? 0
> > -                               : ((uint64_t)1 << 62)),
> > -                              pci_memory, ram_memory);
> > +                              pci_memory, ram_memory, guest_info);
> >      } else {
> >          pci_bus = NULL;
> >          i440fx_state = NULL;
> > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > index 7fb2fb1..963b3d8 100644
> > --- a/hw/pci-host/piix.c
> > +++ b/hw/pci-host/piix.c
> > @@ -40,6 +41,7 @@
> >  
> >  typedef struct I440FXState {
> >      PCIHostState parent_obj;
> > +    uint64_t pci_hole64_size;
> >  } I440FXState;
> >  
> >  #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
> > @@ -234,9 +236,9 @@ static PCIBus *i440fx_common_init(const char
> > *device_name,
> >                                    hwaddr pci_hole_start,
> >                                    hwaddr pci_hole_size,
> >                                    hwaddr pci_hole64_start,
> ^^^ could but to be more consistent if moved to a place where 64 PCI hole is
> initialized, replace it with above_4g_memory_size, and let
> i440fx_common_init()
> set it near the place where 64 PCI hole end is set.
> 
> > -                                  hwaddr pci_hole64_size,
> >                                    MemoryRegion *pci_address_space,
> > -                                  MemoryRegion *ram_memory)
> > +                                  MemoryRegion *ram_memory,
> > +                                  PcGuestInfo *guest_info)
> >  {
> >      DeviceState *dev;
> >      PCIBus *b;
> > @@ -245,15 +247,31 @@ static PCIBus *i440fx_common_init(const char
> > *device_name,
> >      PIIX3State *piix3;
> >      PCII440FXState *f;
> >      unsigned i;
> > +    I440FXState *i440fx;
> >  
> >      dev = qdev_create(NULL, "i440FX-pcihost");
> >      s = PCI_HOST_BRIDGE(dev);
> > +    i440fx = OBJECT_CHECK(I440FXState, dev, "i440FX-pcihost");
> >      b = pci_bus_new(dev, NULL, pci_address_space,
> >                      address_space_io, 0, TYPE_PCI_BUS);
> >      s->bus = b;
> >      object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev),
> >      NULL);
> >      qdev_init_nofail(dev);
> >  
> > +    if (guest_info) {
> > +        /* Set PCI window size the way seabios has always done it. */
> > +        /* Power of 2 so bios can cover it with a single MTRR */
> > +        if (ram_size <= 0x80000000)
> > +            guest_info->pci_info.w32.begin = 0x80000000;
> > +        else if (ram_size <= 0xc0000000)
> > +            guest_info->pci_info.w32.begin = 0xc0000000;
> > +        else
> > +            guest_info->pci_info.w32.begin = 0xe0000000;
> > +
> > +        pc_init_pci_info(&guest_info->pci_info,
> > +                         pci_hole64_start, i440fx->pci_hole64_size);
> > +    }
> split brain init of the same data structure make it ugly, would be more
> readable
> inlined.
> 
> Wouldn't it be better/cleaner to put PcPciInfo inside of
> I440FXState/MCHPCIState
> and make QOM based API to access it as in latest ACPI tables series?
> 
we could event not use PcPciInfo at all if memory_region_find() would return
address for non terminating regions (i.e. aliases and containters).
then we could get all necessary info from f->pci_hole_64bit and f->pci_hole.

Paolo,
 would be following patch acceptable:

diff --git a/memory.c b/memory.c
index 757e9a5..0f1fb10 100644
--- a/memory.c
+++ b/memory.c
@@ -1551,6 +1551,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr,
         addr += root->addr;
     }
 
+    ret.offset_within_region = addr;
     as = memory_region_to_address_space(root);
     range = addrrange_make(int128_make64(addr), int128_make64(size));
     fr = address_space_lookup(as, range);

Then to get PCI hole info all we would need is:

get_pci_hole_info(f, uint64_t *start, uint64_t *end) {
  MemoryRegionSection ms =  memory_region_find(f->pci_hole, 0, 1);
  sz = memory_region_size(mr);
  *start = ms.offset_within_region;
  *end = *start + sz;
}

> 
> >      d = pci_create_simple(b, 0, device_name);
> >      *pi440fx_state = I440FX_PCI_DEVICE(d);
> >      f = *pi440fx_state;
> > @@ -265,8 +283,8 @@ static PCIBus *i440fx_common_init(const char
> > *device_name,
> >      memory_region_add_subregion(f->system_memory, pci_hole_start,
> >      &f->pci_hole);
> >      memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64",
> >                               f->pci_address_space,
> > -                             pci_hole64_start, pci_hole64_size);
> > -    if (pci_hole64_size) {
> > +                             pci_hole64_start, i440fx->pci_hole64_size);
> > +    if (i440fx->pci_hole64_size) {
> >          memory_region_add_subregion(f->system_memory, pci_hole64_start,
> >                                      &f->pci_hole_64bit);
> >      }
> > @@ -322,8 +340,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int
> > *piix3_devfn,
> >                      hwaddr pci_hole_start,
> >                      hwaddr pci_hole_size,
> >                      hwaddr pci_hole64_start,
> > -                    hwaddr pci_hole64_size,
> > -                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
> > +                    MemoryRegion *pci_memory, MemoryRegion *ram_memory,
> > +                    PcGuestInfo *guest_info)
> >  
> >  {
> >      PCIBus *b;
> > @@ -332,8 +350,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int
> > *piix3_devfn,
> >                             piix3_devfn, isa_bus, pic,
> >                             address_space_mem, address_space_io, ram_size,
> >                             pci_hole_start, pci_hole_size,
> > -                           pci_hole64_start, pci_hole64_size,
> > -                           pci_memory, ram_memory);
> > +                           pci_hole64_start,
> > +                           pci_memory, ram_memory,
> > +                           guest_info);
> >      return b;
> >  }
> >  
> > @@ -645,6 +664,12 @@ static const char
> > *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
> >      return "0000";
> >  }
> >  
> > +static Property i440fx_props[] = {
> > +    DEFINE_PROP_UINT64("pci_hole64_size", I440FXState,
> > +                       pci_hole64_size, 0x1ULL << 31),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> >  static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
> >  {
> >      DeviceClass *dc = DEVICE_CLASS(klass);
> > @@ -655,6 +680,7 @@ static void i440fx_pcihost_class_init(ObjectClass
> > *klass, void *data)
> >      k->init = i440fx_pcihost_initfn;
> >      dc->fw_name = "pci";
> >      dc->no_user = 1;
> > +    dc->props = i440fx_props;
> >  }
> >  
> >  static const TypeInfo i440fx_pcihost_info = {
> > diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> > index c761a43..4dd7ca4 100644
> > --- a/hw/pci-host/q35.c
> > +++ b/hw/pci-host/q35.c
> > @@ -73,6 +74,8 @@ static const char *q35_host_root_bus_path(PCIHostState
> > *host_bridge,
> >  static Property mch_props[] = {
> >      DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
> >                          MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
> > +    DEFINE_PROP_UINT64("pci_hole64_size", Q35PCIHost,
> > +                       mch.pci_hole64_size, 0x1ULL << 31),
> >      DEFINE_PROP_END_OF_LIST(),
> >  };
> >  
> > @@ -250,16 +253,20 @@ static void mch_reset(DeviceState *qdev)
> >  static int mch_init(PCIDevice *d)
> >  {
> >      int i;
> > -    hwaddr pci_hole64_size;
> >      MCHPCIState *mch = MCH_PCI_DEVICE(d);
> >  
> > -    /* Leave enough space for the biggest MCFG BAR */
> > -    /* TODO: this matches current bios behaviour, but
> > -     * it's not a power of two, which means an MTRR
> > -     * can't cover it exactly.
> > -     */
> > -    mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT
> > +
> > -        MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > +    if (mch->guest_info) {
> > +        /* Leave enough space for the biggest MCFG BAR */
> > +        /* TODO: this matches current bios behaviour, but
> > +         * it's not a power of two, which means an MTRR
> > +         * can't cover it exactly.
> > +         */
> > +        mch->guest_info->pci_info.w32.begin =
> > MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
> > +            MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > +        pc_init_pci_info(&mch->guest_info->pci_info,
> > +                         0x100000000ULL + mch->above_4g_mem_size,
> > +                         mch->pci_hole64_size);
> > +    }
> >  
> >      /* setup pci memory regions */
> >      memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
> > @@ -268,13 +275,11 @@ static int mch_init(PCIDevice *d)
> >                               0x100000000ULL - mch->below_4g_mem_size);
> >      memory_region_add_subregion(mch->system_memory,
> >      mch->below_4g_mem_size,
> >                                  &mch->pci_hole);
> > -    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
> > -                       ((uint64_t)1 << 62));
> >      memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch),
> >      "pci-hole64",
> >                               mch->pci_address_space,
> >                               0x100000000ULL + mch->above_4g_mem_size,
> > -                             pci_hole64_size);
> > -    if (pci_hole64_size) {
> > +                             mch->pci_hole64_size);
> > +    if (mch->pci_hole64_size) {
> >          memory_region_add_subregion(mch->system_memory,
> >                                      0x100000000ULL +
> >                                      mch->above_4g_mem_size,
> >                                      &mch->pci_hole_64bit);
> > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > index 0e6f519..72b4456 100644
> > --- a/include/hw/i386/pc.h
> > +++ b/include/hw/i386/pc.h
> > @@ -132,6 +132,9 @@ void pc_acpi_init(const char *default_dsdt);
> >  
> >  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> >                                  ram_addr_t above_4g_mem_size);
> > +void pc_init_pci_info(PcPciInfo *pci_info,
> > +                      uint64_t pci_hole64_start,
> > +                      uint64_t pci_hole64_size);
> >  
> >  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
> >                             const char *kernel_filename,
> > @@ -183,9 +186,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int
> > *piix_devfn,
> >                      hwaddr pci_hole_start,
> >                      hwaddr pci_hole_size,
> >                      hwaddr pci_hole64_start,
> > -                    hwaddr pci_hole64_size,
> >                      MemoryRegion *pci_memory,
> > -                    MemoryRegion *ram_memory);
> > +                    MemoryRegion *ram_memory,
> > +                    PcGuestInfo *guest_info);
> >  
> >  PCIBus *find_i440fx(void);
> >  /* piix4.c */
> > diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
> > index 3d59ae1..869ecb2 100644
> > --- a/include/hw/pci-host/q35.h
> > +++ b/include/hw/pci-host/q35.h
> > @@ -52,6 +52,7 @@ typedef struct MCHPCIState {
> >      MemoryRegion smram_region;
> >      MemoryRegion pci_hole;
> >      MemoryRegion pci_hole_64bit;
> > +    uint64_t pci_hole64_size;
> >      uint8_t smm_enabled;
> >      ram_addr_t below_4g_mem_size;
> >      ram_addr_t above_4g_mem_size;
> 
> 
> 

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-25 15:16   ` Igor Mammedov
@ 2013-07-25 15:23     ` Michael S. Tsirkin
  2013-07-25 15:30       ` Igor Mammedov
  0 siblings, 1 reply; 16+ messages in thread
From: Michael S. Tsirkin @ 2013-07-25 15:23 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

On Thu, Jul 25, 2013 at 11:16:06AM -0400, Igor Mammedov wrote:
> 
> 
> ----- Original Message -----
> > From: "Igor Mammedov" <imammedo@redhat.com>
> > To: "Michael S. Tsirkin" <mst@redhat.com>
> > Cc: "Anthony Liguori" <aliguori@us.ibm.com>, "Eduardo Habkost" <ehabkost@redhat.com>, qemu-devel@nongnu.org, "Isaku
> > Yamahata" <yamahata@valinux.co.jp>, "Alex Williamson" <alex.williamson@redhat.com>, "Gerd Hoffmann"
> > <kraxel@redhat.com>, "Paolo Bonzini" <pbonzini@redhat.com>, "Laszlo Ersek" <lersek@redhat.com>, "Andreas Färber"
> > <afaerber@suse.de>, "David Gibson" <david@gibson.dropbear.id.au>
> > Sent: Thursday, July 25, 2013 3:40:05 PM
> > Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
> > 
> > On Wed, 24 Jul 2013 09:01:04 +0300
> > "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > 
> > > It turns out that some 32 bit windows guests crash
> > > if 64 bit PCI hole size is >2G.
> > > Limit it to 2G for piix and q35 by default,
> > > add properties to let management override the hole size.
> > > 
> > > Examples:
> > > -global i440FX-pcihost.pci_hole64_size=137438953472
> > > 
> > > -global q35-pcihost.pci_hole64_size=137438953472
> > > 
> > > Reported-by: Igor Mammedov <imammedo@redhat.com>,
> > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > ---
> > >  hw/i386/pc.c              | 35 ++++++++++++++++++++---------------
> > >  hw/i386/pc_piix.c         | 14 +-------------
> > >  hw/pci-host/piix.c        | 42 ++++++++++++++++++++++++++++++++++--------
> > >  hw/pci-host/q35.c         | 29 +++++++++++++++++------------
> > >  include/hw/i386/pc.h      |  7 +++++--
> > >  include/hw/pci-host/q35.h |  1 +
> > >  6 files changed, 78 insertions(+), 50 deletions(-)
> > > 
> > > diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> > > index a7c578f..9cc0fda 100644
> > > --- a/hw/i386/pc.c
> > > +++ b/hw/i386/pc.c
> > > @@ -1072,27 +1072,32 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t
> > > below_4g_mem_size,
> > >      memset(&guest_info->found_cpus, 0, sizeof guest_info->found_cpus);
> > >      qemu_for_each_cpu(pc_set_cpu_guest_info, guest_info);
> > >  
> > > -    guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
> > > -    if (sizeof(hwaddr) == 4) {
> > > -        guest_info->pci_info.w64.begin = 0;
> > > -        guest_info->pci_info.w64.end = 0;
> > > -    } else {
> > > +    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
> > > +    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > > +    return guest_info;
> > > +}
> > > +
> > > +void pc_init_pci_info(PcPciInfo *pci_info,
> > > +                      uint64_t pci_hole64_start,
> > > +                      uint64_t pci_hole64_size)
> > > +{
> > > +        pci_info->w32.end = IO_APIC_DEFAULT_ADDRESS;
> > weird ident
> > 
> > > +
> > > +        if (pci_hole64_size & ((0x1 << 30) - 1)) {
> > > +            error_report("Invalid value for pci_hole64_size: "
> > > +                         "must be a multiple of 1G. Rounding up.");
> > > +        }
> > > +        pci_hole64_size = ROUND_UP(pci_hole64_size, 0x1ULL << 30);
> > > +
> > if pci_hole64_size is a property it would be better to put check,
> > in property setter (custom one) and error out instead of doing fixup,
> > lets user fix his wrong cmd line.
> >  
> > >          /*
> > >           * BIOS does not set MTRR entries for the 64 bit window, so no
> > >           need to
> > >           * align address to power of two.  Align address at 1G, this makes
> > >           sure
> > >           * it can be exactly covered with a PAT entry even when using huge
> > >           * pages.
> > >           */
> > > -        guest_info->pci_info.w64.begin =
> > > -            ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL << 30);
> > > -        guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin +
> > > -            (0x1ULL << 31);
> > > -        assert(guest_info->pci_info.w64.begin <=
> > > guest_info->pci_info.w64.end);
> > > -    }
> > > -
> > > -    guest_info_state->machine_done.notify = pc_guest_info_machine_done;
> > > -    qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > > -    return guest_info;
> > > +        pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30);
> > > +        pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
> > > +        assert(pci_info->w64.begin <= pci_info->w64.end);
> > >  }
> > >  
> > >  void pc_acpi_init(const char *default_dsdt)
> > > diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> > > index 76df42b..da61fa3 100644
> > > --- a/hw/i386/pc_piix.c
> > > +++ b/hw/i386/pc_piix.c
> > > @@ -137,15 +137,6 @@ static void pc_init1(MemoryRegion *system_memory,
> > >  
> > >      guest_info->has_pci_info = has_pci_info;
> > >  
> > > -    /* Set PCI window size the way seabios has always done it. */
> > > -    /* Power of 2 so bios can cover it with a single MTRR */
> > > -    if (ram_size <= 0x80000000)
> > > -        guest_info->pci_info.w32.begin = 0x80000000;
> > > -    else if (ram_size <= 0xc0000000)
> > > -        guest_info->pci_info.w32.begin = 0xc0000000;
> > > -    else
> > > -        guest_info->pci_info.w32.begin = 0xe0000000;
> > > -
> > >      /* allocate ram and load rom/bios */
> > >      if (!xen_enabled()) {
> > >          fw_cfg = pc_memory_init(system_memory,
> > > @@ -169,10 +160,7 @@ static void pc_init1(MemoryRegion *system_memory,
> > >                                below_4g_mem_size,
> > >                                0x100000000ULL - below_4g_mem_size,
> > >                                0x100000000ULL + above_4g_mem_size,
> > > -                              (sizeof(hwaddr) == 4
> > > -                               ? 0
> > > -                               : ((uint64_t)1 << 62)),
> > > -                              pci_memory, ram_memory);
> > > +                              pci_memory, ram_memory, guest_info);
> > >      } else {
> > >          pci_bus = NULL;
> > >          i440fx_state = NULL;
> > > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > > index 7fb2fb1..963b3d8 100644
> > > --- a/hw/pci-host/piix.c
> > > +++ b/hw/pci-host/piix.c
> > > @@ -40,6 +41,7 @@
> > >  
> > >  typedef struct I440FXState {
> > >      PCIHostState parent_obj;
> > > +    uint64_t pci_hole64_size;
> > >  } I440FXState;
> > >  
> > >  #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
> > > @@ -234,9 +236,9 @@ static PCIBus *i440fx_common_init(const char
> > > *device_name,
> > >                                    hwaddr pci_hole_start,
> > >                                    hwaddr pci_hole_size,
> > >                                    hwaddr pci_hole64_start,
> > ^^^ could but to be more consistent if moved to a place where 64 PCI hole is
> > initialized, replace it with above_4g_memory_size, and let
> > i440fx_common_init()
> > set it near the place where 64 PCI hole end is set.
> > 
> > > -                                  hwaddr pci_hole64_size,
> > >                                    MemoryRegion *pci_address_space,
> > > -                                  MemoryRegion *ram_memory)
> > > +                                  MemoryRegion *ram_memory,
> > > +                                  PcGuestInfo *guest_info)
> > >  {
> > >      DeviceState *dev;
> > >      PCIBus *b;
> > > @@ -245,15 +247,31 @@ static PCIBus *i440fx_common_init(const char
> > > *device_name,
> > >      PIIX3State *piix3;
> > >      PCII440FXState *f;
> > >      unsigned i;
> > > +    I440FXState *i440fx;
> > >  
> > >      dev = qdev_create(NULL, "i440FX-pcihost");
> > >      s = PCI_HOST_BRIDGE(dev);
> > > +    i440fx = OBJECT_CHECK(I440FXState, dev, "i440FX-pcihost");
> > >      b = pci_bus_new(dev, NULL, pci_address_space,
> > >                      address_space_io, 0, TYPE_PCI_BUS);
> > >      s->bus = b;
> > >      object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev),
> > >      NULL);
> > >      qdev_init_nofail(dev);
> > >  
> > > +    if (guest_info) {
> > > +        /* Set PCI window size the way seabios has always done it. */
> > > +        /* Power of 2 so bios can cover it with a single MTRR */
> > > +        if (ram_size <= 0x80000000)
> > > +            guest_info->pci_info.w32.begin = 0x80000000;
> > > +        else if (ram_size <= 0xc0000000)
> > > +            guest_info->pci_info.w32.begin = 0xc0000000;
> > > +        else
> > > +            guest_info->pci_info.w32.begin = 0xe0000000;
> > > +
> > > +        pc_init_pci_info(&guest_info->pci_info,
> > > +                         pci_hole64_start, i440fx->pci_hole64_size);
> > > +    }
> > split brain init of the same data structure make it ugly, would be more
> > readable
> > inlined.
> > 
> > Wouldn't it be better/cleaner to put PcPciInfo inside of
> > I440FXState/MCHPCIState
> > and make QOM based API to access it as in latest ACPI tables series?
> > 
> we could event not use PcPciInfo at all if memory_region_find() would return
> address for non terminating regions (i.e. aliases and containters).
> then we could get all necessary info from f->pci_hole_64bit and f->pci_hole.
> 
> Paolo,
>  would be following patch acceptable:
> 
> diff --git a/memory.c b/memory.c
> index 757e9a5..0f1fb10 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1551,6 +1551,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr,
>          addr += root->addr;
>      }
>  
> +    ret.offset_within_region = addr;
>      as = memory_region_to_address_space(root);
>      range = addrrange_make(int128_make64(addr), int128_make64(size));
>      fr = address_space_lookup(as, range);
> 
> Then to get PCI hole info all we would need is:
> 
> get_pci_hole_info(f, uint64_t *start, uint64_t *end) {
>   MemoryRegionSection ms =  memory_region_find(f->pci_hole, 0, 1);
>   sz = memory_region_size(mr);
>   *start = ms.offset_within_region;
>   *end = *start + sz;
> }

We'll need to get the regions somehow, and all this will
really break for example if we decide to cover the 64 bit
holes in 2 regions instead of one, for some reason.

Frankly I don't see any advantages.


> > 
> > >      d = pci_create_simple(b, 0, device_name);
> > >      *pi440fx_state = I440FX_PCI_DEVICE(d);
> > >      f = *pi440fx_state;
> > > @@ -265,8 +283,8 @@ static PCIBus *i440fx_common_init(const char
> > > *device_name,
> > >      memory_region_add_subregion(f->system_memory, pci_hole_start,
> > >      &f->pci_hole);
> > >      memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64",
> > >                               f->pci_address_space,
> > > -                             pci_hole64_start, pci_hole64_size);
> > > -    if (pci_hole64_size) {
> > > +                             pci_hole64_start, i440fx->pci_hole64_size);
> > > +    if (i440fx->pci_hole64_size) {
> > >          memory_region_add_subregion(f->system_memory, pci_hole64_start,
> > >                                      &f->pci_hole_64bit);
> > >      }
> > > @@ -322,8 +340,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int
> > > *piix3_devfn,
> > >                      hwaddr pci_hole_start,
> > >                      hwaddr pci_hole_size,
> > >                      hwaddr pci_hole64_start,
> > > -                    hwaddr pci_hole64_size,
> > > -                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
> > > +                    MemoryRegion *pci_memory, MemoryRegion *ram_memory,
> > > +                    PcGuestInfo *guest_info)
> > >  
> > >  {
> > >      PCIBus *b;
> > > @@ -332,8 +350,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int
> > > *piix3_devfn,
> > >                             piix3_devfn, isa_bus, pic,
> > >                             address_space_mem, address_space_io, ram_size,
> > >                             pci_hole_start, pci_hole_size,
> > > -                           pci_hole64_start, pci_hole64_size,
> > > -                           pci_memory, ram_memory);
> > > +                           pci_hole64_start,
> > > +                           pci_memory, ram_memory,
> > > +                           guest_info);
> > >      return b;
> > >  }
> > >  
> > > @@ -645,6 +664,12 @@ static const char
> > > *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
> > >      return "0000";
> > >  }
> > >  
> > > +static Property i440fx_props[] = {
> > > +    DEFINE_PROP_UINT64("pci_hole64_size", I440FXState,
> > > +                       pci_hole64_size, 0x1ULL << 31),
> > > +    DEFINE_PROP_END_OF_LIST(),
> > > +};
> > > +
> > >  static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
> > >  {
> > >      DeviceClass *dc = DEVICE_CLASS(klass);
> > > @@ -655,6 +680,7 @@ static void i440fx_pcihost_class_init(ObjectClass
> > > *klass, void *data)
> > >      k->init = i440fx_pcihost_initfn;
> > >      dc->fw_name = "pci";
> > >      dc->no_user = 1;
> > > +    dc->props = i440fx_props;
> > >  }
> > >  
> > >  static const TypeInfo i440fx_pcihost_info = {
> > > diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> > > index c761a43..4dd7ca4 100644
> > > --- a/hw/pci-host/q35.c
> > > +++ b/hw/pci-host/q35.c
> > > @@ -73,6 +74,8 @@ static const char *q35_host_root_bus_path(PCIHostState
> > > *host_bridge,
> > >  static Property mch_props[] = {
> > >      DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
> > >                          MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
> > > +    DEFINE_PROP_UINT64("pci_hole64_size", Q35PCIHost,
> > > +                       mch.pci_hole64_size, 0x1ULL << 31),
> > >      DEFINE_PROP_END_OF_LIST(),
> > >  };
> > >  
> > > @@ -250,16 +253,20 @@ static void mch_reset(DeviceState *qdev)
> > >  static int mch_init(PCIDevice *d)
> > >  {
> > >      int i;
> > > -    hwaddr pci_hole64_size;
> > >      MCHPCIState *mch = MCH_PCI_DEVICE(d);
> > >  
> > > -    /* Leave enough space for the biggest MCFG BAR */
> > > -    /* TODO: this matches current bios behaviour, but
> > > -     * it's not a power of two, which means an MTRR
> > > -     * can't cover it exactly.
> > > -     */
> > > -    mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT
> > > +
> > > -        MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > > +    if (mch->guest_info) {
> > > +        /* Leave enough space for the biggest MCFG BAR */
> > > +        /* TODO: this matches current bios behaviour, but
> > > +         * it's not a power of two, which means an MTRR
> > > +         * can't cover it exactly.
> > > +         */
> > > +        mch->guest_info->pci_info.w32.begin =
> > > MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
> > > +            MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > > +        pc_init_pci_info(&mch->guest_info->pci_info,
> > > +                         0x100000000ULL + mch->above_4g_mem_size,
> > > +                         mch->pci_hole64_size);
> > > +    }
> > >  
> > >      /* setup pci memory regions */
> > >      memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
> > > @@ -268,13 +275,11 @@ static int mch_init(PCIDevice *d)
> > >                               0x100000000ULL - mch->below_4g_mem_size);
> > >      memory_region_add_subregion(mch->system_memory,
> > >      mch->below_4g_mem_size,
> > >                                  &mch->pci_hole);
> > > -    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
> > > -                       ((uint64_t)1 << 62));
> > >      memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch),
> > >      "pci-hole64",
> > >                               mch->pci_address_space,
> > >                               0x100000000ULL + mch->above_4g_mem_size,
> > > -                             pci_hole64_size);
> > > -    if (pci_hole64_size) {
> > > +                             mch->pci_hole64_size);
> > > +    if (mch->pci_hole64_size) {
> > >          memory_region_add_subregion(mch->system_memory,
> > >                                      0x100000000ULL +
> > >                                      mch->above_4g_mem_size,
> > >                                      &mch->pci_hole_64bit);
> > > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > > index 0e6f519..72b4456 100644
> > > --- a/include/hw/i386/pc.h
> > > +++ b/include/hw/i386/pc.h
> > > @@ -132,6 +132,9 @@ void pc_acpi_init(const char *default_dsdt);
> > >  
> > >  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> > >                                  ram_addr_t above_4g_mem_size);
> > > +void pc_init_pci_info(PcPciInfo *pci_info,
> > > +                      uint64_t pci_hole64_start,
> > > +                      uint64_t pci_hole64_size);
> > >  
> > >  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
> > >                             const char *kernel_filename,
> > > @@ -183,9 +186,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int
> > > *piix_devfn,
> > >                      hwaddr pci_hole_start,
> > >                      hwaddr pci_hole_size,
> > >                      hwaddr pci_hole64_start,
> > > -                    hwaddr pci_hole64_size,
> > >                      MemoryRegion *pci_memory,
> > > -                    MemoryRegion *ram_memory);
> > > +                    MemoryRegion *ram_memory,
> > > +                    PcGuestInfo *guest_info);
> > >  
> > >  PCIBus *find_i440fx(void);
> > >  /* piix4.c */
> > > diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
> > > index 3d59ae1..869ecb2 100644
> > > --- a/include/hw/pci-host/q35.h
> > > +++ b/include/hw/pci-host/q35.h
> > > @@ -52,6 +52,7 @@ typedef struct MCHPCIState {
> > >      MemoryRegion smram_region;
> > >      MemoryRegion pci_hole;
> > >      MemoryRegion pci_hole_64bit;
> > > +    uint64_t pci_hole64_size;
> > >      uint8_t smm_enabled;
> > >      ram_addr_t below_4g_mem_size;
> > >      ram_addr_t above_4g_mem_size;
> > 
> > 
> > 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-25 15:23     ` Michael S. Tsirkin
@ 2013-07-25 15:30       ` Igor Mammedov
  2013-07-25 15:35         ` Michael S. Tsirkin
  0 siblings, 1 reply; 16+ messages in thread
From: Igor Mammedov @ 2013-07-25 15:30 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson



----- Original Message -----
> From: "Michael S. Tsirkin" <mst@redhat.com>
> To: "Igor Mammedov" <imammedo@redhat.com>
> Cc: "Anthony Liguori" <aliguori@us.ibm.com>, "Eduardo Habkost" <ehabkost@redhat.com>, qemu-devel@nongnu.org, "Isaku
> Yamahata" <yamahata@valinux.co.jp>, "Alex Williamson" <alex.williamson@redhat.com>, "Gerd Hoffmann"
> <kraxel@redhat.com>, "Laszlo Ersek" <lersek@redhat.com>, "Andreas Färber" <afaerber@suse.de>, "David Gibson"
> <david@gibson.dropbear.id.au>, "Paolo Bonzini" <pbonzini@redhat.com>
> Sent: Thursday, July 25, 2013 5:23:21 PM
> Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
> 
> On Thu, Jul 25, 2013 at 11:16:06AM -0400, Igor Mammedov wrote:
> > 
> > 
> > ----- Original Message -----
> > > From: "Igor Mammedov" <imammedo@redhat.com>
> > > To: "Michael S. Tsirkin" <mst@redhat.com>
> > > Cc: "Anthony Liguori" <aliguori@us.ibm.com>, "Eduardo Habkost"
> > > <ehabkost@redhat.com>, qemu-devel@nongnu.org, "Isaku
> > > Yamahata" <yamahata@valinux.co.jp>, "Alex Williamson"
> > > <alex.williamson@redhat.com>, "Gerd Hoffmann"
> > > <kraxel@redhat.com>, "Paolo Bonzini" <pbonzini@redhat.com>, "Laszlo
> > > Ersek" <lersek@redhat.com>, "Andreas Färber"
> > > <afaerber@suse.de>, "David Gibson" <david@gibson.dropbear.id.au>
> > > Sent: Thursday, July 25, 2013 3:40:05 PM
> > > Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
> > > 
> > > On Wed, 24 Jul 2013 09:01:04 +0300
> > > "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > > 
> > > > It turns out that some 32 bit windows guests crash
> > > > if 64 bit PCI hole size is >2G.
> > > > Limit it to 2G for piix and q35 by default,
> > > > add properties to let management override the hole size.
> > > > 
> > > > Examples:
> > > > -global i440FX-pcihost.pci_hole64_size=137438953472
> > > > 
> > > > -global q35-pcihost.pci_hole64_size=137438953472
> > > > 
> > > > Reported-by: Igor Mammedov <imammedo@redhat.com>,
> > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > ---
> > > >  hw/i386/pc.c              | 35 ++++++++++++++++++++---------------
> > > >  hw/i386/pc_piix.c         | 14 +-------------
> > > >  hw/pci-host/piix.c        | 42
> > > >  ++++++++++++++++++++++++++++++++++--------
> > > >  hw/pci-host/q35.c         | 29 +++++++++++++++++------------
> > > >  include/hw/i386/pc.h      |  7 +++++--
> > > >  include/hw/pci-host/q35.h |  1 +
> > > >  6 files changed, 78 insertions(+), 50 deletions(-)
> > > > 
> > > > diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> > > > index a7c578f..9cc0fda 100644
> > > > --- a/hw/i386/pc.c
> > > > +++ b/hw/i386/pc.c
> > > > @@ -1072,27 +1072,32 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t
> > > > below_4g_mem_size,
> > > >      memset(&guest_info->found_cpus, 0, sizeof guest_info->found_cpus);
> > > >      qemu_for_each_cpu(pc_set_cpu_guest_info, guest_info);
> > > >  
> > > > -    guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
> > > > -    if (sizeof(hwaddr) == 4) {
> > > > -        guest_info->pci_info.w64.begin = 0;
> > > > -        guest_info->pci_info.w64.end = 0;
> > > > -    } else {
> > > > +    guest_info_state->machine_done.notify =
> > > > pc_guest_info_machine_done;
> > > > +
> > > > qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > > > +    return guest_info;
> > > > +}
> > > > +
> > > > +void pc_init_pci_info(PcPciInfo *pci_info,
> > > > +                      uint64_t pci_hole64_start,
> > > > +                      uint64_t pci_hole64_size)
> > > > +{
> > > > +        pci_info->w32.end = IO_APIC_DEFAULT_ADDRESS;
> > > weird ident
> > > 
> > > > +
> > > > +        if (pci_hole64_size & ((0x1 << 30) - 1)) {
> > > > +            error_report("Invalid value for pci_hole64_size: "
> > > > +                         "must be a multiple of 1G. Rounding up.");
> > > > +        }
> > > > +        pci_hole64_size = ROUND_UP(pci_hole64_size, 0x1ULL << 30);
> > > > +
> > > if pci_hole64_size is a property it would be better to put check,
> > > in property setter (custom one) and error out instead of doing fixup,
> > > lets user fix his wrong cmd line.
> > >  
> > > >          /*
> > > >           * BIOS does not set MTRR entries for the 64 bit window, so no
> > > >           need to
> > > >           * align address to power of two.  Align address at 1G, this
> > > >           makes
> > > >           sure
> > > >           * it can be exactly covered with a PAT entry even when using
> > > >           huge
> > > >           * pages.
> > > >           */
> > > > -        guest_info->pci_info.w64.begin =
> > > > -            ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL <<
> > > > 30);
> > > > -        guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin
> > > > +
> > > > -            (0x1ULL << 31);
> > > > -        assert(guest_info->pci_info.w64.begin <=
> > > > guest_info->pci_info.w64.end);
> > > > -    }
> > > > -
> > > > -    guest_info_state->machine_done.notify =
> > > > pc_guest_info_machine_done;
> > > > -
> > > > qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > > > -    return guest_info;
> > > > +        pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL <<
> > > > 30);
> > > > +        pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
> > > > +        assert(pci_info->w64.begin <= pci_info->w64.end);
> > > >  }
> > > >  
> > > >  void pc_acpi_init(const char *default_dsdt)
> > > > diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> > > > index 76df42b..da61fa3 100644
> > > > --- a/hw/i386/pc_piix.c
> > > > +++ b/hw/i386/pc_piix.c
> > > > @@ -137,15 +137,6 @@ static void pc_init1(MemoryRegion *system_memory,
> > > >  
> > > >      guest_info->has_pci_info = has_pci_info;
> > > >  
> > > > -    /* Set PCI window size the way seabios has always done it. */
> > > > -    /* Power of 2 so bios can cover it with a single MTRR */
> > > > -    if (ram_size <= 0x80000000)
> > > > -        guest_info->pci_info.w32.begin = 0x80000000;
> > > > -    else if (ram_size <= 0xc0000000)
> > > > -        guest_info->pci_info.w32.begin = 0xc0000000;
> > > > -    else
> > > > -        guest_info->pci_info.w32.begin = 0xe0000000;
> > > > -
> > > >      /* allocate ram and load rom/bios */
> > > >      if (!xen_enabled()) {
> > > >          fw_cfg = pc_memory_init(system_memory,
> > > > @@ -169,10 +160,7 @@ static void pc_init1(MemoryRegion *system_memory,
> > > >                                below_4g_mem_size,
> > > >                                0x100000000ULL - below_4g_mem_size,
> > > >                                0x100000000ULL + above_4g_mem_size,
> > > > -                              (sizeof(hwaddr) == 4
> > > > -                               ? 0
> > > > -                               : ((uint64_t)1 << 62)),
> > > > -                              pci_memory, ram_memory);
> > > > +                              pci_memory, ram_memory, guest_info);
> > > >      } else {
> > > >          pci_bus = NULL;
> > > >          i440fx_state = NULL;
> > > > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > > > index 7fb2fb1..963b3d8 100644
> > > > --- a/hw/pci-host/piix.c
> > > > +++ b/hw/pci-host/piix.c
> > > > @@ -40,6 +41,7 @@
> > > >  
> > > >  typedef struct I440FXState {
> > > >      PCIHostState parent_obj;
> > > > +    uint64_t pci_hole64_size;
> > > >  } I440FXState;
> > > >  
> > > >  #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
> > > > @@ -234,9 +236,9 @@ static PCIBus *i440fx_common_init(const char
> > > > *device_name,
> > > >                                    hwaddr pci_hole_start,
> > > >                                    hwaddr pci_hole_size,
> > > >                                    hwaddr pci_hole64_start,
> > > ^^^ could but to be more consistent if moved to a place where 64 PCI hole
> > > is
> > > initialized, replace it with above_4g_memory_size, and let
> > > i440fx_common_init()
> > > set it near the place where 64 PCI hole end is set.
> > > 
> > > > -                                  hwaddr pci_hole64_size,
> > > >                                    MemoryRegion *pci_address_space,
> > > > -                                  MemoryRegion *ram_memory)
> > > > +                                  MemoryRegion *ram_memory,
> > > > +                                  PcGuestInfo *guest_info)
> > > >  {
> > > >      DeviceState *dev;
> > > >      PCIBus *b;
> > > > @@ -245,15 +247,31 @@ static PCIBus *i440fx_common_init(const char
> > > > *device_name,
> > > >      PIIX3State *piix3;
> > > >      PCII440FXState *f;
> > > >      unsigned i;
> > > > +    I440FXState *i440fx;
> > > >  
> > > >      dev = qdev_create(NULL, "i440FX-pcihost");
> > > >      s = PCI_HOST_BRIDGE(dev);
> > > > +    i440fx = OBJECT_CHECK(I440FXState, dev, "i440FX-pcihost");
> > > >      b = pci_bus_new(dev, NULL, pci_address_space,
> > > >                      address_space_io, 0, TYPE_PCI_BUS);
> > > >      s->bus = b;
> > > >      object_property_add_child(qdev_get_machine(), "i440fx",
> > > >      OBJECT(dev),
> > > >      NULL);
> > > >      qdev_init_nofail(dev);
> > > >  
> > > > +    if (guest_info) {
> > > > +        /* Set PCI window size the way seabios has always done it. */
> > > > +        /* Power of 2 so bios can cover it with a single MTRR */
> > > > +        if (ram_size <= 0x80000000)
> > > > +            guest_info->pci_info.w32.begin = 0x80000000;
> > > > +        else if (ram_size <= 0xc0000000)
> > > > +            guest_info->pci_info.w32.begin = 0xc0000000;
> > > > +        else
> > > > +            guest_info->pci_info.w32.begin = 0xe0000000;
> > > > +
> > > > +        pc_init_pci_info(&guest_info->pci_info,
> > > > +                         pci_hole64_start, i440fx->pci_hole64_size);
> > > > +    }
> > > split brain init of the same data structure make it ugly, would be more
> > > readable
> > > inlined.
> > > 
> > > Wouldn't it be better/cleaner to put PcPciInfo inside of
> > > I440FXState/MCHPCIState
> > > and make QOM based API to access it as in latest ACPI tables series?
> > > 
> > we could event not use PcPciInfo at all if memory_region_find() would
> > return
> > address for non terminating regions (i.e. aliases and containters).
> > then we could get all necessary info from f->pci_hole_64bit and
> > f->pci_hole.
> > 
> > Paolo,
> >  would be following patch acceptable:
> > 
> > diff --git a/memory.c b/memory.c
> > index 757e9a5..0f1fb10 100644
> > --- a/memory.c
> > +++ b/memory.c
> > @@ -1551,6 +1551,7 @@ MemoryRegionSection memory_region_find(MemoryRegion
> > *mr,
> >          addr += root->addr;
> >      }
> >  
> > +    ret.offset_within_region = addr;
> >      as = memory_region_to_address_space(root);
> >      range = addrrange_make(int128_make64(addr), int128_make64(size));
> >      fr = address_space_lookup(as, range);
> > 
> > Then to get PCI hole info all we would need is:
> > 
> > get_pci_hole_info(f, uint64_t *start, uint64_t *end) {
> >   MemoryRegionSection ms =  memory_region_find(f->pci_hole, 0, 1);
> >   sz = memory_region_size(mr);
> >   *start = ms.offset_within_region;
> >   *end = *start + sz;
> > }
> 
> We'll need to get the regions somehow, and all this will
> really break for example if we decide to cover the 64 bit
> holes in 2 regions instead of one, for some reason.
it would break in case PcPciInfo as well, structure would need 
a second w64x2 range for the second region.

> 
> Frankly I don't see any advantages.
Only single authoritative source of this info => No data duplication? 

> 
> 
> > > 
> > > >      d = pci_create_simple(b, 0, device_name);
> > > >      *pi440fx_state = I440FX_PCI_DEVICE(d);
> > > >      f = *pi440fx_state;
> > > > @@ -265,8 +283,8 @@ static PCIBus *i440fx_common_init(const char
> > > > *device_name,
> > > >      memory_region_add_subregion(f->system_memory, pci_hole_start,
> > > >      &f->pci_hole);
> > > >      memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d),
> > > >      "pci-hole64",
> > > >                               f->pci_address_space,
> > > > -                             pci_hole64_start, pci_hole64_size);
> > > > -    if (pci_hole64_size) {
> > > > +                             pci_hole64_start,
> > > > i440fx->pci_hole64_size);
> > > > +    if (i440fx->pci_hole64_size) {
> > > >          memory_region_add_subregion(f->system_memory,
> > > >          pci_hole64_start,
> > > >                                      &f->pci_hole_64bit);
> > > >      }
> > > > @@ -322,8 +340,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> > > > int
> > > > *piix3_devfn,
> > > >                      hwaddr pci_hole_start,
> > > >                      hwaddr pci_hole_size,
> > > >                      hwaddr pci_hole64_start,
> > > > -                    hwaddr pci_hole64_size,
> > > > -                    MemoryRegion *pci_memory, MemoryRegion
> > > > *ram_memory)
> > > > +                    MemoryRegion *pci_memory, MemoryRegion
> > > > *ram_memory,
> > > > +                    PcGuestInfo *guest_info)
> > > >  
> > > >  {
> > > >      PCIBus *b;
> > > > @@ -332,8 +350,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> > > > int
> > > > *piix3_devfn,
> > > >                             piix3_devfn, isa_bus, pic,
> > > >                             address_space_mem, address_space_io,
> > > >                             ram_size,
> > > >                             pci_hole_start, pci_hole_size,
> > > > -                           pci_hole64_start, pci_hole64_size,
> > > > -                           pci_memory, ram_memory);
> > > > +                           pci_hole64_start,
> > > > +                           pci_memory, ram_memory,
> > > > +                           guest_info);
> > > >      return b;
> > > >  }
> > > >  
> > > > @@ -645,6 +664,12 @@ static const char
> > > > *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
> > > >      return "0000";
> > > >  }
> > > >  
> > > > +static Property i440fx_props[] = {
> > > > +    DEFINE_PROP_UINT64("pci_hole64_size", I440FXState,
> > > > +                       pci_hole64_size, 0x1ULL << 31),
> > > > +    DEFINE_PROP_END_OF_LIST(),
> > > > +};
> > > > +
> > > >  static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
> > > >  {
> > > >      DeviceClass *dc = DEVICE_CLASS(klass);
> > > > @@ -655,6 +680,7 @@ static void i440fx_pcihost_class_init(ObjectClass
> > > > *klass, void *data)
> > > >      k->init = i440fx_pcihost_initfn;
> > > >      dc->fw_name = "pci";
> > > >      dc->no_user = 1;
> > > > +    dc->props = i440fx_props;
> > > >  }
> > > >  
> > > >  static const TypeInfo i440fx_pcihost_info = {
> > > > diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> > > > index c761a43..4dd7ca4 100644
> > > > --- a/hw/pci-host/q35.c
> > > > +++ b/hw/pci-host/q35.c
> > > > @@ -73,6 +74,8 @@ static const char
> > > > *q35_host_root_bus_path(PCIHostState
> > > > *host_bridge,
> > > >  static Property mch_props[] = {
> > > >      DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
> > > >                          MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
> > > > +    DEFINE_PROP_UINT64("pci_hole64_size", Q35PCIHost,
> > > > +                       mch.pci_hole64_size, 0x1ULL << 31),
> > > >      DEFINE_PROP_END_OF_LIST(),
> > > >  };
> > > >  
> > > > @@ -250,16 +253,20 @@ static void mch_reset(DeviceState *qdev)
> > > >  static int mch_init(PCIDevice *d)
> > > >  {
> > > >      int i;
> > > > -    hwaddr pci_hole64_size;
> > > >      MCHPCIState *mch = MCH_PCI_DEVICE(d);
> > > >  
> > > > -    /* Leave enough space for the biggest MCFG BAR */
> > > > -    /* TODO: this matches current bios behaviour, but
> > > > -     * it's not a power of two, which means an MTRR
> > > > -     * can't cover it exactly.
> > > > -     */
> > > > -    mch->guest_info->pci_info.w32.begin =
> > > > MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT
> > > > +
> > > > -        MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > > > +    if (mch->guest_info) {
> > > > +        /* Leave enough space for the biggest MCFG BAR */
> > > > +        /* TODO: this matches current bios behaviour, but
> > > > +         * it's not a power of two, which means an MTRR
> > > > +         * can't cover it exactly.
> > > > +         */
> > > > +        mch->guest_info->pci_info.w32.begin =
> > > > MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
> > > > +            MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > > > +        pc_init_pci_info(&mch->guest_info->pci_info,
> > > > +                         0x100000000ULL + mch->above_4g_mem_size,
> > > > +                         mch->pci_hole64_size);
> > > > +    }
> > > >  
> > > >      /* setup pci memory regions */
> > > >      memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
> > > > @@ -268,13 +275,11 @@ static int mch_init(PCIDevice *d)
> > > >                               0x100000000ULL - mch->below_4g_mem_size);
> > > >      memory_region_add_subregion(mch->system_memory,
> > > >      mch->below_4g_mem_size,
> > > >                                  &mch->pci_hole);
> > > > -    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
> > > > -                       ((uint64_t)1 << 62));
> > > >      memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch),
> > > >      "pci-hole64",
> > > >                               mch->pci_address_space,
> > > >                               0x100000000ULL + mch->above_4g_mem_size,
> > > > -                             pci_hole64_size);
> > > > -    if (pci_hole64_size) {
> > > > +                             mch->pci_hole64_size);
> > > > +    if (mch->pci_hole64_size) {
> > > >          memory_region_add_subregion(mch->system_memory,
> > > >                                      0x100000000ULL +
> > > >                                      mch->above_4g_mem_size,
> > > >                                      &mch->pci_hole_64bit);
> > > > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > > > index 0e6f519..72b4456 100644
> > > > --- a/include/hw/i386/pc.h
> > > > +++ b/include/hw/i386/pc.h
> > > > @@ -132,6 +132,9 @@ void pc_acpi_init(const char *default_dsdt);
> > > >  
> > > >  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> > > >                                  ram_addr_t above_4g_mem_size);
> > > > +void pc_init_pci_info(PcPciInfo *pci_info,
> > > > +                      uint64_t pci_hole64_start,
> > > > +                      uint64_t pci_hole64_size);
> > > >  
> > > >  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
> > > >                             const char *kernel_filename,
> > > > @@ -183,9 +186,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> > > > int
> > > > *piix_devfn,
> > > >                      hwaddr pci_hole_start,
> > > >                      hwaddr pci_hole_size,
> > > >                      hwaddr pci_hole64_start,
> > > > -                    hwaddr pci_hole64_size,
> > > >                      MemoryRegion *pci_memory,
> > > > -                    MemoryRegion *ram_memory);
> > > > +                    MemoryRegion *ram_memory,
> > > > +                    PcGuestInfo *guest_info);
> > > >  
> > > >  PCIBus *find_i440fx(void);
> > > >  /* piix4.c */
> > > > diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
> > > > index 3d59ae1..869ecb2 100644
> > > > --- a/include/hw/pci-host/q35.h
> > > > +++ b/include/hw/pci-host/q35.h
> > > > @@ -52,6 +52,7 @@ typedef struct MCHPCIState {
> > > >      MemoryRegion smram_region;
> > > >      MemoryRegion pci_hole;
> > > >      MemoryRegion pci_hole_64bit;
> > > > +    uint64_t pci_hole64_size;
> > > >      uint8_t smm_enabled;
> > > >      ram_addr_t below_4g_mem_size;
> > > >      ram_addr_t above_4g_mem_size;
> > > 
> > > 
> > > 
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
  2013-07-25 15:30       ` Igor Mammedov
@ 2013-07-25 15:35         ` Michael S. Tsirkin
  0 siblings, 0 replies; 16+ messages in thread
From: Michael S. Tsirkin @ 2013-07-25 15:35 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Anthony Liguori, Eduardo Habkost, qemu-devel, Isaku Yamahata,
	Alex Williamson, Gerd Hoffmann, Paolo Bonzini, Laszlo Ersek,
	Andreas Färber, David Gibson

On Thu, Jul 25, 2013 at 11:30:44AM -0400, Igor Mammedov wrote:
> 
> 
> ----- Original Message -----
> > From: "Michael S. Tsirkin" <mst@redhat.com>
> > To: "Igor Mammedov" <imammedo@redhat.com>
> > Cc: "Anthony Liguori" <aliguori@us.ibm.com>, "Eduardo Habkost" <ehabkost@redhat.com>, qemu-devel@nongnu.org, "Isaku
> > Yamahata" <yamahata@valinux.co.jp>, "Alex Williamson" <alex.williamson@redhat.com>, "Gerd Hoffmann"
> > <kraxel@redhat.com>, "Laszlo Ersek" <lersek@redhat.com>, "Andreas Färber" <afaerber@suse.de>, "David Gibson"
> > <david@gibson.dropbear.id.au>, "Paolo Bonzini" <pbonzini@redhat.com>
> > Sent: Thursday, July 25, 2013 5:23:21 PM
> > Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
> > 
> > On Thu, Jul 25, 2013 at 11:16:06AM -0400, Igor Mammedov wrote:
> > > 
> > > 
> > > ----- Original Message -----
> > > > From: "Igor Mammedov" <imammedo@redhat.com>
> > > > To: "Michael S. Tsirkin" <mst@redhat.com>
> > > > Cc: "Anthony Liguori" <aliguori@us.ibm.com>, "Eduardo Habkost"
> > > > <ehabkost@redhat.com>, qemu-devel@nongnu.org, "Isaku
> > > > Yamahata" <yamahata@valinux.co.jp>, "Alex Williamson"
> > > > <alex.williamson@redhat.com>, "Gerd Hoffmann"
> > > > <kraxel@redhat.com>, "Paolo Bonzini" <pbonzini@redhat.com>, "Laszlo
> > > > Ersek" <lersek@redhat.com>, "Andreas Färber"
> > > > <afaerber@suse.de>, "David Gibson" <david@gibson.dropbear.id.au>
> > > > Sent: Thursday, July 25, 2013 3:40:05 PM
> > > > Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default
> > > > 
> > > > On Wed, 24 Jul 2013 09:01:04 +0300
> > > > "Michael S. Tsirkin" <mst@redhat.com> wrote:
> > > > 
> > > > > It turns out that some 32 bit windows guests crash
> > > > > if 64 bit PCI hole size is >2G.
> > > > > Limit it to 2G for piix and q35 by default,
> > > > > add properties to let management override the hole size.
> > > > > 
> > > > > Examples:
> > > > > -global i440FX-pcihost.pci_hole64_size=137438953472
> > > > > 
> > > > > -global q35-pcihost.pci_hole64_size=137438953472
> > > > > 
> > > > > Reported-by: Igor Mammedov <imammedo@redhat.com>,
> > > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > > ---
> > > > >  hw/i386/pc.c              | 35 ++++++++++++++++++++---------------
> > > > >  hw/i386/pc_piix.c         | 14 +-------------
> > > > >  hw/pci-host/piix.c        | 42
> > > > >  ++++++++++++++++++++++++++++++++++--------
> > > > >  hw/pci-host/q35.c         | 29 +++++++++++++++++------------
> > > > >  include/hw/i386/pc.h      |  7 +++++--
> > > > >  include/hw/pci-host/q35.h |  1 +
> > > > >  6 files changed, 78 insertions(+), 50 deletions(-)
> > > > > 
> > > > > diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> > > > > index a7c578f..9cc0fda 100644
> > > > > --- a/hw/i386/pc.c
> > > > > +++ b/hw/i386/pc.c
> > > > > @@ -1072,27 +1072,32 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t
> > > > > below_4g_mem_size,
> > > > >      memset(&guest_info->found_cpus, 0, sizeof guest_info->found_cpus);
> > > > >      qemu_for_each_cpu(pc_set_cpu_guest_info, guest_info);
> > > > >  
> > > > > -    guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
> > > > > -    if (sizeof(hwaddr) == 4) {
> > > > > -        guest_info->pci_info.w64.begin = 0;
> > > > > -        guest_info->pci_info.w64.end = 0;
> > > > > -    } else {
> > > > > +    guest_info_state->machine_done.notify =
> > > > > pc_guest_info_machine_done;
> > > > > +
> > > > > qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > > > > +    return guest_info;
> > > > > +}
> > > > > +
> > > > > +void pc_init_pci_info(PcPciInfo *pci_info,
> > > > > +                      uint64_t pci_hole64_start,
> > > > > +                      uint64_t pci_hole64_size)
> > > > > +{
> > > > > +        pci_info->w32.end = IO_APIC_DEFAULT_ADDRESS;
> > > > weird ident
> > > > 
> > > > > +
> > > > > +        if (pci_hole64_size & ((0x1 << 30) - 1)) {
> > > > > +            error_report("Invalid value for pci_hole64_size: "
> > > > > +                         "must be a multiple of 1G. Rounding up.");
> > > > > +        }
> > > > > +        pci_hole64_size = ROUND_UP(pci_hole64_size, 0x1ULL << 30);
> > > > > +
> > > > if pci_hole64_size is a property it would be better to put check,
> > > > in property setter (custom one) and error out instead of doing fixup,
> > > > lets user fix his wrong cmd line.
> > > >  
> > > > >          /*
> > > > >           * BIOS does not set MTRR entries for the 64 bit window, so no
> > > > >           need to
> > > > >           * align address to power of two.  Align address at 1G, this
> > > > >           makes
> > > > >           sure
> > > > >           * it can be exactly covered with a PAT entry even when using
> > > > >           huge
> > > > >           * pages.
> > > > >           */
> > > > > -        guest_info->pci_info.w64.begin =
> > > > > -            ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL <<
> > > > > 30);
> > > > > -        guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin
> > > > > +
> > > > > -            (0x1ULL << 31);
> > > > > -        assert(guest_info->pci_info.w64.begin <=
> > > > > guest_info->pci_info.w64.end);
> > > > > -    }
> > > > > -
> > > > > -    guest_info_state->machine_done.notify =
> > > > > pc_guest_info_machine_done;
> > > > > -
> > > > > qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
> > > > > -    return guest_info;
> > > > > +        pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL <<
> > > > > 30);
> > > > > +        pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
> > > > > +        assert(pci_info->w64.begin <= pci_info->w64.end);
> > > > >  }
> > > > >  
> > > > >  void pc_acpi_init(const char *default_dsdt)
> > > > > diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> > > > > index 76df42b..da61fa3 100644
> > > > > --- a/hw/i386/pc_piix.c
> > > > > +++ b/hw/i386/pc_piix.c
> > > > > @@ -137,15 +137,6 @@ static void pc_init1(MemoryRegion *system_memory,
> > > > >  
> > > > >      guest_info->has_pci_info = has_pci_info;
> > > > >  
> > > > > -    /* Set PCI window size the way seabios has always done it. */
> > > > > -    /* Power of 2 so bios can cover it with a single MTRR */
> > > > > -    if (ram_size <= 0x80000000)
> > > > > -        guest_info->pci_info.w32.begin = 0x80000000;
> > > > > -    else if (ram_size <= 0xc0000000)
> > > > > -        guest_info->pci_info.w32.begin = 0xc0000000;
> > > > > -    else
> > > > > -        guest_info->pci_info.w32.begin = 0xe0000000;
> > > > > -
> > > > >      /* allocate ram and load rom/bios */
> > > > >      if (!xen_enabled()) {
> > > > >          fw_cfg = pc_memory_init(system_memory,
> > > > > @@ -169,10 +160,7 @@ static void pc_init1(MemoryRegion *system_memory,
> > > > >                                below_4g_mem_size,
> > > > >                                0x100000000ULL - below_4g_mem_size,
> > > > >                                0x100000000ULL + above_4g_mem_size,
> > > > > -                              (sizeof(hwaddr) == 4
> > > > > -                               ? 0
> > > > > -                               : ((uint64_t)1 << 62)),
> > > > > -                              pci_memory, ram_memory);
> > > > > +                              pci_memory, ram_memory, guest_info);
> > > > >      } else {
> > > > >          pci_bus = NULL;
> > > > >          i440fx_state = NULL;
> > > > > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > > > > index 7fb2fb1..963b3d8 100644
> > > > > --- a/hw/pci-host/piix.c
> > > > > +++ b/hw/pci-host/piix.c
> > > > > @@ -40,6 +41,7 @@
> > > > >  
> > > > >  typedef struct I440FXState {
> > > > >      PCIHostState parent_obj;
> > > > > +    uint64_t pci_hole64_size;
> > > > >  } I440FXState;
> > > > >  
> > > > >  #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
> > > > > @@ -234,9 +236,9 @@ static PCIBus *i440fx_common_init(const char
> > > > > *device_name,
> > > > >                                    hwaddr pci_hole_start,
> > > > >                                    hwaddr pci_hole_size,
> > > > >                                    hwaddr pci_hole64_start,
> > > > ^^^ could but to be more consistent if moved to a place where 64 PCI hole
> > > > is
> > > > initialized, replace it with above_4g_memory_size, and let
> > > > i440fx_common_init()
> > > > set it near the place where 64 PCI hole end is set.
> > > > 
> > > > > -                                  hwaddr pci_hole64_size,
> > > > >                                    MemoryRegion *pci_address_space,
> > > > > -                                  MemoryRegion *ram_memory)
> > > > > +                                  MemoryRegion *ram_memory,
> > > > > +                                  PcGuestInfo *guest_info)
> > > > >  {
> > > > >      DeviceState *dev;
> > > > >      PCIBus *b;
> > > > > @@ -245,15 +247,31 @@ static PCIBus *i440fx_common_init(const char
> > > > > *device_name,
> > > > >      PIIX3State *piix3;
> > > > >      PCII440FXState *f;
> > > > >      unsigned i;
> > > > > +    I440FXState *i440fx;
> > > > >  
> > > > >      dev = qdev_create(NULL, "i440FX-pcihost");
> > > > >      s = PCI_HOST_BRIDGE(dev);
> > > > > +    i440fx = OBJECT_CHECK(I440FXState, dev, "i440FX-pcihost");
> > > > >      b = pci_bus_new(dev, NULL, pci_address_space,
> > > > >                      address_space_io, 0, TYPE_PCI_BUS);
> > > > >      s->bus = b;
> > > > >      object_property_add_child(qdev_get_machine(), "i440fx",
> > > > >      OBJECT(dev),
> > > > >      NULL);
> > > > >      qdev_init_nofail(dev);
> > > > >  
> > > > > +    if (guest_info) {
> > > > > +        /* Set PCI window size the way seabios has always done it. */
> > > > > +        /* Power of 2 so bios can cover it with a single MTRR */
> > > > > +        if (ram_size <= 0x80000000)
> > > > > +            guest_info->pci_info.w32.begin = 0x80000000;
> > > > > +        else if (ram_size <= 0xc0000000)
> > > > > +            guest_info->pci_info.w32.begin = 0xc0000000;
> > > > > +        else
> > > > > +            guest_info->pci_info.w32.begin = 0xe0000000;
> > > > > +
> > > > > +        pc_init_pci_info(&guest_info->pci_info,
> > > > > +                         pci_hole64_start, i440fx->pci_hole64_size);
> > > > > +    }
> > > > split brain init of the same data structure make it ugly, would be more
> > > > readable
> > > > inlined.
> > > > 
> > > > Wouldn't it be better/cleaner to put PcPciInfo inside of
> > > > I440FXState/MCHPCIState
> > > > and make QOM based API to access it as in latest ACPI tables series?
> > > > 
> > > we could event not use PcPciInfo at all if memory_region_find() would
> > > return
> > > address for non terminating regions (i.e. aliases and containters).
> > > then we could get all necessary info from f->pci_hole_64bit and
> > > f->pci_hole.
> > > 
> > > Paolo,
> > >  would be following patch acceptable:
> > > 
> > > diff --git a/memory.c b/memory.c
> > > index 757e9a5..0f1fb10 100644
> > > --- a/memory.c
> > > +++ b/memory.c
> > > @@ -1551,6 +1551,7 @@ MemoryRegionSection memory_region_find(MemoryRegion
> > > *mr,
> > >          addr += root->addr;
> > >      }
> > >  
> > > +    ret.offset_within_region = addr;
> > >      as = memory_region_to_address_space(root);
> > >      range = addrrange_make(int128_make64(addr), int128_make64(size));
> > >      fr = address_space_lookup(as, range);
> > > 
> > > Then to get PCI hole info all we would need is:
> > > 
> > > get_pci_hole_info(f, uint64_t *start, uint64_t *end) {
> > >   MemoryRegionSection ms =  memory_region_find(f->pci_hole, 0, 1);
> > >   sz = memory_region_size(mr);
> > >   *start = ms.offset_within_region;
> > >   *end = *start + sz;
> > > }
> > 
> > We'll need to get the regions somehow, and all this will
> > really break for example if we decide to cover the 64 bit
> > holes in 2 regions instead of one, for some reason.
> it would break in case PcPciInfo as well, structure would need 
> a second w64x2 range for the second region.

Not if the regions are adjacent and look contigious to guest.

> > 
> > Frankly I don't see any advantages.
> Only single authoritative source of this info => No data duplication? 

I'm fine with poking at whatever fields necessary to
get this info but I don't think we should have
external users poke at memory regions of devices,
so PcPciInfo is a better API.

How we fill it I don't care much, but let's separate
bugfixes for 1.6 from cleanups (can wait).

> > 
> > 
> > > > 
> > > > >      d = pci_create_simple(b, 0, device_name);
> > > > >      *pi440fx_state = I440FX_PCI_DEVICE(d);
> > > > >      f = *pi440fx_state;
> > > > > @@ -265,8 +283,8 @@ static PCIBus *i440fx_common_init(const char
> > > > > *device_name,
> > > > >      memory_region_add_subregion(f->system_memory, pci_hole_start,
> > > > >      &f->pci_hole);
> > > > >      memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d),
> > > > >      "pci-hole64",
> > > > >                               f->pci_address_space,
> > > > > -                             pci_hole64_start, pci_hole64_size);
> > > > > -    if (pci_hole64_size) {
> > > > > +                             pci_hole64_start,
> > > > > i440fx->pci_hole64_size);
> > > > > +    if (i440fx->pci_hole64_size) {
> > > > >          memory_region_add_subregion(f->system_memory,
> > > > >          pci_hole64_start,
> > > > >                                      &f->pci_hole_64bit);
> > > > >      }
> > > > > @@ -322,8 +340,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> > > > > int
> > > > > *piix3_devfn,
> > > > >                      hwaddr pci_hole_start,
> > > > >                      hwaddr pci_hole_size,
> > > > >                      hwaddr pci_hole64_start,
> > > > > -                    hwaddr pci_hole64_size,
> > > > > -                    MemoryRegion *pci_memory, MemoryRegion
> > > > > *ram_memory)
> > > > > +                    MemoryRegion *pci_memory, MemoryRegion
> > > > > *ram_memory,
> > > > > +                    PcGuestInfo *guest_info)
> > > > >  
> > > > >  {
> > > > >      PCIBus *b;
> > > > > @@ -332,8 +350,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> > > > > int
> > > > > *piix3_devfn,
> > > > >                             piix3_devfn, isa_bus, pic,
> > > > >                             address_space_mem, address_space_io,
> > > > >                             ram_size,
> > > > >                             pci_hole_start, pci_hole_size,
> > > > > -                           pci_hole64_start, pci_hole64_size,
> > > > > -                           pci_memory, ram_memory);
> > > > > +                           pci_hole64_start,
> > > > > +                           pci_memory, ram_memory,
> > > > > +                           guest_info);
> > > > >      return b;
> > > > >  }
> > > > >  
> > > > > @@ -645,6 +664,12 @@ static const char
> > > > > *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
> > > > >      return "0000";
> > > > >  }
> > > > >  
> > > > > +static Property i440fx_props[] = {
> > > > > +    DEFINE_PROP_UINT64("pci_hole64_size", I440FXState,
> > > > > +                       pci_hole64_size, 0x1ULL << 31),
> > > > > +    DEFINE_PROP_END_OF_LIST(),
> > > > > +};
> > > > > +
> > > > >  static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
> > > > >  {
> > > > >      DeviceClass *dc = DEVICE_CLASS(klass);
> > > > > @@ -655,6 +680,7 @@ static void i440fx_pcihost_class_init(ObjectClass
> > > > > *klass, void *data)
> > > > >      k->init = i440fx_pcihost_initfn;
> > > > >      dc->fw_name = "pci";
> > > > >      dc->no_user = 1;
> > > > > +    dc->props = i440fx_props;
> > > > >  }
> > > > >  
> > > > >  static const TypeInfo i440fx_pcihost_info = {
> > > > > diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> > > > > index c761a43..4dd7ca4 100644
> > > > > --- a/hw/pci-host/q35.c
> > > > > +++ b/hw/pci-host/q35.c
> > > > > @@ -73,6 +74,8 @@ static const char
> > > > > *q35_host_root_bus_path(PCIHostState
> > > > > *host_bridge,
> > > > >  static Property mch_props[] = {
> > > > >      DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
> > > > >                          MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
> > > > > +    DEFINE_PROP_UINT64("pci_hole64_size", Q35PCIHost,
> > > > > +                       mch.pci_hole64_size, 0x1ULL << 31),
> > > > >      DEFINE_PROP_END_OF_LIST(),
> > > > >  };
> > > > >  
> > > > > @@ -250,16 +253,20 @@ static void mch_reset(DeviceState *qdev)
> > > > >  static int mch_init(PCIDevice *d)
> > > > >  {
> > > > >      int i;
> > > > > -    hwaddr pci_hole64_size;
> > > > >      MCHPCIState *mch = MCH_PCI_DEVICE(d);
> > > > >  
> > > > > -    /* Leave enough space for the biggest MCFG BAR */
> > > > > -    /* TODO: this matches current bios behaviour, but
> > > > > -     * it's not a power of two, which means an MTRR
> > > > > -     * can't cover it exactly.
> > > > > -     */
> > > > > -    mch->guest_info->pci_info.w32.begin =
> > > > > MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT
> > > > > +
> > > > > -        MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > > > > +    if (mch->guest_info) {
> > > > > +        /* Leave enough space for the biggest MCFG BAR */
> > > > > +        /* TODO: this matches current bios behaviour, but
> > > > > +         * it's not a power of two, which means an MTRR
> > > > > +         * can't cover it exactly.
> > > > > +         */
> > > > > +        mch->guest_info->pci_info.w32.begin =
> > > > > MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
> > > > > +            MCH_HOST_BRIDGE_PCIEXBAR_MAX;
> > > > > +        pc_init_pci_info(&mch->guest_info->pci_info,
> > > > > +                         0x100000000ULL + mch->above_4g_mem_size,
> > > > > +                         mch->pci_hole64_size);
> > > > > +    }
> > > > >  
> > > > >      /* setup pci memory regions */
> > > > >      memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
> > > > > @@ -268,13 +275,11 @@ static int mch_init(PCIDevice *d)
> > > > >                               0x100000000ULL - mch->below_4g_mem_size);
> > > > >      memory_region_add_subregion(mch->system_memory,
> > > > >      mch->below_4g_mem_size,
> > > > >                                  &mch->pci_hole);
> > > > > -    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
> > > > > -                       ((uint64_t)1 << 62));
> > > > >      memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch),
> > > > >      "pci-hole64",
> > > > >                               mch->pci_address_space,
> > > > >                               0x100000000ULL + mch->above_4g_mem_size,
> > > > > -                             pci_hole64_size);
> > > > > -    if (pci_hole64_size) {
> > > > > +                             mch->pci_hole64_size);
> > > > > +    if (mch->pci_hole64_size) {
> > > > >          memory_region_add_subregion(mch->system_memory,
> > > > >                                      0x100000000ULL +
> > > > >                                      mch->above_4g_mem_size,
> > > > >                                      &mch->pci_hole_64bit);
> > > > > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > > > > index 0e6f519..72b4456 100644
> > > > > --- a/include/hw/i386/pc.h
> > > > > +++ b/include/hw/i386/pc.h
> > > > > @@ -132,6 +132,9 @@ void pc_acpi_init(const char *default_dsdt);
> > > > >  
> > > > >  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> > > > >                                  ram_addr_t above_4g_mem_size);
> > > > > +void pc_init_pci_info(PcPciInfo *pci_info,
> > > > > +                      uint64_t pci_hole64_start,
> > > > > +                      uint64_t pci_hole64_size);
> > > > >  
> > > > >  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
> > > > >                             const char *kernel_filename,
> > > > > @@ -183,9 +186,9 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> > > > > int
> > > > > *piix_devfn,
> > > > >                      hwaddr pci_hole_start,
> > > > >                      hwaddr pci_hole_size,
> > > > >                      hwaddr pci_hole64_start,
> > > > > -                    hwaddr pci_hole64_size,
> > > > >                      MemoryRegion *pci_memory,
> > > > > -                    MemoryRegion *ram_memory);
> > > > > +                    MemoryRegion *ram_memory,
> > > > > +                    PcGuestInfo *guest_info);
> > > > >  
> > > > >  PCIBus *find_i440fx(void);
> > > > >  /* piix4.c */
> > > > > diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
> > > > > index 3d59ae1..869ecb2 100644
> > > > > --- a/include/hw/pci-host/q35.h
> > > > > +++ b/include/hw/pci-host/q35.h
> > > > > @@ -52,6 +52,7 @@ typedef struct MCHPCIState {
> > > > >      MemoryRegion smram_region;
> > > > >      MemoryRegion pci_hole;
> > > > >      MemoryRegion pci_hole_64bit;
> > > > > +    uint64_t pci_hole64_size;
> > > > >      uint8_t smm_enabled;
> > > > >      ram_addr_t below_4g_mem_size;
> > > > >      ram_addr_t above_4g_mem_size;
> > > > 
> > > > 
> > > > 
> > 

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2013-07-25 15:34 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-24  6:01 [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by default Michael S. Tsirkin
2013-07-24  6:50 ` Andreas Färber
2013-07-24  7:01 ` Gerd Hoffmann
2013-07-24  9:51   ` Michael S. Tsirkin
2013-07-24 10:08     ` Igor Mammedov
2013-07-24 12:59     ` Paolo Bonzini
2013-07-24 13:14       ` Michael S. Tsirkin
2013-07-24 13:18         ` Paolo Bonzini
2013-07-24 14:07           ` Michael S. Tsirkin
2013-07-24 13:00     ` Gerd Hoffmann
2013-07-25 13:40 ` Igor Mammedov
2013-07-25 15:03   ` Michael S. Tsirkin
2013-07-25 15:16   ` Igor Mammedov
2013-07-25 15:23     ` Michael S. Tsirkin
2013-07-25 15:30       ` Igor Mammedov
2013-07-25 15:35         ` Michael S. Tsirkin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.