aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2018-08-01 09:32:25 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-08-02 08:22:22 -0400
commit1b3a62643660020cdc68e6139a010c06e8fc96c7 (patch)
tree2396dad62af3c907ef91afe6daac36a64e5609fd
parent6b4703768268d09ac928c64474fd686adf4574f9 (diff)
x86/boot/compressed/64: Validate trampoline placement against E820
There were two report of boot failure cased by trampoline placed into a reserved memory region. It can happen on machines that don't report EBDA correctly. Fix the problem by re-validating the found address against the E820 table. If the address is in a reserved area, find the next usable region below the initial address. Fixes: 3548e131ec6a ("x86/boot/compressed/64: Find a place for 32-bit trampoline") Reported-by: Dmitry Malkin <d.malkin@real-time-systems.com> Reported-by: youling 257 <youling257@gmail.com> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Link: https://lkml.kernel.org/r/20180801133225.38121-1-kirill.shutemov@linux.intel.com
-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