aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2007-04-26 22:25:57 -0400
committerPaul Mundt <lethal@hera.kernel.org>2007-05-06 22:11:56 -0400
commit4d5ade5b29c618e97a8988efb6967cb4dd0e2183 (patch)
tree376d71458747e23e7f5171b9914b0d516cad7c7b
parentdb62e5bd297d1f325811c5495ad23de36db0fdd4 (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/Kconfig14
-rw-r--r--arch/sh/kernel/Makefile1
-rw-r--r--arch/sh/kernel/crash_dump.c46
-rw-r--r--arch/sh/kernel/machine_kexec.c29
-rw-r--r--arch/sh/kernel/setup.c6
-rw-r--r--include/asm-sh/kexec.h42
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
554config 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
554config SMP 568config 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
20obj-$(CONFIG_MODULES) += module.o 20obj-$(CONFIG_MODULES) += module.o
21obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 21obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
22obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o 22obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
23obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
23obj-$(CONFIG_PM) += pm.o 24obj-$(CONFIG_PM) += pm.o
24obj-$(CONFIG_STACKTRACE) += stacktrace.o 25obj-$(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 */
26ssize_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 */
113static 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}
127early_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. */
29static inline void crash_setup_regs(struct pt_regs *newregs, 31static 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 */