aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-03 16:40:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-03 16:40:38 -0400
commit25e09ca52459586eb6171209635bc8b436a56d79 (patch)
tree405d1a8387cf1df44c9e42f17d83b060d42a098f
parent48b5259cf0a2b86b978da122f9459e22a2d1e8f6 (diff)
parentfe2d48b805d01e14ddb8144de01de43171eb516f (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.txt9
-rw-r--r--arch/x86/boot/compressed/cmdline.c2
-rw-r--r--arch/x86/boot/compressed/kaslr.c191
-rw-r--r--arch/x86/boot/copy.S20
-rw-r--r--arch/x86/boot/string.c8
-rw-r--r--arch/x86/kernel/setup.c2
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"
16static unsigned long get_cmd_line_ptr(void) 16unsigned 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
46extern unsigned long get_cmd_line_ptr(void);
47
22/* Simplified build-specific string for starting entropy. */ 48/* Simplified build-specific string for starting entropy. */
23static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@" 49static 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
63static bool memmap_too_large; 89static bool memmap_too_large;
64 90
91
92/* Store memory limit specified by "mem=nn[KMG]" or "memmap=nn[KMG]" */
93unsigned long long mem_limit = ULLONG_MAX;
94
95
65enum mem_avoid_index { 96enum 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/** 119char *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 */
96static 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
132static int 128static int
133parse_memmap(char *p, unsigned long long *start, unsigned long long *size) 129parse_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
165static void mem_avoid_memmap(void) 168static 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
207static 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, &param, &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
67ENDPROC(copy_to_fs) 67ENDPROC(copy_to_fs)
68
69#if 0 /* Not currently used, but can be enabled as needed */
70GLOBAL(copy_from_gs)
71 pushw %ds
72 pushw %gs
73 popw %ds
74 calll memcpy
75 popw %ds
76 retl
77ENDPROC(copy_from_gs)
78
79GLOBAL(copy_to_gs)
80 pushw %es
81 pushw %gs
82 popw %es
83 calll memcpy
84 popw %es
85 retl
86ENDPROC(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
125long 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));