diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 3 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 42 | ||||
-rw-r--r-- | include/linux/kexec.h | 3 | ||||
-rw-r--r-- | kernel/kexec.c | 34 |
4 files changed, 75 insertions, 7 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 363e348bff9b..da0e0773ca96 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
594 | is selected automatically. Check | 594 | is selected automatically. Check |
595 | Documentation/kdump/kdump.txt for further details. | 595 | Documentation/kdump/kdump.txt for further details. |
596 | 596 | ||
597 | crashkernel_low=size[KMG] | ||
598 | [KNL, x86] parts under 4G. | ||
599 | |||
597 | crashkernel=range1:size1[,range2:size2,...][@offset] | 600 | crashkernel=range1:size1[,range2:size2,...][@offset] |
598 | [KNL] Same as above, but depends on the memory | 601 | [KNL] Same as above, but depends on the memory |
599 | in the running system. The syntax of range is | 602 | in the running system. The syntax of range is |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 4778ddeedc8a..5dc47c3e537b 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -508,8 +508,44 @@ static void __init memblock_x86_reserve_range_setup_data(void) | |||
508 | # define CRASH_KERNEL_ADDR_MAX MAXMEM | 508 | # define CRASH_KERNEL_ADDR_MAX MAXMEM |
509 | #endif | 509 | #endif |
510 | 510 | ||
511 | static void __init reserve_crashkernel_low(void) | ||
512 | { | ||
513 | #ifdef CONFIG_X86_64 | ||
514 | const unsigned long long alignment = 16<<20; /* 16M */ | ||
515 | unsigned long long low_base = 0, low_size = 0; | ||
516 | unsigned long total_low_mem; | ||
517 | unsigned long long base; | ||
518 | int ret; | ||
519 | |||
520 | total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT)); | ||
521 | ret = parse_crashkernel_low(boot_command_line, total_low_mem, | ||
522 | &low_size, &base); | ||
523 | if (ret != 0 || low_size <= 0) | ||
524 | return; | ||
525 | |||
526 | low_base = memblock_find_in_range(low_size, (1ULL<<32), | ||
527 | low_size, alignment); | ||
528 | |||
529 | if (!low_base) { | ||
530 | pr_info("crashkernel low reservation failed - No suitable area found.\n"); | ||
531 | |||
532 | return; | ||
533 | } | ||
534 | |||
535 | memblock_reserve(low_base, low_size); | ||
536 | pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (System low RAM: %ldMB)\n", | ||
537 | (unsigned long)(low_size >> 20), | ||
538 | (unsigned long)(low_base >> 20), | ||
539 | (unsigned long)(total_low_mem >> 20)); | ||
540 | crashk_low_res.start = low_base; | ||
541 | crashk_low_res.end = low_base + low_size - 1; | ||
542 | insert_resource(&iomem_resource, &crashk_low_res); | ||
543 | #endif | ||
544 | } | ||
545 | |||
511 | static void __init reserve_crashkernel(void) | 546 | static void __init reserve_crashkernel(void) |
512 | { | 547 | { |
548 | const unsigned long long alignment = 16<<20; /* 16M */ | ||
513 | unsigned long long total_mem; | 549 | unsigned long long total_mem; |
514 | unsigned long long crash_size, crash_base; | 550 | unsigned long long crash_size, crash_base; |
515 | int ret; | 551 | int ret; |
@@ -523,8 +559,6 @@ static void __init reserve_crashkernel(void) | |||
523 | 559 | ||
524 | /* 0 means: find the address automatically */ | 560 | /* 0 means: find the address automatically */ |
525 | if (crash_base <= 0) { | 561 | if (crash_base <= 0) { |
526 | const unsigned long long alignment = 16<<20; /* 16M */ | ||
527 | |||
528 | /* | 562 | /* |
529 | * kexec want bzImage is below CRASH_KERNEL_ADDR_MAX | 563 | * kexec want bzImage is below CRASH_KERNEL_ADDR_MAX |
530 | */ | 564 | */ |
@@ -535,6 +569,7 @@ static void __init reserve_crashkernel(void) | |||
535 | pr_info("crashkernel reservation failed - No suitable area found.\n"); | 569 | pr_info("crashkernel reservation failed - No suitable area found.\n"); |
536 | return; | 570 | return; |
537 | } | 571 | } |
572 | |||
538 | } else { | 573 | } else { |
539 | unsigned long long start; | 574 | unsigned long long start; |
540 | 575 | ||
@@ -556,6 +591,9 @@ static void __init reserve_crashkernel(void) | |||
556 | crashk_res.start = crash_base; | 591 | crashk_res.start = crash_base; |
557 | crashk_res.end = crash_base + crash_size - 1; | 592 | crashk_res.end = crash_base + crash_size - 1; |
558 | insert_resource(&iomem_resource, &crashk_res); | 593 | insert_resource(&iomem_resource, &crashk_res); |
594 | |||
595 | if (crash_base >= (1ULL<<32)) | ||
596 | reserve_crashkernel_low(); | ||
559 | } | 597 | } |
560 | #else | 598 | #else |
561 | static void __init reserve_crashkernel(void) | 599 | static void __init reserve_crashkernel(void) |
diff --git a/include/linux/kexec.h b/include/linux/kexec.h index d0b8458a703a..d2e6927bbaae 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h | |||
@@ -191,6 +191,7 @@ extern struct kimage *kexec_crash_image; | |||
191 | /* Location of a reserved region to hold the crash kernel. | 191 | /* Location of a reserved region to hold the crash kernel. |
192 | */ | 192 | */ |
193 | extern struct resource crashk_res; | 193 | extern struct resource crashk_res; |
194 | extern struct resource crashk_low_res; | ||
194 | typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4]; | 195 | typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4]; |
195 | extern note_buf_t __percpu *crash_notes; | 196 | extern note_buf_t __percpu *crash_notes; |
196 | extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4]; | 197 | extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4]; |
@@ -199,6 +200,8 @@ extern size_t vmcoreinfo_max_size; | |||
199 | 200 | ||
200 | int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, | 201 | int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, |
201 | unsigned long long *crash_size, unsigned long long *crash_base); | 202 | unsigned long long *crash_size, unsigned long long *crash_base); |
203 | int parse_crashkernel_low(char *cmdline, unsigned long long system_ram, | ||
204 | unsigned long long *crash_size, unsigned long long *crash_base); | ||
202 | int crash_shrink_memory(unsigned long new_size); | 205 | int crash_shrink_memory(unsigned long new_size); |
203 | size_t crash_get_memory_size(void); | 206 | size_t crash_get_memory_size(void); |
204 | void crash_free_reserved_phys_range(unsigned long begin, unsigned long end); | 207 | void crash_free_reserved_phys_range(unsigned long begin, unsigned long end); |
diff --git a/kernel/kexec.c b/kernel/kexec.c index 5e4bd7864c5d..2436ffcec91f 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -54,6 +54,12 @@ struct resource crashk_res = { | |||
54 | .end = 0, | 54 | .end = 0, |
55 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | 55 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM |
56 | }; | 56 | }; |
57 | struct resource crashk_low_res = { | ||
58 | .name = "Crash kernel low", | ||
59 | .start = 0, | ||
60 | .end = 0, | ||
61 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | ||
62 | }; | ||
57 | 63 | ||
58 | int kexec_should_crash(struct task_struct *p) | 64 | int kexec_should_crash(struct task_struct *p) |
59 | { | 65 | { |
@@ -1369,10 +1375,11 @@ static int __init parse_crashkernel_simple(char *cmdline, | |||
1369 | * That function is the entry point for command line parsing and should be | 1375 | * That function is the entry point for command line parsing and should be |
1370 | * called from the arch-specific code. | 1376 | * called from the arch-specific code. |
1371 | */ | 1377 | */ |
1372 | int __init parse_crashkernel(char *cmdline, | 1378 | static int __init __parse_crashkernel(char *cmdline, |
1373 | unsigned long long system_ram, | 1379 | unsigned long long system_ram, |
1374 | unsigned long long *crash_size, | 1380 | unsigned long long *crash_size, |
1375 | unsigned long long *crash_base) | 1381 | unsigned long long *crash_base, |
1382 | const char *name) | ||
1376 | { | 1383 | { |
1377 | char *p = cmdline, *ck_cmdline = NULL; | 1384 | char *p = cmdline, *ck_cmdline = NULL; |
1378 | char *first_colon, *first_space; | 1385 | char *first_colon, *first_space; |
@@ -1382,16 +1389,16 @@ int __init parse_crashkernel(char *cmdline, | |||
1382 | *crash_base = 0; | 1389 | *crash_base = 0; |
1383 | 1390 | ||
1384 | /* find crashkernel and use the last one if there are more */ | 1391 | /* find crashkernel and use the last one if there are more */ |
1385 | p = strstr(p, "crashkernel="); | 1392 | p = strstr(p, name); |
1386 | while (p) { | 1393 | while (p) { |
1387 | ck_cmdline = p; | 1394 | ck_cmdline = p; |
1388 | p = strstr(p+1, "crashkernel="); | 1395 | p = strstr(p+1, name); |
1389 | } | 1396 | } |
1390 | 1397 | ||
1391 | if (!ck_cmdline) | 1398 | if (!ck_cmdline) |
1392 | return -EINVAL; | 1399 | return -EINVAL; |
1393 | 1400 | ||
1394 | ck_cmdline += 12; /* strlen("crashkernel=") */ | 1401 | ck_cmdline += strlen(name); |
1395 | 1402 | ||
1396 | /* | 1403 | /* |
1397 | * if the commandline contains a ':', then that's the extended | 1404 | * if the commandline contains a ':', then that's the extended |
@@ -1409,6 +1416,23 @@ int __init parse_crashkernel(char *cmdline, | |||
1409 | return 0; | 1416 | return 0; |
1410 | } | 1417 | } |
1411 | 1418 | ||
1419 | int __init parse_crashkernel(char *cmdline, | ||
1420 | unsigned long long system_ram, | ||
1421 | unsigned long long *crash_size, | ||
1422 | unsigned long long *crash_base) | ||
1423 | { | ||
1424 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | ||
1425 | "crashkernel="); | ||
1426 | } | ||
1427 | |||
1428 | int __init parse_crashkernel_low(char *cmdline, | ||
1429 | unsigned long long system_ram, | ||
1430 | unsigned long long *crash_size, | ||
1431 | unsigned long long *crash_base) | ||
1432 | { | ||
1433 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | ||
1434 | "crashkernel_low="); | ||
1435 | } | ||
1412 | 1436 | ||
1413 | static void update_vmcoreinfo_note(void) | 1437 | static void update_vmcoreinfo_note(void) |
1414 | { | 1438 | { |