diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-05 12:39:30 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-05 12:39:30 -0400 |
commit | a8c199208cd68cc2d71684d84e37e3b56a2ae640 (patch) | |
tree | 81f1e6c897a96f518a602fb431a8ad1f227f3e3e | |
parent | 2f3672cbf9da468340a540fc23cefdd81c0b7be3 (diff) | |
parent | 1b3a62643660020cdc68e6139a010c06e8fc96c7 (diff) |
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fix from Thomas Gleixner:
"A single fix, which addresses boot failures on machines which do not
report EBDA correctly, which can place the trampoline into reserved
memory regions. Validating against E820 prevents that"
* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/boot/compressed/64: Validate trampoline placement against E820
-rw-r--r-- | arch/x86/boot/compressed/pgtable_64.c | 73 |
1 files changed, 55 insertions, 18 deletions
diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c index 8c5107545251..9e2157371491 100644 --- a/arch/x86/boot/compressed/pgtable_64.c +++ b/arch/x86/boot/compressed/pgtable_64.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <asm/e820/types.h> | ||
1 | #include <asm/processor.h> | 2 | #include <asm/processor.h> |
2 | #include "pgtable.h" | 3 | #include "pgtable.h" |
3 | #include "../string.h" | 4 | #include "../string.h" |
@@ -34,10 +35,62 @@ unsigned long *trampoline_32bit __section(.data); | |||
34 | extern struct boot_params *boot_params; | 35 | extern struct boot_params *boot_params; |
35 | int cmdline_find_option_bool(const char *option); | 36 | int cmdline_find_option_bool(const char *option); |
36 | 37 | ||
38 | static unsigned long find_trampoline_placement(void) | ||
39 | { | ||
40 | unsigned long bios_start, ebda_start; | ||
41 | unsigned long trampoline_start; | ||
42 | struct boot_e820_entry *entry; | ||
43 | int i; | ||
44 | |||
45 | /* | ||
46 | * Find a suitable spot for the trampoline. | ||
47 | * This code is based on reserve_bios_regions(). | ||
48 | */ | ||
49 | |||
50 | ebda_start = *(unsigned short *)0x40e << 4; | ||
51 | bios_start = *(unsigned short *)0x413 << 10; | ||
52 | |||
53 | if (bios_start < BIOS_START_MIN || bios_start > BIOS_START_MAX) | ||
54 | bios_start = BIOS_START_MAX; | ||
55 | |||
56 | if (ebda_start > BIOS_START_MIN && ebda_start < bios_start) | ||
57 | bios_start = ebda_start; | ||
58 | |||
59 | bios_start = round_down(bios_start, PAGE_SIZE); | ||
60 | |||
61 | /* Find the first usable memory region under bios_start. */ | ||
62 | for (i = boot_params->e820_entries - 1; i >= 0; i--) { | ||
63 | entry = &boot_params->e820_table[i]; | ||
64 | |||
65 | /* Skip all entries above bios_start. */ | ||
66 | if (bios_start <= entry->addr) | ||
67 | continue; | ||
68 | |||
69 | /* Skip non-RAM entries. */ | ||
70 | if (entry->type != E820_TYPE_RAM) | ||
71 | continue; | ||
72 | |||
73 | /* Adjust bios_start to the end of the entry if needed. */ | ||
74 | if (bios_start > entry->addr + entry->size) | ||
75 | bios_start = entry->addr + entry->size; | ||
76 | |||
77 | /* Keep bios_start page-aligned. */ | ||
78 | bios_start = round_down(bios_start, PAGE_SIZE); | ||
79 | |||
80 | /* Skip the entry if it's too small. */ | ||
81 | if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr) | ||
82 | continue; | ||
83 | |||
84 | break; | ||
85 | } | ||
86 | |||
87 | /* Place the trampoline just below the end of low memory */ | ||
88 | return bios_start - TRAMPOLINE_32BIT_SIZE; | ||
89 | } | ||
90 | |||
37 | struct paging_config paging_prepare(void *rmode) | 91 | struct paging_config paging_prepare(void *rmode) |
38 | { | 92 | { |
39 | struct paging_config paging_config = {}; | 93 | struct paging_config paging_config = {}; |
40 | unsigned long bios_start, ebda_start; | ||
41 | 94 | ||
42 | /* Initialize boot_params. Required for cmdline_find_option_bool(). */ | 95 | /* Initialize boot_params. Required for cmdline_find_option_bool(). */ |
43 | boot_params = rmode; | 96 | boot_params = rmode; |
@@ -61,23 +114,7 @@ struct paging_config paging_prepare(void *rmode) | |||
61 | paging_config.l5_required = 1; | 114 | paging_config.l5_required = 1; |
62 | } | 115 | } |
63 | 116 | ||
64 | /* | 117 | paging_config.trampoline_start = find_trampoline_placement(); |
65 | * Find a suitable spot for the trampoline. | ||
66 | * This code is based on reserve_bios_regions(). | ||
67 | */ | ||
68 | |||
69 | ebda_start = *(unsigned short *)0x40e << 4; | ||
70 | bios_start = *(unsigned short *)0x413 << 10; | ||
71 | |||
72 | if (bios_start < BIOS_START_MIN || bios_start > BIOS_START_MAX) | ||
73 | bios_start = BIOS_START_MAX; | ||
74 | |||
75 | if (ebda_start > BIOS_START_MIN && ebda_start < bios_start) | ||
76 | bios_start = ebda_start; | ||
77 | |||
78 | /* Place the trampoline just below the end of low memory, aligned to 4k */ | ||
79 | paging_config.trampoline_start = bios_start - TRAMPOLINE_32BIT_SIZE; | ||
80 | paging_config.trampoline_start = round_down(paging_config.trampoline_start, PAGE_SIZE); | ||
81 | 118 | ||
82 | trampoline_32bit = (unsigned long *)paging_config.trampoline_start; | 119 | trampoline_32bit = (unsigned long *)paging_config.trampoline_start; |
83 | 120 | ||