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 */ | ||
