diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 16:40:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 16:40:38 -0400 |
commit | 25e09ca52459586eb6171209635bc8b436a56d79 (patch) | |
tree | 405d1a8387cf1df44c9e42f17d83b060d42a098f | |
parent | 48b5259cf0a2b86b978da122f9459e22a2d1e8f6 (diff) | |
parent | fe2d48b805d01e14ddb8144de01de43171eb516f (diff) |
Merge branch 'x86-boot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 boot updates from Ingo Molnar:
"The main changes in this cycle were KASLR improvements for rare
environments with special boot options, by Baoquan He. Also misc
smaller changes/cleanups"
* 'x86-boot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/debug: Extend the lower bound of crash kernel low reservations
x86/boot: Remove unused copy_*_gs() functions
x86/KASLR: Use the right memcpy() implementation
Documentation/kernel-parameters.txt: Update 'memmap=' boot option description
x86/KASLR: Handle the memory limit specified by the 'memmap=' and 'mem=' boot options
x86/KASLR: Parse all 'memmap=' boot option entries
-rw-r--r-- | Documentation/admin-guide/kernel-parameters.txt | 9 | ||||
-rw-r--r-- | arch/x86/boot/compressed/cmdline.c | 2 | ||||
-rw-r--r-- | arch/x86/boot/compressed/kaslr.c | 191 | ||||
-rw-r--r-- | arch/x86/boot/copy.S | 20 | ||||
-rw-r--r-- | arch/x86/boot/string.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 2 |
6 files changed, 145 insertions, 87 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index f59aad5c2270..9b0b3dea6326 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt | |||
@@ -2136,6 +2136,12 @@ | |||
2136 | memmap=nn[KMG]@ss[KMG] | 2136 | memmap=nn[KMG]@ss[KMG] |
2137 | [KNL] Force usage of a specific region of memory. | 2137 | [KNL] Force usage of a specific region of memory. |
2138 | Region of memory to be used is from ss to ss+nn. | 2138 | Region of memory to be used is from ss to ss+nn. |
2139 | If @ss[KMG] is omitted, it is equivalent to mem=nn[KMG], | ||
2140 | which limits max address to nn[KMG]. | ||
2141 | Multiple different regions can be specified, | ||
2142 | comma delimited. | ||
2143 | Example: | ||
2144 | memmap=100M@2G,100M#3G,1G!1024G | ||
2139 | 2145 | ||
2140 | memmap=nn[KMG]#ss[KMG] | 2146 | memmap=nn[KMG]#ss[KMG] |
2141 | [KNL,ACPI] Mark specific memory as ACPI data. | 2147 | [KNL,ACPI] Mark specific memory as ACPI data. |
@@ -2148,6 +2154,9 @@ | |||
2148 | memmap=64K$0x18690000 | 2154 | memmap=64K$0x18690000 |
2149 | or | 2155 | or |
2150 | memmap=0x10000$0x18690000 | 2156 | memmap=0x10000$0x18690000 |
2157 | Some bootloaders may need an escape character before '$', | ||
2158 | like Grub2, otherwise '$' and the following number | ||
2159 | will be eaten. | ||
2151 | 2160 | ||
2152 | memmap=nn[KMG]!ss[KMG] | 2161 | memmap=nn[KMG]!ss[KMG] |
2153 | [KNL,X86] Mark specific memory as protected. | 2162 | [KNL,X86] Mark specific memory as protected. |
diff --git a/arch/x86/boot/compressed/cmdline.c b/arch/x86/boot/compressed/cmdline.c index 73ccf63b0f48..9dc1ce6ba3c0 100644 --- a/arch/x86/boot/compressed/cmdline.c +++ b/arch/x86/boot/compressed/cmdline.c | |||
@@ -13,7 +13,7 @@ static inline char rdfs8(addr_t addr) | |||
13 | return *((char *)(fs + addr)); | 13 | return *((char *)(fs + addr)); |
14 | } | 14 | } |
15 | #include "../cmdline.c" | 15 | #include "../cmdline.c" |
16 | static unsigned long get_cmd_line_ptr(void) | 16 | unsigned long get_cmd_line_ptr(void) |
17 | { | 17 | { |
18 | unsigned long cmd_line_ptr = boot_params->hdr.cmd_line_ptr; | 18 | unsigned long cmd_line_ptr = boot_params->hdr.cmd_line_ptr; |
19 | 19 | ||
diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 56a7e9201741..91f27ab970ef 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c | |||
@@ -9,16 +9,42 @@ | |||
9 | * contain the entire properly aligned running kernel image. | 9 | * contain the entire properly aligned running kernel image. |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | |||
13 | /* | ||
14 | * isspace() in linux/ctype.h is expected by next_args() to filter | ||
15 | * out "space/lf/tab". While boot/ctype.h conflicts with linux/ctype.h, | ||
16 | * since isdigit() is implemented in both of them. Hence disable it | ||
17 | * here. | ||
18 | */ | ||
19 | #define BOOT_CTYPE_H | ||
20 | |||
21 | /* | ||
22 | * _ctype[] in lib/ctype.c is needed by isspace() of linux/ctype.h. | ||
23 | * While both lib/ctype.c and lib/cmdline.c will bring EXPORT_SYMBOL | ||
24 | * which is meaningless and will cause compiling error in some cases. | ||
25 | * So do not include linux/export.h and define EXPORT_SYMBOL(sym) | ||
26 | * as empty. | ||
27 | */ | ||
28 | #define _LINUX_EXPORT_H | ||
29 | #define EXPORT_SYMBOL(sym) | ||
30 | |||
12 | #include "misc.h" | 31 | #include "misc.h" |
13 | #include "error.h" | 32 | #include "error.h" |
14 | #include "../boot.h" | 33 | #include "../string.h" |
15 | 34 | ||
16 | #include <generated/compile.h> | 35 | #include <generated/compile.h> |
17 | #include <linux/module.h> | 36 | #include <linux/module.h> |
18 | #include <linux/uts.h> | 37 | #include <linux/uts.h> |
19 | #include <linux/utsname.h> | 38 | #include <linux/utsname.h> |
39 | #include <linux/ctype.h> | ||
20 | #include <generated/utsrelease.h> | 40 | #include <generated/utsrelease.h> |
21 | 41 | ||
42 | /* Macros used by the included decompressor code below. */ | ||
43 | #define STATIC | ||
44 | #include <linux/decompress/mm.h> | ||
45 | |||
46 | extern unsigned long get_cmd_line_ptr(void); | ||
47 | |||
22 | /* Simplified build-specific string for starting entropy. */ | 48 | /* Simplified build-specific string for starting entropy. */ |
23 | static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@" | 49 | static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@" |
24 | LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION; | 50 | LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION; |
@@ -62,6 +88,11 @@ struct mem_vector { | |||
62 | 88 | ||
63 | static bool memmap_too_large; | 89 | static bool memmap_too_large; |
64 | 90 | ||
91 | |||
92 | /* Store memory limit specified by "mem=nn[KMG]" or "memmap=nn[KMG]" */ | ||
93 | unsigned long long mem_limit = ULLONG_MAX; | ||
94 | |||
95 | |||
65 | enum mem_avoid_index { | 96 | enum mem_avoid_index { |
66 | MEM_AVOID_ZO_RANGE = 0, | 97 | MEM_AVOID_ZO_RANGE = 0, |
67 | MEM_AVOID_INITRD, | 98 | MEM_AVOID_INITRD, |
@@ -85,49 +116,14 @@ static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two) | |||
85 | return true; | 116 | return true; |
86 | } | 117 | } |
87 | 118 | ||
88 | /** | 119 | char *skip_spaces(const char *str) |
89 | * _memparse - Parse a string with mem suffixes into a number | ||
90 | * @ptr: Where parse begins | ||
91 | * @retptr: (output) Optional pointer to next char after parse completes | ||
92 | * | ||
93 | * Parses a string into a number. The number stored at @ptr is | ||
94 | * potentially suffixed with K, M, G, T, P, E. | ||
95 | */ | ||
96 | static unsigned long long _memparse(const char *ptr, char **retptr) | ||
97 | { | 120 | { |
98 | char *endptr; /* Local pointer to end of parsed string */ | 121 | while (isspace(*str)) |
99 | 122 | ++str; | |
100 | unsigned long long ret = simple_strtoull(ptr, &endptr, 0); | 123 | return (char *)str; |
101 | |||
102 | switch (*endptr) { | ||
103 | case 'E': | ||
104 | case 'e': | ||
105 | ret <<= 10; | ||
106 | case 'P': | ||
107 | case 'p': | ||
108 | ret <<= 10; | ||
109 | case 'T': | ||
110 | case 't': | ||
111 | ret <<= 10; | ||
112 | case 'G': | ||
113 | case 'g': | ||
114 | ret <<= 10; | ||
115 | case 'M': | ||
116 | case 'm': | ||
117 | ret <<= 10; | ||
118 | case 'K': | ||
119 | case 'k': | ||
120 | ret <<= 10; | ||
121 | endptr++; | ||
122 | default: | ||
123 | break; | ||
124 | } | ||
125 | |||
126 | if (retptr) | ||
127 | *retptr = endptr; | ||
128 | |||
129 | return ret; | ||
130 | } | 124 | } |
125 | #include "../../../../lib/ctype.c" | ||
126 | #include "../../../../lib/cmdline.c" | ||
131 | 127 | ||
132 | static int | 128 | static int |
133 | parse_memmap(char *p, unsigned long long *start, unsigned long long *size) | 129 | parse_memmap(char *p, unsigned long long *start, unsigned long long *size) |
@@ -142,40 +138,41 @@ parse_memmap(char *p, unsigned long long *start, unsigned long long *size) | |||
142 | return -EINVAL; | 138 | return -EINVAL; |
143 | 139 | ||
144 | oldp = p; | 140 | oldp = p; |
145 | *size = _memparse(p, &p); | 141 | *size = memparse(p, &p); |
146 | if (p == oldp) | 142 | if (p == oldp) |
147 | return -EINVAL; | 143 | return -EINVAL; |
148 | 144 | ||
149 | switch (*p) { | 145 | switch (*p) { |
150 | case '@': | ||
151 | /* Skip this region, usable */ | ||
152 | *start = 0; | ||
153 | *size = 0; | ||
154 | return 0; | ||
155 | case '#': | 146 | case '#': |
156 | case '$': | 147 | case '$': |
157 | case '!': | 148 | case '!': |
158 | *start = _memparse(p + 1, &p); | 149 | *start = memparse(p + 1, &p); |
150 | return 0; | ||
151 | case '@': | ||
152 | /* memmap=nn@ss specifies usable region, should be skipped */ | ||
153 | *size = 0; | ||
154 | /* Fall through */ | ||
155 | default: | ||
156 | /* | ||
157 | * If w/o offset, only size specified, memmap=nn[KMG] has the | ||
158 | * same behaviour as mem=nn[KMG]. It limits the max address | ||
159 | * system can use. Region above the limit should be avoided. | ||
160 | */ | ||
161 | *start = 0; | ||
159 | return 0; | 162 | return 0; |
160 | } | 163 | } |
161 | 164 | ||
162 | return -EINVAL; | 165 | return -EINVAL; |
163 | } | 166 | } |
164 | 167 | ||
165 | static void mem_avoid_memmap(void) | 168 | static void mem_avoid_memmap(char *str) |
166 | { | 169 | { |
167 | char arg[128]; | 170 | static int i; |
168 | int rc; | 171 | int rc; |
169 | int i; | ||
170 | char *str; | ||
171 | 172 | ||
172 | /* See if we have any memmap areas */ | 173 | if (i >= MAX_MEMMAP_REGIONS) |
173 | rc = cmdline_find_option("memmap", arg, sizeof(arg)); | ||
174 | if (rc <= 0) | ||
175 | return; | 174 | return; |
176 | 175 | ||
177 | i = 0; | ||
178 | str = arg; | ||
179 | while (str && (i < MAX_MEMMAP_REGIONS)) { | 176 | while (str && (i < MAX_MEMMAP_REGIONS)) { |
180 | int rc; | 177 | int rc; |
181 | unsigned long long start, size; | 178 | unsigned long long start, size; |
@@ -188,9 +185,14 @@ static void mem_avoid_memmap(void) | |||
188 | if (rc < 0) | 185 | if (rc < 0) |
189 | break; | 186 | break; |
190 | str = k; | 187 | str = k; |
191 | /* A usable region that should not be skipped */ | 188 | |
192 | if (size == 0) | 189 | if (start == 0) { |
190 | /* Store the specified memory limit if size > 0 */ | ||
191 | if (size > 0) | ||
192 | mem_limit = size; | ||
193 | |||
193 | continue; | 194 | continue; |
195 | } | ||
194 | 196 | ||
195 | mem_avoid[MEM_AVOID_MEMMAP_BEGIN + i].start = start; | 197 | mem_avoid[MEM_AVOID_MEMMAP_BEGIN + i].start = start; |
196 | mem_avoid[MEM_AVOID_MEMMAP_BEGIN + i].size = size; | 198 | mem_avoid[MEM_AVOID_MEMMAP_BEGIN + i].size = size; |
@@ -202,6 +204,57 @@ static void mem_avoid_memmap(void) | |||
202 | memmap_too_large = true; | 204 | memmap_too_large = true; |
203 | } | 205 | } |
204 | 206 | ||
207 | static int handle_mem_memmap(void) | ||
208 | { | ||
209 | char *args = (char *)get_cmd_line_ptr(); | ||
210 | size_t len = strlen((char *)args); | ||
211 | char *tmp_cmdline; | ||
212 | char *param, *val; | ||
213 | u64 mem_size; | ||
214 | |||
215 | if (!strstr(args, "memmap=") && !strstr(args, "mem=")) | ||
216 | return 0; | ||
217 | |||
218 | tmp_cmdline = malloc(len + 1); | ||
219 | if (!tmp_cmdline ) | ||
220 | error("Failed to allocate space for tmp_cmdline"); | ||
221 | |||
222 | memcpy(tmp_cmdline, args, len); | ||
223 | tmp_cmdline[len] = 0; | ||
224 | args = tmp_cmdline; | ||
225 | |||
226 | /* Chew leading spaces */ | ||
227 | args = skip_spaces(args); | ||
228 | |||
229 | while (*args) { | ||
230 | args = next_arg(args, ¶m, &val); | ||
231 | /* Stop at -- */ | ||
232 | if (!val && strcmp(param, "--") == 0) { | ||
233 | warn("Only '--' specified in cmdline"); | ||
234 | free(tmp_cmdline); | ||
235 | return -1; | ||
236 | } | ||
237 | |||
238 | if (!strcmp(param, "memmap")) { | ||
239 | mem_avoid_memmap(val); | ||
240 | } else if (!strcmp(param, "mem")) { | ||
241 | char *p = val; | ||
242 | |||
243 | if (!strcmp(p, "nopentium")) | ||
244 | continue; | ||
245 | mem_size = memparse(p, &p); | ||
246 | if (mem_size == 0) { | ||
247 | free(tmp_cmdline); | ||
248 | return -EINVAL; | ||
249 | } | ||
250 | mem_limit = mem_size; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | free(tmp_cmdline); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
205 | /* | 258 | /* |
206 | * In theory, KASLR can put the kernel anywhere in the range of [16M, 64T). | 259 | * In theory, KASLR can put the kernel anywhere in the range of [16M, 64T). |
207 | * The mem_avoid array is used to store the ranges that need to be avoided | 260 | * The mem_avoid array is used to store the ranges that need to be avoided |
@@ -323,7 +376,7 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size, | |||
323 | /* We don't need to set a mapping for setup_data. */ | 376 | /* We don't need to set a mapping for setup_data. */ |
324 | 377 | ||
325 | /* Mark the memmap regions we need to avoid */ | 378 | /* Mark the memmap regions we need to avoid */ |
326 | mem_avoid_memmap(); | 379 | handle_mem_memmap(); |
327 | 380 | ||
328 | #ifdef CONFIG_X86_VERBOSE_BOOTUP | 381 | #ifdef CONFIG_X86_VERBOSE_BOOTUP |
329 | /* Make sure video RAM can be used. */ | 382 | /* Make sure video RAM can be used. */ |
@@ -432,7 +485,8 @@ static void process_e820_entry(struct boot_e820_entry *entry, | |||
432 | { | 485 | { |
433 | struct mem_vector region, overlap; | 486 | struct mem_vector region, overlap; |
434 | struct slot_area slot_area; | 487 | struct slot_area slot_area; |
435 | unsigned long start_orig; | 488 | unsigned long start_orig, end; |
489 | struct boot_e820_entry cur_entry; | ||
436 | 490 | ||
437 | /* Skip non-RAM entries. */ | 491 | /* Skip non-RAM entries. */ |
438 | if (entry->type != E820_TYPE_RAM) | 492 | if (entry->type != E820_TYPE_RAM) |
@@ -446,8 +500,15 @@ static void process_e820_entry(struct boot_e820_entry *entry, | |||
446 | if (entry->addr + entry->size < minimum) | 500 | if (entry->addr + entry->size < minimum) |
447 | return; | 501 | return; |
448 | 502 | ||
449 | region.start = entry->addr; | 503 | /* Ignore entries above memory limit */ |
450 | region.size = entry->size; | 504 | end = min(entry->size + entry->addr, mem_limit); |
505 | if (entry->addr >= end) | ||
506 | return; | ||
507 | cur_entry.addr = entry->addr; | ||
508 | cur_entry.size = end - entry->addr; | ||
509 | |||
510 | region.start = cur_entry.addr; | ||
511 | region.size = cur_entry.size; | ||
451 | 512 | ||
452 | /* Give up if slot area array is full. */ | 513 | /* Give up if slot area array is full. */ |
453 | while (slot_area_index < MAX_SLOT_AREA) { | 514 | while (slot_area_index < MAX_SLOT_AREA) { |
@@ -461,7 +522,7 @@ static void process_e820_entry(struct boot_e820_entry *entry, | |||
461 | region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN); | 522 | region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN); |
462 | 523 | ||
463 | /* Did we raise the address above this e820 region? */ | 524 | /* Did we raise the address above this e820 region? */ |
464 | if (region.start > entry->addr + entry->size) | 525 | if (region.start > cur_entry.addr + cur_entry.size) |
465 | return; | 526 | return; |
466 | 527 | ||
467 | /* Reduce size by any delta from the original address. */ | 528 | /* Reduce size by any delta from the original address. */ |
diff --git a/arch/x86/boot/copy.S b/arch/x86/boot/copy.S index 1eb7d298b47d..15d9f74b0008 100644 --- a/arch/x86/boot/copy.S +++ b/arch/x86/boot/copy.S | |||
@@ -65,23 +65,3 @@ GLOBAL(copy_to_fs) | |||
65 | popw %es | 65 | popw %es |
66 | retl | 66 | retl |
67 | ENDPROC(copy_to_fs) | 67 | ENDPROC(copy_to_fs) |
68 | |||
69 | #if 0 /* Not currently used, but can be enabled as needed */ | ||
70 | GLOBAL(copy_from_gs) | ||
71 | pushw %ds | ||
72 | pushw %gs | ||
73 | popw %ds | ||
74 | calll memcpy | ||
75 | popw %ds | ||
76 | retl | ||
77 | ENDPROC(copy_from_gs) | ||
78 | |||
79 | GLOBAL(copy_to_gs) | ||
80 | pushw %es | ||
81 | pushw %gs | ||
82 | popw %es | ||
83 | calll memcpy | ||
84 | popw %es | ||
85 | retl | ||
86 | ENDPROC(copy_to_gs) | ||
87 | #endif | ||
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index 5457b02fc050..630e3664906b 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c | |||
@@ -122,6 +122,14 @@ unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int bas | |||
122 | return result; | 122 | return result; |
123 | } | 123 | } |
124 | 124 | ||
125 | long simple_strtol(const char *cp, char **endp, unsigned int base) | ||
126 | { | ||
127 | if (*cp == '-') | ||
128 | return -simple_strtoull(cp + 1, endp, base); | ||
129 | |||
130 | return simple_strtoull(cp, endp, base); | ||
131 | } | ||
132 | |||
125 | /** | 133 | /** |
126 | * strlen - Find the length of a string | 134 | * strlen - Find the length of a string |
127 | * @s: The string to be sized | 135 | * @s: The string to be sized |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index f81823695014..65622f07e633 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -503,7 +503,7 @@ static int __init reserve_crashkernel_low(void) | |||
503 | return 0; | 503 | return 0; |
504 | } | 504 | } |
505 | 505 | ||
506 | low_base = memblock_find_in_range(low_size, 1ULL << 32, low_size, CRASH_ALIGN); | 506 | low_base = memblock_find_in_range(0, 1ULL << 32, low_size, CRASH_ALIGN); |
507 | if (!low_base) { | 507 | if (!low_base) { |
508 | pr_err("Cannot reserve %ldMB crashkernel low memory, please try smaller size.\n", | 508 | pr_err("Cannot reserve %ldMB crashkernel low memory, please try smaller size.\n", |
509 | (unsigned long)(low_size >> 20)); | 509 | (unsigned long)(low_size >> 20)); |