diff mbox

[03/27] pc: add 'etc/reserved-memory-end' fw_cfg interface for SeaBIOS

Message ID 1385001528-12003-4-git-send-email-imammedo@redhat.com
State New
Headers show

Commit Message

Igor Mammedov Nov. 21, 2013, 2:38 a.m. UTC
'etc/reserved-memory-end' will allow QEMU to tell BIOS where PCI
BARs mapping could safely start in high memory.

Allowing BIOS to start mapping 64-bit PCI BARs at address where it
wouldn't conflict with other mappings QEMU might place before it.

That permits QEMU to reserve extra address space before
64-bit PCI hole for memory hotplug.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
v2:
   * disable 'etc/reserved-memory-end' for 1.7 and older machine types
---
 hw/i386/pc.c         |   27 +++++++++++++++++++++++++--
 hw/i386/pc_piix.c    |    1 +
 hw/i386/pc_q35.c     |    1 +
 hw/pci-host/piix.c   |    3 ++-
 hw/pci-host/q35.c    |    3 ++-
 include/hw/i386/pc.h |   11 +++++++++--
 6 files changed, 40 insertions(+), 6 deletions(-)

Comments

Michael S. Tsirkin Dec. 19, 2013, 2:35 p.m. UTC | #1
On Thu, Nov 21, 2013 at 03:38:24AM +0100, Igor Mammedov wrote:
> 'etc/reserved-memory-end' will allow QEMU to tell BIOS where PCI
> BARs mapping could safely start in high memory.
> 
> Allowing BIOS to start mapping 64-bit PCI BARs at address where it
> wouldn't conflict with other mappings QEMU might place before it.
> 
> That permits QEMU to reserve extra address space before
> 64-bit PCI hole for memory hotplug.
> 
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> v2:
>    * disable 'etc/reserved-memory-end' for 1.7 and older machine types
> ---
>  hw/i386/pc.c         |   27 +++++++++++++++++++++++++--
>  hw/i386/pc_piix.c    |    1 +
>  hw/i386/pc_q35.c     |    1 +
>  hw/pci-host/piix.c   |    3 ++-
>  hw/pci-host/q35.c    |    3 ++-
>  include/hw/i386/pc.h |   11 +++++++++--
>  6 files changed, 40 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index 6c82ada..ba82c67 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -1094,14 +1094,37 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
>  }
>  
>  /* setup pci memory address space mapping into system address space */
> -void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
> -                            MemoryRegion *pci_address_space)
> +void pc_pci_as_mapping_init_1_7(Object *owner, MemoryRegion *system_memory,
> +                                MemoryRegion *pci_address_space,
> +                                uint64_t reserved_memory_end)
>  {
>      /* Set to lower priority than RAM */
>      memory_region_add_subregion_overlap(system_memory, 0x0,
>                                          pci_address_space, -1);
>  }
>  
> +static
> +void pc_pci_as_mapping_init_1_8(Object *owner, MemoryRegion *system_memory,
> +                                MemoryRegion *pci_address_space,
> +                                uint64_t reserved_memory_end)
> +{
> +    uint64_t *val;
> +    FWCfgState *fw_cfg = fw_cfg_find();
> +    g_assert(fw_cfg);
> +    /*
> +     *  Align address at 1G, this makes sure it can be exactly covered
> +     *  with a PAT entry even when using huge pages.
> +     */
> +    val = g_malloc(sizeof(*val));
> +    *val = cpu_to_le64(ROUND_UP(reserved_memory_end, 0x1ULL << 30));
> +    fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
> +
> +    pc_pci_as_mapping_init_1_7(owner, system_memory, pci_address_space,
> +                               reserved_memory_end);
> +}
> +
> +pc_pci_as_mapping_init_fn pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_8;
> +
>  void pc_acpi_init(const char *default_dsdt)
>  {
>      char *filename;
> diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> index 36f2495..e1fe85a 100644
> --- a/hw/i386/pc_piix.c
> +++ b/hw/i386/pc_piix.c
> @@ -249,6 +249,7 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
>  static void pc_compat_1_7(QEMUMachineInitArgs *args)
>  {
>      smbios_type1_defaults = false;
> +    pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_7;
>  }
>  
>  static void pc_compat_1_6(QEMUMachineInitArgs *args)
> diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
> index 50ca458..5525465 100644
> --- a/hw/i386/pc_q35.c
> +++ b/hw/i386/pc_q35.c
> @@ -233,6 +233,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
>  static void pc_compat_1_7(QEMUMachineInitArgs *args)
>  {
>      smbios_type1_defaults = false;
> +    pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_7;
>  }
>  
>  static void pc_compat_1_6(QEMUMachineInitArgs *args)

I don't much like this: why not use a global flag like we do
for other properties?

Also, 1_8 should be replaced with 2_0 now.

> diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> index 63be7f6..615ab0d 100644
> --- a/hw/pci-host/piix.c
> +++ b/hw/pci-host/piix.c
> @@ -352,7 +352,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
>  
>      /* setup pci memory mapping */
>      pc_pci_as_mapping_init(OBJECT(f), f->system_memory,
> -                           f->pci_address_space);
> +                           f->pci_address_space,
> +                           0x100000000ULL + above_4g_mem_size);
>  
>      memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
>                               f->pci_address_space, 0xa0000, 0x20000);
> diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> index 81c8240..6e28418 100644
> --- a/hw/pci-host/q35.c
> +++ b/hw/pci-host/q35.c
> @@ -359,7 +359,8 @@ static int mch_init(PCIDevice *d)
>  
>      /* setup pci memory mapping */
>      pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
> -                           mch->pci_address_space);
> +                           mch->pci_address_space,
> +                           0x100000000ULL + mch->above_4g_mem_size);
>  
>      /* smram */
>      cpu_smm_register(&mch_set_smm, mch);
> diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> index 9af09d3..c4e8048 100644
> --- a/include/hw/i386/pc.h
> +++ b/include/hw/i386/pc.h
> @@ -129,8 +129,15 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
>  #define DEFAULT_PCI_HOLE64_SIZE (~0x0ULL)
>  
>  
> -void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
> -                            MemoryRegion *pci_address_space);
> +typedef
> +void (*pc_pci_as_mapping_init_fn)(Object *owner, MemoryRegion *system_memory,
> +                                  MemoryRegion *pci_address_space,
> +                                  uint64_t reserved_memory_end);
> +extern pc_pci_as_mapping_init_fn pc_pci_as_mapping_init;
> +
> +void pc_pci_as_mapping_init_1_7(Object *owner, MemoryRegion *system_memory,
> +                                MemoryRegion *pci_address_space,
> +                                uint64_t reserved_memory_end);
>  
>  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
>                             const char *kernel_filename,
> -- 
> 1.7.1
Igor Mammedov Dec. 20, 2013, 12:48 p.m. UTC | #2
On Thu, 19 Dec 2013 16:35:05 +0200
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Thu, Nov 21, 2013 at 03:38:24AM +0100, Igor Mammedov wrote:
> > 'etc/reserved-memory-end' will allow QEMU to tell BIOS where PCI
> > BARs mapping could safely start in high memory.
> > 
> > Allowing BIOS to start mapping 64-bit PCI BARs at address where it
> > wouldn't conflict with other mappings QEMU might place before it.
> > 
> > That permits QEMU to reserve extra address space before
> > 64-bit PCI hole for memory hotplug.
> > 
> > Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> > ---
> > v2:
> >    * disable 'etc/reserved-memory-end' for 1.7 and older machine types
> > ---
> >  hw/i386/pc.c         |   27 +++++++++++++++++++++++++--
> >  hw/i386/pc_piix.c    |    1 +
> >  hw/i386/pc_q35.c     |    1 +
> >  hw/pci-host/piix.c   |    3 ++-
> >  hw/pci-host/q35.c    |    3 ++-
> >  include/hw/i386/pc.h |   11 +++++++++--
> >  6 files changed, 40 insertions(+), 6 deletions(-)
> > 
> > diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> > index 6c82ada..ba82c67 100644
> > --- a/hw/i386/pc.c
> > +++ b/hw/i386/pc.c
> > @@ -1094,14 +1094,37 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> >  }
> >  
> >  /* setup pci memory address space mapping into system address space */
> > -void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
> > -                            MemoryRegion *pci_address_space)
> > +void pc_pci_as_mapping_init_1_7(Object *owner, MemoryRegion *system_memory,
> > +                                MemoryRegion *pci_address_space,
> > +                                uint64_t reserved_memory_end)
> >  {
> >      /* Set to lower priority than RAM */
> >      memory_region_add_subregion_overlap(system_memory, 0x0,
> >                                          pci_address_space, -1);
> >  }
> >  
> > +static
> > +void pc_pci_as_mapping_init_1_8(Object *owner, MemoryRegion *system_memory,
> > +                                MemoryRegion *pci_address_space,
> > +                                uint64_t reserved_memory_end)
> > +{
> > +    uint64_t *val;
> > +    FWCfgState *fw_cfg = fw_cfg_find();
> > +    g_assert(fw_cfg);
> > +    /*
> > +     *  Align address at 1G, this makes sure it can be exactly covered
> > +     *  with a PAT entry even when using huge pages.
> > +     */
> > +    val = g_malloc(sizeof(*val));
> > +    *val = cpu_to_le64(ROUND_UP(reserved_memory_end, 0x1ULL << 30));
> > +    fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
> > +
> > +    pc_pci_as_mapping_init_1_7(owner, system_memory, pci_address_space,
> > +                               reserved_memory_end);
> > +}
> > +
> > +pc_pci_as_mapping_init_fn pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_8;
> > +
> >  void pc_acpi_init(const char *default_dsdt)
> >  {
> >      char *filename;
> > diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> > index 36f2495..e1fe85a 100644
> > --- a/hw/i386/pc_piix.c
> > +++ b/hw/i386/pc_piix.c
> > @@ -249,6 +249,7 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
> >  static void pc_compat_1_7(QEMUMachineInitArgs *args)
> >  {
> >      smbios_type1_defaults = false;
> > +    pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_7;
> >  }
> >  
> >  static void pc_compat_1_6(QEMUMachineInitArgs *args)
> > diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
> > index 50ca458..5525465 100644
> > --- a/hw/i386/pc_q35.c
> > +++ b/hw/i386/pc_q35.c
> > @@ -233,6 +233,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
> >  static void pc_compat_1_7(QEMUMachineInitArgs *args)
> >  {
> >      smbios_type1_defaults = false;
> > +    pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_7;
> >  }
> >  
> >  static void pc_compat_1_6(QEMUMachineInitArgs *args)
> 
> I don't much like this: why not use a global flag like we do
> for other properties?
because flag would add extra branching clattering code, while
overriding function makes caller cleaner and potentially maps
well into method override when machines are converted to QOM objects.
So why not to try this vs flags?

> 
> Also, 1_8 should be replaced with 2_0 now.
sure

> 
> > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > index 63be7f6..615ab0d 100644
> > --- a/hw/pci-host/piix.c
> > +++ b/hw/pci-host/piix.c
> > @@ -352,7 +352,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> >  
> >      /* setup pci memory mapping */
> >      pc_pci_as_mapping_init(OBJECT(f), f->system_memory,
> > -                           f->pci_address_space);
> > +                           f->pci_address_space,
> > +                           0x100000000ULL + above_4g_mem_size);
> >  
> >      memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
> >                               f->pci_address_space, 0xa0000, 0x20000);
> > diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> > index 81c8240..6e28418 100644
> > --- a/hw/pci-host/q35.c
> > +++ b/hw/pci-host/q35.c
> > @@ -359,7 +359,8 @@ static int mch_init(PCIDevice *d)
> >  
> >      /* setup pci memory mapping */
> >      pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
> > -                           mch->pci_address_space);
> > +                           mch->pci_address_space,
> > +                           0x100000000ULL + mch->above_4g_mem_size);
> >  
> >      /* smram */
> >      cpu_smm_register(&mch_set_smm, mch);
> > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > index 9af09d3..c4e8048 100644
> > --- a/include/hw/i386/pc.h
> > +++ b/include/hw/i386/pc.h
> > @@ -129,8 +129,15 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> >  #define DEFAULT_PCI_HOLE64_SIZE (~0x0ULL)
> >  
> >  
> > -void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
> > -                            MemoryRegion *pci_address_space);
> > +typedef
> > +void (*pc_pci_as_mapping_init_fn)(Object *owner, MemoryRegion *system_memory,
> > +                                  MemoryRegion *pci_address_space,
> > +                                  uint64_t reserved_memory_end);
> > +extern pc_pci_as_mapping_init_fn pc_pci_as_mapping_init;
> > +
> > +void pc_pci_as_mapping_init_1_7(Object *owner, MemoryRegion *system_memory,
> > +                                MemoryRegion *pci_address_space,
> > +                                uint64_t reserved_memory_end);
> >  
> >  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
> >                             const char *kernel_filename,
> > -- 
> > 1.7.1
>
Michael S. Tsirkin Dec. 22, 2013, 11:20 a.m. UTC | #3
On Fri, Dec 20, 2013 at 01:48:47PM +0100, Igor Mammedov wrote:
> On Thu, 19 Dec 2013 16:35:05 +0200
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
> > On Thu, Nov 21, 2013 at 03:38:24AM +0100, Igor Mammedov wrote:
> > > 'etc/reserved-memory-end' will allow QEMU to tell BIOS where PCI
> > > BARs mapping could safely start in high memory.
> > > 
> > > Allowing BIOS to start mapping 64-bit PCI BARs at address where it
> > > wouldn't conflict with other mappings QEMU might place before it.
> > > 
> > > That permits QEMU to reserve extra address space before
> > > 64-bit PCI hole for memory hotplug.
> > > 
> > > Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> > > ---
> > > v2:
> > >    * disable 'etc/reserved-memory-end' for 1.7 and older machine types
> > > ---
> > >  hw/i386/pc.c         |   27 +++++++++++++++++++++++++--
> > >  hw/i386/pc_piix.c    |    1 +
> > >  hw/i386/pc_q35.c     |    1 +
> > >  hw/pci-host/piix.c   |    3 ++-
> > >  hw/pci-host/q35.c    |    3 ++-
> > >  include/hw/i386/pc.h |   11 +++++++++--
> > >  6 files changed, 40 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> > > index 6c82ada..ba82c67 100644
> > > --- a/hw/i386/pc.c
> > > +++ b/hw/i386/pc.c
> > > @@ -1094,14 +1094,37 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> > >  }
> > >  
> > >  /* setup pci memory address space mapping into system address space */
> > > -void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
> > > -                            MemoryRegion *pci_address_space)
> > > +void pc_pci_as_mapping_init_1_7(Object *owner, MemoryRegion *system_memory,
> > > +                                MemoryRegion *pci_address_space,
> > > +                                uint64_t reserved_memory_end)
> > >  {
> > >      /* Set to lower priority than RAM */
> > >      memory_region_add_subregion_overlap(system_memory, 0x0,
> > >                                          pci_address_space, -1);
> > >  }
> > >  
> > > +static
> > > +void pc_pci_as_mapping_init_1_8(Object *owner, MemoryRegion *system_memory,
> > > +                                MemoryRegion *pci_address_space,
> > > +                                uint64_t reserved_memory_end)
> > > +{
> > > +    uint64_t *val;
> > > +    FWCfgState *fw_cfg = fw_cfg_find();
> > > +    g_assert(fw_cfg);
> > > +    /*
> > > +     *  Align address at 1G, this makes sure it can be exactly covered
> > > +     *  with a PAT entry even when using huge pages.
> > > +     */
> > > +    val = g_malloc(sizeof(*val));
> > > +    *val = cpu_to_le64(ROUND_UP(reserved_memory_end, 0x1ULL << 30));
> > > +    fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
> > > +
> > > +    pc_pci_as_mapping_init_1_7(owner, system_memory, pci_address_space,
> > > +                               reserved_memory_end);
> > > +}
> > > +
> > > +pc_pci_as_mapping_init_fn pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_8;
> > > +
> > >  void pc_acpi_init(const char *default_dsdt)
> > >  {
> > >      char *filename;
> > > diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
> > > index 36f2495..e1fe85a 100644
> > > --- a/hw/i386/pc_piix.c
> > > +++ b/hw/i386/pc_piix.c
> > > @@ -249,6 +249,7 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
> > >  static void pc_compat_1_7(QEMUMachineInitArgs *args)
> > >  {
> > >      smbios_type1_defaults = false;
> > > +    pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_7;
> > >  }
> > >  
> > >  static void pc_compat_1_6(QEMUMachineInitArgs *args)
> > > diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
> > > index 50ca458..5525465 100644
> > > --- a/hw/i386/pc_q35.c
> > > +++ b/hw/i386/pc_q35.c
> > > @@ -233,6 +233,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
> > >  static void pc_compat_1_7(QEMUMachineInitArgs *args)
> > >  {
> > >      smbios_type1_defaults = false;
> > > +    pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_7;
> > >  }
> > >  
> > >  static void pc_compat_1_6(QEMUMachineInitArgs *args)
> > 
> > I don't much like this: why not use a global flag like we do
> > for other properties?
> because flag would add extra branching clattering code, while
> overriding function makes caller cleaner and potentially maps
> well into method override when machines are converted to QOM objects.
> So why not to try this vs flags?

For consistency with other code. We have too many unfinished
conversions across the codebase, they are a bigger problem
than some branches here and there.

So I would say let's delay these experiments until this QOM
cleanup happens.

> > 
> > Also, 1_8 should be replaced with 2_0 now.
> sure
> 
> > 
> > > diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
> > > index 63be7f6..615ab0d 100644
> > > --- a/hw/pci-host/piix.c
> > > +++ b/hw/pci-host/piix.c
> > > @@ -352,7 +352,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
> > >  
> > >      /* setup pci memory mapping */
> > >      pc_pci_as_mapping_init(OBJECT(f), f->system_memory,
> > > -                           f->pci_address_space);
> > > +                           f->pci_address_space,
> > > +                           0x100000000ULL + above_4g_mem_size);
> > >  
> > >      memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
> > >                               f->pci_address_space, 0xa0000, 0x20000);
> > > diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
> > > index 81c8240..6e28418 100644
> > > --- a/hw/pci-host/q35.c
> > > +++ b/hw/pci-host/q35.c
> > > @@ -359,7 +359,8 @@ static int mch_init(PCIDevice *d)
> > >  
> > >      /* setup pci memory mapping */
> > >      pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
> > > -                           mch->pci_address_space);
> > > +                           mch->pci_address_space,
> > > +                           0x100000000ULL + mch->above_4g_mem_size);
> > >  
> > >      /* smram */
> > >      cpu_smm_register(&mch_set_smm, mch);
> > > diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
> > > index 9af09d3..c4e8048 100644
> > > --- a/include/hw/i386/pc.h
> > > +++ b/include/hw/i386/pc.h
> > > @@ -129,8 +129,15 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
> > >  #define DEFAULT_PCI_HOLE64_SIZE (~0x0ULL)
> > >  
> > >  
> > > -void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
> > > -                            MemoryRegion *pci_address_space);
> > > +typedef
> > > +void (*pc_pci_as_mapping_init_fn)(Object *owner, MemoryRegion *system_memory,
> > > +                                  MemoryRegion *pci_address_space,
> > > +                                  uint64_t reserved_memory_end);
> > > +extern pc_pci_as_mapping_init_fn pc_pci_as_mapping_init;
> > > +
> > > +void pc_pci_as_mapping_init_1_7(Object *owner, MemoryRegion *system_memory,
> > > +                                MemoryRegion *pci_address_space,
> > > +                                uint64_t reserved_memory_end);
> > >  
> > >  FWCfgState *pc_memory_init(MemoryRegion *system_memory,
> > >                             const char *kernel_filename,
> > > -- 
> > > 1.7.1
> >
diff mbox

Patch

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 6c82ada..ba82c67 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1094,14 +1094,37 @@  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
 }
 
 /* setup pci memory address space mapping into system address space */
-void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
-                            MemoryRegion *pci_address_space)
+void pc_pci_as_mapping_init_1_7(Object *owner, MemoryRegion *system_memory,
+                                MemoryRegion *pci_address_space,
+                                uint64_t reserved_memory_end)
 {
     /* Set to lower priority than RAM */
     memory_region_add_subregion_overlap(system_memory, 0x0,
                                         pci_address_space, -1);
 }
 
+static
+void pc_pci_as_mapping_init_1_8(Object *owner, MemoryRegion *system_memory,
+                                MemoryRegion *pci_address_space,
+                                uint64_t reserved_memory_end)
+{
+    uint64_t *val;
+    FWCfgState *fw_cfg = fw_cfg_find();
+    g_assert(fw_cfg);
+    /*
+     *  Align address at 1G, this makes sure it can be exactly covered
+     *  with a PAT entry even when using huge pages.
+     */
+    val = g_malloc(sizeof(*val));
+    *val = cpu_to_le64(ROUND_UP(reserved_memory_end, 0x1ULL << 30));
+    fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
+
+    pc_pci_as_mapping_init_1_7(owner, system_memory, pci_address_space,
+                               reserved_memory_end);
+}
+
+pc_pci_as_mapping_init_fn pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_8;
+
 void pc_acpi_init(const char *default_dsdt)
 {
     char *filename;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 36f2495..e1fe85a 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -249,6 +249,7 @@  static void pc_init_pci(QEMUMachineInitArgs *args)
 static void pc_compat_1_7(QEMUMachineInitArgs *args)
 {
     smbios_type1_defaults = false;
+    pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_7;
 }
 
 static void pc_compat_1_6(QEMUMachineInitArgs *args)
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 50ca458..5525465 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -233,6 +233,7 @@  static void pc_q35_init(QEMUMachineInitArgs *args)
 static void pc_compat_1_7(QEMUMachineInitArgs *args)
 {
     smbios_type1_defaults = false;
+    pc_pci_as_mapping_init = pc_pci_as_mapping_init_1_7;
 }
 
 static void pc_compat_1_6(QEMUMachineInitArgs *args)
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 63be7f6..615ab0d 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -352,7 +352,8 @@  PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
 
     /* setup pci memory mapping */
     pc_pci_as_mapping_init(OBJECT(f), f->system_memory,
-                           f->pci_address_space);
+                           f->pci_address_space,
+                           0x100000000ULL + above_4g_mem_size);
 
     memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
                              f->pci_address_space, 0xa0000, 0x20000);
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 81c8240..6e28418 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -359,7 +359,8 @@  static int mch_init(PCIDevice *d)
 
     /* setup pci memory mapping */
     pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
-                           mch->pci_address_space);
+                           mch->pci_address_space,
+                           0x100000000ULL + mch->above_4g_mem_size);
 
     /* smram */
     cpu_smm_register(&mch_set_smm, mch);
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 9af09d3..c4e8048 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -129,8 +129,15 @@  PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
 #define DEFAULT_PCI_HOLE64_SIZE (~0x0ULL)
 
 
-void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
-                            MemoryRegion *pci_address_space);
+typedef
+void (*pc_pci_as_mapping_init_fn)(Object *owner, MemoryRegion *system_memory,
+                                  MemoryRegion *pci_address_space,
+                                  uint64_t reserved_memory_end);
+extern pc_pci_as_mapping_init_fn pc_pci_as_mapping_init;
+
+void pc_pci_as_mapping_init_1_7(Object *owner, MemoryRegion *system_memory,
+                                MemoryRegion *pci_address_space,
+                                uint64_t reserved_memory_end);
 
 FWCfgState *pc_memory_init(MemoryRegion *system_memory,
                            const char *kernel_filename,