Hi,
The following patchset completes the basic functionality on
kexec based crashdumps on i386. The first patch makes it
possible to boot an i386 kernel from a non-default physical
address. The rest of the patches are minor clean-ups and
bug-fixes.
All the patches are on top of 2.6.9-rc4-mm1.
Kindly review them and let us know your feedback.
Thanks and Regards,
Hari
Signed-off-by: Hariprasad Nellitheertha <[email protected]>
---
linux-old-hari/arch/i386/Kconfig | 10 ++++
linux-old-hari/arch/i386/boot/compressed/head.S | 6 +-
linux-old-hari/arch/i386/boot/compressed/misc.c | 7 +-
linux-old-hari/arch/i386/kernel/vmlinux.lds.S | 56 +++++++++++++----------
linux-old-hari/include/asm-generic/vmlinux.lds.h | 2
linux-old-hari/include/asm-i386/segment.h | 2
6 files changed, 54 insertions(+), 29 deletions(-)
diff -puN arch/i386/Kconfig~kd-kern-offset arch/i386/Kconfig
--- linux-old/arch/i386/Kconfig~kd-kern-offset 2004-10-19 19:00:17.000000000 +0530
+++ linux-old-hari/arch/i386/Kconfig 2004-10-19 19:03:47.000000000 +0530
@@ -882,6 +882,16 @@ config REGPARM
source "drivers/perfctr/Kconfig"
+config KERN_PHYS_OFFSET
+ int "Physical address where the kernel is loaded (1-112)MB"
+ range 1 112
+ default "1"
+ help
+ This gives the physical address where the kernel is loaded.
+ Primarily used in the case of kexec on panic where the
+ recovery kernel needs to run at a different address than
+ the panic-ed kernel.
+
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
depends on EXPERIMENTAL
diff -puN arch/i386/boot/compressed/head.S~kd-kern-offset arch/i386/boot/compressed/head.S
--- linux-old/arch/i386/boot/compressed/head.S~kd-kern-offset 2004-10-19 19:04:55.000000000 +0530
+++ linux-old-hari/arch/i386/boot/compressed/head.S 2004-10-19 19:06:02.000000000 +0530
@@ -74,7 +74,7 @@ startup_32:
popl %esi # discard address
popl %esi # real mode pointer
xorl %ebx,%ebx
- ljmp $(__BOOT_CS), $0x100000
+ ljmp $(__BOOT_CS), $KERN_PHYS_OFFSET
/*
* We come here, if we were loaded high.
@@ -99,7 +99,7 @@ startup_32:
popl %ecx # lcount
popl %edx # high_buffer_start
popl %eax # hcount
- movl $0x100000,%edi
+ movl $KERN_PHYS_OFFSET,%edi
cli # make sure we don't get interrupted
ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine
@@ -124,5 +124,5 @@ move_routine_start:
movsl
movl %ebx,%esi # Restore setup pointer
xorl %ebx,%ebx
- ljmp $(__BOOT_CS), $0x100000
+ ljmp $(__BOOT_CS), $KERN_PHYS_OFFSET
move_routine_end:
diff -puN arch/i386/boot/compressed/misc.c~kd-kern-offset arch/i386/boot/compressed/misc.c
--- linux-old/arch/i386/boot/compressed/misc.c~kd-kern-offset 2004-10-19 19:04:55.000000000 +0530
+++ linux-old-hari/arch/i386/boot/compressed/misc.c 2004-10-19 19:08:07.000000000 +0530
@@ -14,6 +14,7 @@
#include <linux/tty.h>
#include <video/edid.h>
#include <asm/io.h>
+#include <asm/segment.h>
/*
* gzip declarations
@@ -309,7 +310,7 @@ static void setup_normal_output_buffer(v
#else
if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
#endif
- output_data = (char *)0x100000; /* Points to 1M */
+ output_data = (char *)KERN_PHYS_OFFSET; /* Points to 1M */
free_mem_end_ptr = (long)real_mode;
}
@@ -334,8 +335,8 @@ static void setup_output_buffer_if_we_ru
low_buffer_size = low_buffer_end - LOW_BUFFER_START;
high_loaded = 1;
free_mem_end_ptr = (long)high_buffer_start;
- if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
- high_buffer_start = (uch *)(0x100000 + low_buffer_size);
+ if ( (KERN_PHYS_OFFSET + low_buffer_size) > ((ulg)high_buffer_start)) {
+ high_buffer_start = (uch *)(KERN_PHYS_OFFSET + low_buffer_size);
mv->hcount = 0; /* say: we need not to move high_buffer */
}
else mv->hcount = -1;
diff -puN include/asm-i386/segment.h~kd-kern-offset include/asm-i386/segment.h
--- linux-old/include/asm-i386/segment.h~kd-kern-offset 2004-10-19 19:09:19.000000000 +0530
+++ linux-old-hari/include/asm-i386/segment.h 2004-10-19 19:09:59.000000000 +0530
@@ -95,4 +95,6 @@
*/
#define IDT_ENTRIES 256
+#define KERN_PHYS_OFFSET (CONFIG_KERN_PHYS_OFFSET * 0x100000)
+
#endif
diff -puN include/asm-generic/vmlinux.lds.h~kd-kern-offset include/asm-generic/vmlinux.lds.h
--- linux-old/include/asm-generic/vmlinux.lds.h~kd-kern-offset 2004-10-19 19:09:19.000000000 +0530
+++ linux-old-hari/include/asm-generic/vmlinux.lds.h 2004-10-19 19:21:09.000000000 +0530
@@ -70,7 +70,7 @@
}
#define SECURITY_INIT \
- .security_initcall.init : { \
+ .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) {\
VMLINUX_SYMBOL(__security_initcall_start) = .; \
*(.security_initcall.init) \
VMLINUX_SYMBOL(__security_initcall_end) = .; \
diff -puN arch/i386/kernel/vmlinux.lds.S~kd-kern-offset arch/i386/kernel/vmlinux.lds.S
--- linux-old/arch/i386/kernel/vmlinux.lds.S~kd-kern-offset 2004-10-19 19:33:47.000000000 +0530
+++ linux-old-hari/arch/i386/kernel/vmlinux.lds.S 2004-10-19 19:43:27.000000000 +0530
@@ -2,20 +2,24 @@
* Written by Martin Mares <[email protected]>;
*/
+#define LOAD_OFFSET __PAGE_OFFSET
+
#include <asm-generic/vmlinux.lds.h>
#include <asm/thread_info.h>
#include <asm/page.h>
+#include <asm/segment.h>
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
-ENTRY(startup_32)
+ENTRY(phys_startup_32)
jiffies = jiffies_64;
SECTIONS
{
- . = __PAGE_OFFSET + 0x100000;
+ . = LOAD_OFFSET + KERN_PHYS_OFFSET;
+ phys_startup_32 = startup_32 - LOAD_OFFSET;
/* read-only */
_text = .; /* Text and read-only data */
- .text : {
+ .text : AT(ADDR(.text) - LOAD_OFFSET) {
*(.text)
SCHED_TEXT
LOCK_TEXT
@@ -27,49 +31,51 @@ SECTIONS
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
- __ex_table : { *(__ex_table) }
+ __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
__stop___ex_table = .;
RODATA
/* writeable */
- .data : { /* Data */
+ .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
*(.data)
CONSTRUCTORS
}
. = ALIGN(4096);
__nosave_begin = .;
- .data_nosave : { *(.data.nosave) }
+ .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) }
. = ALIGN(4096);
__nosave_end = .;
. = ALIGN(4096);
- .data.page_aligned : { *(.data.idt) }
+ .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { *(.data.idt) }
. = ALIGN(32);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+ *(.data.cacheline_aligned)
+ }
_edata = .; /* End of data section */
. = ALIGN(THREAD_SIZE); /* init_task */
- .data.init_task : { *(.data.init_task) }
+ .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { *(.data.init_task) }
/* will be freed after init */
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
- .init.text : {
+ .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
_sinittext = .;
*(.init.text)
_einittext = .;
}
- .init.data : { *(.init.data) }
+ .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
. = ALIGN(16);
__setup_start = .;
- .init.setup : { *(.init.setup) }
+ .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : {
+ .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
@@ -80,32 +86,38 @@ SECTIONS
}
__initcall_end = .;
__con_initcall_start = .;
- .con_initcall.init : { *(.con_initcall.init) }
+ .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+ *(.con_initcall.init)
+ }
__con_initcall_end = .;
SECURITY_INIT
. = ALIGN(4);
__alt_instructions = .;
- .altinstructions : { *(.altinstructions) }
- __alt_instructions_end = .;
- .altinstr_replacement : { *(.altinstr_replacement) }
+ .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+ *(.altinstructions)
+ }
+ __alt_instructions_end = .;
+ .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
+ *(.altinstr_replacement)
+ }
/* .exit.text is discard at runtime, not link time, to deal with references
from .altinstructions and .eh_frame */
- .exit.text : { *(.exit.text) }
- .exit.data : { *(.exit.data) }
+ .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
+ .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
. = ALIGN(4096);
__initramfs_start = .;
- .init.ramfs : { *(.init.ramfs) }
+ .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
__initramfs_end = .;
. = ALIGN(32);
__per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
+ .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
__per_cpu_end = .;
. = ALIGN(4096);
__init_end = .;
/* freed after init ends here */
__bss_start = .; /* BSS */
- .bss : {
+ .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
*(.bss.page_aligned)
*(.bss)
}
_
Signed-off-by: Vivek Goyal <[email protected]>
Signed-off-by: Hariprasad Nellitheertha <[email protected]>
---
linux-2.6.9-rc4-hari/Documentation/kdump.txt | 24 ++++++++----------------
linux-2.6.9-rc4-hari/include/linux/crash_dump.h | 11 ++++++++---
linux-2.6.9-rc4-hari/kernel/crash.c | 5 ++++-
3 files changed, 20 insertions(+), 20 deletions(-)
diff -puN Documentation/kdump.txt~kd-misc-changes Documentation/kdump.txt
--- linux-2.6.9-rc4/Documentation/kdump.txt~kd-misc-changes 2004-10-21 15:10:58.000000000 +0530
+++ linux-2.6.9-rc4-hari/Documentation/kdump.txt 2004-10-21 15:10:58.000000000 +0530
@@ -27,19 +27,11 @@ SETUP
1) Obtain the appropriate -mm tree patch and apply it on to the vanilla
kernel tree.
-2) In order to enable the kernel to boot from a non-default location, the
- following patches (by Eric Biederman) needs to be applied.
-
- http://www.xmission.com/~ebiederm/files/kexec/2.6.8.1-kexec3/
- broken-out/highbzImage.i386.patch
- http://www.xmission.com/~ebiederm/files/kexec/2.6.8.1-kexec3/
- broken-out/vmlinux-lds.i386.patch
-
-3) Two kernels need to be built in order to get this feature working.
+2) Two kernels need to be built in order to get this feature working.
For the first kernel, choose the default values for the following options.
- a) Physical address where the kernel expects to be loaded
+ a) Physical address where the kernel is loaded
b) kexec system call
c) kernel crash dumps
@@ -51,28 +43,28 @@ SETUP
Also ensure you have CONFIG_HIGHMEM on.
-4) Boot into the first kernel. You are now ready to try out kexec based crash
+3) Boot into the first kernel. You are now ready to try out kexec based crash
dumps.
-5) Load the second kernel to be booted using
+4) Load the second kernel to be booted using
- kexec -l <second-kernel> --args-linux --append="root=<root-dev> dump
+ kexec -p <second-kernel> --args-linux --append="root=<root-dev> dump
init 1 memmap=exactmap memmap=640k@0 memmap=32M@16M"
Note that <second-kernel> has to be a vmlinux image. bzImage will not
work, as of now.
-6) Enable kexec based dumping by
+5) Enable kexec based dumping by
echo 1 > /proc/kexec-dump
If this is not set, the system will not do a kexec reboot in the event
of a panic.
-7) System reboots into the second kernel when a panic occurs.
+6) System reboots into the second kernel when a panic occurs.
You could write a module to call panic, for testing purposes.
-8) Write out the dump file using
+7) Write out the dump file using
cp /proc/vmcore <dump-file>
diff -puN include/linux/crash_dump.h~kd-misc-changes include/linux/crash_dump.h
--- linux-2.6.9-rc4/include/linux/crash_dump.h~kd-misc-changes 2004-10-21 15:10:58.000000000 +0530
+++ linux-2.6.9-rc4-hari/include/linux/crash_dump.h 2004-10-21 15:10:58.000000000 +0530
@@ -15,15 +15,20 @@ extern void elf_kcore_store_hdr(char *,
#ifdef CONFIG_CRASH_DUMP
extern ssize_t copy_oldmem_page(unsigned long, char *, size_t, int);
extern void __crash_machine_kexec(void);
-extern void crash_enable_by_proc(void);
-extern void crash_create_proc_entry(void);
extern int crash_dump_on;
static inline void crash_machine_kexec(void)
{
__crash_machine_kexec();
}
#else
+#define crash_machine_kexec() do { } while(0)
+#endif
+
+
+#if defined(CONFIG_CRASH_DUMP) && defined(CONFIG_PROC_FS)
+extern void crash_enable_by_proc(void);
+extern void crash_create_proc_entry(void);
+#else
#define crash_enable_by_proc() do { } while(0)
#define crash_create_proc_entry() do { } while(0)
-#define crash_machine_kexec() do { } while(0)
#endif
diff -puN kernel/crash.c~kd-misc-changes kernel/crash.c
--- linux-2.6.9-rc4/kernel/crash.c~kd-misc-changes 2004-10-21 15:10:58.000000000 +0530
+++ linux-2.6.9-rc4-hari/kernel/crash.c 2004-10-21 15:10:58.000000000 +0530
@@ -16,6 +16,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PROC_FS
/*
* Enable kexec reboot upon panic; for dumping
*/
@@ -57,6 +58,8 @@ void crash_create_proc_entry(void)
}
}
+#endif /* CONFIG_PROC_FS */
+
void __crash_machine_kexec(void)
{
struct kimage *image;
@@ -64,7 +67,7 @@ void __crash_machine_kexec(void)
if ((!crash_dump_on) || (crashed))
return;
- image = xchg(&kexec_image, 0);
+ image = xchg(&kexec_crash_image, 0);
if (image) {
crashed = 1;
printk(KERN_EMERG "kexec: opening parachute\n");
_
Signed-off-by: Vivek Goyal <[email protected]>
Signed-off-by: Hariprasad Nellitheertha <[email protected]>
---
linux-2.6.9-rc4-hari/arch/i386/kernel/machine_kexec.c | 10 ----------
linux-2.6.9-rc4-hari/kernel/crash.c | 9 +++++++++
2 files changed, 9 insertions(+), 10 deletions(-)
diff -puN arch/i386/kernel/machine_kexec.c~kd-cleanup arch/i386/kernel/machine_kexec.c
--- linux-2.6.9-rc4/arch/i386/kernel/machine_kexec.c~kd-cleanup 2004-10-21 15:11:05.000000000 +0530
+++ linux-2.6.9-rc4-hari/arch/i386/kernel/machine_kexec.c 2004-10-21 15:11:05.000000000 +0530
@@ -195,9 +195,6 @@ void machine_kexec(struct kimage *image)
unsigned long reboot_code_buffer;
relocate_new_kernel_t rnk;
- crash_dump_stop_cpus();
- crash_dump_save_registers();
-
/* Interrupts aren't acceptable while we reboot */
local_irq_disable();
@@ -208,13 +205,6 @@ void machine_kexec(struct kimage *image)
/* Set up an identity mapping for the reboot_code_buffer */
identity_map_page(reboot_code_buffer);
- /*
- * If we are here to do a crash dump, save the memory from
- * 0-640k before we copy over the kexec kernel image. Otherwise
- * our dump will show the wrong kernel entirely.
- */
- crash_relocate_mem();
-
/* copy it out */
memcpy((void *)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size);
diff -puN kernel/crash.c~kd-cleanup kernel/crash.c
--- linux-2.6.9-rc4/kernel/crash.c~kd-cleanup 2004-10-21 15:11:05.000000000 +0530
+++ linux-2.6.9-rc4-hari/kernel/crash.c 2004-10-21 15:11:05.000000000 +0530
@@ -71,6 +71,15 @@ void __crash_machine_kexec(void)
if (image) {
crashed = 1;
printk(KERN_EMERG "kexec: opening parachute\n");
+ crash_dump_stop_cpus();
+ crash_dump_save_registers();
+
+ /* If we are here to do a crash dump, save the memory from
+ * 0-640k before we copy over the kexec kernel image. Otherwise
+ * our dump will show the wrong kernel entirely.
+ */
+ crash_relocate_mem();
+
machine_kexec(image);
} else {
printk(KERN_EMERG "kexec: No kernel image loaded!\n");
_
Signed-off-by: Hariprasad Nellitheertha <[email protected]>
---
linux-kexec-hari/include/linux/kexec.h | 1 +
linux-kexec-hari/kernel/kexec.c | 13 +++++--------
2 files changed, 6 insertions(+), 8 deletions(-)
diff -puN include/linux/kexec.h~kexec-panic include/linux/kexec.h
--- linux-kexec/include/linux/kexec.h~kexec-panic 2004-10-18 14:59:01.000000000 +0530
+++ linux-kexec-hari/include/linux/kexec.h 2004-10-18 15:00:33.000000000 +0530
@@ -52,5 +52,6 @@ extern asmlinkage long sys_kexec(unsigne
struct kexec_segment *segments);
extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order);
extern struct kimage *kexec_image;
+extern struct kimage *kexec_crash_image;
#endif
#endif /* LINUX_KEXEC_H */
diff -puN kernel/kexec.c~kexec-panic kernel/kexec.c
--- linux-kexec/kernel/kexec.c~kexec-panic 2004-10-18 14:59:01.000000000 +0530
+++ linux-kexec-hari/kernel/kexec.c 2004-10-19 14:12:33.000000000 +0530
@@ -585,6 +585,7 @@ static int kimage_load_segment(struct ki
* that to happen you need to do that yourself.
*/
struct kimage *kexec_image = NULL;
+struct kimage *kexec_crash_image = NULL;
asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
struct kexec_segment *segments, unsigned long flags)
@@ -596,13 +597,6 @@ asmlinkage long sys_kexec_load(unsigned
if (!capable(CAP_SYS_BOOT))
return -EPERM;
- /*
- * In case we need just a little bit of special behavior for
- * reboot on panic.
- */
- if (flags != 0)
- return -EINVAL;
-
if (nr_segments > KEXEC_SEGMENT_MAX)
return -EINVAL;
@@ -632,7 +626,10 @@ asmlinkage long sys_kexec_load(unsigned
}
}
- image = xchg(&kexec_image, image);
+ if (!flags)
+ image = xchg(&kexec_image, image);
+ else
+ image = xchg(&kexec_crash_image, image);
out:
kimage_free(image);
_