pc: limit 64 bit hole to 2G by default
PATCH 1/1 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,
add properties to let management override the hole size.
Examples:
-global i440FX-pcihost.pci_hole64_size=137438953472
-global q35-pcihost.pci_hole64_size=137438953472
--- 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(-)
hw/i386/pc.c +20 -15
@@ -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)
hw/i386/pc_piix.c +1 -13
@@ -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 ;
hw/pci-host/piix.c +33 -8
99 lines not on this page · raw message
hw/pci-host/q35.c +16 -12
@@ -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);
include/hw/i386/pc.h +5 -2
@@ -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 */
include/hw/pci-host/q35.h +1 -0
@@ -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;
Signature · 1 line
MST
Hi,
Am 24.07.2013 08:01, schrieb Michael S. Tsirkin:
Quoted 20 lines
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:
(quoted diff) +0
-2-global i440FX-pcihost.pci_hole64_size=137438953472 -global q35-pcihost.pci_hole64_size=137438953472Reported-by Igor Mammedov <[email protected]>,Signed-off-by Michael S. Tsirkin <[email protected]>--- 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(-)
[...]
Quoted 25 lines
hw/pci-host/piix.c +3
-2@@ -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;
hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char *device_name, · line 254
Quoted 8 lines
hw/pci-host/piix.c +2
-0@@ -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.
Quoted 58 lines
hw/pci-host/piix.c +21
-6b =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; }
hw/pci-host/piix.c static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge, · line 668
Quoted 5 lines
hw/pci-host/piix.c +2
-0@@ -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.
Quoted 20 lines
hw/pci-host/piix.c +5
-0+ 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 = {hw/pci-host/q35.c +0
-0
hw/pci-host/q35.c static const char *q35_host_root_bus_path(PCIHostState *host_bridge, · line 81
Quoted 8 lines
hw/pci-host/q35.c +2
-0@@ -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
Signature · 2 lines
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
Quoted 2 lines · Michael S. Tsirkin
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.
Quoted 5 lines
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
Quoted 9 lines · Gerd Hoffmann
Quoted 2 lines · Michael S. Tsirkin
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.
Quoted 11 lines
Quoted 5 lines
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=137438953472Do 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?
Quoted 22 lines · On Wed, 24 Jul 2013 12:51:16 +0300 "Michael S. Tsirkin" <[email protected]> wrote:
Quoted 9 lines · Gerd Hoffmann
Quoted 2 lines · Michael S. Tsirkin
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.
Quoted 9 lines
Quoted 5 lines
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=137438953472Do we really want specify this in bytes? Using megabytes or gigabytes instead looks more sane to me.
Quoted 8 lines
Quoted 2 lines
cheers,
GerdI 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
Il 24/07/2013 11:51, Michael S. Tsirkin ha scritto:
Quoted 5 lines
Quoted 3 lines
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
Quoted 8 lines · Paolo Bonzini
Il 24/07/2013 11:51, Michael S. Tsirkin ha scritto:
Quoted 5 lines
Quoted 3 lines
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.
Quoted 4 lines
(Also, what happens if you do -global i440FX-pcihost.pci_hole64_size=0?
Does that return a_CRSwith only the 32-bit hole)?Paolo
Yes.
Il 24/07/2013 15:14, Michael S. Tsirkin ha scritto:
Quoted 6 lines · Paolo Bonzini
Quoted 5 lines
Il 24/07/2013 11:51, Michael S. Tsirkin ha scritto:
Quoted 4 lines
Quoted 3 lines
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.
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
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
Quoted 12 lines
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.
Quoted 4 lines
(Also, what happens if you do -global i440FX-pcihost.pci_hole64_size=0?
Does that return a_CRSwith only the 32-bit hole)?Paolo
Yes.
Quoted 11 lines · Paolo Bonzini
Il 24/07/2013 15:14, Michael S. Tsirkin ha scritto:
Quoted 10 lines · Paolo Bonzini
Quoted 8 lines
Il 24/07/2013 11:51, Michael S. Tsirkin ha scritto:
Quoted 5 lines
Quoted 3 lines
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?
Quoted 7 lines
Quoted 2 lines
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.
Quoted 12 lines
Quoted 12 lines
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.
Quoted 4 lines
(Also, what happens if you do -global i440FX-pcihost.pci_hole64_size=0?
Does that return a_CRSwith only the 32-bit hole)?Paolo
Yes.
Quoted 5 lines · Michael S. Tsirkin
Quoted 4 lines · Gerd Hoffmann
Quoted 2 lines · Michael S. Tsirkin
It turns out that some 32 bit windows guests crash if 64 bit PCI hole size is >2G.
Quoted 7 lines
Quoted 5 lines
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.
Quoted 3 lines
I intend to send a patch to properties that allows writing "size=1G" instead.
Will this address your comment?
Sounds good.
cheers,
Gerd
Quoted 34 lines · On Wed, 24 Jul 2013 09:01:04 +0300 "Michael S. Tsirkin" <[email protected]> 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:
(quoted diff) +0
-2-global i440FX-pcihost.pci_hole64_size=137438953472 -global q35-pcihost.pci_hole64_size=137438953472Reported-by Igor Mammedov <[email protected]>,Signed-off-by Michael S. Tsirkin <[email protected]>--- 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(-)hw/i386/pc.c +0
-5@@ -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 {
hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, · line 1084
Quoted 10 lines
hw/i386/pc.c +10
-0+ 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
hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, · line 1091
Quoted 7 lines
hw/i386/pc.c +7
-0+ +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.
Quoted 67 lines
hw/i386/pc.c +3
-10/* * 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)hw/i386/pc_piix.c +1
-13@@ -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 ;hw/pci-host/piix.c +1
-0@@ -40,6 +41,7 @@typedef struct I440FXState {PCIHostState parent_obj; +uint64_t pci_hole64_size; }I440FXState ;#define PIIX_NUM_PIC_IRQS 16/* i8259 * 2 */
hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char *device_name, · line 238
Quoted 3 lines
hw/pci-host/piix.c +0
-0@@ -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.
Quoted 26 lines
hw/pci-host/piix.c +7
-2-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 */
hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char *device_name, · line 273
Quoted 10 lines
hw/pci-host/piix.c +10
-0+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?
Quoted 154 lines
hw/pci-host/piix.c +14
-6d =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 = {hw/pci-host/q35.c +16
-12@@ -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);include/hw/i386/pc.h +5
-2@@ -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 */ include/hw/pci-host/q35.h +1
-0@@ -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;
Quoted 32 lines · Igor Mammedov
Quoted 29 lines · On Wed, 24 Jul 2013 09:01:04 +0300 "Michael S. Tsirkin" <[email protected]> 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:
(quoted diff) +0
-2-global i440FX-pcihost.pci_hole64_size=137438953472 -global q35-pcihost.pci_hole64_size=137438953472Reported-by Igor Mammedov <[email protected]>,Signed-off-by Michael S. Tsirkin <[email protected]>--- 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(-)hw/i386/pc.c +0
-0@@ -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);
Quoted 16 lines
Quoted 5 lines
hw/i386/pc.c +0
-5- 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 {hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, · line 1084
Quoted 10 lines
hw/i386/pc.c +10
-0+ 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.
Quoted 10 lines
hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, · line 1091
Quoted 7 lines
hw/i386/pc.c +7
-0+ +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_sizeis 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.
Quoted 65 lines
Quoted 65 lines
hw/i386/pc.c +3
-10/* * 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)hw/i386/pc_piix.c +1
-13@@ -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 ;hw/pci-host/piix.c +1
-0@@ -40,6 +41,7 @@typedef struct I440FXState {PCIHostState parent_obj; +uint64_t pci_hole64_size; }I440FXState ;
Quoted 8 lines
hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char *device_name, · line 238
Quoted 5 lines
hw/pci-host/piix.c +0
-0#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 leti440fx_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.
Quoted 23 lines
Quoted 23 lines
hw/pci-host/piix.c +4
-2-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);
Quoted 15 lines
hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char *device_name, · line 273
Quoted 13 lines
hw/pci-host/piix.c +13
-0+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.
Quoted 3 lines
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.
Quoted 154 lines
Quoted 154 lines
hw/pci-host/piix.c +14
-6d =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 = {hw/pci-host/q35.c +16
-12@@ -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);include/hw/i386/pc.h +5
-2@@ -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 */ include/hw/pci-host/q35.h +1
-0@@ -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;
----- Original Message -----
Quoted 191 lines
From: "Igor Mammedov" <[email protected]>
To: "Michael S. Tsirkin" <[email protected]>
Cc: "Anthony Liguori" <[email protected]>, "Eduardo Habkost" <[email protected]>, [email protected], "Isaku Yamahata" <[email protected]>, "Alex Williamson" <[email protected]>, "Gerd Hoffmann" <[email protected]>, "Paolo Bonzini" <[email protected]>, "Laszlo Ersek" <[email protected]>, "Andreas Färber" <[email protected]>, "David Gibson" <[email protected]>
Sent: Thursday, July 25, 2013 3:40:05 PM
Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by defaultQuoted 35 lines · On Wed, 24 Jul 2013 09:01:04 +0300 "Michael S. Tsirkin" <[email protected]> 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:
(quoted diff) +0
-2-global i440FX-pcihost.pci_hole64_size=137438953472 -global q35-pcihost.pci_hole64_size=137438953472Reported-by Igor Mammedov <[email protected]>,Signed-off-by Michael S. Tsirkin <[email protected]>--- 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(-)hw/i386/pc.c +0
-5@@ -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 {hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t · line 1085
Quoted 10 lines
hw/i386/pc.c +10
-0+ 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
hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t · line 1092
Quoted 7 lines
hw/i386/pc.c +7
-0+ +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_sizeis 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.Quoted 70 lines
hw/i386/pc.c +3
-10/* * 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)hw/i386/pc_piix.c +1
-13@@ -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 ;hw/pci-host/piix.c +1
-0@@ -40,6 +41,7 @@typedef struct I440FXState {PCIHostState parent_obj; +uint64_t pci_hole64_size; }I440FXState ;#define PIIX_NUM_PIC_IRQS 16/* i8259 * 2 */ hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char · line 239
Quoted 4 lines
hw/pci-host/piix.c +0
-0@@ -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 leti440fx_common_init()
set it near the place where 64 PCI hole end is set.Quoted 28 lines
hw/pci-host/piix.c +2
-2-hwaddr pci_hole64_size, MemoryRegion *pci_address_space, - MemoryRegion *ram_memory) + MemoryRegion *ram_memory, + PcGuestInfo *guest_info) {DeviceState *dev;PCIBus *b;hw/pci-host/piix.c +5
-0@@ -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 */ hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char · line 275
Quoted 10 lines
hw/pci-host/piix.c +10
-0+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.
Quoted 4 lines
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:
memory.c +1 -0
@@ -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;
}
Quoted 171 lines
Quoted 168 lines
hw/pci-host/piix.c +2
-2d =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); }hw/pci-host/piix.c +2
-2@@ -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;hw/pci-host/piix.c +9
-2@@ -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);hw/pci-host/piix.c +1
-0@@ -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= {hw/pci-host/q35.c +10
-8@@ -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+hw/pci-host/q35.c +7
-4+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);include/hw/i386/pc.h +5
-2@@ -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*/include/hw/pci-host/q35.h +1
-0@@ -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;
Quoted 218 lines · Igor Mammedov
----- Original Message -----
Quoted 191 lines
From: "Igor Mammedov" <[email protected]>
To: "Michael S. Tsirkin" <[email protected]>
Cc: "Anthony Liguori" <[email protected]>, "Eduardo Habkost" <[email protected]>, [email protected], "Isaku Yamahata" <[email protected]>, "Alex Williamson" <[email protected]>, "Gerd Hoffmann" <[email protected]>, "Paolo Bonzini" <[email protected]>, "Laszlo Ersek" <[email protected]>, "Andreas Färber" <[email protected]>, "David Gibson" <[email protected]>
Sent: Thursday, July 25, 2013 3:40:05 PM
Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by defaultQuoted 35 lines · On Wed, 24 Jul 2013 09:01:04 +0300 "Michael S. Tsirkin" <[email protected]> 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:
(quoted diff) +0
-2-global i440FX-pcihost.pci_hole64_size=137438953472 -global q35-pcihost.pci_hole64_size=137438953472Reported-by Igor Mammedov <[email protected]>,Signed-off-by Michael S. Tsirkin <[email protected]>--- 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(-)hw/i386/pc.c +0
-5@@ -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 {hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t · line 1085
Quoted 10 lines
hw/i386/pc.c +10
-0+ 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
hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t · line 1092
Quoted 7 lines
hw/i386/pc.c +7
-0+ +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_sizeis 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.Quoted 70 lines
hw/i386/pc.c +3
-10/* * 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)hw/i386/pc_piix.c +1
-13@@ -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 ;hw/pci-host/piix.c +1
-0@@ -40,6 +41,7 @@typedef struct I440FXState {PCIHostState parent_obj; +uint64_t pci_hole64_size; }I440FXState ;#define PIIX_NUM_PIC_IRQS 16/* i8259 * 2 */ hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char · line 239
Quoted 4 lines
hw/pci-host/piix.c +0
-0@@ -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 leti440fx_common_init()
set it near the place where 64 PCI hole end is set.Quoted 28 lines
hw/pci-host/piix.c +2
-2-hwaddr pci_hole64_size, MemoryRegion *pci_address_space, - MemoryRegion *ram_memory) + MemoryRegion *ram_memory, + PcGuestInfo *guest_info) {DeviceState *dev;PCIBus *b;hw/pci-host/piix.c +5
-0@@ -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 */ hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char · line 275
Quoted 10 lines
hw/pci-host/piix.c +10
-0+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.Quoted 4 lines
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 fromf->pci_hole_64bitandf->pci_hole.Paolo,
would be following patch acceptable:memory.c +1
-0@@ -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);
Quoted 8 lines
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.
Quoted 171 lines
Quoted 171 lines
Quoted 168 lines
hw/pci-host/piix.c +2
-2d =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); }hw/pci-host/piix.c +2
-2@@ -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;hw/pci-host/piix.c +9
-2@@ -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);hw/pci-host/piix.c +1
-0@@ -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= {hw/pci-host/q35.c +10
-8@@ -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+hw/pci-host/q35.c +7
-4+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);include/hw/i386/pc.h +5
-2@@ -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*/include/hw/pci-host/q35.h +1
-0@@ -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;
----- Original Message -----
Quoted 248 lines
From: "Michael S. Tsirkin" <[email protected]>
To: "Igor Mammedov" <[email protected]>
Cc: "Anthony Liguori" <[email protected]>, "Eduardo Habkost" <[email protected]>, [email protected], "Isaku Yamahata" <[email protected]>, "Alex Williamson" <[email protected]>, "Gerd Hoffmann" <[email protected]>, "Laszlo Ersek" <[email protected]>, "Andreas Färber" <[email protected]>, "David Gibson" <[email protected]>, "Paolo Bonzini" <[email protected]>
Sent: Thursday, July 25, 2013 5:23:21 PM
Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by defaultQuoted 238 lines · Igor Mammedov
----- Original Message -----
Quoted 206 lines
From: "Igor Mammedov" <[email protected]>
To: "Michael S. Tsirkin" <[email protected]>
Cc: "Anthony Liguori" <[email protected]>, "Eduardo Habkost" <[email protected]>, [email protected], "Isaku Yamahata" <[email protected]>, "Alex Williamson" <[email protected]>, "Gerd Hoffmann" <[email protected]>, "Paolo Bonzini" <[email protected]>, "Laszlo Ersek" <[email protected]>, "Andreas Färber" <[email protected]>, "David Gibson" <[email protected]>
Sent: Thursday, July 25, 2013 3:40:05 PM
Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by defaultQuoted 38 lines · On Wed, 24 Jul 2013 09:01:04 +0300 "Michael S. Tsirkin" <[email protected]> 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:
(quoted diff) +0
-2-global i440FX-pcihost.pci_hole64_size=137438953472 -global q35-pcihost.pci_hole64_size=137438953472Reported-by Igor Mammedov <[email protected]>,Signed-off-by Michael S. Tsirkin <[email protected]>--- 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(-)hw/i386/pc.c +1
-5@@ -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;hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t · line 1087
Quoted 10 lines
hw/i386/pc.c +9
-0+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
hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t · line 1094
Quoted 7 lines
hw/i386/pc.c +7
-0+ +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_sizeis 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.Quoted 77 lines
hw/i386/pc.c +0
-2/* * 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);
hw/i386/pc.c +1
-3- 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);hw/i386/pc.c +0
-3- } - - guest_info_state->machine_done.notify =
pc_guest_info_machine_done;
-qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);hw/i386/pc.c +1
-1-return guest_info; + pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL <<30);
hw/i386/pc.c +2
-0+ 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)hw/i386/pc_piix.c +1
-13@@ -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 ;hw/pci-host/piix.c +1
-0@@ -40,6 +41,7 @@typedef struct I440FXState {PCIHostState parent_obj; +uint64_t pci_hole64_size; }I440FXState ;#define PIIX_NUM_PIC_IRQS 16/* i8259 * 2 */ hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char · line 239
Quoted 4 lines
hw/pci-host/piix.c +0
-0@@ -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 withabove_4g_memory_size, and leti440fx_common_init()
set it near the place where 64 PCI hole end is set.Quoted 29 lines
hw/pci-host/piix.c +2
-2-hwaddr pci_hole64_size, MemoryRegion *pci_address_space, - MemoryRegion *ram_memory) + MemoryRegion *ram_memory, + PcGuestInfo *guest_info) {DeviceState *dev;PCIBus *b;hw/pci-host/piix.c +5
-0@@ -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 */ hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char · line 276
Quoted 10 lines
hw/pci-host/piix.c +10
-0+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.Quoted 4 lines
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 fromf->pci_hole_64bitandf->pci_hole.Paolo,
would be following patch acceptable:memory.c +1
-0@@ -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:
Quoted 10 lines
Quoted 6 lines
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.
Quoted 2 lines
Frankly I don't see any advantages.
Only single authoritative source of this info => No data duplication?
Quoted 185 lines
Quoted 184 lines
Quoted 184 lines
Quoted 181 lines
hw/pci-host/piix.c +1
-2d =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);hw/pci-host/piix.c +1
-0+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,
hwaddrpci_hole_start, hwaddrpci_hole_size, hwaddrpci_hole64_start,hw/pci-host/piix.c +0
-2-hwaddr pci_hole64_size, - MemoryRegion *pci_memory, MemoryRegion
*ram_memory)
+ MemoryRegion*pci_memory, MemoryRegion*ram_memory,hw/pci-host/piix.c +1
-0+ 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,hw/pci-host/piix.c +9
-2- 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);hw/pci-host/piix.c +1
-0@@ -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= {hw/pci-host/q35.c +2
-0@@ -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(),};
hw/pci-host/q35.c +0
-7@@ -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_DEFAULThw/pci-host/q35.c +8
-1+ -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+hw/pci-host/q35.c +7
-4+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);include/hw/i386/pc.h +3
-0@@ -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,
hwaddrpci_hole_start, hwaddrpci_hole_size, hwaddrpci_hole64_start,include/hw/i386/pc.h +2
-2-hwaddr pci_hole64_size, MemoryRegion *pci_memory, - MemoryRegion *ram_memory); + MemoryRegion *ram_memory, + PcGuestInfo *guest_info);PCIBus *find_i440fx (void );/* piix4.c */ include/hw/pci-host/q35.h +1
-0@@ -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;
Quoted 261 lines · Igor Mammedov
----- Original Message -----
Quoted 248 lines
From: "Michael S. Tsirkin" <[email protected]>
To: "Igor Mammedov" <[email protected]>
Cc: "Anthony Liguori" <[email protected]>, "Eduardo Habkost" <[email protected]>, [email protected], "Isaku Yamahata" <[email protected]>, "Alex Williamson" <[email protected]>, "Gerd Hoffmann" <[email protected]>, "Laszlo Ersek" <[email protected]>, "Andreas Färber" <[email protected]>, "David Gibson" <[email protected]>, "Paolo Bonzini" <[email protected]>
Sent: Thursday, July 25, 2013 5:23:21 PM
Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by defaultQuoted 238 lines · Igor Mammedov
----- Original Message -----
Quoted 206 lines
From: "Igor Mammedov" <[email protected]>
To: "Michael S. Tsirkin" <[email protected]>
Cc: "Anthony Liguori" <[email protected]>, "Eduardo Habkost" <[email protected]>, [email protected], "Isaku Yamahata" <[email protected]>, "Alex Williamson" <[email protected]>, "Gerd Hoffmann" <[email protected]>, "Paolo Bonzini" <[email protected]>, "Laszlo Ersek" <[email protected]>, "Andreas Färber" <[email protected]>, "David Gibson" <[email protected]>
Sent: Thursday, July 25, 2013 3:40:05 PM
Subject: Re: [Qemu-devel] [PATCH] pc: limit 64 bit hole to 2G by defaultQuoted 38 lines · On Wed, 24 Jul 2013 09:01:04 +0300 "Michael S. Tsirkin" <[email protected]> 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:
(quoted diff) +0
-2-global i440FX-pcihost.pci_hole64_size=137438953472 -global q35-pcihost.pci_hole64_size=137438953472Reported-by Igor Mammedov <[email protected]>,Signed-off-by Michael S. Tsirkin <[email protected]>--- 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(-)hw/i386/pc.c +1
-5@@ -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;hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t · line 1087
Quoted 10 lines
hw/i386/pc.c +9
-0+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
hw/i386/pc.c PcGuestInfo *pc_guest_info_init(ram_addr_t · line 1094
Quoted 7 lines
hw/i386/pc.c +7
-0+ +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_sizeis 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.Quoted 77 lines
hw/i386/pc.c +0
-2/* * 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);
hw/i386/pc.c +1
-3- 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);hw/i386/pc.c +0
-3- } - - guest_info_state->machine_done.notify =
pc_guest_info_machine_done;
-qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);hw/i386/pc.c +1
-1-return guest_info; + pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL <<30);
hw/i386/pc.c +2
-0+ 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)hw/i386/pc_piix.c +1
-13@@ -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 ;hw/pci-host/piix.c +1
-0@@ -40,6 +41,7 @@typedef struct I440FXState {PCIHostState parent_obj; +uint64_t pci_hole64_size; }I440FXState ;#define PIIX_NUM_PIC_IRQS 16/* i8259 * 2 */ hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char · line 239
Quoted 4 lines
hw/pci-host/piix.c +0
-0@@ -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 withabove_4g_memory_size, and leti440fx_common_init()
set it near the place where 64 PCI hole end is set.Quoted 29 lines
hw/pci-host/piix.c +2
-2-hwaddr pci_hole64_size, MemoryRegion *pci_address_space, - MemoryRegion *ram_memory) + MemoryRegion *ram_memory, + PcGuestInfo *guest_info) {DeviceState *dev;PCIBus *b;hw/pci-host/piix.c +5
-0@@ -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 */ hw/pci-host/piix.c static PCIBus *i440fx_common_init(const char · line 276
Quoted 10 lines
hw/pci-host/piix.c +10
-0+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.Quoted 4 lines
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 fromf->pci_hole_64bitandf->pci_hole.Paolo,
would be following patch acceptable:memory.c +1
-0@@ -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:
Quoted 10 lines
Quoted 6 lines
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.
Quoted 2 lines
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.
Quoted 3 lines
Quoted 2 lines
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).
Quoted 185 lines
Quoted 185 lines
Quoted 184 lines
Quoted 184 lines
Quoted 181 lines
hw/pci-host/piix.c +1
-2d =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);hw/pci-host/piix.c +1
-0+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,
hwaddrpci_hole_start, hwaddrpci_hole_size, hwaddrpci_hole64_start,hw/pci-host/piix.c +0
-2-hwaddr pci_hole64_size, - MemoryRegion *pci_memory, MemoryRegion
*ram_memory)
+ MemoryRegion*pci_memory, MemoryRegion*ram_memory,hw/pci-host/piix.c +1
-0+ 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,hw/pci-host/piix.c +9
-2- 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);hw/pci-host/piix.c +1
-0@@ -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= {hw/pci-host/q35.c +2
-0@@ -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(),};
hw/pci-host/q35.c +0
-7@@ -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_DEFAULThw/pci-host/q35.c +8
-1+ -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+hw/pci-host/q35.c +7
-4+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);include/hw/i386/pc.h +3
-0@@ -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,
hwaddrpci_hole_start, hwaddrpci_hole_size, hwaddrpci_hole64_start,include/hw/i386/pc.h +2
-2-hwaddr pci_hole64_size, MemoryRegion *pci_memory, - MemoryRegion *ram_memory); + MemoryRegion *ram_memory, + PcGuestInfo *guest_info);PCIBus *find_i440fx (void );/* piix4.c */ include/hw/pci-host/q35.h +1
-0@@ -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;