summary refs log tree commit diff stats
path: root/hw/pci-host
diff options
context:
space:
mode:
authorIgor Mammedov <imammedo@redhat.com>2013-07-29 16:47:57 +0200
committerAnthony Liguori <aliguori@us.ibm.com>2013-07-29 19:33:34 -0500
commit398489018183d613306ab022653552247d93919f (patch)
tree65bd612a22d9f0c3d9d92d00ed3f9dce2b9712a2 /hw/pci-host
parente8cd45c78f53501e75bd455140da63d1b7ed3685 (diff)
downloadfocaccia-qemu-398489018183d613306ab022653552247d93919f.tar.gz
focaccia-qemu-398489018183d613306ab022653552247d93919f.zip
pc: limit 64 bit hole to 2G by default
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.
User may override default 64-bit PCI hole size by
using "pci-hole64-size" property.

Examples:
-global i440FX-pcihost.pci-hole64-size=4G

-global q35-pcihost.pci-hole64-size=4G

Reported-by: Igor Mammedov <imammedo@redhat.com>,
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Message-id: 1375109277-25561-8-git-send-email-imammedo@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/pci-host')
-rw-r--r--hw/pci-host/piix.c95
-rw-r--r--hw/pci-host/q35.c88
2 files changed, 163 insertions, 20 deletions
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 3f539ec140..dc1718fe30 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -32,6 +32,8 @@
 #include "hw/xen/xen.h"
 #include "hw/pci-host/pam.h"
 #include "sysemu/sysemu.h"
+#include "hw/i386/ioapic.h"
+#include "qapi/visitor.h"
 
 /*
  * I440FX chipset data sheet.
@@ -44,6 +46,8 @@
 
 typedef struct I440FXState {
     PCIHostState parent_obj;
+    PcPciInfo pci_info;
+    uint64_t pci_hole64_size;
 } I440FXState;
 
 #define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
@@ -207,14 +211,71 @@ static const VMStateDescription vmstate_i440fx = {
     }
 };
 
+static void i440fx_pcihost_get_pci_hole_start(Object *obj, Visitor *v,
+                                              void *opaque, const char *name,
+                                              Error **errp)
+{
+    I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
+    uint32_t value = s->pci_info.w32.begin;
+
+    visit_type_uint32(v, &value, name, errp);
+}
+
+static void i440fx_pcihost_get_pci_hole_end(Object *obj, Visitor *v,
+                                            void *opaque, const char *name,
+                                            Error **errp)
+{
+    I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
+    uint32_t value = s->pci_info.w32.end;
+
+    visit_type_uint32(v, &value, name, errp);
+}
+
+static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v,
+                                                void *opaque, const char *name,
+                                                Error **errp)
+{
+    I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
+
+    visit_type_uint64(v, &s->pci_info.w64.begin, name, errp);
+}
+
+static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v,
+                                              void *opaque, const char *name,
+                                              Error **errp)
+{
+    I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
+
+    visit_type_uint64(v, &s->pci_info.w64.end, name, errp);
+}
+
 static void i440fx_pcihost_initfn(Object *obj)
 {
     PCIHostState *s = PCI_HOST_BRIDGE(obj);
+    I440FXState *d = I440FX_PCI_HOST_BRIDGE(obj);
 
     memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s,
                           "pci-conf-idx", 4);
     memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s,
                           "pci-conf-data", 4);
+
+    object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int",
+                        i440fx_pcihost_get_pci_hole_start,
+                        NULL, NULL, NULL, NULL);
+
+    object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int",
+                        i440fx_pcihost_get_pci_hole_end,
+                        NULL, NULL, NULL, NULL);
+
+    object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int",
+                        i440fx_pcihost_get_pci_hole64_start,
+                        NULL, NULL, NULL, NULL);
+
+    object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int",
+                        i440fx_pcihost_get_pci_hole64_end,
+                        NULL, NULL, NULL, NULL);
+
+    d->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
 }
 
 static void i440fx_pcihost_realize(DeviceState *dev, Error **errp)
@@ -247,8 +308,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
                     ram_addr_t ram_size,
                     hwaddr pci_hole_start,
                     hwaddr pci_hole_size,
-                    hwaddr pci_hole64_start,
-                    hwaddr pci_hole64_size,
+                    ram_addr_t above_4g_mem_size,
                     MemoryRegion *pci_address_space,
                     MemoryRegion *ram_memory)
 {
@@ -259,6 +319,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
     PIIX3State *piix3;
     PCII440FXState *f;
     unsigned i;
+    I440FXState *i440fx;
 
     dev = qdev_create(NULL, TYPE_I440FX_PCI_HOST_BRIDGE);
     s = PCI_HOST_BRIDGE(dev);
@@ -274,14 +335,31 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
     f->system_memory = address_space_mem;
     f->pci_address_space = pci_address_space;
     f->ram_memory = ram_memory;
+
+    i440fx = I440FX_PCI_HOST_BRIDGE(dev);
+    /* 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) {
+        i440fx->pci_info.w32.begin = 0x80000000;
+    } else if (ram_size <= 0xc0000000) {
+        i440fx->pci_info.w32.begin = 0xc0000000;
+    } else {
+        i440fx->pci_info.w32.begin = 0xe0000000;
+    }
+
     memory_region_init_alias(&f->pci_hole, OBJECT(d), "pci-hole", f->pci_address_space,
                              pci_hole_start, pci_hole_size);
     memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
+
+    pc_init_pci64_hole(&i440fx->pci_info, 0x100000000ULL + above_4g_mem_size,
+                       i440fx->pci_hole64_size);
     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) {
-        memory_region_add_subregion(f->system_memory, pci_hole64_start,
+                             i440fx->pci_info.w64.begin,
+                             i440fx->pci_hole64_size);
+    if (i440fx->pci_hole64_size) {
+        memory_region_add_subregion(f->system_memory,
+                                    i440fx->pci_info.w64.begin,
                                     &f->pci_hole_64bit);
     }
     memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
@@ -629,6 +707,12 @@ static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
     return "0000";
 }
 
+static Property i440fx_props[] = {
+    DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState,
+                     pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -638,6 +722,7 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
     dc->realize = i440fx_pcihost_realize;
     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 69234de871..12314d8dfe 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -29,6 +29,7 @@
  */
 #include "hw/hw.h"
 #include "hw/pci-host/q35.h"
+#include "qapi/visitor.h"
 
 /****************************************************************************
  * Q35 host
@@ -64,9 +65,49 @@ static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
     return "0000";
 }
 
+static void q35_host_get_pci_hole_start(Object *obj, Visitor *v,
+                                        void *opaque, const char *name,
+                                        Error **errp)
+{
+    Q35PCIHost *s = Q35_HOST_DEVICE(obj);
+    uint32_t value = s->mch.pci_info.w32.begin;
+
+    visit_type_uint32(v, &value, name, errp);
+}
+
+static void q35_host_get_pci_hole_end(Object *obj, Visitor *v,
+                                      void *opaque, const char *name,
+                                      Error **errp)
+{
+    Q35PCIHost *s = Q35_HOST_DEVICE(obj);
+    uint32_t value = s->mch.pci_info.w32.end;
+
+    visit_type_uint32(v, &value, name, errp);
+}
+
+static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v,
+                                          void *opaque, const char *name,
+                                          Error **errp)
+{
+    Q35PCIHost *s = Q35_HOST_DEVICE(obj);
+
+    visit_type_uint64(v, &s->mch.pci_info.w64.begin, name, errp);
+}
+
+static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v,
+                                        void *opaque, const char *name,
+                                        Error **errp)
+{
+    Q35PCIHost *s = Q35_HOST_DEVICE(obj);
+
+    visit_type_uint64(v, &s->mch.pci_info.w64.end, name, errp);
+}
+
 static Property mch_props[] = {
     DEFINE_PROP_UINT64("MCFG", Q35PCIHost, parent_obj.base_addr,
                         MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
+    DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost,
+                     mch.pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -96,6 +137,31 @@ static void q35_host_initfn(Object *obj)
     object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL);
     qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0));
     qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false);
+
+    object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_START, "int",
+                        q35_host_get_pci_hole_start,
+                        NULL, NULL, NULL, NULL);
+
+    object_property_add(obj, PCI_HOST_PROP_PCI_HOLE_END, "int",
+                        q35_host_get_pci_hole_end,
+                        NULL, NULL, NULL, NULL);
+
+    object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_START, "int",
+                        q35_host_get_pci_hole64_start,
+                        NULL, NULL, NULL, NULL);
+
+    object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int",
+                        q35_host_get_pci_hole64_end,
+                        NULL, NULL, NULL, NULL);
+
+    /* 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.
+     */
+    s->mch.pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
+        MCH_HOST_BRIDGE_PCIEXBAR_MAX;
+    s->mch.pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
 }
 
 static const TypeInfo q35_host_info = {
@@ -253,17 +319,8 @@ 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;
-
     /* setup pci memory regions */
     memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
                              mch->pci_address_space,
@@ -271,15 +328,16 @@ 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));
+
+    pc_init_pci64_hole(&mch->pci_info, 0x100000000ULL + mch->above_4g_mem_size,
+                       mch->pci_hole64_size);
     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_info.w64.begin,
+                             mch->pci_hole64_size);
+    if (mch->pci_hole64_size) {
         memory_region_add_subregion(mch->system_memory,
-                                    0x100000000ULL + mch->above_4g_mem_size,
+                                    mch->pci_info.w64.begin,
                                     &mch->pci_hole_64bit);
     }
     /* smram */