Enforce that the crash kernel region never overlaps the current kernel, as it will be written directly on kexec load. Also, default to the previous KDUMP_KERNELBASE if the start is 0. Other architectures (x86, ia64) state that specifying the start address 0 (or omitting it) will result in the kernel allocating it. Before the relocatable patch in 2.6.28, powerpc would adjust any other start value to the hardcoded KDUMP_KERNELBASE of 32M. Signed-off-by: Milton Miller <miltonm at bga.com> --- consider for stable 2.6.28: A crash region start of 0 results either in a kernel panic (if all of segemnt 0 is reserved) or confused kexec userspace (as the start and length are not exported to userspace): Starting new kernel Reserving 512MB of memory at 0MB for crashkernel (System RAM: 2048MB) Using pSeries machine description ... [boot]0012 Setup Arch Kernel panic - not syncing: ERROR: Failed to allocate 0x4000 bytes below 0x10000000. or # kexec -p /root/vmlinux Memory for crashkernel is not reserved Please reserve memory by passing "crashkernel=X at Y" parameter to the kernel Then try loading kdump kernel # cat /proc/cmdline retain_initrd crashkernel=64M # Index: common/arch/powerpc/kernel/machine_kexec.c =================================================================== --- common.orig/arch/powerpc/kernel/machine_kexec.c 2009-01-01 23:43:45.000000000 -0600 +++ common/arch/powerpc/kernel/machine_kexec.c 2009-01-02 00:40:24.000000000 -0600 @@ -13,6 +13,7 @@ #include <linux/reboot.h> #include <linux/threads.h> #include <linux/lmb.h> +#include <asm/sections.h> #include <asm/machdep.h> #include <asm/prom.h> @@ -94,10 +95,35 @@ void __init reserve_crashkernel(void) KDUMP_KERNELBASE); crashk_res.start = KDUMP_KERNELBASE; +#else + if (!crashk_res.start) { + /* + * unspecified address, choose a region of specified size + * can overlap with initrd (ignoring corruption when retained) + * ppc64 requires kernel and some stacks to be in first segemnt + */ + crashk_res.start = KDUMP_KERNELBASE; + } + + crash_base = PAGE_ALIGN(crashk_res.start); + if (crash_base != crashk_res.start) { + printk("Crash kernel base must be aligned to 0x%lx\n", + PAGE_SIZE); + crashk_res.start = crash_base; + } + #endif crash_size = PAGE_ALIGN(crash_size); crashk_res.end = crashk_res.start + crash_size - 1; + /* The crash region must not overlap the current kernel */ + if (overlaps_crashkernel(__pa(_stext), _end - _stext)) { + printk(KERN_WARNING + "Crash kernel can not overlap current kernel\n"); + crashk_res.start = crashk_res.end = 0; + return; + } + /* Crash kernel trumps memory limit */ if (memory_limit && memory_limit <= crashk_res.end) { memory_limit = crashk_res.end + 1;