aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2016-03-14 19:34:37 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2016-05-03 11:13:45 +0100
commit61603016e2122bf95328321b2f1a64277202b6e3 (patch)
tree02a04c1043bca3f4872ef8b2374f8516e7cba64e /arch/arm
parentLinux 4.6-rc1 (diff)
downloadlinux-dev-61603016e2122bf95328321b2f1a64277202b6e3.tar.xz
linux-dev-61603016e2122bf95328321b2f1a64277202b6e3.zip
ARM: kexec: fix crashkernel= handling
When the kernel crashkernel parameter is specified with just a size, we are supposed to allocate a region from RAM to store the crashkernel. However, ARM merely reserves physical address zero with no checking that there is even RAM there. Fix this by lifting similar code from x86, importing it to ARM with the ARM specific parameters added. In the absence of any platform specific information, we allocate the crashkernel region from the first 512MB of physical memory. Update the kdump documentation to reflect this change. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Reviewed-by: Pratyush Anand <panand@redhat.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/kernel/setup.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 139791ed473d..77b54c461c52 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -938,6 +938,13 @@ static int __init init_machine_late(void)
late_initcall(init_machine_late);
#ifdef CONFIG_KEXEC
+/*
+ * The crash region must be aligned to 128MB to avoid
+ * zImage relocating below the reserved region.
+ */
+#define CRASH_ALIGN (128 << 20)
+#define CRASH_ADDR_MAX (PHYS_OFFSET + (512 << 20))
+
static inline unsigned long long get_total_mem(void)
{
unsigned long total;
@@ -965,6 +972,28 @@ static void __init reserve_crashkernel(void)
if (ret)
return;
+ if (crash_base <= 0) {
+ unsigned long long crash_max = CRASH_ADDR_MAX;
+ if (crash_max > (u32)~0)
+ crash_max = (u32)~0;
+ crash_base = memblock_find_in_range(CRASH_ALIGN, crash_max,
+ crash_size, CRASH_ALIGN);
+ if (!crash_base) {
+ pr_err("crashkernel reservation failed - No suitable area found.\n");
+ return;
+ }
+ } else {
+ unsigned long long start;
+
+ start = memblock_find_in_range(crash_base,
+ crash_base + crash_size,
+ crash_size, SECTION_SIZE);
+ if (start != crash_base) {
+ pr_err("crashkernel reservation failed - memory is in use.\n");
+ return;
+ }
+ }
+
ret = memblock_reserve(crash_base, crash_size);
if (ret < 0) {
pr_warn("crashkernel reservation failed - memory is in use (0x%lx)\n",