This commit was manufactured by cvs2svn to create branch
[linux-2.6.git] / kernel / crash.c
1 /*
2  *      kernel/crash.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/smp_lock.h>
9 #include <linux/kexec.h>
10 #include <linux/errno.h>
11 #include <linux/proc_fs.h>
12 #include <linux/bootmem.h>
13 #include <linux/highmem.h>
14 #include <linux/crash_dump.h>
15
16 #include <asm/io.h>
17 #include <asm/uaccess.h>
18
19 #ifdef CONFIG_PROC_FS
20 /*
21  * Enable kexec reboot upon panic; for dumping
22  */
23 static ssize_t write_crash_dump_on(struct file *file, const char __user *buf,
24                                         size_t count, loff_t *ppos)
25 {
26         if (count) {
27                 if (get_user(crash_dump_on, buf))
28                         return -EFAULT;
29         }
30         return count;
31 }
32
33 static struct file_operations proc_crash_dump_on_operations = {
34         .write = write_crash_dump_on,
35 };
36
37 extern struct file_operations proc_vmcore_operations;
38 extern struct proc_dir_entry *proc_vmcore;
39
40 void crash_enable_by_proc(void)
41 {
42         struct proc_dir_entry *entry;
43
44         entry = create_proc_entry("kexec-dump", S_IWUSR, NULL);
45         if (entry)
46                 entry->proc_fops = &proc_crash_dump_on_operations;
47 }
48
49 void crash_create_proc_entry(void)
50 {
51         if (dump_enabled) {
52                 proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
53                 if (proc_vmcore) {
54                         proc_vmcore->proc_fops = &proc_vmcore_operations;
55                         proc_vmcore->size =
56                         (size_t)(saved_max_pfn << PAGE_SHIFT);
57                 }
58         }
59 }
60
61 #endif /* CONFIG_PROC_FS */
62
63 void __crash_machine_kexec(void)
64 {
65         struct kimage *image;
66
67         if ((!crash_dump_on) || (crashed))
68                 return;
69
70         image = xchg(&kexec_crash_image, 0);
71         if (image) {
72                 crashed = 1;
73                 printk(KERN_EMERG "kexec: opening parachute\n");
74                 crash_dump_stop_cpus();
75                 crash_dump_save_registers();
76
77         /* If we are here to do a crash dump, save the memory from
78          * 0-640k before we copy over the kexec kernel image.  Otherwise
79          * our dump will show the wrong kernel entirely.
80          */
81                 crash_relocate_mem();
82
83                 machine_kexec(image);
84         } else {
85                 printk(KERN_EMERG "kexec: No kernel image loaded!\n");
86         }
87 }
88
89 /*
90  * Copy a page from "oldmem". For this page, there is no pte mapped
91  * in the current kernel. We stitch up a pte, similar to kmap_atomic.
92  */
93 ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
94                                 size_t csize, int userbuf)
95 {
96         void *page, *vaddr;
97
98         if (!csize)
99                 return 0;
100
101         page = kmalloc(PAGE_SIZE, GFP_KERNEL);
102
103         vaddr = kmap_atomic_pfn(pfn, KM_PTE0);
104         copy_page(page, vaddr);
105         kunmap_atomic(vaddr, KM_PTE0);
106
107         if (userbuf) {
108                 if (copy_to_user(buf, page, csize)) {
109                         kfree(page);
110                         return -EFAULT;
111                 }
112         } else
113                 memcpy(buf, page, csize);
114         kfree(page);
115
116         return 0;
117 }