aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-05 12:39:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-05 12:39:30 -0400
commita8c199208cd68cc2d71684d84e37e3b56a2ae640 (patch)
tree81f1e6c897a96f518a602fb431a8ad1f227f3e3e
parent2f3672cbf9da468340a540fc23cefdd81c0b7be3 (diff)
parent1b3a62643660020cdc68e6139a010c06e8fc96c7 (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.c73
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);
34extern struct boot_params *boot_params; 35extern struct boot_params *boot_params;
35int cmdline_find_option_bool(const char *option); 36int cmdline_find_option_bool(const char *option);
36 37
38static 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
37struct paging_config paging_prepare(void *rmode) 91struct 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