The initrd is loaded close to the top of memory, with some extra padding on top to account for memory that the BIOS could reserve in the memory map (for ACPI tables and the like).
This reserved high memory area can get quite big. We currently force a 128k size for 2.1+ machine types, but even that might not be enough: if the BIOS allocates more memory from the high area than just the ACPI tables, loading the initrd can stumble on that memory and break. So, we want to do two things. First, increase the size of the padding to account for BIOS data structures. 32k will do, since in practice the problems were fixed with just 4k. Second, to avoid wasting memory, size the padding based on the actual size of the ACPI tables. The table builder can pass the right size, padded as above and with a minimum of 64k. For older machine types, the padding has basically no consequence; simply, the acpi_data_size will be set at machine_ready time instead of machine init, which is made possible by calling load_linux after the ACPI tables are built. Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- hw/i386/acpi-build.c | 1 + hw/i386/pc.c | 6 +++--- hw/i386/pc_piix.c | 1 - hw/i386/pc_q35.c | 1 - include/hw/i386/pc.h | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index a313321..694ee91 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -1691,6 +1691,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) acpi_align_size(tables->table_data, ACPI_BUILD_TABLE_SIZE); } + pc_set_acpi_data_size(tables->table_data->len); acpi_align_size(tables->linker, ACPI_BUILD_ALIGN_SIZE); /* Cleanup memory that's no longer used. */ diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 863a40e..b4158f2 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -73,10 +73,10 @@ #endif /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ -unsigned acpi_data_size = 0x28000; -void pc_set_legacy_acpi_data_size(void) +unsigned acpi_data_size = 0x10000; +void pc_set_acpi_data_size(unsigned size) { - acpi_data_size = 0x10000; + acpi_data_size = MAX(size + 0x8000, 0x10000); } #define BIOS_CFG_IOPORT 0x510 diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2aa2b6d..ca9f07c 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -316,7 +316,6 @@ static void pc_compat_2_0(MachineState *machine) legacy_acpi_table_size = 6652; smbios_legacy_mode = true; has_reserved_memory = false; - pc_set_legacy_acpi_data_size(); } static void pc_compat_1_7(MachineState *machine) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index d4a907c..4b5a274 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -280,7 +280,6 @@ static void pc_compat_2_0(MachineState *machine) { smbios_legacy_mode = true; has_reserved_memory = false; - pc_set_legacy_acpi_data_size(); } static void pc_compat_1_7(MachineState *machine) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 77316d5..853829b 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -176,7 +176,7 @@ 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_set_legacy_acpi_data_size(void); +void pc_set_acpi_data_size(unsigned); #define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start" #define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end" -- 2.1.0