Skip to content

Commit

Permalink
x86/boot/compressed/64: Fix boot on machines with broken E820 table
Browse files Browse the repository at this point in the history
BIOS on Samsung 500C Chromebook reports very rudimentary E820 table that
consists of 2 entries:

  BIOS-e820: [mem 0x0000000000000000-0x0000000000000fff] usable
  BIOS-e820: [mem 0x00000000fffff000-0x00000000ffffffff] reserved

It breaks logic in find_trampoline_placement(): bios_start lands on the
end of the first 4k page and trampoline start gets placed below 0.

Detect underflow and don't touch bios_start for such cases. It makes
kernel ignore E820 table on machines that doesn't have two usable pages
below BIOS_START_MAX.

Fixes: 1b3a626 ("x86/boot/compressed/64: Validate trampoline placement against E820")
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: x86-ml <x86@kernel.org>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=203463
Link: https://lkml.kernel.org/r/20190813131654.24378-1-kirill.shutemov@linux.intel.com
  • Loading branch information
Kirill A. Shutemov authored and Borislav Petkov committed Aug 19, 2019
1 parent f897e60 commit 0a46fff
Showing 1 changed file with 10 additions and 3 deletions.
13 changes: 10 additions & 3 deletions arch/x86/boot/compressed/pgtable_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)

/* Find the first usable memory region under bios_start. */
for (i = boot_params->e820_entries - 1; i >= 0; i--) {
unsigned long new;

entry = &boot_params->e820_table[i];

/* Skip all entries above bios_start. */
Expand All @@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)

/* Adjust bios_start to the end of the entry if needed. */
if (bios_start > entry->addr + entry->size)
bios_start = entry->addr + entry->size;
new = entry->addr + entry->size;

/* Keep bios_start page-aligned. */
bios_start = round_down(bios_start, PAGE_SIZE);
new = round_down(new, PAGE_SIZE);

/* Skip the entry if it's too small. */
if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr)
if (new - TRAMPOLINE_32BIT_SIZE < entry->addr)
continue;

/* Protect against underflow. */
if (new - TRAMPOLINE_32BIT_SIZE > bios_start)
break;

bios_start = new;
break;
}

Expand Down

0 comments on commit 0a46fff

Please sign in to comment.