enable floppy module generation for boot cd
[linux-2.6.git] / drivers / dump / dump_setup.c
1 /*
2  * Standard kernel function entry points for Linux crash dumps.
3  *
4  * Created by: Matt Robinson (yakker@sourceforge.net)
5  * Contributions from SGI, IBM, HP, MCL, and others.
6  *
7  * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
8  * Copyright (C) 2000 - 2002 TurboLinux, Inc.  All rights reserved.
9  * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
10  * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
11  *
12  * This code is released under version 2 of the GNU GPL.
13  */
14
15 /*
16  * -----------------------------------------------------------------------
17  *
18  * DUMP HISTORY
19  *
20  * This dump code goes back to SGI's first attempts at dumping system
21  * memory on SGI systems running IRIX.  A few developers at SGI needed
22  * a way to take this system dump and analyze it, and created 'icrash',
23  * or IRIX Crash.  The mechanism (the dumps and 'icrash') were used
24  * by support people to generate crash reports when a system failure
25  * occurred.  This was vital for large system configurations that
26  * couldn't apply patch after patch after fix just to hope that the
27  * problems would go away.  So the system memory, along with the crash
28  * dump analyzer, allowed support people to quickly figure out what the
29  * problem was on the system with the crash dump.
30  *
31  * In comes Linux.  SGI started moving towards the open source community,
32  * and upon doing so, SGI wanted to take its support utilities into Linux
33  * with the hopes that they would end up the in kernel and user space to
34  * be used by SGI's customers buying SGI Linux systems.  One of the first
35  * few products to be open sourced by SGI was LKCD, or Linux Kernel Crash
36  * Dumps.  LKCD comprises of a patch to the kernel to enable system
37  * dumping, along with 'lcrash', or Linux Crash, to analyze the system
38  * memory dump.  A few additional system scripts and kernel modifications
39  * are also included to make the dump mechanism and dump data easier to
40  * process and use.
41  *
42  * As soon as LKCD was released into the open source community, a number
43  * of larger companies started to take advantage of it.  Today, there are
44  * many community members that contribute to LKCD, and it continues to
45  * flourish and grow as an open source project.
46  */
47
48 /*
49  * DUMP TUNABLES
50  *
51  * This is the list of system tunables (via /proc) that are available
52  * for Linux systems.  All the read, write, etc., functions are listed
53  * here.  Currently, there are a few different tunables for dumps:
54  *
55  * dump_device (used to be dumpdev):
56  *     The device for dumping the memory pages out to.  This 
57  *     may be set to the primary swap partition for disruptive dumps,
58  *     and must be an unused partition for non-disruptive dumps.
59  *     Todo: In the case of network dumps, this may be interpreted 
60  *     as the IP address of the netdump server to connect to.
61  *
62  * dump_compress (used to be dump_compress_pages):
63  *     This is the flag which indicates which compression mechanism
64  *     to use.  This is a BITMASK, not an index (0,1,2,4,8,16,etc.).
65  *     This is the current set of values:
66  *
67  *     0: DUMP_COMPRESS_NONE -- Don't compress any pages.
68  *     1: DUMP_COMPRESS_RLE  -- This uses RLE compression.
69  *     2: DUMP_COMPRESS_GZIP -- This uses GZIP compression.
70  *
71  * dump_level:
72  *     The amount of effort the dump module should make to save
73  *     information for post crash analysis.  This value is now
74  *     a BITMASK value, not an index:
75  *
76  *     0:   Do nothing, no dumping. (DUMP_LEVEL_NONE)
77  *
78  *     1:   Print out the dump information to the dump header, and
79  *          write it out to the dump_device. (DUMP_LEVEL_HEADER)
80  *
81  *     2:   Write out the dump header and all kernel memory pages.
82  *          (DUMP_LEVEL_KERN)
83  *
84  *     4:   Write out the dump header and all kernel and user
85  *          memory pages.  (DUMP_LEVEL_USED)
86  *
87  *     8:   Write out the dump header and all conventional/cached 
88  *          memory (RAM) pages in the system (kernel, user, free).  
89  *          (DUMP_LEVEL_ALL_RAM)
90  *
91  *    16:   Write out everything, including non-conventional memory
92  *          like firmware, proms, I/O registers, uncached memory.
93  *          (DUMP_LEVEL_ALL)
94  *
95  *     The dump_level will default to 1.
96  *
97  * dump_flags:
98  *     These are the flags to use when talking about dumps.  There
99  *     are lots of possibilities.  This is a BITMASK value, not an index.
100  * 
101  * -----------------------------------------------------------------------
102  */
103
104 #include <linux/kernel.h>
105 #include <linux/delay.h>
106 #include <linux/reboot.h>
107 #include <linux/fs.h>
108 #include <linux/dump.h>
109 #include "dump_methods.h"
110 #include <linux/proc_fs.h>
111 #include <linux/module.h>
112 #include <linux/utsname.h>
113 #include <linux/highmem.h>
114 #include <linux/miscdevice.h>
115 #include <linux/sysrq.h>
116 #include <linux/sysctl.h>
117 #include <linux/nmi.h>
118 #include <linux/init.h>
119
120 #include <asm/hardirq.h>
121 #include <asm/uaccess.h>
122
123 /*
124  * -----------------------------------------------------------------------
125  *                         V A R I A B L E S
126  * -----------------------------------------------------------------------
127  */
128
129 /* Dump tunables */
130 struct dump_config dump_config = {
131         .level          = 0,
132         .flags          = 0,
133         .dump_device    = 0,
134         .dump_addr      = 0,
135         .dumper         = NULL
136 };
137 #ifdef CONFIG_ARM 
138 static _dump_regs_t all_regs;
139 #endif
140
141 /* Global variables used in dump.h */
142 /* degree of system freeze when dumping */
143 enum dump_silence_levels dump_silence_level = DUMP_HARD_SPIN_CPUS;       
144
145 /* Other global fields */
146 extern struct __dump_header dump_header; 
147 struct dump_dev *dump_dev = NULL;  /* Active dump device                   */
148 static int dump_compress = 0;
149
150 static u16 dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize);
151 struct __dump_compress dump_none_compression = {
152         .compress_type  = DUMP_COMPRESS_NONE,
153         .compress_func  = dump_compress_none,
154         .compress_name  = "none",
155 };
156
157 /* our device operations and functions */
158 static int dump_ioctl(struct inode *i, struct file *f,
159         unsigned int cmd, unsigned long arg);
160
161 static struct file_operations dump_fops = {
162         .owner  = THIS_MODULE,
163         .ioctl  = dump_ioctl,
164 };
165
166 static struct miscdevice dump_miscdev = {
167         .minor  = CRASH_DUMP_MINOR,
168         .name   = "dump",
169         .fops   = &dump_fops,
170 };
171 MODULE_ALIAS_MISCDEV(CRASH_DUMP_MINOR);
172
173 /* static variables                                                     */
174 static int dump_okay = 0;               /* can we dump out to disk?     */
175 static spinlock_t dump_lock = SPIN_LOCK_UNLOCKED;
176
177 /* used for dump compressors */
178 static struct list_head dump_compress_list = LIST_HEAD_INIT(dump_compress_list);
179
180 /* list of registered dump targets */
181 static struct list_head dump_target_list = LIST_HEAD_INIT(dump_target_list);
182
183 /* lkcd info structure -- this is used by lcrash for basic system data     */
184 struct __lkcdinfo lkcdinfo = {
185         .ptrsz          = (sizeof(void *) * 8),
186 #if defined(__LITTLE_ENDIAN) 
187         .byte_order     = __LITTLE_ENDIAN,
188 #else
189         .byte_order     = __BIG_ENDIAN,
190 #endif
191         .page_shift     = PAGE_SHIFT,
192         .page_size      = PAGE_SIZE,
193         .page_mask      = PAGE_MASK,
194         .page_offset    = PAGE_OFFSET,
195 };
196
197 /*
198  * -----------------------------------------------------------------------
199  *            / P R O C   T U N A B L E   F U N C T I O N S
200  * -----------------------------------------------------------------------
201  */
202
203 static int proc_dump_device(ctl_table *ctl, int write, struct file *f,
204                             void *buffer, size_t *lenp);
205
206 static int proc_doulonghex(ctl_table *ctl, int write, struct file *f,
207                             void *buffer, size_t *lenp);
208 /*
209  * sysctl-tuning infrastructure.
210  */
211 static ctl_table dump_table[] = {
212         { .ctl_name = CTL_DUMP_LEVEL,
213           .procname = DUMP_LEVEL_NAME, 
214           .data = &dump_config.level,    
215           .maxlen = sizeof(int),
216           .mode = 0644,
217           .proc_handler = proc_doulonghex, },
218
219         { .ctl_name = CTL_DUMP_FLAGS,
220           .procname = DUMP_FLAGS_NAME,
221           .data = &dump_config.flags,   
222           .maxlen = sizeof(int),
223           .mode = 0644,
224           .proc_handler = proc_doulonghex, },
225
226         { .ctl_name = CTL_DUMP_COMPRESS,
227           .procname = DUMP_COMPRESS_NAME,
228           .data = &dump_compress, /* FIXME */
229           .maxlen = sizeof(int),
230           .mode = 0644,
231           .proc_handler = proc_dointvec, },
232           
233         { .ctl_name = CTL_DUMP_DEVICE,
234           .procname = DUMP_DEVICE_NAME,
235           .mode = 0644,
236           .data = &dump_config.dump_device, /* FIXME */
237           .maxlen = sizeof(int),
238           .proc_handler = proc_dump_device },
239
240 #ifdef CONFIG_CRASH_DUMP_MEMDEV
241         { .ctl_name = CTL_DUMP_ADDR,
242           .procname = DUMP_ADDR_NAME,
243           .mode = 0444,
244           .data = &dump_config.dump_addr,
245           .maxlen = sizeof(unsigned long),
246           .proc_handler = proc_doulonghex },
247 #endif
248
249         { 0, }
250 };
251
252 static ctl_table dump_root[] = {
253         { .ctl_name = KERN_DUMP,
254           .procname = "dump",
255           .mode = 0555, 
256           .child = dump_table },
257         { 0, }
258 };
259
260 static ctl_table kernel_root[] = {
261         { .ctl_name = CTL_KERN,
262           .procname = "kernel",
263           .mode = 0555,
264           .child = dump_root, },
265         { 0, }
266 };
267
268 static struct ctl_table_header *sysctl_header;
269
270 /*
271  * -----------------------------------------------------------------------
272  *              C O M P R E S S I O N   F U N C T I O N S
273  * -----------------------------------------------------------------------
274  */
275
276 /*
277  * Name: dump_compress_none()
278  * Func: Don't do any compression, period.
279  */
280 static u16
281 dump_compress_none(const u8 *old, u16 oldsize, u8 *new, u16 newsize)
282 {
283         /* just return the old size */
284         return oldsize;
285 }
286
287
288 /*
289  * Name: dump_execute()
290  * Func: Execute the dumping process.  This makes sure all the appropriate
291  *       fields are updated correctly, and calls dump_execute_memdump(),
292  *       which does the real work.
293  */
294 void
295 dump_execute(const char *panic_str, const struct pt_regs *regs)
296 {
297         int state = -1;
298         unsigned long flags;
299
300         /* make sure we can dump */
301         if (!dump_okay) {
302                 pr_info("LKCD not yet configured, can't take dump now\n");
303                 return;
304         }
305
306         /* Exclude multiple dumps at the same time,
307          * and disable interrupts,  some drivers may re-enable
308          * interrupts in with silence()
309          *
310          * Try and acquire spin lock. If successful, leave preempt
311          * and interrupts disabled.  See spin_lock_irqsave in spinlock.h
312          */
313         local_irq_save(flags);
314         if (!spin_trylock(&dump_lock)) {
315                 local_irq_restore(flags);
316                 pr_info("LKCD dump already in progress\n");
317                 return;
318         }
319
320         /* Bring system into the strictest level of quiescing for min drift 
321          * dump drivers can soften this as required in dev->ops->silence() 
322          */
323         dump_oncpu = smp_processor_id() + 1;
324         dump_silence_level = DUMP_HARD_SPIN_CPUS; 
325
326         state = dump_generic_execute(panic_str, regs);
327         
328         dump_oncpu = 0;
329         spin_unlock_irqrestore(&dump_lock, flags);
330
331         if (state < 0) {
332                 printk("Dump Incomplete or failed!\n");
333         } else {
334                 printk("Dump Complete; %d dump pages saved.\n", 
335                        dump_header.dh_num_dump_pages);
336         }
337 }
338
339 /*
340  * Name: dump_register_compression()
341  * Func: Register a dump compression mechanism.
342  */
343 void
344 dump_register_compression(struct __dump_compress *item)
345 {
346         if (item)
347                 list_add(&(item->list), &dump_compress_list);
348 }
349
350 /*
351  * Name: dump_unregister_compression()
352  * Func: Remove a dump compression mechanism, and re-assign the dump
353  *       compression pointer if necessary.
354  */
355 void
356 dump_unregister_compression(int compression_type)
357 {
358         struct list_head *tmp;
359         struct __dump_compress *dc;
360
361         /* let's make sure our list is valid */
362         if (compression_type != DUMP_COMPRESS_NONE) {
363                 list_for_each(tmp, &dump_compress_list) {
364                         dc = list_entry(tmp, struct __dump_compress, list);
365                         if (dc->compress_type == compression_type) {
366                                 list_del(&(dc->list));
367                                 break;
368                         }
369                 }
370         }
371 }
372
373 /*
374  * Name: dump_compress_init()
375  * Func: Initialize (or re-initialize) compression scheme.
376  */
377 static int
378 dump_compress_init(int compression_type)
379 {
380         struct list_head *tmp;
381         struct __dump_compress *dc;
382
383         /* try to remove the compression item */
384         list_for_each(tmp, &dump_compress_list) {
385                 dc = list_entry(tmp, struct __dump_compress, list);
386                 if (dc->compress_type == compression_type) {
387                         dump_config.dumper->compress = dc;
388                         dump_compress = compression_type;
389                         pr_debug("Dump Compress %s\n", dc->compress_name);
390                         return 0;
391                 }
392         }
393
394         /* 
395          * nothing on the list -- return ENODATA to indicate an error 
396          *
397          * NB: 
398          *      EAGAIN: reports "Resource temporarily unavailable" which
399          *              isn't very enlightening.
400          */
401         printk("compression_type:%d not found\n", compression_type);
402
403         return -ENODATA;
404 }
405
406 static int
407 dumper_setup(unsigned long flags, unsigned long devid)
408 {
409         int ret = 0;
410
411         /* unconfigure old dumper if it exists */
412         dump_okay = 0;
413         if (dump_config.dumper) {
414                 pr_debug("Unconfiguring current dumper\n");
415                 dump_unconfigure();
416         }
417         /* set up new dumper */
418         if (dump_config.flags & DUMP_FLAGS_SOFTBOOT) {
419                 printk("Configuring softboot based dump \n");
420 #ifdef CONFIG_CRASH_DUMP_MEMDEV
421                 dump_config.dumper = &dumper_stage1; 
422 #else
423                 printk("Requires CONFIG_CRASHDUMP_MEMDEV. Can't proceed.\n");
424                 return -1;
425 #endif
426         } else {
427                 dump_config.dumper = &dumper_singlestage;
428         }       
429         dump_config.dumper->dev = dump_dev;
430
431         ret = dump_configure(devid);
432         if (!ret) {
433                 dump_okay = 1;
434                 pr_debug("%s dumper set up for dev 0x%lx\n", 
435                         dump_config.dumper->name, devid);
436                 dump_config.dump_device = devid;
437         } else {
438                 printk("%s dumper set up failed for dev 0x%lx\n", 
439                        dump_config.dumper->name, devid);
440                 dump_config.dumper = NULL;
441         }
442         return ret;
443 }
444
445 static int
446 dump_target_init(int target)
447 {
448         char type[20];
449         struct list_head *tmp;
450         struct dump_dev *dev;
451         
452         switch (target) {
453                 case DUMP_FLAGS_DISKDUMP:
454                         strcpy(type, "blockdev"); break;
455                 case DUMP_FLAGS_NETDUMP:
456                         strcpy(type, "networkdev"); break;
457                 default:
458                         return -1;
459         }
460
461         /*
462          * This is a bit stupid, generating strings from flag
463          * and doing strcmp. This is done because 'struct dump_dev'
464          * has string 'type_name' and not interger 'type'.
465          */
466         list_for_each(tmp, &dump_target_list) {
467                 dev = list_entry(tmp, struct dump_dev, list);
468                 if (strcmp(type, dev->type_name) == 0) {
469                         dump_dev = dev;
470                         return 0;
471                 }
472         }
473         return -1;
474 }
475
476 /*
477  * Name: dump_ioctl()
478  * Func: Allow all dump tunables through a standard ioctl() mechanism.
479  *       This is far better than before, where we'd go through /proc,
480  *       because now this will work for multiple OS and architectures.
481  */
482 static int
483 dump_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
484 {
485         /* check capabilities */
486         if (!capable(CAP_SYS_ADMIN))
487                 return -EPERM;
488
489         if (!dump_config.dumper && cmd == DIOSDUMPCOMPRESS)
490                 /* dump device must be configured first */
491                 return -ENODEV;
492
493         /*
494          * This is the main mechanism for controlling get/set data
495          * for various dump device parameters.  The real trick here
496          * is setting the dump device (DIOSDUMPDEV).  That's what
497          * triggers everything else.
498          */
499         switch (cmd) {
500         case DIOSDUMPDEV:       /* set dump_device */
501                 pr_debug("Configuring dump device\n"); 
502                 if (!(f->f_flags & O_RDWR))
503                         return -EPERM;
504
505                 __dump_open();
506                 return dumper_setup(dump_config.flags, arg);
507
508                 
509         case DIOGDUMPDEV:       /* get dump_device */
510                 return put_user((long)dump_config.dump_device, (long *)arg);
511
512         case DIOSDUMPLEVEL:     /* set dump_level */
513                 if (!(f->f_flags & O_RDWR))
514                         return -EPERM;
515
516                 /* make sure we have a positive value */
517                 if (arg < 0)
518                         return -EINVAL;
519
520                 /* Fixme: clean this up */
521                 dump_config.level = 0;
522                 switch ((int)arg) {
523                         case DUMP_LEVEL_ALL:
524                         case DUMP_LEVEL_ALL_RAM:
525                                 dump_config.level |= DUMP_MASK_UNUSED;
526                         case DUMP_LEVEL_USED:
527                                 dump_config.level |= DUMP_MASK_USED;
528                         case DUMP_LEVEL_KERN:
529                                 dump_config.level |= DUMP_MASK_KERN;
530                         case DUMP_LEVEL_HEADER:
531                                 dump_config.level |= DUMP_MASK_HEADER;
532                         case DUMP_LEVEL_NONE:
533                                 break;
534                         default:
535                                 return (-EINVAL);
536                         }
537                 pr_debug("Dump Level 0x%lx\n", dump_config.level);
538                 break;
539
540         case DIOGDUMPLEVEL:     /* get dump_level */
541                 /* fixme: handle conversion */
542                 return put_user((long)dump_config.level, (long *)arg);
543
544                 
545         case DIOSDUMPFLAGS:     /* set dump_flags */
546                 /* check flags */
547                 if (!(f->f_flags & O_RDWR))
548                         return -EPERM;
549
550                 /* make sure we have a positive value */
551                 if (arg < 0)
552                         return -EINVAL;
553                         
554                 if (dump_target_init(arg & DUMP_FLAGS_TARGETMASK) < 0)
555                         return -EINVAL; /* return proper error */
556
557                 dump_config.flags = arg;
558                 
559                 pr_debug("Dump Flags 0x%lx\n", dump_config.flags);
560                 break;
561                 
562         case DIOGDUMPFLAGS:     /* get dump_flags */
563                 return put_user((long)dump_config.flags, (long *)arg);
564
565         case DIOSDUMPCOMPRESS:  /* set the dump_compress status */
566                 if (!(f->f_flags & O_RDWR))
567                         return -EPERM;
568
569                 return dump_compress_init((int)arg);
570
571         case DIOGDUMPCOMPRESS:  /* get the dump_compress status */
572                 return put_user((long)(dump_config.dumper ? 
573                         dump_config.dumper->compress->compress_type : 0), 
574                         (long *)arg);
575         case DIOGDUMPOKAY: /* check if dump is configured */
576                 return put_user((long)dump_okay, (long *)arg);
577         
578         case DIOSDUMPTAKE: /* Trigger a manual dump */
579                 /* Do not proceed if lkcd not yet configured */
580                 if(!dump_okay) {
581                         printk("LKCD not yet configured. Cannot take manual dump\n");
582                         return -ENODEV;
583                 }
584
585                 /* Take the dump */
586                 return  manual_handle_crashdump();
587                         
588         default:
589                 /* 
590                  * these are network dump specific ioctls, let the
591                  * module handle them.
592                  */
593                 return dump_dev_ioctl(cmd, arg);
594         }
595         return 0;
596 }
597
598 /*
599  * Handle special cases for dump_device 
600  * changing dump device requires doing an opening the device
601  */
602 static int 
603 proc_dump_device(ctl_table *ctl, int write, struct file *f,
604                  void *buffer, size_t *lenp)
605 {
606         int *valp = ctl->data;
607         int oval = *valp;
608         int ret = -EPERM;
609
610         /* same permission checks as ioctl */
611         if (capable(CAP_SYS_ADMIN)) {
612                 ret = proc_doulonghex(ctl, write, f, buffer, lenp);
613                 if (ret == 0 && write && *valp != oval) {
614                         /* need to restore old value to close properly */
615                         dump_config.dump_device = (dev_t) oval;
616                         __dump_open();
617                         ret = dumper_setup(dump_config.flags, (dev_t) *valp);
618                 }
619         }
620
621         return ret;
622 }
623
624 /* All for the want of a proc_do_xxx routine which prints values in hex */
625 static int 
626 proc_doulonghex(ctl_table *ctl, int write, struct file *f,
627                  void *buffer, size_t *lenp)
628 {
629 #define TMPBUFLEN 20
630         unsigned long *i;
631         size_t len, left;
632         char buf[TMPBUFLEN];
633
634         if (!ctl->data || !ctl->maxlen || !*lenp || (f->f_pos)) {
635                 *lenp = 0;
636                 return 0;
637         }
638         
639         i = (unsigned long *) ctl->data;
640         left = *lenp;
641         
642         sprintf(buf, "0x%lx\n", (*i));
643         len = strlen(buf);
644         if (len > left)
645                 len = left;
646         if(copy_to_user(buffer, buf, len))
647                 return -EFAULT;
648         
649         left -= len;
650         *lenp -= left;
651         f->f_pos += *lenp;
652         return 0;
653 }
654
655 /*
656  * -----------------------------------------------------------------------
657  *                     I N I T   F U N C T I O N S
658  * -----------------------------------------------------------------------
659  */
660
661 /*
662  * These register and unregister routines are exported for modules
663  * to register their dump drivers (like block, net etc)
664  */
665 int
666 dump_register_device(struct dump_dev *ddev)
667 {
668         struct list_head *tmp;
669         struct dump_dev *dev;
670
671         list_for_each(tmp, &dump_target_list) {
672                 dev = list_entry(tmp, struct dump_dev, list);
673                 if (strcmp(ddev->type_name, dev->type_name) == 0) {
674                         printk("Target type %s already registered\n",
675                                         dev->type_name);
676                         return -1; /* return proper error */
677                 }
678         }
679         list_add(&(ddev->list), &dump_target_list);
680         
681         return 0;
682 }
683
684 void
685 dump_unregister_device(struct dump_dev *ddev)
686 {
687         list_del(&(ddev->list));
688         if (ddev != dump_dev)
689                 return;
690
691         dump_okay = 0;
692
693         if (dump_config.dumper)
694                 dump_unconfigure();
695
696         dump_config.flags &= ~DUMP_FLAGS_TARGETMASK;
697         dump_okay = 0;
698         dump_dev = NULL;
699         dump_config.dumper = NULL;
700 }
701
702 static int panic_event(struct notifier_block *this, unsigned long event,
703                        void *ptr)
704 {
705 #ifdef CONFIG_ARM
706         get_current_general_regs(&all_regs);
707         get_current_cp14_regs(&all_regs);
708         get_current_cp15_regs(&all_regs);
709         dump_execute((const char *)ptr, &all_regs);
710 #else
711         struct pt_regs regs;
712         
713         get_current_regs(&regs);
714         dump_execute((const char *)ptr, &regs);
715 #endif
716         return 0;
717 }
718
719 extern struct notifier_block *panic_notifier_list;
720 static int panic_event(struct notifier_block *, unsigned long, void *);
721 static struct notifier_block panic_block = {
722         .notifier_call = panic_event,
723 };
724
725 #ifdef CONFIG_MAGIC_SYSRQ
726 /* Sysrq handler */
727 static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
728                 struct tty_struct *tty) {
729         dump_execute("sysrq", pt_regs);
730 }
731
732 static struct sysrq_key_op sysrq_crashdump_op = {
733         .handler        =       sysrq_handle_crashdump,
734         .help_msg       =       "Dump",
735         .action_msg     =       "Starting crash dump",
736 };
737 #endif
738
739 static inline void
740 dump_sysrq_register(void) 
741 {
742 #ifdef CONFIG_MAGIC_SYSRQ
743         __sysrq_lock_table();
744         __sysrq_put_key_op(DUMP_SYSRQ_KEY, &sysrq_crashdump_op);
745         __sysrq_unlock_table();
746 #endif
747 }
748
749 static inline void
750 dump_sysrq_unregister(void)
751 {
752 #ifdef CONFIG_MAGIC_SYSRQ
753         __sysrq_lock_table();
754         if (__sysrq_get_key_op(DUMP_SYSRQ_KEY) == &sysrq_crashdump_op)
755                 __sysrq_put_key_op(DUMP_SYSRQ_KEY, NULL);
756         __sysrq_unlock_table();
757 #endif
758 }
759
760 /*
761  * Name: dump_init()
762  * Func: Initialize the dump process.  This will set up any architecture
763  *       dependent code.  The big key is we need the memory offsets before
764  *       the page table is initialized, because the base memory offset
765  *       is changed after paging_init() is called.
766  */
767 static int __init
768 dump_init(void)
769 {
770         struct sysinfo info;
771         int err;
772
773         /* try to create our dump device */
774         err = misc_register(&dump_miscdev);
775         if (err) {
776                 printk("cannot register dump character device!\n");
777                 return err;
778         }
779
780         __dump_init((u64)PAGE_OFFSET);
781
782         /* set the dump_compression_list structure up */
783         dump_register_compression(&dump_none_compression);
784
785         /* grab the total memory size now (not if/when we crash) */
786         si_meminfo(&info);
787
788         /* set the memory size */
789         dump_header.dh_memory_size = (u64)info.totalram;
790
791         sysctl_header = register_sysctl_table(kernel_root, 0);
792         dump_sysrq_register();
793
794         notifier_chain_register(&panic_notifier_list, &panic_block);
795         dump_function_ptr = dump_execute;
796
797         pr_info("Crash dump driver initialized.\n");
798         return 0;
799 }
800
801 static void __exit
802 dump_cleanup(void)
803 {
804         dump_okay = 0;
805
806         if (dump_config.dumper)
807                 dump_unconfigure();
808
809         /* arch-specific cleanup routine */
810         __dump_cleanup();
811
812         /* ignore errors while unregistering -- since can't do anything */
813         unregister_sysctl_table(sysctl_header);
814         misc_deregister(&dump_miscdev);
815         dump_sysrq_unregister();
816         notifier_chain_unregister(&panic_notifier_list, &panic_block);
817         dump_function_ptr = NULL;
818 }
819
820 EXPORT_SYMBOL(dump_register_compression);
821 EXPORT_SYMBOL(dump_unregister_compression);
822 EXPORT_SYMBOL(dump_register_device);
823 EXPORT_SYMBOL(dump_unregister_device);
824 EXPORT_SYMBOL(dump_config);
825 EXPORT_SYMBOL(dump_silence_level);
826
827 EXPORT_SYMBOL(__dump_irq_enable);
828 EXPORT_SYMBOL(__dump_irq_restore);
829
830 MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
831 MODULE_DESCRIPTION("Linux Kernel Crash Dump (LKCD) driver");
832 MODULE_LICENSE("GPL");
833
834 module_init(dump_init);
835 module_exit(dump_cleanup);