Commit 0212f915 authored by Yinghai Lu's avatar Yinghai Lu Committed by H. Peter Anvin

x86: Add Crash kernel low reservation

During kdump kernel's booting stage, it need to find low ram for
swiotlb buffer when system does not support intel iommu/dmar remapping.

kexed-tools is appending memmap=exactmap and range from /proc/iomem
with "Crash kernel", and that range is above 4G for 64bit after boot
protocol 2.12.

We need to add another range in /proc/iomem like "Crash kernel low",
so kexec-tools could find that info and append to kdump kernel
command line.

Try to reserve some under 4G if the normal "Crash kernel" is above 4G.

User could specify the size with crashkernel_low=XX[KMG].

-v2: fix warning that is found by Fengguang's test robot.
-v3: move out get_mem_size change to another patch, to solve compiling
     warning that is found by Borislav Petkov <bp@alien8.de>
-v4: user must specify crashkernel_low if system does not support
     intel or amd iommu.
Signed-off-by: default avatarYinghai Lu <yinghai@kernel.org>
Link: http://lkml.kernel.org/r/1359058816-7615-31-git-send-email-yinghai@kernel.org
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Rob Landley <rob@landley.net>
Signed-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent 7d41a8a4
...@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -594,6 +594,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
is selected automatically. Check is selected automatically. Check
Documentation/kdump/kdump.txt for further details. Documentation/kdump/kdump.txt for further details.
crashkernel_low=size[KMG]
[KNL, x86] parts under 4G.
crashkernel=range1:size1[,range2:size2,...][@offset] crashkernel=range1:size1[,range2:size2,...][@offset]
[KNL] Same as above, but depends on the memory [KNL] Same as above, but depends on the memory
in the running system. The syntax of range is in the running system. The syntax of range is
......
...@@ -508,8 +508,44 @@ static void __init memblock_x86_reserve_range_setup_data(void) ...@@ -508,8 +508,44 @@ static void __init memblock_x86_reserve_range_setup_data(void)
# define CRASH_KERNEL_ADDR_MAX MAXMEM # define CRASH_KERNEL_ADDR_MAX MAXMEM
#endif #endif
static void __init reserve_crashkernel_low(void)
{
#ifdef CONFIG_X86_64
const unsigned long long alignment = 16<<20; /* 16M */
unsigned long long low_base = 0, low_size = 0;
unsigned long total_low_mem;
unsigned long long base;
int ret;
total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT));
ret = parse_crashkernel_low(boot_command_line, total_low_mem,
&low_size, &base);
if (ret != 0 || low_size <= 0)
return;
low_base = memblock_find_in_range(low_size, (1ULL<<32),
low_size, alignment);
if (!low_base) {
pr_info("crashkernel low reservation failed - No suitable area found.\n");
return;
}
memblock_reserve(low_base, low_size);
pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (System low RAM: %ldMB)\n",
(unsigned long)(low_size >> 20),
(unsigned long)(low_base >> 20),
(unsigned long)(total_low_mem >> 20));
crashk_low_res.start = low_base;
crashk_low_res.end = low_base + low_size - 1;
insert_resource(&iomem_resource, &crashk_low_res);
#endif
}
static void __init reserve_crashkernel(void) static void __init reserve_crashkernel(void)
{ {
const unsigned long long alignment = 16<<20; /* 16M */
unsigned long long total_mem; unsigned long long total_mem;
unsigned long long crash_size, crash_base; unsigned long long crash_size, crash_base;
int ret; int ret;
...@@ -523,8 +559,6 @@ static void __init reserve_crashkernel(void) ...@@ -523,8 +559,6 @@ static void __init reserve_crashkernel(void)
/* 0 means: find the address automatically */ /* 0 means: find the address automatically */
if (crash_base <= 0) { if (crash_base <= 0) {
const unsigned long long alignment = 16<<20; /* 16M */
/* /*
* kexec want bzImage is below CRASH_KERNEL_ADDR_MAX * kexec want bzImage is below CRASH_KERNEL_ADDR_MAX
*/ */
...@@ -535,6 +569,7 @@ static void __init reserve_crashkernel(void) ...@@ -535,6 +569,7 @@ static void __init reserve_crashkernel(void)
pr_info("crashkernel reservation failed - No suitable area found.\n"); pr_info("crashkernel reservation failed - No suitable area found.\n");
return; return;
} }
} else { } else {
unsigned long long start; unsigned long long start;
...@@ -556,6 +591,9 @@ static void __init reserve_crashkernel(void) ...@@ -556,6 +591,9 @@ static void __init reserve_crashkernel(void)
crashk_res.start = crash_base; crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1; crashk_res.end = crash_base + crash_size - 1;
insert_resource(&iomem_resource, &crashk_res); insert_resource(&iomem_resource, &crashk_res);
if (crash_base >= (1ULL<<32))
reserve_crashkernel_low();
} }
#else #else
static void __init reserve_crashkernel(void) static void __init reserve_crashkernel(void)
......
...@@ -191,6 +191,7 @@ extern struct kimage *kexec_crash_image; ...@@ -191,6 +191,7 @@ extern struct kimage *kexec_crash_image;
/* Location of a reserved region to hold the crash kernel. /* Location of a reserved region to hold the crash kernel.
*/ */
extern struct resource crashk_res; extern struct resource crashk_res;
extern struct resource crashk_low_res;
typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4]; typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4];
extern note_buf_t __percpu *crash_notes; extern note_buf_t __percpu *crash_notes;
extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4]; extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
...@@ -199,6 +200,8 @@ extern size_t vmcoreinfo_max_size; ...@@ -199,6 +200,8 @@ extern size_t vmcoreinfo_max_size;
int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
unsigned long long *crash_size, unsigned long long *crash_base); unsigned long long *crash_size, unsigned long long *crash_base);
int parse_crashkernel_low(char *cmdline, unsigned long long system_ram,
unsigned long long *crash_size, unsigned long long *crash_base);
int crash_shrink_memory(unsigned long new_size); int crash_shrink_memory(unsigned long new_size);
size_t crash_get_memory_size(void); size_t crash_get_memory_size(void);
void crash_free_reserved_phys_range(unsigned long begin, unsigned long end); void crash_free_reserved_phys_range(unsigned long begin, unsigned long end);
......
...@@ -54,6 +54,12 @@ struct resource crashk_res = { ...@@ -54,6 +54,12 @@ struct resource crashk_res = {
.end = 0, .end = 0,
.flags = IORESOURCE_BUSY | IORESOURCE_MEM .flags = IORESOURCE_BUSY | IORESOURCE_MEM
}; };
struct resource crashk_low_res = {
.name = "Crash kernel low",
.start = 0,
.end = 0,
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
};
int kexec_should_crash(struct task_struct *p) int kexec_should_crash(struct task_struct *p)
{ {
...@@ -1369,10 +1375,11 @@ static int __init parse_crashkernel_simple(char *cmdline, ...@@ -1369,10 +1375,11 @@ static int __init parse_crashkernel_simple(char *cmdline,
* That function is the entry point for command line parsing and should be * That function is the entry point for command line parsing and should be
* called from the arch-specific code. * called from the arch-specific code.
*/ */
int __init parse_crashkernel(char *cmdline, static int __init __parse_crashkernel(char *cmdline,
unsigned long long system_ram, unsigned long long system_ram,
unsigned long long *crash_size, unsigned long long *crash_size,
unsigned long long *crash_base) unsigned long long *crash_base,
const char *name)
{ {
char *p = cmdline, *ck_cmdline = NULL; char *p = cmdline, *ck_cmdline = NULL;
char *first_colon, *first_space; char *first_colon, *first_space;
...@@ -1382,16 +1389,16 @@ int __init parse_crashkernel(char *cmdline, ...@@ -1382,16 +1389,16 @@ int __init parse_crashkernel(char *cmdline,
*crash_base = 0; *crash_base = 0;
/* find crashkernel and use the last one if there are more */ /* find crashkernel and use the last one if there are more */
p = strstr(p, "crashkernel="); p = strstr(p, name);
while (p) { while (p) {
ck_cmdline = p; ck_cmdline = p;
p = strstr(p+1, "crashkernel="); p = strstr(p+1, name);
} }
if (!ck_cmdline) if (!ck_cmdline)
return -EINVAL; return -EINVAL;
ck_cmdline += 12; /* strlen("crashkernel=") */ ck_cmdline += strlen(name);
/* /*
* if the commandline contains a ':', then that's the extended * if the commandline contains a ':', then that's the extended
...@@ -1409,6 +1416,23 @@ int __init parse_crashkernel(char *cmdline, ...@@ -1409,6 +1416,23 @@ int __init parse_crashkernel(char *cmdline,
return 0; return 0;
} }
int __init parse_crashkernel(char *cmdline,
unsigned long long system_ram,
unsigned long long *crash_size,
unsigned long long *crash_base)
{
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
"crashkernel=");
}
int __init parse_crashkernel_low(char *cmdline,
unsigned long long system_ram,
unsigned long long *crash_size,
unsigned long long *crash_base)
{
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
"crashkernel_low=");
}
static void update_vmcoreinfo_note(void) static void update_vmcoreinfo_note(void)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment