Skip to content

Commit

Permalink
x86/setup: Consolidate early memory reservations
Browse files Browse the repository at this point in the history
The early reservations of memory areas used by the firmware, bootloader,
kernel text and data are spread over setup_arch(). Moreover, some of them
happen *after* memblock allocations, e.g trim_platform_memory_ranges() and
trim_low_memory_range() are called after reserve_real_mode() that allocates
memory.

There was no corruption of these memory regions because memblock always
allocates memory either from the end of memory (in top-down mode) or above
the kernel image (in bottom-up mode). However, the bottom up mode is going
to be updated to span the entire memory [1] to avoid limitations caused by
KASLR.

Consolidate early memory reservations in a dedicated function to improve
robustness against future changes. Having the early reservations in one
place also makes it clearer what memory must be reserved before memblock
allocations are allowed.

Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Reviewed-by: Baoquan He <bhe@redhat.com>
Acked-by: Borislav Petkov <bp@suse.de>
Acked-by: David Hildenbrand <david@redhat.com>
Link: [1] https://lore.kernel.org/lkml/20201217201214.3414100-2-guro@fb.com
Link: https://lkml.kernel.org/r/20210302100406.22059-2-rppt@kernel.org
  • Loading branch information
Mike Rapoport authored and Borislav Petkov committed Mar 23, 2021
1 parent e14cfb3 commit a799c2b
Showing 1 changed file with 44 additions and 48 deletions.
92 changes: 44 additions & 48 deletions arch/x86/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,18 +645,6 @@ static void __init trim_snb_memory(void)
}
}

/*
* Here we put platform-specific memory range workarounds, i.e.
* memory known to be corrupt or otherwise in need to be reserved on
* specific platforms.
*
* If this gets used more widely it could use a real dispatch mechanism.
*/
static void __init trim_platform_memory_ranges(void)
{
trim_snb_memory();
}

static void __init trim_bios_range(void)
{
/*
Expand Down Expand Up @@ -729,7 +717,38 @@ static void __init trim_low_memory_range(void)
{
memblock_reserve(0, ALIGN(reserve_low, PAGE_SIZE));
}


static void __init early_reserve_memory(void)
{
/*
* Reserve the memory occupied by the kernel between _text and
* __end_of_kernel_reserve symbols. Any kernel sections after the
* __end_of_kernel_reserve symbol must be explicitly reserved with a
* separate memblock_reserve() or they will be discarded.
*/
memblock_reserve(__pa_symbol(_text),
(unsigned long)__end_of_kernel_reserve - (unsigned long)_text);

/*
* Make sure page 0 is always reserved because on systems with
* L1TF its contents can be leaked to user processes.
*/
memblock_reserve(0, PAGE_SIZE);

early_reserve_initrd();

if (efi_enabled(EFI_BOOT))
efi_memblock_x86_reserve_range();

memblock_x86_reserve_range_setup_data();

reserve_ibft_region();
reserve_bios_regions();

trim_snb_memory();
trim_low_memory_range();
}

/*
* Dump out kernel offset information on panic.
*/
Expand Down Expand Up @@ -764,29 +783,6 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)

void __init setup_arch(char **cmdline_p)
{
/*
* Reserve the memory occupied by the kernel between _text and
* __end_of_kernel_reserve symbols. Any kernel sections after the
* __end_of_kernel_reserve symbol must be explicitly reserved with a
* separate memblock_reserve() or they will be discarded.
*/
memblock_reserve(__pa_symbol(_text),
(unsigned long)__end_of_kernel_reserve - (unsigned long)_text);

/*
* Make sure page 0 is always reserved because on systems with
* L1TF its contents can be leaked to user processes.
*/
memblock_reserve(0, PAGE_SIZE);

early_reserve_initrd();

/*
* At this point everything still needed from the boot loader
* or BIOS or kernel text should be early reserved or marked not
* RAM in e820. All other memory is free game.
*/

#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));

Expand Down Expand Up @@ -910,8 +906,18 @@ void __init setup_arch(char **cmdline_p)

parse_early_param();

if (efi_enabled(EFI_BOOT))
efi_memblock_x86_reserve_range();
/*
* Do some memory reservations *before* memory is added to
* memblock, so memblock allocations won't overwrite it.
* Do it after early param, so we could get (unlikely) panic from
* serial.
*
* After this point everything still needed from the boot loader or
* firmware or kernel text should be early reserved or marked not
* RAM in e820. All other memory is free game.
*/
early_reserve_memory();

#ifdef CONFIG_MEMORY_HOTPLUG
/*
* Memory used by the kernel cannot be hot-removed because Linux
Expand All @@ -938,9 +944,6 @@ void __init setup_arch(char **cmdline_p)

x86_report_nx();

/* after early param, so could get panic from serial */
memblock_x86_reserve_range_setup_data();

if (acpi_mps_check()) {
#ifdef CONFIG_X86_LOCAL_APIC
disable_apic = 1;
Expand Down Expand Up @@ -1032,8 +1035,6 @@ void __init setup_arch(char **cmdline_p)
*/
find_smp_config();

reserve_ibft_region();

early_alloc_pgt_buf();

/*
Expand All @@ -1054,8 +1055,6 @@ void __init setup_arch(char **cmdline_p)
*/
sev_setup_arch();

reserve_bios_regions();

efi_fake_memmap();
efi_find_mirror();
efi_esrt_init();
Expand All @@ -1081,9 +1080,6 @@ void __init setup_arch(char **cmdline_p)

reserve_real_mode();

trim_platform_memory_ranges();
trim_low_memory_range();

init_mem_mapping();

idt_setup_early_pf();
Expand Down

0 comments on commit a799c2b

Please sign in to comment.