diff options
author | Paul Mundt <lethal@linux-sh.org> | 2007-04-26 22:25:57 -0400 |
---|---|---|
committer | Paul Mundt <lethal@hera.kernel.org> | 2007-05-06 22:11:56 -0400 |
commit | 4d5ade5b29c618e97a8988efb6967cb4dd0e2183 (patch) | |
tree | 376d71458747e23e7f5171b9914b0d516cad7c7b | |
parent | db62e5bd297d1f325811c5495ad23de36db0fdd4 (diff) |
sh: kdump support.
This adds support for kexec based crash dumps.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/Kconfig | 14 | ||||
-rw-r--r-- | arch/sh/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/sh/kernel/crash_dump.c | 46 | ||||
-rw-r--r-- | arch/sh/kernel/machine_kexec.c | 29 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 6 | ||||
-rw-r--r-- | include/asm-sh/kexec.h | 42 |
6 files changed, 129 insertions, 9 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 0b465d622cfc..dfdfaae6772f 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -551,6 +551,20 @@ config KEXEC | |||
551 | support. As of this writing the exact hardware interface is | 551 | support. As of this writing the exact hardware interface is |
552 | strongly in flux, so no good recommendation can be made. | 552 | strongly in flux, so no good recommendation can be made. |
553 | 553 | ||
554 | config CRASH_DUMP | ||
555 | bool "kernel crash dumps (EXPERIMENTAL)" | ||
556 | depends on EXPERIMENTAL | ||
557 | help | ||
558 | Generate crash dump after being started by kexec. | ||
559 | This should be normally only set in special crash dump kernels | ||
560 | which are loaded in the main kernel with kexec-tools into | ||
561 | a specially reserved region and then later executed after | ||
562 | a crash by kdump/kexec. The crash dump kernel must be compiled | ||
563 | to a memory address not used by the main kernel using | ||
564 | MEMORY_START. | ||
565 | |||
566 | For more details see Documentation/kdump/kdump.txt | ||
567 | |||
554 | config SMP | 568 | config SMP |
555 | bool "Symmetric multi-processing support" | 569 | bool "Symmetric multi-processing support" |
556 | ---help--- | 570 | ---help--- |
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index ff30d7f58043..9104b6257644 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -20,5 +20,6 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o | |||
20 | obj-$(CONFIG_MODULES) += module.o | 20 | obj-$(CONFIG_MODULES) += module.o |
21 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 21 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
22 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 22 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
23 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | ||
23 | obj-$(CONFIG_PM) += pm.o | 24 | obj-$(CONFIG_PM) += pm.o |
24 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 25 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
diff --git a/arch/sh/kernel/crash_dump.c b/arch/sh/kernel/crash_dump.c new file mode 100644 index 000000000000..4a2ecbe27d8e --- /dev/null +++ b/arch/sh/kernel/crash_dump.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * crash_dump.c - Memory preserving reboot related code. | ||
3 | * | ||
4 | * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) | ||
5 | * Copyright (C) IBM Corporation, 2004. All rights reserved | ||
6 | */ | ||
7 | |||
8 | #include <linux/errno.h> | ||
9 | #include <linux/crash_dump.h> | ||
10 | #include <linux/io.h> | ||
11 | #include <asm/uaccess.h> | ||
12 | |||
13 | /** | ||
14 | * copy_oldmem_page - copy one page from "oldmem" | ||
15 | * @pfn: page frame number to be copied | ||
16 | * @buf: target memory address for the copy; this can be in kernel address | ||
17 | * space or user address space (see @userbuf) | ||
18 | * @csize: number of bytes to copy | ||
19 | * @offset: offset in bytes into the page (based on pfn) to begin the copy | ||
20 | * @userbuf: if set, @buf is in user address space, use copy_to_user(), | ||
21 | * otherwise @buf is in kernel address space, use memcpy(). | ||
22 | * | ||
23 | * Copy a page from "oldmem". For this page, there is no pte mapped | ||
24 | * in the current kernel. We stitch up a pte, similar to kmap_atomic. | ||
25 | */ | ||
26 | ssize_t copy_oldmem_page(unsigned long pfn, char *buf, | ||
27 | size_t csize, unsigned long offset, int userbuf) | ||
28 | { | ||
29 | void *vaddr; | ||
30 | |||
31 | if (!csize) | ||
32 | return 0; | ||
33 | |||
34 | vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE); | ||
35 | |||
36 | if (userbuf) { | ||
37 | if (copy_to_user(buf, (vaddr + offset), csize)) { | ||
38 | iounmap(vaddr); | ||
39 | return -EFAULT; | ||
40 | } | ||
41 | } else | ||
42 | memcpy(buf, (vaddr + offset), csize); | ||
43 | |||
44 | iounmap(vaddr); | ||
45 | return csize; | ||
46 | } | ||
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index 08587cdb64d6..790ed69b8666 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c | |||
@@ -59,13 +59,13 @@ static void kexec_info(struct kimage *image) | |||
59 | printk(" segment[%d]: 0x%08x - 0x%08x (0x%08x)\n", | 59 | printk(" segment[%d]: 0x%08x - 0x%08x (0x%08x)\n", |
60 | i, | 60 | i, |
61 | (unsigned int)image->segment[i].mem, | 61 | (unsigned int)image->segment[i].mem, |
62 | (unsigned int)image->segment[i].mem + image->segment[i].memsz, | 62 | (unsigned int)image->segment[i].mem + |
63 | image->segment[i].memsz, | ||
63 | (unsigned int)image->segment[i].memsz); | 64 | (unsigned int)image->segment[i].memsz); |
64 | } | 65 | } |
65 | printk(" start : 0x%08x\n\n", (unsigned int)image->start); | 66 | printk(" start : 0x%08x\n\n", (unsigned int)image->start); |
66 | } | 67 | } |
67 | 68 | ||
68 | |||
69 | /* | 69 | /* |
70 | * Do not allocate memory (or fail in any way) in machine_kexec(). | 70 | * Do not allocate memory (or fail in any way) in machine_kexec(). |
71 | * We are past the point of no return, committed to rebooting now. | 71 | * We are past the point of no return, committed to rebooting now. |
@@ -101,6 +101,27 @@ NORET_TYPE void machine_kexec(struct kimage *image) | |||
101 | 101 | ||
102 | /* now call it */ | 102 | /* now call it */ |
103 | rnk = (relocate_new_kernel_t) reboot_code_buffer; | 103 | rnk = (relocate_new_kernel_t) reboot_code_buffer; |
104 | (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg); | 104 | (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg); |
105 | } | 105 | } |
106 | 106 | ||
107 | /* crashkernel=size@addr specifies the location to reserve for | ||
108 | * a crash kernel. By reserving this memory we guarantee | ||
109 | * that linux never sets it up as a DMA target. | ||
110 | * Useful for holding code to do something appropriate | ||
111 | * after a kernel panic. | ||
112 | */ | ||
113 | static int __init parse_crashkernel(char *arg) | ||
114 | { | ||
115 | unsigned long size, base; | ||
116 | size = memparse(arg, &arg); | ||
117 | if (*arg == '@') { | ||
118 | base = memparse(arg+1, &arg); | ||
119 | /* FIXME: Do I want a sanity check | ||
120 | * to validate the memory range? | ||
121 | */ | ||
122 | crashk_res.start = base; | ||
123 | crashk_res.end = base + size - 1; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | early_param("crashkernel", parse_crashkernel); | ||
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index cab91a7665da..477d2a854fc4 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/pfn.h> | 20 | #include <linux/pfn.h> |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/kexec.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
25 | #include <asm/sections.h> | 26 | #include <asm/sections.h> |
@@ -287,6 +288,11 @@ void __init setup_bootmem_allocator(unsigned long start_pfn) | |||
287 | } | 288 | } |
288 | } | 289 | } |
289 | #endif | 290 | #endif |
291 | #ifdef CONFIG_KEXEC | ||
292 | if (crashk_res.start != crashk_res.end) | ||
293 | reserve_bootmem(crashk_res.start, | ||
294 | crashk_res.end - crashk_res.start + 1); | ||
295 | #endif | ||
290 | } | 296 | } |
291 | 297 | ||
292 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 298 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
diff --git a/include/asm-sh/kexec.h b/include/asm-sh/kexec.h index 9d235af20cdd..da36a7548601 100644 --- a/include/asm-sh/kexec.h +++ b/include/asm-sh/kexec.h | |||
@@ -1,5 +1,8 @@ | |||
1 | #ifndef _SH_KEXEC_H | 1 | #ifndef __ASM_SH_KEXEC_H |
2 | #define _SH_KEXEC_H | 2 | #define __ASM_SH_KEXEC_H |
3 | |||
4 | #include <asm/ptrace.h> | ||
5 | #include <asm/string.h> | ||
3 | 6 | ||
4 | /* | 7 | /* |
5 | * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. | 8 | * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. |
@@ -25,8 +28,37 @@ | |||
25 | 28 | ||
26 | #define MAX_NOTE_BYTES 1024 | 29 | #define MAX_NOTE_BYTES 1024 |
27 | 30 | ||
28 | /* Provide a dummy definition to avoid build failures. */ | ||
29 | static inline void crash_setup_regs(struct pt_regs *newregs, | 31 | static inline void crash_setup_regs(struct pt_regs *newregs, |
30 | struct pt_regs *oldregs) { } | 32 | struct pt_regs *oldregs) |
33 | { | ||
34 | if (oldregs) | ||
35 | memcpy(newregs, oldregs, sizeof(*newregs)); | ||
36 | else { | ||
37 | __asm__ __volatile__ ("mov r0, %0" : "=r" (newregs->regs[0])); | ||
38 | __asm__ __volatile__ ("mov r1, %0" : "=r" (newregs->regs[1])); | ||
39 | __asm__ __volatile__ ("mov r2, %0" : "=r" (newregs->regs[2])); | ||
40 | __asm__ __volatile__ ("mov r3, %0" : "=r" (newregs->regs[3])); | ||
41 | __asm__ __volatile__ ("mov r4, %0" : "=r" (newregs->regs[4])); | ||
42 | __asm__ __volatile__ ("mov r5, %0" : "=r" (newregs->regs[5])); | ||
43 | __asm__ __volatile__ ("mov r6, %0" : "=r" (newregs->regs[6])); | ||
44 | __asm__ __volatile__ ("mov r7, %0" : "=r" (newregs->regs[7])); | ||
45 | __asm__ __volatile__ ("mov r8, %0" : "=r" (newregs->regs[8])); | ||
46 | __asm__ __volatile__ ("mov r9, %0" : "=r" (newregs->regs[9])); | ||
47 | __asm__ __volatile__ ("mov r10, %0" : "=r" (newregs->regs[10])); | ||
48 | __asm__ __volatile__ ("mov r11, %0" : "=r" (newregs->regs[11])); | ||
49 | __asm__ __volatile__ ("mov r12, %0" : "=r" (newregs->regs[12])); | ||
50 | __asm__ __volatile__ ("mov r13, %0" : "=r" (newregs->regs[13])); | ||
51 | __asm__ __volatile__ ("mov r14, %0" : "=r" (newregs->regs[14])); | ||
52 | __asm__ __volatile__ ("mov r15, %0" : "=r" (newregs->regs[15])); | ||
53 | |||
54 | __asm__ __volatile__ ("sts pr, %0" : "=r" (newregs->pr)); | ||
55 | __asm__ __volatile__ ("sts macl, %0" : "=r" (newregs->macl)); | ||
56 | __asm__ __volatile__ ("sts mach, %0" : "=r" (newregs->mach)); | ||
57 | |||
58 | __asm__ __volatile__ ("stc gbr, %0" : "=r" (newregs->gbr)); | ||
59 | __asm__ __volatile__ ("stc sr, %0" : "=r" (newregs->sr)); | ||
31 | 60 | ||
32 | #endif /* _SH_KEXEC_H */ | 61 | newregs->pc = (unsigned long)current_text_addr(); |
62 | } | ||
63 | } | ||
64 | #endif /* __ASM_SH_KEXEC_H */ | ||