Whamcloud - gitweb
Branch: HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / linux-2.6.10-fc3-lkcd.patch
1 Index: linux-2.6.10/arch/i386/Kconfig.debug
2 ===================================================================
3 --- linux-2.6.10.orig/arch/i386/Kconfig.debug   2005-04-05 16:29:30.191000944 +0800
4 +++ linux-2.6.10/arch/i386/Kconfig.debug        2005-04-05 16:47:53.904211032 +0800
5 @@ -2,6 +2,63 @@
6  
7  source "lib/Kconfig.debug"
8  
9 +config CRASH_DUMP
10 +       tristate "Crash dump support (EXPERIMENTAL)"
11 +       depends on EXPERIMENTAL
12 +       default n
13 +       ---help---
14 +         Say Y here to enable saving an image of system memory when a panic
15 +         or other error occurs. Dumps can also be forced with the SysRq+d
16 +         key if MAGIC_SYSRQ is enabled.
17 +
18 +config KERNTYPES
19 +       bool
20 +       depends on CRASH_DUMP
21 +       default y
22 +
23 +config CRASH_DUMP_BLOCKDEV
24 +       tristate "Crash dump block device driver"
25 +       depends on CRASH_DUMP
26 +       help
27 +         Say Y to allow saving crash dumps directly to a disk device.
28 +
29 +config CRASH_DUMP_NETDEV
30 +       tristate "Crash dump network device driver"
31 +       depends on CRASH_DUMP
32 +       help
33 +         Say Y to allow saving crash dumps over a network device.
34 +
35 +config CRASH_DUMP_MEMDEV
36 +       bool "Crash dump staged memory driver"
37 +       depends on CRASH_DUMP
38 +       help
39 +         Say Y to allow intermediate saving crash dumps in spare 
40 +         memory pages which would then be written out to disk
41 +         later.
42 +
43 +config CRASH_DUMP_SOFTBOOT
44 +       bool "Save crash dump across a soft reboot"
45 +       depends on CRASH_DUMP_MEMDEV
46 +       help
47 +         Say Y to allow a crash dump to be preserved in memory
48 +         pages across a soft reboot and written out to disk
49 +         thereafter. For this to work, CRASH_DUMP must be 
50 +         configured as part of the kernel (not as a module).
51 +
52 +config CRASH_DUMP_COMPRESS_RLE
53 +       tristate "Crash dump RLE compression"
54 +       depends on CRASH_DUMP
55 +       help
56 +         Say Y to allow saving dumps with Run Length Encoding compression.
57 +
58 +config CRASH_DUMP_COMPRESS_GZIP
59 +       tristate "Crash dump GZIP compression"
60 +       select ZLIB_INFLATE
61 +       select ZLIB_DEFLATE
62 +       depends on CRASH_DUMP
63 +       help
64 +         Say Y to allow saving dumps with Gnu Zip compression.
65 +
66  config EARLY_PRINTK
67         bool "Early printk" if EMBEDDED
68         default y
69 @@ -15,8 +72,8 @@
70           with klogd/syslogd or the X server. You should normally N here,
71           unless you want to debug such a crash.
72  
73 -config DEBUG_STACKOVERFLOW
74 -       bool "Check for stack overflows"
75 +config DEBUG_STACKOVERFLOW 
76 +       bool "Check for stack overflows" 
77         depends on DEBUG_KERNEL
78  
79  config KPROBES
80 Index: linux-2.6.10/arch/i386/mm/init.c
81 ===================================================================
82 --- linux-2.6.10.orig/arch/i386/mm/init.c       2005-04-05 16:47:05.157621640 +0800
83 +++ linux-2.6.10/arch/i386/mm/init.c    2005-04-05 16:47:53.909210272 +0800
84 @@ -244,6 +244,13 @@
85     return 0;
86  }
87  
88 +/* To enable modules to check if a page is in RAM */
89 +int pfn_is_ram(unsigned long pfn)
90 +{
91 +       return (page_is_ram(pfn));
92 +}
93 +
94 +
95  #ifdef CONFIG_HIGHMEM
96  pte_t *kmap_pte;
97  pgprot_t kmap_prot;
98 Index: linux-2.6.10/arch/i386/kernel/traps.c
99 ===================================================================
100 --- linux-2.6.10.orig/arch/i386/kernel/traps.c  2005-04-05 16:47:05.156621792 +0800
101 +++ linux-2.6.10/arch/i386/kernel/traps.c       2005-04-05 16:47:53.906210728 +0800
102 @@ -27,6 +27,7 @@
103  #include <linux/ptrace.h>
104  #include <linux/utsname.h>
105  #include <linux/kprobes.h>
106 +#include <linux/dump.h>
107  
108  #ifdef CONFIG_EISA
109  #include <linux/ioport.h>
110 @@ -382,6 +383,7 @@
111         bust_spinlocks(0);
112         die.lock_owner = -1;
113         spin_unlock_irq(&die.lock);
114 +       dump((char *)str, regs);
115         if (in_interrupt())
116                 panic("Fatal exception in interrupt");
117  
118 @@ -654,6 +656,7 @@
119         printk(" on CPU%d, eip %08lx, registers:\n",
120                 smp_processor_id(), regs->eip);
121         show_registers(regs);
122 +       dump((char *)msg, regs);
123         printk("console shuts up ...\n");
124         console_silent();
125         spin_unlock(&nmi_print_lock);
126 Index: linux-2.6.10/arch/i386/kernel/setup.c
127 ===================================================================
128 --- linux-2.6.10.orig/arch/i386/kernel/setup.c  2004-12-25 05:34:45.000000000 +0800
129 +++ linux-2.6.10/arch/i386/kernel/setup.c       2005-04-05 16:47:53.905210880 +0800
130 @@ -662,6 +662,10 @@
131   */
132  #define LOWMEMSIZE()   (0x9f000)
133  
134 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
135 +unsigned long crashdump_addr = 0xdeadbeef;
136 +#endif
137 +
138  static void __init parse_cmdline_early (char ** cmdline_p)
139  {
140         char c = ' ', *to = command_line, *from = saved_command_line;
141 @@ -823,6 +827,11 @@
142                 if (c == ' ' && !memcmp(from, "vmalloc=", 8))
143                         __VMALLOC_RESERVE = memparse(from+8, &from);
144  
145 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
146 +               if (c == ' ' && !memcmp(from, "crashdump=", 10))
147 +                   crashdump_addr = memparse(from+10, &from); 
148 +#endif
149 +
150                 c = *(from++);
151                 if (!c)
152                         break;
153 @@ -1288,6 +1297,10 @@
154  
155  static char * __init machine_specific_memory_setup(void);
156  
157 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
158 +extern void crashdump_reserve(void);
159 +#endif
160 +
161  /*
162   * Determine if we were loaded by an EFI loader.  If so, then we have also been
163   * passed the efi memmap, systab, etc., so we should use these data structures
164 @@ -1393,6 +1406,10 @@
165  #endif
166  
167  
168 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
169 +       crashdump_reserve(); /* Preserve crash dump state from prev boot */
170 +#endif
171 +
172         dmi_scan_machine();
173  
174  #ifdef CONFIG_X86_GENERICARCH
175 Index: linux-2.6.10/arch/i386/kernel/smp.c
176 ===================================================================
177 --- linux-2.6.10.orig/arch/i386/kernel/smp.c    2005-04-05 16:47:05.154622096 +0800
178 +++ linux-2.6.10/arch/i386/kernel/smp.c 2005-04-05 16:47:53.908210424 +0800
179 @@ -19,6 +19,7 @@
180  #include <linux/mc146818rtc.h>
181  #include <linux/cache.h>
182  #include <linux/interrupt.h>
183 +#include <linux/dump.h>
184  
185  #include <asm/mtrr.h>
186  #include <asm/tlbflush.h>
187 @@ -143,6 +144,13 @@
188          */
189         cfg = __prepare_ICR(shortcut, vector);
190  
191 +       if (vector == DUMP_VECTOR) {
192 +               /*
193 +                * Setup DUMP IPI to be delivered as an NMI
194 +                */
195 +               cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI;
196 +       }
197 +
198         /*
199          * Send the IPI. The write to APIC_ICR fires this off.
200          */
201 @@ -220,6 +228,13 @@
202                          * program the ICR 
203                          */
204                         cfg = __prepare_ICR(0, vector);
205 +
206 +                       if (vector == DUMP_VECTOR) {
207 +                               /*
208 +                                * Setup DUMP IPI to be delivered as an NMI
209 +                                */
210 +                               cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI;
211 +                       }       
212                         
213                         /*
214                          * Send the IPI. The write to APIC_ICR fires this off.
215 @@ -506,6 +521,11 @@
216  
217  static struct call_data_struct * call_data;
218  
219 +void dump_send_ipi(void)
220 +{
221 +       send_IPI_allbutself(DUMP_VECTOR);
222 +}
223 +
224  /*
225   * this function sends a 'generic call function' IPI to all other CPUs
226   * in the system.
227 @@ -561,7 +581,7 @@
228         return 0;
229  }
230  
231 -static void stop_this_cpu (void * dummy)
232 +void stop_this_cpu (void * dummy)
233  {
234         /*
235          * Remove this CPU:
236 @@ -622,4 +642,3 @@
237                 atomic_inc(&call_data->finished);
238         }
239  }
240 -
241 Index: linux-2.6.10/arch/i386/kernel/i386_ksyms.c
242 ===================================================================
243 --- linux-2.6.10.orig/arch/i386/kernel/i386_ksyms.c     2004-12-25 05:35:40.000000000 +0800
244 +++ linux-2.6.10/arch/i386/kernel/i386_ksyms.c  2005-04-05 16:47:53.907210576 +0800
245 @@ -16,6 +16,7 @@
246  #include <linux/tty.h>
247  #include <linux/highmem.h>
248  #include <linux/time.h>
249 +#include <linux/nmi.h>
250  
251  #include <asm/semaphore.h>
252  #include <asm/processor.h>
253 @@ -31,6 +32,7 @@
254  #include <asm/tlbflush.h>
255  #include <asm/nmi.h>
256  #include <asm/ist.h>
257 +#include <asm/e820.h>
258  #include <asm/kdebug.h>
259  
260  extern void dump_thread(struct pt_regs *, struct user *);
261 @@ -192,3 +194,20 @@
262  #endif
263  
264  EXPORT_SYMBOL(csum_partial);
265 +
266 +#ifdef CONFIG_CRASH_DUMP_MODULE
267 +#ifdef CONFIG_SMP
268 +extern irq_desc_t irq_desc[NR_IRQS];
269 +extern cpumask_t irq_affinity[NR_IRQS];
270 +extern void stop_this_cpu(void *);
271 +EXPORT_SYMBOL(irq_desc);
272 +EXPORT_SYMBOL(irq_affinity);
273 +EXPORT_SYMBOL(stop_this_cpu);
274 +EXPORT_SYMBOL(dump_send_ipi);
275 +#endif
276 +extern int pfn_is_ram(unsigned long);
277 +EXPORT_SYMBOL(pfn_is_ram);
278 +#ifdef ARCH_HAS_NMI_WATCHDOG
279 +EXPORT_SYMBOL(touch_nmi_watchdog);
280 +#endif
281 +#endif
282 Index: linux-2.6.10/arch/s390/Kconfig.debug
283 ===================================================================
284 --- linux-2.6.10.orig/arch/s390/Kconfig.debug   2004-12-25 05:34:31.000000000 +0800
285 +++ linux-2.6.10/arch/s390/Kconfig.debug        2005-04-05 16:47:53.921208448 +0800
286 @@ -2,4 +2,13 @@
287  
288  source "lib/Kconfig.debug"
289  
290 +config KERNTYPES
291 +       bool "Kerntypes debugging information"
292 +       default y
293 +       ---help---
294 +         Say Y here to save additional kernel debugging information in the
295 +         file init/kerntypes.o. This information is used by crash analysis
296 +         tools such as lcrash to assign structures to kernel addresses.
297 +
298 +
299  endmenu
300 Index: linux-2.6.10/arch/s390/boot/Makefile
301 ===================================================================
302 --- linux-2.6.10.orig/arch/s390/boot/Makefile   2004-12-25 05:35:49.000000000 +0800
303 +++ linux-2.6.10/arch/s390/boot/Makefile        2005-04-05 16:47:53.922208296 +0800
304 @@ -15,4 +15,4 @@
305  
306  install: $(CONFIGURE) $(obj)/image
307         sh -x  $(srctree)/$(obj)/install.sh $(KERNELRELEASE) $(obj)/image \
308 -             System.map Kerntypes "$(INSTALL_PATH)"
309 +             System.map init/Kerntypes "$(INSTALL_PATH)"
310 Index: linux-2.6.10/arch/s390/boot/install.sh
311 ===================================================================
312 --- linux-2.6.10.orig/arch/s390/boot/install.sh 2004-12-25 05:35:01.000000000 +0800
313 +++ linux-2.6.10/arch/s390/boot/install.sh      2005-04-05 16:47:53.921208448 +0800
314 @@ -16,7 +16,8 @@
315  #   $1 - kernel version
316  #   $2 - kernel image file
317  #   $3 - kernel map file
318 -#   $4 - default install path (blank if root directory)
319 +#   $4 - kernel type file
320 +#   $5 - default install path (blank if root directory)
321  #
322  
323  # User may have a custom install script
324 @@ -26,13 +27,13 @@
325  
326  # Default install - same as make zlilo
327  
328 -if [ -f $4/vmlinuz ]; then
329 -       mv $4/vmlinuz $4/vmlinuz.old
330 +if [ -f $5/vmlinuz ]; then
331 +       mv $5/vmlinuz $5/vmlinuz.old
332  fi
333  
334 -if [ -f $4/System.map ]; then
335 -       mv $4/System.map $4/System.old
336 +if [ -f $5/System.map ]; then
337 +       mv $5/System.map $5/System.old
338  fi
339  
340 -cat $2 > $4/vmlinuz
341 -cp $3 $4/System.map
342 +cat $2 > $5/vmlinuz
343 +cp $3 $5/System.map
344 Index: linux-2.6.10/arch/ia64/Kconfig.debug
345 ===================================================================
346 --- linux-2.6.10.orig/arch/ia64/Kconfig.debug   2004-12-25 05:34:32.000000000 +0800
347 +++ linux-2.6.10/arch/ia64/Kconfig.debug        2005-04-05 16:47:53.917209056 +0800
348 @@ -2,6 +2,65 @@
349  
350  source "lib/Kconfig.debug"
351  
352 +config CRASH_DUMP
353 +       tristate "Crash dump support (EXPERIMENTAL)"
354 +       depends on EXPERIMENTAL
355 +       default n
356 +       ---help---
357 +         Say Y here to enable saving an image of system memory when a panic
358 +         or other error occurs. Dumps can also be forced with the SysRq+d
359 +         key if MAGIC_SYSRQ is enabled.
360 +
361 +config KERNTYPES
362 +        bool
363 +        depends on CRASH_DUMP
364 +        default y
365 +
366 +config CRASH_DUMP_BLOCKDEV
367 +       tristate "Crash dump block device driver"
368 +       depends on CRASH_DUMP
369 +       help
370 +         Say Y to allow saving crash dumps directly to a disk device.
371 +
372 +config CRASH_DUMP_NETDEV
373 +       tristate "Crash dump network device driver"
374 +       depends on CRASH_DUMP
375 +       help
376 +        Say Y to allow saving crash dumps over a network device.
377 +
378 +config CRASH_DUMP_MEMDEV
379 +       bool "Crash dump staged memory driver"
380 +       depends on CRASH_DUMP
381 +       help
382 +         Say Y to allow intermediate saving crash dumps in spare
383 +         memory pages which would then be written out to disk
384 +         later.
385 +
386 +config CRASH_DUMP_SOFTBOOT
387 +       bool "Save crash dump across a soft reboot"
388 +       depends on CRASH_DUMP_MEMDEV
389 +       help
390 +         Say Y to allow a crash dump to be preserved in memory
391 +         pages across a soft reboot and written out to disk
392 +         thereafter. For this to work, CRASH_DUMP must be
393 +         configured as part of the kernel (not as a module).
394 +
395 +config CRASH_DUMP_COMPRESS_RLE
396 +       tristate "Crash dump RLE compression"
397 +       depends on CRASH_DUMP
398 +       help
399 +         Say Y to allow saving dumps with Run Length Encoding compression.
400 +
401 +config CRASH_DUMP_COMPRESS_GZIP
402 +       tristate "Crash dump GZIP compression"
403 +       select ZLIB_INFLATE
404 +       select ZLIB_DEFLATE
405 +       depends on CRASH_DUMP
406 +       help
407 +         Say Y to allow saving dumps with Gnu Zip compression.
408 +
409 +
410 +
411  choice
412         prompt "Physical memory granularity"
413         default IA64_GRANULE_64MB
414 Index: linux-2.6.10/arch/ia64/kernel/traps.c
415 ===================================================================
416 --- linux-2.6.10.orig/arch/ia64/kernel/traps.c  2004-12-25 05:35:39.000000000 +0800
417 +++ linux-2.6.10/arch/ia64/kernel/traps.c       2005-04-05 16:47:53.918208904 +0800
418 @@ -21,6 +21,8 @@
419  #include <asm/intrinsics.h>
420  #include <asm/processor.h>
421  #include <asm/uaccess.h>
422 +#include <asm/nmi.h>
423 +#include <linux/dump.h>
424  
425  extern spinlock_t timerlist_lock;
426  
427 @@ -89,6 +91,7 @@
428                 printk("%s[%d]: %s %ld [%d]\n",
429                         current->comm, current->pid, str, err, ++die_counter);
430                 show_regs(regs);
431 +               dump((char *)str, regs);
432         } else
433                 printk(KERN_ERR "Recursive die() failure, output suppressed\n");
434  
435 Index: linux-2.6.10/arch/ia64/kernel/ia64_ksyms.c
436 ===================================================================
437 --- linux-2.6.10.orig/arch/ia64/kernel/ia64_ksyms.c     2005-04-05 16:29:27.954340968 +0800
438 +++ linux-2.6.10/arch/ia64/kernel/ia64_ksyms.c  2005-04-05 16:47:53.917209056 +0800
439 @@ -7,7 +7,6 @@
440  
441  #include <linux/config.h>
442  #include <linux/module.h>
443 -
444  #include <linux/string.h>
445  EXPORT_SYMBOL(memset);
446  EXPORT_SYMBOL(memchr);
447 @@ -28,6 +27,9 @@
448  EXPORT_SYMBOL(strstr);
449  EXPORT_SYMBOL(strpbrk);
450  
451 +#include <linux/syscalls.h>
452 +EXPORT_SYMBOL(sys_ioctl);
453 +
454  #include <asm/checksum.h>
455  EXPORT_SYMBOL(ip_fast_csum);           /* hand-coded assembly */
456  
457 @@ -125,3 +127,21 @@
458  #  endif
459  # endif
460  #endif
461 +
462 +#include <asm/hw_irq.h>
463 +
464 +#ifdef CONFIG_CRASH_DUMP_MODULE
465 +#ifdef CONFIG_SMP
466 +extern irq_desc_t _irq_desc[NR_IRQS];
467 +extern cpumask_t irq_affinity[NR_IRQS];
468 +extern void stop_this_cpu(void *);
469 +extern int (*dump_ipi_function_ptr)(struct pt_regs *);
470 +extern void dump_send_ipi(void);
471 +EXPORT_SYMBOL(_irq_desc);
472 +EXPORT_SYMBOL(irq_affinity);
473 +EXPORT_SYMBOL(stop_this_cpu);
474 +EXPORT_SYMBOL(dump_send_ipi);
475 +EXPORT_SYMBOL(dump_ipi_function_ptr);
476 +#endif
477 +#endif
478 +
479 Index: linux-2.6.10/arch/ia64/kernel/irq.c
480 ===================================================================
481 --- linux-2.6.10.orig/arch/ia64/kernel/irq.c    2004-12-25 05:35:27.000000000 +0800
482 +++ linux-2.6.10/arch/ia64/kernel/irq.c 2005-04-05 16:47:53.919208752 +0800
483 @@ -933,7 +933,11 @@
484  
485  static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
486  
487 +#if defined(CONFIG_CRASH_DUMP) || defined (CONFIG_CRASH_DUMP_MODULE)
488 +cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
489 +#else
490  static cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
491 +#endif
492  
493  static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
494  
495 Index: linux-2.6.10/arch/ia64/kernel/smp.c
496 ===================================================================
497 --- linux-2.6.10.orig/arch/ia64/kernel/smp.c    2004-12-25 05:35:40.000000000 +0800
498 +++ linux-2.6.10/arch/ia64/kernel/smp.c 2005-04-05 16:47:53.920208600 +0800
499 @@ -31,6 +31,10 @@
500  #include <linux/efi.h>
501  #include <linux/bitops.h>
502  
503 +#if defined(CONFIG_CRASH_DUMP) || defined(CONFIG_CRASH_DUMP_MODULE)
504 +#include <linux/dump.h>
505 +#endif
506 +
507  #include <asm/atomic.h>
508  #include <asm/current.h>
509  #include <asm/delay.h>
510 @@ -67,6 +71,11 @@
511  #define IPI_CALL_FUNC          0
512  #define IPI_CPU_STOP           1
513  
514 +#if defined(CONFIG_CRASH_DUMP) || defined(CONFIG_CRASH_DUMP_MODULE)
515 +#define IPI_DUMP_INTERRUPT      4
516 +       int (*dump_ipi_function_ptr)(struct pt_regs *) = NULL;
517 +#endif
518 +
519  /* This needs to be cacheline aligned because it is written to by *other* CPUs.  */
520  static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
521  
522 @@ -84,7 +93,9 @@
523         spin_unlock_irq(&call_lock);
524  }
525  
526 -static void
527 +
528 +/*changed static void stop_this_cpu -> void stop_this_cpu */
529 +void
530  stop_this_cpu (void)
531  {
532         /*
533 @@ -155,6 +166,15 @@
534                               case IPI_CPU_STOP:
535                                 stop_this_cpu();
536                                 break;
537 +#if defined(CONFIG_CRASH_DUMP) || defined(CONFIG_CRASH_DUMP_MODULE)
538 +                       case IPI_DUMP_INTERRUPT:
539 +                        if( dump_ipi_function_ptr != NULL ) {
540 +                                if (!dump_ipi_function_ptr(regs)) {
541 +                                         printk(KERN_ERR "(*dump_ipi_function_ptr)(): rejected IPI_DUMP_INTERRUPT\n");
542 +                                }
543 +                        }
544 +                        break;
545 +#endif
546  
547                               default:
548                                 printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
549 @@ -369,9 +389,17 @@
550  {
551         send_IPI_allbutself(IPI_CPU_STOP);
552  }
553 +EXPORT_SYMBOL(smp_send_stop);
554  
555  int __init
556  setup_profiling_timer (unsigned int multiplier)
557  {
558         return -EINVAL;
559  }
560 +
561 +#if defined(CONFIG_CRASH_DUMP) || defined(CONFIG_CRASH_DUMP_MODULE)
562 +void dump_send_ipi(void)
563 +{
564 +        send_IPI_allbutself(IPI_DUMP_INTERRUPT);
565 +}
566 +#endif
567 Index: linux-2.6.10/arch/ppc64/Kconfig.debug
568 ===================================================================
569 --- linux-2.6.10.orig/arch/ppc64/Kconfig.debug  2004-12-25 05:35:27.000000000 +0800
570 +++ linux-2.6.10/arch/ppc64/Kconfig.debug       2005-04-05 16:47:53.922208296 +0800
571 @@ -2,6 +2,64 @@
572  
573  source "lib/Kconfig.debug"
574  
575 +config KERNTYPES
576 +       bool
577 +       depends on CRASH_DUMP
578 +       default y
579 +
580 +config CRASH_DUMP
581 +       tristate "Crash dump support"
582 +       default n
583 +       ---help---
584 +          Say Y here to enable saving an image of system memory when a panic
585 +          or other error occurs. Dumps can also be forced with the SysRq+d
586 +          key if MAGIC_SYSRQ is enabled.
587 +
588 +config CRASH_DUMP_BLOCKDEV
589 +       tristate "Crash dump block device driver"
590 +       depends on CRASH_DUMP
591 +       help
592 +         Say Y to allow saving crash dumps directly to a disk device.
593 +       
594 +config CRASH_DUMP_NETDEV
595 +       tristate "Crash dump network device driver"
596 +       depends on CRASH_DUMP
597 +       help
598 +         Say Y to allow saving crash dumps over a network device.
599 +
600 +config CRASH_DUMP_MEMDEV
601 +       bool "Crash dump staged memory driver"
602 +       depends on CRASH_DUMP
603 +       help
604 +         Say Y to allow intermediate saving crash dumps in spare
605 +         memory pages which would then be written out to disk
606 +         later. Need 'kexec' support for this to work.
607 +            **** Not supported at present ****
608 +
609 +config CRASH_DUMP_SOFTBOOT
610 +       bool "Save crash dump across a soft reboot"
611 +       help
612 +         Say Y to allow a crash dump to be preserved in memory
613 +         pages across a soft reboot and written out to disk
614 +         thereafter. For this to work, CRASH_DUMP must be
615 +         configured as part of the kernel (not as a module).
616 +         Need 'kexec' support to use this option.
617 +           **** Not supported at present ****
618 +
619 +config CRASH_DUMP_COMPRESS_RLE
620 +       tristate "Crash dump RLE compression"
621 +       depends on CRASH_DUMP
622 +       help
623 +         Say Y to allow saving dumps with Run Length Encoding compression.
624 +
625 +config CRASH_DUMP_COMPRESS_GZIP
626 +       tristate "Crash dump GZIP compression"
627 +       select ZLIB_INFLATE
628 +       select ZLIB_DEFLATE
629 +       depends on CRASH_DUMP
630 +       help
631 +         Say Y to allow saving dumps with Gnu Zip compression.
632 +
633  config DEBUG_STACKOVERFLOW
634         bool "Check for stack overflows"
635         depends on DEBUG_KERNEL
636 Index: linux-2.6.10/arch/ppc64/kernel/traps.c
637 ===================================================================
638 --- linux-2.6.10.orig/arch/ppc64/kernel/traps.c 2004-12-25 05:34:47.000000000 +0800
639 +++ linux-2.6.10/arch/ppc64/kernel/traps.c      2005-04-05 16:47:53.923208144 +0800
640 @@ -29,6 +29,7 @@
641  #include <linux/interrupt.h>
642  #include <linux/init.h>
643  #include <linux/module.h>
644 +#include <linux/dump.h>
645  
646  #include <asm/pgtable.h>
647  #include <asm/uaccess.h>
648 @@ -116,6 +117,7 @@
649         if (nl)
650                 printk("\n");
651         show_regs(regs);
652 +       dump((char *)str, regs);
653         bust_spinlocks(0);
654         spin_unlock_irq(&die_lock);
655  
656 Index: linux-2.6.10/arch/ppc64/kernel/ppc_ksyms.c
657 ===================================================================
658 --- linux-2.6.10.orig/arch/ppc64/kernel/ppc_ksyms.c     2004-12-25 05:34:26.000000000 +0800
659 +++ linux-2.6.10/arch/ppc64/kernel/ppc_ksyms.c  2005-04-05 16:47:53.925207840 +0800
660 @@ -159,6 +159,17 @@
661  EXPORT_SYMBOL(get_wchan);
662  EXPORT_SYMBOL(console_drivers);
663  
664 +#ifdef CONFIG_CRASH_DUMP_MODULE
665 +extern int dump_page_is_ram(unsigned long);
666 +EXPORT_SYMBOL(dump_page_is_ram);
667 +#ifdef CONFIG_SMP
668 +EXPORT_SYMBOL(irq_affinity);
669 +extern void stop_this_cpu(void *);
670 +EXPORT_SYMBOL(stop_this_cpu);
671 +EXPORT_SYMBOL(dump_send_ipi);
672 +#endif
673 +#endif
674 +
675  EXPORT_SYMBOL(tb_ticks_per_usec);
676  EXPORT_SYMBOL(paca);
677  EXPORT_SYMBOL(cur_cpu_spec);
678 Index: linux-2.6.10/arch/ppc64/kernel/lmb.c
679 ===================================================================
680 --- linux-2.6.10.orig/arch/ppc64/kernel/lmb.c   2004-12-25 05:34:58.000000000 +0800
681 +++ linux-2.6.10/arch/ppc64/kernel/lmb.c        2005-04-05 16:47:53.924207992 +0800
682 @@ -344,3 +344,31 @@
683  
684         return pa;
685  }
686 +
687 +
688 +/*
689 + * This is the copy of page_is_ram (mm/init.c). The difference is 
690 + * it identifies all memory holes.
691 + */
692 +int dump_page_is_ram(unsigned long pfn)
693 +{
694 +        int i;
695 +       unsigned long paddr = (pfn << PAGE_SHIFT);
696 +
697 +       for (i=0; i < lmb.memory.cnt ;i++) {
698 +               unsigned long base;
699 +
700 +#ifdef CONFIG_MSCHUNKS
701 +               base = lmb.memory.region[i].physbase;
702 +#else
703 +               base = lmb.memory.region[i].base;
704 +#endif
705 +               if ((paddr >= base) &&
706 +                       (paddr < (base + lmb.memory.region[i].size))) {
707 +                       return 1;
708 +               }
709 +       }
710 +
711 +       return 0;
712 +}
713 +
714 Index: linux-2.6.10/arch/ppc64/kernel/xics.c
715 ===================================================================
716 --- linux-2.6.10.orig/arch/ppc64/kernel/xics.c  2004-12-25 05:34:58.000000000 +0800
717 +++ linux-2.6.10/arch/ppc64/kernel/xics.c       2005-04-05 16:47:53.925207840 +0800
718 @@ -421,7 +421,8 @@
719                         smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
720                 }
721  #endif
722 -#ifdef CONFIG_DEBUGGER
723 +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_CRASH_DUMP) \
724 +       || defined(CONFIG_CRASH_DUMP_MODULE)
725                 if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
726                                        &xics_ipi_message[cpu].value)) {
727                         mb();
728 Index: linux-2.6.10/arch/ppc64/kernel/smp.c
729 ===================================================================
730 --- linux-2.6.10.orig/arch/ppc64/kernel/smp.c   2004-12-25 05:35:23.000000000 +0800
731 +++ linux-2.6.10/arch/ppc64/kernel/smp.c        2005-04-05 16:47:53.926207688 +0800
732 @@ -30,6 +30,7 @@
733  #include <linux/spinlock.h>
734  #include <linux/cache.h>
735  #include <linux/err.h>
736 +#include <linux/dump.h>
737  #include <linux/sysdev.h>
738  #include <linux/cpu.h>
739  
740 @@ -71,6 +72,7 @@
741  struct smp_ops_t *smp_ops;
742  
743  static volatile unsigned int cpu_callin_map[NR_CPUS];
744 +static int (*dump_ipi_function_ptr)(struct pt_regs *) = NULL;
745  
746  extern unsigned char stab_array[];
747  
748 @@ -177,9 +179,16 @@
749                 /* spare */
750                 break;
751  #endif
752 -#ifdef CONFIG_DEBUGGER
753 +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_CRASH_DUMP) \
754 +       || defined(CONFIG_CRASH_DUMP_MODULE)
755         case PPC_MSG_DEBUGGER_BREAK:
756 -               debugger_ipi(regs);
757 +               if (dump_ipi_function_ptr) {
758 +                       dump_ipi_function_ptr(regs);
759 +               }
760 +#ifdef CONFIG_DEBUGGER
761 +               else
762 +                       debugger_ipi(regs);
763 +#endif
764                 break;
765  #endif
766         default:
767 @@ -201,7 +210,16 @@
768  }
769  #endif
770  
771 -static void stop_this_cpu(void *dummy)
772 +void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *))
773 +{
774 +       dump_ipi_function_ptr = dump_ipi_callback;
775 +       if (dump_ipi_callback) {
776 +               mb();
777 +               smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
778 +       }
779 +}
780 +
781 +void stop_this_cpu(void *dummy)
782  {
783         local_irq_disable();
784         while (1)
785 Index: linux-2.6.10/arch/x86_64/Kconfig.debug
786 ===================================================================
787 --- linux-2.6.10.orig/arch/x86_64/Kconfig.debug 2004-12-25 05:34:01.000000000 +0800
788 +++ linux-2.6.10/arch/x86_64/Kconfig.debug      2005-04-05 16:47:53.909210272 +0800
789 @@ -2,6 +2,66 @@
790  
791  source "lib/Kconfig.debug"
792  
793 +config CRASH_DUMP
794 +       tristate "Crash dump support (EXPERIMENTAL)"
795 +       depends on EXPERIMENTAL
796 +       default n
797 +       ---help---
798 +         Say Y here to enable saving an image of system memory when a panic
799 +         or other error occurs. Dumps can also be forced with the SysRq+d
800 +         key if MAGIC_SYSRQ is enabled.
801 +
802 +config KERNTYPES
803 +       bool
804 +       depends on CRASH_DUMP
805 +       default y
806 +
807 +config CRASH_DUMP_BLOCKDEV
808 +       tristate "Crash dump block device driver"
809 +       depends on CRASH_DUMP
810 +       help
811 +         Say Y to allow saving crash dumps directly to a disk device.
812 +
813 +config CRASH_DUMP_NETDEV
814 +       tristate "Crash dump network device driver"
815 +       depends on CRASH_DUMP
816 +       help
817 +         Say Y to allow saving crash dumps over a network device.
818 +
819 +config CRASH_DUMP_MEMDEV
820 +       bool "Crash dump staged memory driver"
821 +       depends on CRASH_DUMP
822 +       help
823 +         Say Y to allow intermediate saving crash dumps in spare
824 +         memory pages which would then be written out to disk
825 +         later.
826 +
827 +config CRASH_DUMP_SOFTBOOT
828 +       bool "Save crash dump across a soft reboot"
829 +       depends on CRASH_DUMP_MEMDEV
830 +       help
831 +         Say Y to allow a crash dump to be preserved in memory
832 +        lkcd-kernpages across a soft reboot and written out to disk
833 +         thereafter. For this to work, CRASH_DUMP must be
834 +         configured as part of the kernel (not as a module).
835 +
836 +config CRASH_DUMP_COMPRESS_RLE
837 +       tristate "Crash dump RLE compression"
838 +       depends on CRASH_DUMP
839 +       help
840 +         Say Y to allow saving dumps with Run Length Encoding compression.
841 +
842 +
843 +config CRASH_DUMP_COMPRESS_GZIP
844 +       tristate "Crash dump GZIP compression"
845 +       select ZLIB_INFLATE
846 +       select ZLIB_DEFLATE
847 +       depends on CRASH_DUMP
848 +       help
849 +         Say Y to allow saving dumps with Gnu Zip compression.
850 +
851 +
852 +
853  # !SMP for now because the context switch early causes GPF in segment reloading
854  # and the GS base checking does the wrong thing then, causing a hang.
855  config CHECKING
856 Index: linux-2.6.10/arch/x86_64/mm/init.c
857 ===================================================================
858 --- linux-2.6.10.orig/arch/x86_64/mm/init.c     2005-04-05 16:29:30.040023896 +0800
859 +++ linux-2.6.10/arch/x86_64/mm/init.c  2005-04-05 16:47:53.916209208 +0800
860 @@ -378,7 +378,7 @@
861         __flush_tlb_all();
862  } 
863  
864 -static inline int page_is_ram (unsigned long pagenr)
865 +inline int page_is_ram (unsigned long pagenr)
866  {
867         int i;
868  
869 Index: linux-2.6.10/arch/x86_64/kernel/traps.c
870 ===================================================================
871 --- linux-2.6.10.orig/arch/x86_64/kernel/traps.c        2004-12-25 05:33:49.000000000 +0800
872 +++ linux-2.6.10/arch/x86_64/kernel/traps.c     2005-04-05 16:47:53.915209360 +0800
873 @@ -27,6 +27,7 @@
874  #include <linux/spinlock.h>
875  #include <linux/interrupt.h>
876  #include <linux/module.h>
877 +#include <linux/dump.h>
878  #include <linux/moduleparam.h>
879  
880  #include <asm/system.h>
881 @@ -369,6 +370,7 @@
882         printk("\n");
883         notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
884         show_registers(regs);
885 +       dump((char *)str, regs); 
886         /* Executive summary in case the oops scrolled away */
887         printk(KERN_ALERT "RIP ");
888         printk_address(regs->rip); 
889 Index: linux-2.6.10/arch/x86_64/kernel/setup.c
890 ===================================================================
891 --- linux-2.6.10.orig/arch/x86_64/kernel/setup.c        2004-12-25 05:33:50.000000000 +0800
892 +++ linux-2.6.10/arch/x86_64/kernel/setup.c     2005-04-05 16:47:53.911209968 +0800
893 @@ -221,6 +221,8 @@
894         }
895  }
896  
897 +unsigned long crashdump_addr = 0xdeadbeef;
898 +
899  static __init void parse_cmdline_early (char ** cmdline_p)
900  {
901         char c = ' ', *to = command_line, *from = COMMAND_LINE;
902 @@ -311,6 +313,9 @@
903  
904                 if (!memcmp(from,"oops=panic", 10))
905                         panic_on_oops = 1;
906 +               
907 +               if (c == ' ' && !memcmp(from, "crashdump=", 10))
908 +                       crashdump_addr = memparse(from+10, &from);
909  
910         next_char:
911                 c = *(from++);
912 @@ -441,6 +446,10 @@
913                 reserve_bootmem_generic(addr, PAGE_SIZE);
914  }
915  
916 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
917 +extern void crashdump_reserve(void);
918 +#endif
919 +
920  void __init setup_arch(char **cmdline_p)
921  {
922         unsigned long low_mem_size;
923 @@ -550,6 +559,9 @@
924         }
925  #endif
926         paging_init();
927 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
928 +       crashdump_reserve(); /* Preserve crash dump state from prev boot */
929 +#endif
930  
931                 check_ioapic();
932  #ifdef CONFIG_ACPI_BOOT
933 Index: linux-2.6.10/arch/x86_64/kernel/smp.c
934 ===================================================================
935 --- linux-2.6.10.orig/arch/x86_64/kernel/smp.c  2004-12-25 05:35:50.000000000 +0800
936 +++ linux-2.6.10/arch/x86_64/kernel/smp.c       2005-04-05 16:47:53.915209360 +0800
937 @@ -20,6 +20,7 @@
938  #include <linux/kernel_stat.h>
939  #include <linux/mc146818rtc.h>
940  #include <linux/interrupt.h>
941 +#include <linux/dump.h>
942  
943  #include <asm/mtrr.h>
944  #include <asm/pgalloc.h>
945 @@ -151,6 +152,13 @@
946         if (!mm)
947                 BUG();
948  
949 +        if (vector == DUMP_VECTOR) {
950 +                /*
951 +                 * Setup DUMP IPI to be delivered as an NMI
952 +                 */
953 +                cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI;
954 +        }
955 +
956         /*
957          * I'm not happy about this global shared spinlock in the
958          * MM hot path, but we'll see how contended it is.
959 @@ -253,6 +261,13 @@
960         send_IPI_allbutself(KDB_VECTOR);
961  }
962  
963 +
964 +/* void dump_send_ipi(int (*dump_ipi_handler)(struct pt_regs *)); */
965 +void dump_send_ipi(void)
966 +{
967 +       send_IPI_allbutself(DUMP_VECTOR);
968 +}
969 +
970  /*
971   * this function sends a 'reschedule' IPI to another CPU.
972   * it goes straight through and wastes no time serializing
973 @@ -340,6 +355,18 @@
974         return 0;
975  }
976  
977 +void stop_this_cpu(void* dummy)
978 +{
979 +       /*
980 +        * Remove this CPU:
981 +        */
982 +       cpu_clear(smp_processor_id(), cpu_online_map);
983 +       local_irq_disable();
984 +       disable_local_APIC();
985 +       for (;;) 
986 +               asm("hlt"); 
987 +}
988 +
989  void smp_stop_cpu(void)
990  {
991         /*
992 Index: linux-2.6.10/arch/x86_64/kernel/x8664_ksyms.c
993 ===================================================================
994 --- linux-2.6.10.orig/arch/x86_64/kernel/x8664_ksyms.c  2004-12-25 05:34:01.000000000 +0800
995 +++ linux-2.6.10/arch/x86_64/kernel/x8664_ksyms.c       2005-04-05 16:47:53.914209512 +0800
996 @@ -32,6 +32,7 @@
997  #include <asm/unistd.h>
998  #include <asm/delay.h>
999  #include <asm/tlbflush.h>
1000 +#include <asm/e820.h>
1001  #include <asm/kdebug.h>
1002  
1003  extern spinlock_t rtc_lock;
1004 @@ -216,6 +217,20 @@
1005  extern unsigned long __supported_pte_mask;
1006  EXPORT_SYMBOL(__supported_pte_mask);
1007  
1008 +#ifdef CONFIG_CRASH_DUMP_MODULE
1009 +#ifdef CONFIG_SMP
1010 +extern irq_desc_t irq_desc[NR_IRQS];
1011 +extern cpumask_t irq_affinity[NR_IRQS];
1012 +extern void stop_this_cpu(void *);
1013 +EXPORT_SYMBOL(irq_desc);
1014 +EXPORT_SYMBOL(irq_affinity);
1015 +EXPORT_SYMBOL(dump_send_ipi);
1016 +EXPORT_SYMBOL(stop_this_cpu);
1017 +#endif
1018 +extern int page_is_ram(unsigned long);
1019 +EXPORT_SYMBOL(page_is_ram);
1020 +#endif
1021 +
1022  #ifdef CONFIG_SMP
1023  EXPORT_SYMBOL(flush_tlb_page);
1024  EXPORT_SYMBOL_GPL(flush_tlb_all);
1025 Index: linux-2.6.10/arch/x86_64/kernel/pci-gart.c
1026 ===================================================================
1027 --- linux-2.6.10.orig/arch/x86_64/kernel/pci-gart.c     2004-12-25 05:34:32.000000000 +0800
1028 +++ linux-2.6.10/arch/x86_64/kernel/pci-gart.c  2005-04-05 16:47:53.913209664 +0800
1029 @@ -34,7 +34,7 @@
1030  dma_addr_t bad_dma_address;
1031  
1032  unsigned long iommu_bus_base;  /* GART remapping area (physical) */
1033 -static unsigned long iommu_size;       /* size of remapping area bytes */
1034 +unsigned long iommu_size;      /* size of remapping area bytes */
1035  static unsigned long iommu_pages;      /* .. and in pages */
1036  
1037  u32 *iommu_gatt_base;          /* Remapping table */
1038 Index: linux-2.6.10/init/version.c
1039 ===================================================================
1040 --- linux-2.6.10.orig/init/version.c    2004-12-25 05:34:45.000000000 +0800
1041 +++ linux-2.6.10/init/version.c 2005-04-05 16:47:53.896212248 +0800
1042 @@ -11,6 +11,7 @@
1043  #include <linux/uts.h>
1044  #include <linux/utsname.h>
1045  #include <linux/version.h>
1046 +#include <linux/stringify.h>
1047  
1048  #define version(a) Version_ ## a
1049  #define version_string(a) version(a)
1050 @@ -31,3 +32,6 @@
1051  const char *linux_banner = 
1052         "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
1053         LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
1054 +
1055 +const char *LINUX_COMPILE_VERSION_ID = __stringify(LINUX_COMPILE_VERSION_ID);
1056 +LINUX_COMPILE_VERSION_ID_TYPE;
1057 Index: linux-2.6.10/init/kerntypes.c
1058 ===================================================================
1059 --- linux-2.6.10.orig/init/kerntypes.c  2005-04-05 19:01:49.158500672 +0800
1060 +++ linux-2.6.10/init/kerntypes.c       2005-04-05 16:47:53.895212400 +0800
1061 @@ -0,0 +1,40 @@
1062 +/*
1063 + * kerntypes.c
1064 + *
1065 + * Copyright (C) 2000 Tom Morano (tjm@sgi.com) and
1066 + *                    Matt D. Robinson (yakker@alacritech.com)
1067 + *
1068 + * Dummy module that includes headers for all kernel types of interest. 
1069 + * The kernel type information is used by the lcrash utility when 
1070 + * analyzing system crash dumps or the live system. Using the type 
1071 + * information for the running system, rather than kernel header files,
1072 + * makes for a more flexible and robust analysis tool.
1073 + *
1074 + * This source code is released under version 2 of the GNU GPL.
1075 + */
1076 +
1077 +#include <linux/compile.h>
1078 +#include <linux/module.h>
1079 +#include <linux/mm.h>
1080 +#include <linux/vmalloc.h>
1081 +#include <linux/config.h>
1082 +#include <linux/utsname.h>
1083 +#include <linux/kernel_stat.h>
1084 +#include <linux/dump.h>
1085 +
1086 +#include <asm/kerntypes.h>
1087 +
1088 +#ifdef LINUX_COMPILE_VERSION_ID_TYPE
1089 +/* Define version type for version validation of dump and kerntypes */
1090 +LINUX_COMPILE_VERSION_ID_TYPE;
1091 +#endif
1092 +#if defined(CONFIG_SMP) && defined(CONFIG_CRASH_DUMP)
1093 +extern struct runqueue runqueues;
1094 +struct runqueue rn;
1095 +#endif
1096 +
1097 +struct new_utsname *p;
1098 +void
1099 +kerntypes_dummy(void)
1100 +{
1101 +}
1102 Index: linux-2.6.10/init/main.c
1103 ===================================================================
1104 --- linux-2.6.10.orig/init/main.c       2005-04-05 16:29:30.028025720 +0800
1105 +++ linux-2.6.10/init/main.c    2005-04-05 16:47:53.897212096 +0800
1106 @@ -109,6 +109,16 @@
1107  EXPORT_SYMBOL(system_state);
1108  
1109  /*
1110 + * The kernel_magic value represents the address of _end, which allows
1111 + * namelist tools to "match" each other respectively.  That way a tool
1112 + * that looks at /dev/mem can verify that it is using the right System.map
1113 + * file -- if kernel_magic doesn't equal the namelist value of _end,
1114 + * something's wrong.
1115 + */
1116 +extern unsigned long _end;
1117 +unsigned long *kernel_magic = &_end;
1118 +
1119 +/*
1120   * Boot command-line arguments
1121   */
1122  #define MAX_INIT_ARGS 32
1123 Index: linux-2.6.10/init/Makefile
1124 ===================================================================
1125 --- linux-2.6.10.orig/init/Makefile     2004-12-25 05:34:32.000000000 +0800
1126 +++ linux-2.6.10/init/Makefile  2005-04-05 16:47:53.897212096 +0800
1127 @@ -9,12 +9,20 @@
1128  mounts-$(CONFIG_BLK_DEV_INITRD)        += do_mounts_initrd.o
1129  mounts-$(CONFIG_BLK_DEV_MD)    += do_mounts_md.o
1130  
1131 +extra-$(CONFIG_KERNTYPES)      += kerntypes.o
1132 +#For IA64, compile kerntypes in dwarf-2 format.
1133 +ifeq ($(CONFIG_IA64),y)
1134 +CFLAGS_kerntypes.o             := -gdwarf-2
1135 +else
1136 +CFLAGS_kerntypes.o             := -gstabs
1137 +endif
1138 +
1139  # files to be removed upon make clean
1140  clean-files := ../include/linux/compile.h
1141  
1142  # dependencies on generated files need to be listed explicitly
1143  
1144 -$(obj)/version.o: include/linux/compile.h
1145 +$(obj)/version.o $(obj)/kerntypes.o: include/linux/compile.h
1146  
1147  # compile.h changes depending on hostname, generation number, etc,
1148  # so we regenerate it always.
1149 @@ -24,3 +32,4 @@
1150  include/linux/compile.h: FORCE
1151         @echo '  CHK     $@'
1152         @$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
1153 +
1154 Index: linux-2.6.10/include/asm-um/kerntypes.h
1155 ===================================================================
1156 --- linux-2.6.10.orig/include/asm-um/kerntypes.h        2005-04-05 19:01:49.158500672 +0800
1157 +++ linux-2.6.10/include/asm-um/kerntypes.h     2005-04-05 16:47:53.864217112 +0800
1158 @@ -0,0 +1,21 @@
1159 +/*
1160 + * asm-um/kerntypes.h
1161 + *
1162 + * Arch-dependent header file that includes headers for all arch-specific 
1163 + * types of interest.
1164 + * The kernel type information is used by the lcrash utility when
1165 + * analyzing system crash dumps or the live system. Using the type
1166 + * information for the running system, rather than kernel header files,
1167 + * makes for a more flexible and robust analysis tool.
1168 + *
1169 + * This source code is released under the GNU GPL.
1170 + */
1171 +
1172 +/* Usermode-Linux-specific header files */
1173 +#ifndef _UM_KERNTYPES_H
1174 +#define _UM_KERNTYPES_H
1175 +
1176 +/* Use the default */
1177 +#include <asm-generic/kerntypes.h>
1178 +
1179 +#endif /* _UM_KERNTYPES_H */
1180 Index: linux-2.6.10/include/linux/sysctl.h
1181 ===================================================================
1182 --- linux-2.6.10.orig/include/linux/sysctl.h    2005-04-05 16:29:27.969338688 +0800
1183 +++ linux-2.6.10/include/linux/sysctl.h 2005-04-05 16:47:53.894212552 +0800
1184 @@ -135,6 +135,7 @@
1185         KERN_HZ_TIMER=65,       /* int: hz timer on or off */
1186         KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */
1187         KERN_SETUID_DUMPABLE=67, /* int: behaviour of dumps for setuid core */
1188 +       KERN_DUMP=68,           /* directory: dump parameters */
1189  };
1190  
1191  
1192 Index: linux-2.6.10/include/linux/sched.h
1193 ===================================================================
1194 --- linux-2.6.10.orig/include/linux/sched.h     2005-04-05 16:47:05.178618448 +0800
1195 +++ linux-2.6.10/include/linux/sched.h  2005-04-05 16:47:53.891213008 +0800
1196 @@ -94,6 +94,7 @@
1197  extern int nr_threads;
1198  extern int last_pid;
1199  DECLARE_PER_CPU(unsigned long, process_counts);
1200 +DECLARE_PER_CPU(struct runqueue, runqueues);
1201  extern int nr_processes(void);
1202  extern unsigned long nr_running(void);
1203  extern unsigned long nr_uninterruptible(void);
1204 @@ -760,6 +761,110 @@
1205  void yield(void);
1206  
1207  /*
1208 + * These are the runqueue data structures:
1209 + */
1210 +
1211 +#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
1212 +
1213 +typedef struct runqueue runqueue_t;
1214 +
1215 +struct prio_array {
1216 +       unsigned int nr_active;
1217 +       unsigned long bitmap[BITMAP_SIZE];
1218 +       struct list_head queue[MAX_PRIO];
1219 +};
1220 +
1221 +/*
1222 + * This is the main, per-CPU runqueue data structure.
1223 + *
1224 + * Locking rule: those places that want to lock multiple runqueues
1225 + * (such as the load balancing or the thread migration code), lock
1226 + * acquire operations must be ordered by ascending &runqueue.
1227 + */
1228 +struct runqueue {
1229 +       spinlock_t lock;
1230 +
1231 +       /*
1232 +        * nr_running and cpu_load should be in the same cacheline because
1233 +        * remote CPUs use both these fields when doing load calculation.
1234 +        */
1235 +       unsigned long nr_running;
1236 +#ifdef CONFIG_SMP
1237 +       unsigned long cpu_load;
1238 +#endif
1239 +       unsigned long long nr_switches;
1240 +
1241 +       /*
1242 +        * This is part of a global counter where only the total sum
1243 +        * over all CPUs matters. A task can increase this counter on
1244 +        * one CPU and if it got migrated afterwards it may decrease
1245 +        * it on another CPU. Always updated under the runqueue lock:
1246 +        */
1247 +       unsigned long nr_uninterruptible;
1248 +
1249 +       unsigned long expired_timestamp;
1250 +       unsigned long long timestamp_last_tick;
1251 +       task_t *curr, *idle;
1252 +       struct mm_struct *prev_mm;
1253 +       prio_array_t *active, *expired, arrays[2];
1254 +       int best_expired_prio;
1255 +       atomic_t nr_iowait;
1256 +
1257 +#ifdef CONFIG_SMP
1258 +       struct sched_domain *sd;
1259 +
1260 +       /* For active balancing */
1261 +       int active_balance;
1262 +       int push_cpu;
1263 +
1264 +       task_t *migration_thread;
1265 +       struct list_head migration_queue;
1266 +#endif
1267 +
1268 +#ifdef CONFIG_SCHEDSTATS
1269 +       /* latency stats */
1270 +       struct sched_info rq_sched_info;
1271 +
1272 +       /* sys_sched_yield() stats */
1273 +       unsigned long yld_exp_empty;
1274 +       unsigned long yld_act_empty;
1275 +       unsigned long yld_both_empty;
1276 +       unsigned long yld_cnt;
1277 +
1278 +       /* schedule() stats */
1279 +       unsigned long sched_noswitch;
1280 +       unsigned long sched_switch;
1281 +       unsigned long sched_cnt;
1282 +       unsigned long sched_goidle;
1283 +
1284 +       /* pull_task() stats */
1285 +       unsigned long pt_gained[MAX_IDLE_TYPES];
1286 +       unsigned long pt_lost[MAX_IDLE_TYPES];
1287 +
1288 +       /* active_load_balance() stats */
1289 +       unsigned long alb_cnt;
1290 +       unsigned long alb_lost;
1291 +       unsigned long alb_gained;
1292 +       unsigned long alb_failed;
1293 +
1294 +       /* try_to_wake_up() stats */
1295 +       unsigned long ttwu_cnt;
1296 +       unsigned long ttwu_attempts;
1297 +       unsigned long ttwu_moved;
1298 +
1299 +       /* wake_up_new_task() stats */
1300 +       unsigned long wunt_cnt;
1301 +       unsigned long wunt_moved;
1302 +
1303 +       /* sched_migrate_task() stats */
1304 +       unsigned long smt_cnt;
1305 +
1306 +       /* sched_balance_exec() stats */
1307 +       unsigned long sbe_cnt;
1308 +#endif
1309 +};
1310 +
1311 +/*
1312   * The default (Linux) execution domain.
1313   */
1314  extern struct exec_domain      default_exec_domain;
1315 Index: linux-2.6.10/include/linux/miscdevice.h
1316 ===================================================================
1317 --- linux-2.6.10.orig/include/linux/miscdevice.h        2004-12-25 05:34:58.000000000 +0800
1318 +++ linux-2.6.10/include/linux/miscdevice.h     2005-04-05 16:47:53.893212704 +0800
1319 @@ -25,6 +25,7 @@
1320  #define MICROCODE_MINOR                184
1321  #define MWAVE_MINOR    219             /* ACP/Mwave Modem */
1322  #define MPT_MINOR      220
1323 +#define CRASH_DUMP_MINOR   230         /* LKCD */
1324  #define MISC_DYNAMIC_MINOR 255
1325  
1326  #define TUN_MINOR           200
1327 Index: linux-2.6.10/include/linux/dump.h
1328 ===================================================================
1329 --- linux-2.6.10.orig/include/linux/dump.h      2005-04-05 19:01:49.158500672 +0800
1330 +++ linux-2.6.10/include/linux/dump.h   2005-04-05 16:47:53.893212704 +0800
1331 @@ -0,0 +1,406 @@
1332 +/*
1333 + * Kernel header file for Linux crash dumps.
1334 + *
1335 + * Created by: Matt Robinson (yakker@sgi.com)
1336 + * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
1337 + *
1338 + * vmdump.h to dump.h by: Matt D. Robinson (yakker@sourceforge.net)
1339 + * Copyright 2001 - 2002 Matt D. Robinson.  All rights reserved.
1340 + * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
1341 + *
1342 + * Most of this is the same old stuff from vmdump.h, except now we're
1343 + * actually a stand-alone driver plugged into the block layer interface,
1344 + * with the exception that we now allow for compression modes externally
1345 + * loaded (e.g., someone can come up with their own).
1346 + *
1347 + * This code is released under version 2 of the GNU GPL.
1348 + */
1349 +
1350 +/* This header file includes all structure definitions for crash dumps. */
1351 +#ifndef _DUMP_H
1352 +#define _DUMP_H
1353 +
1354 +#if defined(CONFIG_CRASH_DUMP) || defined (CONFIG_CRASH_DUMP_MODULE)
1355 +
1356 +#include <linux/list.h>
1357 +#include <linux/notifier.h>
1358 +#include <linux/dumpdev.h>
1359 +#include <asm/ioctl.h>
1360 +
1361 +/* 
1362 + * Predefine default DUMP_PAGE constants, asm header may override.
1363 + *
1364 + * On ia64 discontinuous memory systems it's possible for the memory
1365 + * banks to stop at 2**12 page alignments, the smallest possible page
1366 + * size. But the system page size, PAGE_SIZE, is in fact larger.
1367 + */
1368 +#define DUMP_PAGE_SHIFT        PAGE_SHIFT
1369 +#define DUMP_PAGE_MASK         PAGE_MASK
1370 +#define DUMP_PAGE_ALIGN(addr)  PAGE_ALIGN(addr)
1371 +
1372 +/*
1373 + * Dump offset changed from 4Kb to 64Kb to support multiple PAGE_SIZE 
1374 + * (kernel page size). Assumption goes that 64K is the highest page size 
1375 + * supported 
1376 + */
1377 +
1378 +#define DUMP_HEADER_OFFSET     (1ULL << 16)
1379 +
1380 +#define OLDMINORBITS   8
1381 +#define OLDMINORMASK   ((1U << OLDMINORBITS) -1)
1382 +
1383 +/* Making DUMP_PAGE_SIZE = PAGE_SIZE, to support dumping on architectures 
1384 + * which support page sizes (PAGE_SIZE) greater than 4KB.
1385 + * Will it affect ia64 discontinuous memory systems ????
1386 + */
1387 +#define DUMP_PAGE_SIZE         PAGE_SIZE
1388 +
1389 +/* thread_info lies at the bottom of stack, (Except IA64). */
1390 +#define STACK_START_POSITION(tsk)               (tsk->thread_info)
1391 +/* 
1392 + * Predefined default memcpy() to use when copying memory to the dump buffer.
1393 + *
1394 + * On ia64 there is a heads up function that can be called to let the prom
1395 + * machine check monitor know that the current activity is risky and it should
1396 + * ignore the fault (nofault). In this case the ia64 header will redefine this
1397 + * macro to __dump_memcpy() and use it's arch specific version.
1398 + */
1399 +#define DUMP_memcpy            memcpy
1400 +#define bzero(a,b)              memset(a, 0, b)
1401 +
1402 +/* necessary header files */
1403 +#include <asm/dump.h>                  /* for architecture-specific header */
1404 +
1405 +/* 
1406 + * Size of the buffer that's used to hold:
1407 + *
1408 + *     1. the dump header (padded to fill the complete buffer)
1409 + *     2. the possibly compressed page headers and data
1410 + *   
1411 + *  = 256k for page size >= 64k
1412 + *  = 64k  for page size < 64k
1413 + */
1414 +#if (PAGE_SHIFT >= 16)
1415 +#define DUMP_BUFFER_SIZE       (256 * 1024)  /* size of dump buffer         */
1416 +#else
1417 +#define DUMP_BUFFER_SIZE       (64 * 1024)  /* size of dump buffer         */
1418 +#endif
1419 +
1420 +#define DUMP_HEADER_SIZE       DUMP_BUFFER_SIZE
1421 +
1422 +/* standard header definitions */
1423 +#define DUMP_MAGIC_NUMBER      0xa8190173618f23edULL  /* dump magic number */
1424 +#define DUMP_MAGIC_LIVE                0xa8190173618f23cdULL  /* live magic number */
1425 +#define DUMP_VERSION_NUMBER    0x8     /* dump version number              */
1426 +#define DUMP_PANIC_LEN         0x100   /* dump panic string length         */
1427 +
1428 +/* dump levels - type specific stuff added later -- add as necessary */
1429 +#define DUMP_LEVEL_NONE                0x0     /* no dumping at all -- just bail   */
1430 +#define DUMP_LEVEL_HEADER      0x1     /* kernel dump header only          */
1431 +#define DUMP_LEVEL_KERN                0x2     /* dump header and kernel pages     */
1432 +#define DUMP_LEVEL_USED                0x4     /* dump header, kernel/user pages   */
1433 +#define DUMP_LEVEL_ALL_RAM     0x8     /* dump header, all RAM pages       */
1434 +#define DUMP_LEVEL_ALL         0x10    /* dump all memory RAM and firmware */
1435 +
1436 +
1437 +/* dump compression options -- add as necessary */
1438 +#define DUMP_COMPRESS_NONE     0x0     /* don't compress this dump         */
1439 +#define DUMP_COMPRESS_RLE      0x1     /* use RLE compression              */
1440 +#define DUMP_COMPRESS_GZIP     0x2     /* use GZIP compression             */
1441 +
1442 +/* dump flags - any dump-type specific flags -- add as necessary */
1443 +#define DUMP_FLAGS_NONE                0x0     /* no flags are set for this dump   */
1444 +#define DUMP_FLAGS_SOFTBOOT    0x2     /* 2 stage soft-boot based dump     */
1445 +#define DUMP_FLAGS_NONDISRUPT   0X1    /* non-disruptive dumping           */
1446 +
1447 +#define DUMP_FLAGS_TARGETMASK  0xf0000000 /* handle special case targets   */
1448 +#define DUMP_FLAGS_DISKDUMP    0x80000000 /* dump to local disk            */
1449 +#define DUMP_FLAGS_NETDUMP     0x40000000 /* dump over the network         */
1450 +
1451 +/* dump header flags -- add as necessary */
1452 +#define DUMP_DH_FLAGS_NONE     0x0     /* no flags set (error condition!)  */
1453 +#define DUMP_DH_RAW            0x1     /* raw page (no compression)        */
1454 +#define DUMP_DH_COMPRESSED     0x2     /* page is compressed               */
1455 +#define DUMP_DH_END            0x4     /* end marker on a full dump        */
1456 +#define DUMP_DH_TRUNCATED      0x8     /* dump is incomplete               */
1457 +#define DUMP_DH_TEST_PATTERN   0x10    /* dump page is a test pattern      */
1458 +#define DUMP_DH_NOT_USED       0x20    /* 1st bit not used in flags        */
1459 +
1460 +/* names for various dump parameters in /proc/kernel */
1461 +#define DUMP_ROOT_NAME         "sys/dump"
1462 +#define DUMP_DEVICE_NAME       "device"
1463 +#define DUMP_COMPRESS_NAME     "compress"
1464 +#define DUMP_LEVEL_NAME                "level"
1465 +#define DUMP_FLAGS_NAME                "flags"
1466 +#define DUMP_ADDR_NAME         "addr"
1467 +
1468 +#define DUMP_SYSRQ_KEY         'd'     /* key to use for MAGIC_SYSRQ key   */
1469 +
1470 +/* CTL_DUMP names: */
1471 +enum
1472 +{
1473 +       CTL_DUMP_DEVICE=1,
1474 +       CTL_DUMP_COMPRESS=3,
1475 +       CTL_DUMP_LEVEL=3,
1476 +       CTL_DUMP_FLAGS=4,
1477 +       CTL_DUMP_ADDR=5,
1478 +       CTL_DUMP_TEST=6,
1479 +};
1480 +
1481 +
1482 +/* page size for gzip compression -- buffered slightly beyond hardware PAGE_SIZE used by DUMP */
1483 +#define DUMP_DPC_PAGE_SIZE     (DUMP_PAGE_SIZE + 512)
1484 +
1485 +/* dump ioctl() control options */
1486 +#define DIOSDUMPDEV     _IOW('p', 0xA0, unsigned int)  /* set the dump device              */
1487 +#define DIOGDUMPDEV     _IOR('p', 0xA1, unsigned int)  /* get the dump device              */
1488 +#define DIOSDUMPLEVEL   _IOW('p', 0xA2, unsigned int)  /* set the dump level               */
1489 +#define DIOGDUMPLEVEL   _IOR('p', 0xA3, unsigned int)  /* get the dump level               */
1490 +#define DIOSDUMPFLAGS   _IOW('p', 0xA4, unsigned int)  /* set the dump flag parameters     */
1491 +#define DIOGDUMPFLAGS   _IOR('p', 0xA5, unsigned int)  /* get the dump flag parameters     */
1492 +#define DIOSDUMPCOMPRESS _IOW('p', 0xA6, unsigned int) /* set the dump compress level      */
1493 +#define DIOGDUMPCOMPRESS _IOR('p', 0xA7, unsigned int) /* get the dump compress level      */
1494 +
1495 +/* these ioctls are used only by netdump module */
1496 +#define DIOSTARGETIP    _IOW('p', 0xA8, unsigned int)  /* set the target m/c's ip           */
1497 +#define DIOGTARGETIP    _IOR('p', 0xA9, unsigned int)  /* get the target m/c's ip           */
1498 +#define DIOSTARGETPORT  _IOW('p', 0xAA, unsigned int) /* set the target m/c's port          */
1499 +#define DIOGTARGETPORT  _IOR('p', 0xAB, unsigned int) /* get the target m/c's port          */
1500 +#define DIOSSOURCEPORT  _IOW('p', 0xAC, unsigned int) /* set the source m/c's port          */
1501 +#define DIOGSOURCEPORT  _IOR('p', 0xAD, unsigned int) /* get the source m/c's port          */
1502 +#define DIOSETHADDR     _IOW('p', 0xAE, unsigned int) /* set ethernet address      */
1503 +#define DIOGETHADDR     _IOR('p', 0xAF, unsigned int) /* get ethernet address       */
1504 +#define DIOGDUMPOKAY   _IOR('p', 0xB0, unsigned int) /* check if dump is configured      */
1505 +#define DIOSDUMPTAKE    _IOW('p', 0xB1, unsigned int) /* Take a manual dump               */
1506 +
1507 +/*
1508 + * Structure: __dump_header
1509 + *  Function: This is the header dumped at the top of every valid crash
1510 + *            dump.  
1511 + */
1512 +struct __dump_header {
1513 +       /* the dump magic number -- unique to verify dump is valid */
1514 +       u64     dh_magic_number;
1515 +
1516 +       /* the version number of this dump */
1517 +       u32     dh_version;
1518 +
1519 +       /* the size of this header (in case we can't read it) */
1520 +       u32     dh_header_size;
1521 +
1522 +       /* the level of this dump (just a header?) */
1523 +       u32     dh_dump_level;
1524 +
1525 +       /* 
1526 +        * We assume dump_page_size to be 4K in every case.
1527 +        * Store here the configurable system page size (4K, 8K, 16K, etc.) 
1528 +        */
1529 +       u32     dh_page_size;
1530 +
1531 +       /* the size of all physical memory */
1532 +       u64     dh_memory_size;
1533 +
1534 +       /* the start of physical memory */
1535 +       u64     dh_memory_start;
1536 +
1537 +       /* the end of physical memory */
1538 +       u64     dh_memory_end;
1539 +
1540 +       /* the number of hardware/physical pages in this dump specifically */
1541 +       u32     dh_num_dump_pages;
1542 +
1543 +       /* the panic string, if available */
1544 +       char    dh_panic_string[DUMP_PANIC_LEN];
1545 +
1546 +       /* timeval depends on architecture, two long values */
1547 +       struct {
1548 +               u64 tv_sec;
1549 +               u64 tv_usec;
1550 +       } dh_time; /* the time of the system crash */
1551 +
1552 +       /* the NEW utsname (uname) information -- in character form */
1553 +       /* we do this so we don't have to include utsname.h         */
1554 +       /* plus it helps us be more architecture independent        */
1555 +       /* now maybe one day soon they'll make the [65] a #define!  */
1556 +       char    dh_utsname_sysname[65];
1557 +       char    dh_utsname_nodename[65];
1558 +       char    dh_utsname_release[65];
1559 +       char    dh_utsname_version[65];
1560 +       char    dh_utsname_machine[65];
1561 +       char    dh_utsname_domainname[65];
1562 +
1563 +       /* the address of current task (OLD = void *, NEW = u64) */
1564 +       u64     dh_current_task;
1565 +
1566 +       /* what type of compression we're using in this dump (if any) */
1567 +       u32     dh_dump_compress;
1568 +
1569 +       /* any additional flags */
1570 +       u32     dh_dump_flags;
1571 +
1572 +       /* any additional flags */
1573 +       u32     dh_dump_device;
1574 +} __attribute__((packed));
1575 +
1576 +/*
1577 + * Structure: __dump_page
1578 + *  Function: To act as the header associated to each physical page of
1579 + *            memory saved in the system crash dump.  This allows for
1580 + *            easy reassembly of each crash dump page.  The address bits
1581 + *            are split to make things easier for 64-bit/32-bit system
1582 + *            conversions.
1583 + *
1584 + * dp_byte_offset and dp_page_index are landmarks that are helpful when
1585 + * looking at a hex dump of /dev/vmdump,
1586 + */
1587 +struct __dump_page {
1588 +       /* the address of this dump page */
1589 +       u64     dp_address;
1590 +
1591 +       /* the size of this dump page */
1592 +       u32     dp_size;
1593 +
1594 +       /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */
1595 +       u32     dp_flags;
1596 +} __attribute__((packed));
1597 +
1598 +/*
1599 + * Structure: __lkcdinfo
1600 + * Function:  This structure contains information needed for the lkcdutils
1601 + *            package (particularly lcrash) to determine what information is
1602 + *            associated to this kernel, specifically.
1603 + */
1604 +struct __lkcdinfo {
1605 +       int     arch;
1606 +       int     ptrsz;
1607 +       int     byte_order;
1608 +       int     linux_release;
1609 +       int     page_shift;
1610 +       int     page_size;
1611 +       u64     page_mask;
1612 +       u64     page_offset;
1613 +       int     stack_offset;
1614 +};
1615 +
1616 +#ifdef __KERNEL__
1617 +
1618 +/*
1619 + * Structure: __dump_compress
1620 + *  Function: This is what an individual compression mechanism can use
1621 + *            to plug in their own compression techniques.  It's always
1622 + *            best to build these as individual modules so that people
1623 + *            can put in whatever they want.
1624 + */
1625 +struct __dump_compress {
1626 +       /* the list_head structure for list storage */
1627 +       struct list_head list;
1628 +
1629 +       /* the type of compression to use (DUMP_COMPRESS_XXX) */
1630 +       int compress_type;
1631 +       const char *compress_name;
1632 +
1633 +       /* the compression function to call */
1634 +       u32 (*compress_func)(const u8 *, u32, u8 *, u32, unsigned long);
1635 +};
1636 +
1637 +/* functions for dump compression registration */
1638 +extern void dump_register_compression(struct __dump_compress *);
1639 +extern void dump_unregister_compression(int);
1640 +
1641 +/*
1642 + * Structure dump_mbank[]:
1643 + *
1644 + * For CONFIG_DISCONTIGMEM systems this array specifies the
1645 + * memory banks/chunks that need to be dumped after a panic.
1646 + *
1647 + * For classic systems it specifies a single set of pages from
1648 + * 0 to max_mapnr.
1649 + */
1650 +struct __dump_mbank {
1651 +       u64     start;
1652 +       u64     end;
1653 +       int     type;
1654 +       int     pad1;
1655 +       long    pad2;
1656 +};
1657 +
1658 +#define DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY            1
1659 +#define DUMP_MBANK_TYPE_OTHER                          2
1660 +
1661 +#define MAXCHUNKS 256
1662 +extern int dump_mbanks;
1663 +extern struct __dump_mbank dump_mbank[MAXCHUNKS];
1664 +
1665 +/* notification event codes */
1666 +#define DUMP_BEGIN             0x0001  /* dump beginning */
1667 +#define DUMP_END               0x0002  /* dump ending */
1668 +
1669 +/* Scheduler soft spin control.
1670 + *
1671 + * 0 - no dump in progress
1672 + * 1 - cpu0 is dumping, ...
1673 + */
1674 +extern unsigned long dump_oncpu;
1675 +extern void dump_execute(const char *, const struct pt_regs *);
1676 +
1677 +/*
1678 + *     Notifier list for kernel code which wants to be called
1679 + *     at kernel dump. 
1680 + */
1681 +extern struct notifier_block *dump_notifier_list;
1682 +static inline int register_dump_notifier(struct notifier_block *nb)
1683 +{
1684 +       return notifier_chain_register(&dump_notifier_list, nb);
1685 +}
1686 +static inline int unregister_dump_notifier(struct notifier_block * nb)
1687 +{
1688 +       return notifier_chain_unregister(&dump_notifier_list, nb);
1689 +}
1690 +
1691 +extern void (*dump_function_ptr)(const char *, const struct pt_regs *);
1692 +static inline void dump(char * str, struct pt_regs * regs)
1693 +{
1694 +       if (dump_function_ptr)
1695 +               dump_function_ptr(str, regs);
1696 +}
1697 +
1698 +/*
1699 + * Common Arch Specific Functions should be declared here.
1700 + * This allows the C compiler to detect discrepancies.
1701 + */
1702 +extern void    __dump_open(void);
1703 +extern void    __dump_cleanup(void);
1704 +extern void    __dump_clean_irq_state(void);
1705 +extern void    __dump_init(u64);
1706 +extern void    __dump_save_regs(struct pt_regs *, const struct pt_regs *);
1707 +extern void    __dump_save_context(int cpu, const struct pt_regs *, struct task_struct *tsk);
1708 +extern int     __dump_configure_header(const struct pt_regs *);
1709 +extern int     __dump_irq_enable(void);
1710 +extern void    __dump_irq_restore(void);
1711 +extern int     __dump_page_valid(unsigned long index);
1712 +#ifdef CONFIG_SMP
1713 +extern void    __dump_save_other_cpus(void);
1714 +#else
1715 +#define        __dump_save_other_cpus()
1716 +#endif
1717 +
1718 +extern int manual_handle_crashdump(void);
1719 +
1720 +/* to track all used (compound + zero order) pages */
1721 +#define PageInuse(p)   (PageCompound(p) || page_count(p))
1722 +
1723 +#endif /* __KERNEL__ */
1724 +
1725 +#else  /* !CONFIG_CRASH_DUMP */
1726 +
1727 +/* If not configured then make code disappear! */
1728 +#define register_dump_watchdog(x)      do { } while(0)
1729 +#define unregister_dump_watchdog(x)    do { } while(0)
1730 +#define register_dump_notifier(x)      do { } while(0)
1731 +#define unregister_dump_notifier(x)    do { } while(0)
1732 +#define dump_in_progress()             0
1733 +#define dump(x, y)                     do { } while(0)
1734 +
1735 +#endif /* !CONFIG_CRASH_DUMP */
1736 +
1737 +#endif /* _DUMP_H */
1738 Index: linux-2.6.10/include/linux/dumpdev.h
1739 ===================================================================
1740 --- linux-2.6.10.orig/include/linux/dumpdev.h   2005-04-05 19:01:49.158500672 +0800
1741 +++ linux-2.6.10/include/linux/dumpdev.h        2005-04-05 16:47:53.890213160 +0800
1742 @@ -0,0 +1,163 @@
1743 +/*
1744 + * Generic dump device interfaces for flexible system dump 
1745 + * (Enables variation of dump target types e.g disk, network, memory)
1746 + *
1747 + * These interfaces have evolved based on discussions on lkcd-devel. 
1748 + * Eventually the intent is to support primary and secondary or 
1749 + * alternate targets registered at the same time, with scope for 
1750 + * situation based failover or multiple dump devices used for parallel 
1751 + * dump i/o.
1752 + *
1753 + * Started: Oct 2002 - Suparna Bhattacharya (suparna@in.ibm.com)
1754 + *
1755 + * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
1756 + * Copyright (C) 2002 International Business Machines Corp. 
1757 + *
1758 + * This code is released under version 2 of the GNU GPL.
1759 + */
1760 +
1761 +#ifndef _LINUX_DUMPDEV_H
1762 +#define _LINUX_DUMPDEV_H
1763 +
1764 +#include <linux/kernel.h>
1765 +#include <linux/wait.h>
1766 +#include <linux/netpoll.h>
1767 +#include <linux/bio.h>
1768 +
1769 +/* Determined by the dump target (device) type */
1770 +
1771 +struct dump_dev;
1772 +
1773 +struct dump_dev_ops {
1774 +       int (*open)(struct dump_dev *, unsigned long); /* configure */
1775 +       int (*release)(struct dump_dev *); /* unconfigure */
1776 +       int (*silence)(struct dump_dev *); /* when dump starts */
1777 +       int (*resume)(struct dump_dev *); /* when dump is over */
1778 +       int (*seek)(struct dump_dev *, loff_t);
1779 +       /* trigger a write (async in nature typically) */
1780 +       int (*write)(struct dump_dev *, void *, unsigned long);
1781 +       /* not usually used during dump, but option available */
1782 +       int (*read)(struct dump_dev *, void *, unsigned long);
1783 +       /* use to poll for completion */
1784 +       int (*ready)(struct dump_dev *, void *); 
1785 +       int (*ioctl)(struct dump_dev *, unsigned int, unsigned long);
1786 +};
1787 +
1788 +struct dump_dev {
1789 +       char type_name[32]; /* block, net-poll etc */
1790 +       unsigned long device_id; /* interpreted differently for various types */
1791 +       struct dump_dev_ops *ops;
1792 +       struct list_head list;
1793 +       loff_t curr_offset;
1794 +       struct netpoll np;
1795 +};
1796 +
1797 +/*
1798 + * dump_dev type variations: 
1799 + */
1800 +
1801 +/* block */
1802 +struct dump_blockdev {
1803 +       struct dump_dev ddev;
1804 +       dev_t dev_id;
1805 +       struct block_device *bdev;
1806 +       struct bio *bio;
1807 +       loff_t start_offset;
1808 +       loff_t limit;
1809 +       int err;
1810 +};
1811 +
1812 +static inline struct dump_blockdev *DUMP_BDEV(struct dump_dev *dev)
1813 +{
1814 +       return container_of(dev, struct dump_blockdev, ddev);
1815 +}
1816 +
1817 +
1818 +/* mem  - for internal use by soft-boot based dumper */
1819 +struct dump_memdev {
1820 +       struct dump_dev ddev;
1821 +       unsigned long indirect_map_root;
1822 +       unsigned long nr_free;
1823 +       struct page *curr_page;
1824 +       unsigned long *curr_map;
1825 +       unsigned long curr_map_offset;
1826 +       unsigned long last_offset;
1827 +       unsigned long last_used_offset;
1828 +       unsigned long last_bs_offset;
1829 +};     
1830 +
1831 +static inline struct dump_memdev *DUMP_MDEV(struct dump_dev *dev)
1832 +{
1833 +       return container_of(dev, struct dump_memdev, ddev);
1834 +}
1835 +
1836 +/* Todo/future - meant for raw dedicated interfaces e.g. mini-ide driver */
1837 +struct dump_rdev {
1838 +       struct dump_dev ddev;
1839 +       char name[32];
1840 +       int (*reset)(struct dump_rdev *, unsigned int, 
1841 +               unsigned long);
1842 +       /* ... to do ... */
1843 +};
1844 +
1845 +/* just to get the size right when saving config across a soft-reboot */
1846 +struct dump_anydev {
1847 +       union {
1848 +               struct dump_blockdev bddev;
1849 +               /* .. add other types here .. */
1850 +       };
1851 +};
1852 +
1853 +
1854 +
1855 +/* Dump device / target operation wrappers */
1856 +/* These assume that dump_dev is initiatized to dump_config.dumper->dev */
1857 +
1858 +extern struct dump_dev *dump_dev;
1859 +
1860 +static inline int dump_dev_open(unsigned long arg)
1861 +{
1862 +       return dump_dev->ops->open(dump_dev, arg);
1863 +}
1864 +
1865 +static inline int dump_dev_release(void)
1866 +{
1867 +       return dump_dev->ops->release(dump_dev);
1868 +}
1869 +
1870 +static inline int dump_dev_silence(void)
1871 +{
1872 +       return dump_dev->ops->silence(dump_dev);
1873 +}
1874 +
1875 +static inline int dump_dev_resume(void)
1876 +{
1877 +       return dump_dev->ops->resume(dump_dev);
1878 +}
1879 +
1880 +static inline int dump_dev_seek(loff_t offset)
1881 +{
1882 +       return dump_dev->ops->seek(dump_dev, offset);
1883 +}
1884 +
1885 +static inline int dump_dev_write(void *buf, unsigned long len)
1886 +{
1887 +       return dump_dev->ops->write(dump_dev, buf, len);
1888 +}
1889 +
1890 +static inline int dump_dev_ready(void *buf)
1891 +{
1892 +       return dump_dev->ops->ready(dump_dev, buf);
1893 +}
1894 +
1895 +static inline int dump_dev_ioctl(unsigned int cmd, unsigned long arg)
1896 +{
1897 +       if (!dump_dev || !dump_dev->ops->ioctl)
1898 +               return -EINVAL;
1899 +       return dump_dev->ops->ioctl(dump_dev, cmd, arg);
1900 +}
1901 +
1902 +extern int dump_register_device(struct dump_dev *);
1903 +extern void dump_unregister_device(struct dump_dev *);
1904 +
1905 +#endif /*  _LINUX_DUMPDEV_H */
1906 Index: linux-2.6.10/include/linux/dump_netdev.h
1907 ===================================================================
1908 --- linux-2.6.10.orig/include/linux/dump_netdev.h       2005-04-05 19:01:49.158500672 +0800
1909 +++ linux-2.6.10/include/linux/dump_netdev.h    2005-04-05 16:47:53.889213312 +0800
1910 @@ -0,0 +1,80 @@
1911 +/*
1912 + *  linux/drivers/net/netconsole.h
1913 + *
1914 + *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
1915 + *
1916 + *  This file contains the implementation of an IRQ-safe, crash-safe
1917 + *  kernel console implementation that outputs kernel messages to the
1918 + *  network.
1919 + *
1920 + * Modification history:
1921 + *
1922 + * 2001-09-17    started by Ingo Molnar.
1923 + */
1924 +
1925 +/****************************************************************
1926 + *      This program is free software; you can redistribute it and/or modify
1927 + *      it under the terms of the GNU General Public License as published by
1928 + *      the Free Software Foundation; either version 2, or (at your option)
1929 + *      any later version.
1930 + *
1931 + *      This program is distributed in the hope that it will be useful,
1932 + *      but WITHOUT ANY WARRANTY; without even the implied warranty of
1933 + *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1934 + *      GNU General Public License for more details.
1935 + *
1936 + *      You should have received a copy of the GNU General Public License
1937 + *      along with this program; if not, write to the Free Software
1938 + *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1939 + *
1940 + ****************************************************************/
1941 +
1942 +#define NETCONSOLE_VERSION 0x03
1943 +
1944 +enum netdump_commands {
1945 +       COMM_NONE = 0,
1946 +       COMM_SEND_MEM = 1,
1947 +       COMM_EXIT = 2,
1948 +       COMM_REBOOT = 3,
1949 +       COMM_HELLO = 4,
1950 +       COMM_GET_NR_PAGES = 5,
1951 +       COMM_GET_PAGE_SIZE = 6,
1952 +       COMM_START_NETDUMP_ACK = 7,
1953 +       COMM_GET_REGS = 8,
1954 +       COMM_GET_MAGIC = 9,
1955 +       COMM_START_WRITE_NETDUMP_ACK = 10,
1956 +};
1957 +
1958 +typedef struct netdump_req_s {
1959 +       u64 magic;
1960 +       u32 nr;
1961 +       u32 command;
1962 +       u32 from;
1963 +       u32 to;
1964 +} req_t;
1965 +
1966 +enum netdump_replies {
1967 +       REPLY_NONE = 0,
1968 +       REPLY_ERROR = 1,
1969 +       REPLY_LOG = 2,
1970 +       REPLY_MEM = 3,
1971 +       REPLY_RESERVED = 4,
1972 +       REPLY_HELLO = 5,
1973 +       REPLY_NR_PAGES = 6,
1974 +       REPLY_PAGE_SIZE = 7,
1975 +       REPLY_START_NETDUMP = 8,
1976 +       REPLY_END_NETDUMP = 9,
1977 +       REPLY_REGS = 10,
1978 +       REPLY_MAGIC = 11,
1979 +       REPLY_START_WRITE_NETDUMP = 12,
1980 +};
1981 +
1982 +typedef struct netdump_reply_s {
1983 +       u32 nr;
1984 +       u32 code;
1985 +       u32 info;
1986 +} reply_t;
1987 +
1988 +#define HEADER_LEN (1 + sizeof(reply_t))
1989 +
1990 +
1991 Index: linux-2.6.10/include/asm-parisc/kerntypes.h
1992 ===================================================================
1993 --- linux-2.6.10.orig/include/asm-parisc/kerntypes.h    2005-04-05 19:01:49.158500672 +0800
1994 +++ linux-2.6.10/include/asm-parisc/kerntypes.h 2005-04-05 16:47:53.870216200 +0800
1995 @@ -0,0 +1,21 @@
1996 +/*
1997 + * asm-parisc/kerntypes.h
1998 + *
1999 + * Arch-dependent header file that includes headers for all arch-specific 
2000 + * types of interest.
2001 + * The kernel type information is used by the lcrash utility when
2002 + * analyzing system crash dumps or the live system. Using the type
2003 + * information for the running system, rather than kernel header files,
2004 + * makes for a more flexible and robust analysis tool.
2005 + *
2006 + * This source code is released under the GNU GPL.
2007 + */
2008 +
2009 +/* PA-RISC-specific header files */
2010 +#ifndef _PARISC_KERNTYPES_H
2011 +#define _PARISC_KERNTYPES_H
2012 +
2013 +/* Use the default */
2014 +#include <asm-generic/kerntypes.h>
2015 +
2016 +#endif /* _PARISC_KERNTYPES_H */
2017 Index: linux-2.6.10/include/asm-h8300/kerntypes.h
2018 ===================================================================
2019 --- linux-2.6.10.orig/include/asm-h8300/kerntypes.h     2005-04-05 19:01:49.158500672 +0800
2020 +++ linux-2.6.10/include/asm-h8300/kerntypes.h  2005-04-05 16:47:53.880214680 +0800
2021 @@ -0,0 +1,21 @@
2022 +/*
2023 + * asm-h8300/kerntypes.h
2024 + *
2025 + * Arch-dependent header file that includes headers for all arch-specific 
2026 + * types of interest.
2027 + * The kernel type information is used by the lcrash utility when
2028 + * analyzing system crash dumps or the live system. Using the type
2029 + * information for the running system, rather than kernel header files,
2030 + * makes for a more flexible and robust analysis tool.
2031 + *
2032 + * This source code is released under the GNU GPL.
2033 + */
2034 +
2035 +/* H8300-specific header files */
2036 +#ifndef _H8300_KERNTYPES_H
2037 +#define _H8300_KERNTYPES_H
2038 +
2039 +/* Use the default */
2040 +#include <asm-generic/kerntypes.h>
2041 +
2042 +#endif /* _H8300_KERNTYPES_H */
2043 Index: linux-2.6.10/include/asm-ppc/kerntypes.h
2044 ===================================================================
2045 --- linux-2.6.10.orig/include/asm-ppc/kerntypes.h       2005-04-05 19:01:49.158500672 +0800
2046 +++ linux-2.6.10/include/asm-ppc/kerntypes.h    2005-04-05 16:47:53.882214376 +0800
2047 @@ -0,0 +1,21 @@
2048 +/*
2049 + * asm-ppc/kerntypes.h
2050 + *
2051 + * Arch-dependent header file that includes headers for all arch-specific 
2052 + * types of interest.
2053 + * The kernel type information is used by the lcrash utility when
2054 + * analyzing system crash dumps or the live system. Using the type
2055 + * information for the running system, rather than kernel header files,
2056 + * makes for a more flexible and robust analysis tool.
2057 + *
2058 + * This source code is released under the GNU GPL.
2059 + */
2060 +
2061 +/* PowerPC-specific header files */
2062 +#ifndef _PPC_KERNTYPES_H
2063 +#define _PPC_KERNTYPES_H
2064 +
2065 +/* Use the default */
2066 +#include <asm-generic/kerntypes.h>
2067 +
2068 +#endif /* _PPC_KERNTYPES_H */
2069 Index: linux-2.6.10/include/asm-alpha/kerntypes.h
2070 ===================================================================
2071 --- linux-2.6.10.orig/include/asm-alpha/kerntypes.h     2005-04-05 19:01:49.158500672 +0800
2072 +++ linux-2.6.10/include/asm-alpha/kerntypes.h  2005-04-05 16:47:53.876215288 +0800
2073 @@ -0,0 +1,21 @@
2074 +/*
2075 + * asm-alpha/kerntypes.h
2076 + *
2077 + * Arch-dependent header file that includes headers for all arch-specific 
2078 + * types of interest.
2079 + * The kernel type information is used by the lcrash utility when
2080 + * analyzing system crash dumps or the live system. Using the type
2081 + * information for the running system, rather than kernel header files,
2082 + * makes for a more flexible and robust analysis tool.
2083 + *
2084 + * This source code is released under the GNU GPL.
2085 + */
2086 +
2087 +/* Alpha-specific header files */
2088 +#ifndef _ALPHA_KERNTYPES_H
2089 +#define _ALPHA_KERNTYPES_H
2090 +
2091 +/* Use the default */
2092 +#include <asm-generic/kerntypes.h>
2093 +
2094 +#endif /* _ALPHA_KERNTYPES_H */
2095 Index: linux-2.6.10/include/asm-arm26/kerntypes.h
2096 ===================================================================
2097 --- linux-2.6.10.orig/include/asm-arm26/kerntypes.h     2005-04-05 19:01:49.158500672 +0800
2098 +++ linux-2.6.10/include/asm-arm26/kerntypes.h  2005-04-05 16:47:53.865216960 +0800
2099 @@ -0,0 +1,21 @@
2100 +/*
2101 + * asm-arm26/kerntypes.h
2102 + *
2103 + * Arch-dependent header file that includes headers for all arch-specific 
2104 + * types of interest.
2105 + * The kernel type information is used by the lcrash utility when
2106 + * analyzing system crash dumps or the live system. Using the type
2107 + * information for the running system, rather than kernel header files,
2108 + * makes for a more flexible and robust analysis tool.
2109 + *
2110 + * This source code is released under the GNU GPL.
2111 + */
2112 +
2113 +/* ARM26-specific header files */
2114 +#ifndef _ARM26_KERNTYPES_H
2115 +#define _ARM26_KERNTYPES_H
2116 +
2117 +/* Use the default */
2118 +#include <asm-generic/kerntypes.h>
2119 +
2120 +#endif /* _ARM26_KERNTYPES_H */
2121 Index: linux-2.6.10/include/asm-sh/kerntypes.h
2122 ===================================================================
2123 --- linux-2.6.10.orig/include/asm-sh/kerntypes.h        2005-04-05 19:01:49.158500672 +0800
2124 +++ linux-2.6.10/include/asm-sh/kerntypes.h     2005-04-05 16:47:53.877215136 +0800
2125 @@ -0,0 +1,21 @@
2126 +/*
2127 + * asm-sh/kerntypes.h
2128 + *
2129 + * Arch-dependent header file that includes headers for all arch-specific 
2130 + * types of interest.
2131 + * The kernel type information is used by the lcrash utility when
2132 + * analyzing system crash dumps or the live system. Using the type
2133 + * information for the running system, rather than kernel header files,
2134 + * makes for a more flexible and robust analysis tool.
2135 + *
2136 + * This source code is released under the GNU GPL.
2137 + */
2138 +
2139 +/* Super-H-specific header files */
2140 +#ifndef _SH_KERNTYPES_H
2141 +#define _SH_KERNTYPES_H
2142 +
2143 +/* Use the default */
2144 +#include <asm-generic/kerntypes.h>
2145 +
2146 +#endif /* _SH_KERNTYPES_H */
2147 Index: linux-2.6.10/include/asm-ia64/nmi.h
2148 ===================================================================
2149 --- linux-2.6.10.orig/include/asm-ia64/nmi.h    2005-04-05 19:01:49.158500672 +0800
2150 +++ linux-2.6.10/include/asm-ia64/nmi.h 2005-04-05 16:47:53.883214224 +0800
2151 @@ -0,0 +1,28 @@
2152 +/*
2153 + *  linux/include/asm-ia64/nmi.h
2154 + */
2155 +#ifndef ASM_NMI_H
2156 +#define ASM_NMI_H
2157 +
2158 +#include <linux/pm.h>
2159 +
2160 +struct pt_regs;
2161
2162 +typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
2163
2164 +/** 
2165 + * set_nmi_callback
2166 + *
2167 + * Set a handler for an NMI. Only one handler may be
2168 + * set. Return 1 if the NMI was handled.
2169 + */
2170 +void set_nmi_callback(nmi_callback_t callback);
2171
2172 +/** 
2173 + * unset_nmi_callback
2174 + *
2175 + * Remove the handler previously set.
2176 + */
2177 +void unset_nmi_callback(void);
2178
2179 +#endif /* ASM_NMI_H */
2180 Index: linux-2.6.10/include/asm-ia64/dump.h
2181 ===================================================================
2182 --- linux-2.6.10.orig/include/asm-ia64/dump.h   2005-04-05 19:01:49.158500672 +0800
2183 +++ linux-2.6.10/include/asm-ia64/dump.h        2005-04-05 16:47:53.884214072 +0800
2184 @@ -0,0 +1,201 @@
2185 +/*
2186 + * Kernel header file for Linux crash dumps.
2187 + *
2188 + * Created by: Matt Robinson (yakker@sgi.com)
2189 + *
2190 + * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
2191 + *
2192 + * This code is released under version 2 of the GNU GPL.
2193 + */
2194 +
2195 +/* This header file holds the architecture specific crash dump header */
2196 +#ifndef _ASM_DUMP_H
2197 +#define _ASM_DUMP_H
2198 +
2199 +/* definitions */
2200 +#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
2201 +#define DUMP_ASM_VERSION_NUMBER   0x4            /* version number          */
2202 +
2203 +#ifdef __KERNEL__
2204 +#include <linux/efi.h>
2205 +#include <asm/pal.h>
2206 +#include <asm/ptrace.h>
2207 +
2208 +#ifdef CONFIG_SMP
2209 +extern cpumask_t irq_affinity[];
2210 +extern int (*dump_ipi_function_ptr)(struct pt_regs *);
2211 +extern void dump_send_ipi(void);
2212 +#else /* !CONFIG_SMP */
2213 +#define dump_send_ipi() do { } while(0)
2214 +#endif
2215 +
2216 +#else  /* !__KERNEL__ */
2217 +/* necessary header files */
2218 +#include <asm/ptrace.h>                          /* for pt_regs             */
2219 +#include <linux/threads.h>
2220 +#endif /* __KERNEL__ */
2221 +
2222 +/* 
2223 + * mkswap.c calls getpagesize() to get the system page size,
2224 + * which is not  necessarily the same as the hardware page size.
2225 + *
2226 + * For ia64 the kernel PAGE_SIZE can be configured from 4KB ... 16KB.
2227 + *
2228 + * The physical memory is layed out out in the hardware/minimal pages.
2229 + * This is the size we need to use for dumping physical pages.
2230 + *
2231 + * Note ths hardware/minimal page size being use in;
2232 + *      arch/ia64/kernel/efi.c`efi_memmap_walk():
2233 + *         curr.end   = curr.start + (md->num_pages << 12);
2234 + *
2235 + * Since the system page size could change between the kernel we boot
2236 + * on the the kernel that cause the core dume we may want to have something
2237 + * more constant like the maximum system page size (See include/asm-ia64/page.h).
2238 + */
2239 +/* IA64 manages the stack in differnt manner as compared to other architectures.
2240 + * task_struct lies at the bottom of stack.
2241 + */
2242 +#undef STACK_START_POSITION
2243 +#define STACK_START_POSITION(tsk)              (tsk)
2244 +#define DUMP_MIN_PAGE_SHIFT                    12
2245 +#define DUMP_MIN_PAGE_SIZE                     (1UL << DUMP_MIN_PAGE_SHIFT)
2246 +#define DUMP_MIN_PAGE_MASK                     (~(DUMP_MIN_PAGE_SIZE - 1))
2247 +#define DUMP_MIN_PAGE_ALIGN(addr)              (((addr) + DUMP_MIN_PAGE_SIZE - 1) & DUMP_MIN_PAGE_MASK)
2248 +
2249 +#define DUMP_MAX_PAGE_SHIFT                    16
2250 +#define DUMP_MAX_PAGE_SIZE                     (1UL << DUMP_MAX_PAGE_SHIFT)
2251 +#define DUMP_MAX_PAGE_MASK                     (~(DUMP_MAX_PAGE_SIZE - 1))
2252 +#define DUMP_MAX_PAGE_ALIGN(addr)              (((addr) + DUMP_MAX_PAGE_SIZE - 1) & DUMP_MAX_PAGE_MASK)
2253 +
2254 +#define DUMP_EF_PAGE_SHIFT                     DUMP_MIN_PAGE_SHIFT
2255 +
2256 +extern int _end,_start;
2257 +
2258 +/*
2259 + * Structure: dump_header_asm_t
2260 + *  Function: This is the header for architecture-specific stuff.  It
2261 + *            follows right after the dump header.
2262 + */
2263 +/*typedef struct _dump_header_asm {*/
2264 +
2265 +typedef struct __dump_header_asm {
2266 +
2267 +        /* the dump magic number -- unique to verify dump is valid */
2268 +        uint64_t             dha_magic_number;
2269 +
2270 +        /* the version number of this dump */
2271 +        uint32_t             dha_version;
2272 +
2273 +        /* the size of this header (in case we can't read it) */
2274 +        uint32_t             dha_header_size;
2275 +
2276 +        /* pointer to pt_regs, (OLD: (struct pt_regs *, NEW: (uint64_t)) */
2277 +       uint64_t             dha_pt_regs;
2278 +
2279 +       /* the dump registers */
2280 +       struct pt_regs       dha_regs;
2281 +
2282 +        /* the rnat register saved after flushrs */
2283 +        uint64_t             dha_rnat;
2284 +
2285 +       /* the pfs register saved after flushrs */
2286 +       uint64_t             dha_pfs;
2287 +
2288 +       /* the bspstore register saved after flushrs */
2289 +       uint64_t             dha_bspstore;
2290 +
2291 +       /* smp specific */
2292 +       uint32_t             dha_smp_num_cpus;
2293 +       uint32_t             dha_dumping_cpu;   
2294 +       struct pt_regs       dha_smp_regs[NR_CPUS];
2295 +       uint64_t             dha_smp_current_task[NR_CPUS];
2296 +       uint64_t             dha_stack[NR_CPUS];
2297 +       uint64_t             dha_stack_ptr[NR_CPUS];
2298 +
2299 +} __attribute__((packed)) dump_header_asm_t;
2300 +
2301 +
2302 +extern struct __dump_header_asm dump_header_asm;
2303 +
2304 +#ifdef __KERNEL__
2305 +static inline void get_current_regs(struct pt_regs *regs)
2306 +{
2307 +       /* 
2308 +        * REMIND: Looking at functions/Macros like:
2309 +        *               DO_SAVE_SWITCH_STACK
2310 +        *               ia64_switch_to()
2311 +        *               ia64_save_extra()
2312 +        *               switch_to()
2313 +        *         to implement this new feature that Matt seem to have added
2314 +        *         to panic.c; seems all platforms are now expected to provide
2315 +        *         this function to dump the current registers into the pt_regs
2316 +        *         structure.
2317 +        */
2318 +       volatile unsigned long rsc_value;/*for storing the rsc value*/
2319 +       volatile unsigned long ic_value;
2320 +
2321 +       __asm__ __volatile__("mov %0=b6;;":"=r"(regs->b6));
2322 +       __asm__ __volatile__("mov %0=b7;;":"=r"(regs->b7));
2323 +       
2324 +        __asm__ __volatile__("mov %0=ar.csd;;":"=r"(regs->ar_csd));
2325 +       __asm__ __volatile__("mov %0=ar.ssd;;":"=r"(regs->ar_ssd));
2326 +       __asm__ __volatile__("mov %0=psr;;":"=r"(ic_value));
2327 +       if(ic_value & 0x1000)/*Within an interrupt*/
2328 +       {
2329 +               __asm__ __volatile__("mov %0=cr.ipsr;;":"=r"(regs->cr_ipsr));
2330 +               __asm__ __volatile__("mov %0=cr.iip;;":"=r"(regs->cr_iip));
2331 +               __asm__ __volatile__("mov %0=cr.ifs;;":"=r"(regs->cr_ifs));
2332 +       }
2333 +       else
2334 +       {
2335 +               regs->cr_ipsr=regs->cr_iip=regs->cr_ifs=(unsigned long)-1;
2336 +       }
2337 +       __asm__ __volatile__("mov %0=ar.unat;;":"=r"(regs->ar_unat));
2338 +       __asm__ __volatile__("mov %0=ar.pfs;;":"=r"(regs->ar_pfs));
2339 +       __asm__ __volatile__("mov %0=ar.rsc;;":"=r"(rsc_value));
2340 +       regs->ar_rsc = rsc_value;
2341 +       /*loadrs is from 16th bit to 29th bit of rsc*/
2342 +       regs->loadrs =  rsc_value >> 16 & (unsigned long)0x3fff;
2343 +       /*setting the rsc.mode value to 0 (rsc.mode is the last two bits of rsc)*/
2344 +       __asm__ __volatile__("mov ar.rsc=%0;;"::"r"(rsc_value & (unsigned long)(~3)));
2345 +       __asm__ __volatile__("mov %0=ar.rnat;;":"=r"(regs->ar_rnat));
2346 +       __asm__ __volatile__("mov %0=ar.bspstore;;":"=r"(regs->ar_bspstore));
2347 +       /*copying the original value back*/
2348 +       __asm__ __volatile__("mov ar.rsc=%0;;"::"r"(rsc_value));
2349 +       __asm__ __volatile__("mov %0=pr;;":"=r"(regs->pr));
2350 +       __asm__ __volatile__("mov %0=ar.fpsr;;":"=r"(regs->ar_fpsr));
2351 +       __asm__ __volatile__("mov %0=ar.ccv;;":"=r"(regs->ar_ccv));
2352 +
2353 +       __asm__ __volatile__("mov %0=r2;;":"=r"(regs->r2));
2354 +        __asm__ __volatile__("mov %0=r3;;":"=r"(regs->r3));
2355 +        __asm__ __volatile__("mov %0=r8;;":"=r"(regs->r8));
2356 +        __asm__ __volatile__("mov %0=r9;;":"=r"(regs->r9));
2357 +        __asm__ __volatile__("mov %0=r10;;":"=r"(regs->r10));
2358 +       __asm__ __volatile__("mov %0=r11;;":"=r"(regs->r11));
2359 +        __asm__ __volatile__("mov %0=r12;;":"=r"(regs->r12));
2360 +       __asm__ __volatile__("mov %0=r13;;":"=r"(regs->r13));
2361 +       __asm__ __volatile__("mov %0=r14;;":"=r"(regs->r14));
2362 +       __asm__ __volatile__("mov %0=r15;;":"=r"(regs->r15));
2363 +       __asm__ __volatile__("mov %0=r16;;":"=r"(regs->r16));
2364 +       __asm__ __volatile__("mov %0=r17;;":"=r"(regs->r17));
2365 +       __asm__ __volatile__("mov %0=r18;;":"=r"(regs->r18));
2366 +       __asm__ __volatile__("mov %0=r19;;":"=r"(regs->r19));
2367 +       __asm__ __volatile__("mov %0=r20;;":"=r"(regs->r20));
2368 +       __asm__ __volatile__("mov %0=r21;;":"=r"(regs->r21));
2369 +       __asm__ __volatile__("mov %0=r22;;":"=r"(regs->r22));
2370 +       __asm__ __volatile__("mov %0=r23;;":"=r"(regs->r23));
2371 +       __asm__ __volatile__("mov %0=r24;;":"=r"(regs->r24));
2372 +       __asm__ __volatile__("mov %0=r25;;":"=r"(regs->r25));
2373 +       __asm__ __volatile__("mov %0=r26;;":"=r"(regs->r26));
2374 +       __asm__ __volatile__("mov %0=r27;;":"=r"(regs->r27));
2375 +       __asm__ __volatile__("mov %0=r28;;":"=r"(regs->r28));
2376 +       __asm__ __volatile__("mov %0=r29;;":"=r"(regs->r29));
2377 +       __asm__ __volatile__("mov %0=r30;;":"=r"(regs->r30));
2378 +       __asm__ __volatile__("mov %0=r31;;":"=r"(regs->r31));
2379 +}
2380 +
2381 +/* Perhaps added to Common Arch Specific Functions and moved to dump.h some day */
2382 +extern void * __dump_memcpy(void *, const void *, size_t);
2383 +#endif /* __KERNEL__ */
2384 +
2385 +#endif /* _ASM_DUMP_H */
2386 Index: linux-2.6.10/include/asm-ia64/kerntypes.h
2387 ===================================================================
2388 --- linux-2.6.10.orig/include/asm-ia64/kerntypes.h      2005-04-05 19:01:49.158500672 +0800
2389 +++ linux-2.6.10/include/asm-ia64/kerntypes.h   2005-04-05 16:47:53.884214072 +0800
2390 @@ -0,0 +1,21 @@
2391 +/*
2392 + * asm-ia64/kerntypes.h
2393 + *
2394 + * Arch-dependent header file that includes headers for all arch-specific 
2395 + * types of interest.
2396 + * The kernel type information is used by the lcrash utility when
2397 + * analyzing system crash dumps or the live system. Using the type
2398 + * information for the running system, rather than kernel header files,
2399 + * makes for a more flexible and robust analysis tool.
2400 + *
2401 + * This source code is released under the GNU GPL.
2402 + */
2403 +
2404 +/* IA64-specific header files */
2405 +#ifndef _IA64_KERNTYPES_H
2406 +#define _IA64_KERNTYPES_H
2407 +
2408 +/* Use the default */
2409 +#include <asm-generic/kerntypes.h>
2410 +
2411 +#endif /* _IA64_KERNTYPES_H */
2412 Index: linux-2.6.10/include/asm-ppc64/dump.h
2413 ===================================================================
2414 --- linux-2.6.10.orig/include/asm-ppc64/dump.h  2005-04-05 19:01:49.158500672 +0800
2415 +++ linux-2.6.10/include/asm-ppc64/dump.h       2005-04-05 16:47:53.878214984 +0800
2416 @@ -0,0 +1,115 @@
2417 +/*
2418 + * Kernel header file for Linux crash dumps.
2419 + *
2420 + * Created by: Todd Inglett <tinglett@vnet.ibm.com>
2421 + *
2422 + * Copyright 2002 - 2004 International Business Machines
2423 + *
2424 + * This code is released under version 2 of the GNU GPL.
2425 + */
2426 +
2427 +/* This header file holds the architecture specific crash dump header */
2428 +#ifndef _ASM_DUMP_H
2429 +#define _ASM_DUMP_H
2430 +
2431 +/* necessary header files */
2432 +#include <asm/ptrace.h>                          /* for pt_regs             */
2433 +#include <asm/kmap_types.h>
2434 +#include <linux/threads.h>
2435 +
2436 +/* definitions */
2437 +#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
2438 +#define DUMP_ASM_VERSION_NUMBER   0x5            /* version number          */
2439 +
2440 +/*
2441 + * Structure: __dump_header_asm
2442 + *  Function: This is the header for architecture-specific stuff.  It
2443 + *            follows right after the dump header.
2444 + */
2445 +struct __dump_header_asm {
2446 +
2447 +        /* the dump magic number -- unique to verify dump is valid */
2448 +        uint64_t             dha_magic_number;
2449 +
2450 +        /* the version number of this dump */
2451 +        uint32_t             dha_version;
2452 +
2453 +        /* the size of this header (in case we can't read it) */
2454 +        uint32_t             dha_header_size;
2455 +
2456 +       /* the dump registers */
2457 +       struct pt_regs       dha_regs;
2458 +
2459 +       /* smp specific */
2460 +       uint32_t             dha_smp_num_cpus;
2461 +       int                  dha_dumping_cpu;   
2462 +       struct pt_regs       dha_smp_regs[NR_CPUS];
2463 +       uint64_t             dha_smp_current_task[NR_CPUS];
2464 +       uint64_t             dha_stack[NR_CPUS];
2465 +       uint64_t             dha_stack_ptr[NR_CPUS];
2466 +} __attribute__((packed));
2467 +
2468 +#ifdef __KERNEL__
2469 +static inline void get_current_regs(struct pt_regs *regs)
2470 +{
2471 +       unsigned long tmp1, tmp2;
2472 +
2473 +       __asm__ __volatile__ (
2474 +               "std    0,0(%2)\n"
2475 +               "std    1,8(%2)\n"
2476 +               "std    2,16(%2)\n"
2477 +               "std    3,24(%2)\n"
2478 +               "std    4,32(%2)\n"
2479 +               "std    5,40(%2)\n"
2480 +               "std    6,48(%2)\n"
2481 +               "std    7,56(%2)\n"
2482 +               "std    8,64(%2)\n"
2483 +               "std    9,72(%2)\n"
2484 +               "std    10,80(%2)\n"
2485 +               "std    11,88(%2)\n"
2486 +               "std    12,96(%2)\n"
2487 +               "std    13,104(%2)\n"
2488 +               "std    14,112(%2)\n"
2489 +               "std    15,120(%2)\n"
2490 +               "std    16,128(%2)\n"
2491 +               "std    17,136(%2)\n"
2492 +               "std    18,144(%2)\n"
2493 +               "std    19,152(%2)\n"
2494 +               "std    20,160(%2)\n"
2495 +               "std    21,168(%2)\n"
2496 +               "std    22,176(%2)\n"
2497 +               "std    23,184(%2)\n"
2498 +               "std    24,192(%2)\n"
2499 +               "std    25,200(%2)\n"
2500 +               "std    26,208(%2)\n"
2501 +               "std    27,216(%2)\n"
2502 +               "std    28,224(%2)\n"
2503 +               "std    29,232(%2)\n"
2504 +               "std    30,240(%2)\n"
2505 +               "std    31,248(%2)\n"
2506 +               "mfmsr  %0\n"
2507 +               "std    %0, 264(%2)\n"
2508 +               "mfctr  %0\n"
2509 +               "std    %0, 280(%2)\n"
2510 +               "mflr   %0\n"
2511 +               "std    %0, 288(%2)\n"
2512 +               "bl     1f\n"
2513 +       "1:      mflr   %1\n"
2514 +               "std    %1, 256(%2)\n"
2515 +               "mtlr   %0\n"
2516 +               "mfxer  %0\n"
2517 +               "std    %0, 296(%2)\n"
2518 +               : "=&r" (tmp1), "=&r" (tmp2)
2519 +               : "b" (regs));
2520 +}
2521 +
2522 +extern struct __dump_header_asm dump_header_asm;
2523 +
2524 +#ifdef CONFIG_SMP
2525 +extern void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *));
2526 +#else
2527 +#define dump_send_ipi() do { } while(0)
2528 +#endif
2529 +#endif /* __KERNEL__ */
2530 +
2531 +#endif /* _ASM_DUMP_H */
2532 Index: linux-2.6.10/include/asm-ppc64/kerntypes.h
2533 ===================================================================
2534 --- linux-2.6.10.orig/include/asm-ppc64/kerntypes.h     2005-04-05 19:01:49.158500672 +0800
2535 +++ linux-2.6.10/include/asm-ppc64/kerntypes.h  2005-04-05 16:47:53.879214832 +0800
2536 @@ -0,0 +1,21 @@
2537 +/*
2538 + * asm-ppc64/kerntypes.h
2539 + *
2540 + * Arch-dependent header file that includes headers for all arch-specific 
2541 + * types of interest.
2542 + * The kernel type information is used by the lcrash utility when
2543 + * analyzing system crash dumps or the live system. Using the type
2544 + * information for the running system, rather than kernel header files,
2545 + * makes for a more flexible and robust analysis tool.
2546 + *
2547 + * This source code is released under the GNU GPL.
2548 + */
2549 +
2550 +/* PPC64-specific header files */
2551 +#ifndef _PPC64_KERNTYPES_H
2552 +#define _PPC64_KERNTYPES_H
2553 +
2554 +/* Use the default */
2555 +#include <asm-generic/kerntypes.h>
2556 +
2557 +#endif /* _PPC64_KERNTYPES_H */
2558 Index: linux-2.6.10/include/asm-ppc64/kmap_types.h
2559 ===================================================================
2560 --- linux-2.6.10.orig/include/asm-ppc64/kmap_types.h    2004-12-25 05:34:45.000000000 +0800
2561 +++ linux-2.6.10/include/asm-ppc64/kmap_types.h 2005-04-05 16:47:53.878214984 +0800
2562 @@ -16,7 +16,8 @@
2563         KM_IRQ1,
2564         KM_SOFTIRQ0,
2565         KM_SOFTIRQ1,    
2566 -       KM_TYPE_NR
2567 +       KM_TYPE_NR,
2568 +       KM_DUMP
2569  };
2570  
2571  #endif
2572 Index: linux-2.6.10/include/asm-ppc64/smp.h
2573 ===================================================================
2574 --- linux-2.6.10.orig/include/asm-ppc64/smp.h   2004-12-25 05:33:47.000000000 +0800
2575 +++ linux-2.6.10/include/asm-ppc64/smp.h        2005-04-05 16:47:53.877215136 +0800
2576 @@ -36,7 +36,7 @@
2577  extern void smp_send_debugger_break(int cpu);
2578  struct pt_regs;
2579  extern void smp_message_recv(int, struct pt_regs *);
2580 -
2581 +extern void dump_send_ipi(int (*dump_ipi_callback)(struct pt_regs *));
2582  
2583  #define smp_processor_id() (get_paca()->paca_index)
2584  #define hard_smp_processor_id() (get_paca()->hw_cpu_id)
2585 Index: linux-2.6.10/include/asm-cris/kerntypes.h
2586 ===================================================================
2587 --- linux-2.6.10.orig/include/asm-cris/kerntypes.h      2005-04-05 19:01:49.158500672 +0800
2588 +++ linux-2.6.10/include/asm-cris/kerntypes.h   2005-04-05 16:47:53.874215592 +0800
2589 @@ -0,0 +1,21 @@
2590 +/*
2591 + * asm-cris/kerntypes.h
2592 + *
2593 + * Arch-dependent header file that includes headers for all arch-specific 
2594 + * types of interest.
2595 + * The kernel type information is used by the lcrash utility when
2596 + * analyzing system crash dumps or the live system. Using the type
2597 + * information for the running system, rather than kernel header files,
2598 + * makes for a more flexible and robust analysis tool.
2599 + *
2600 + * This source code is released under the GNU GPL.
2601 + */
2602 +
2603 +/* CRIS-specific header files */
2604 +#ifndef _CRIS_KERNTYPES_H
2605 +#define _CRIS_KERNTYPES_H
2606 +
2607 +/* Use the default */
2608 +#include <asm-generic/kerntypes.h>
2609 +
2610 +#endif /* _CRIS_KERNTYPES_H */
2611 Index: linux-2.6.10/include/asm-m68knommu/kerntypes.h
2612 ===================================================================
2613 --- linux-2.6.10.orig/include/asm-m68knommu/kerntypes.h 2005-04-05 19:01:49.158500672 +0800
2614 +++ linux-2.6.10/include/asm-m68knommu/kerntypes.h      2005-04-05 16:47:53.870216200 +0800
2615 @@ -0,0 +1,21 @@
2616 +/*
2617 + * asm-m68knommu/kerntypes.h
2618 + *
2619 + * Arch-dependent header file that includes headers for all arch-specific 
2620 + * types of interest.
2621 + * The kernel type information is used by the lcrash utility when
2622 + * analyzing system crash dumps or the live system. Using the type
2623 + * information for the running system, rather than kernel header files,
2624 + * makes for a more flexible and robust analysis tool.
2625 + *
2626 + * This source code is released under the GNU GPL.
2627 + */
2628 +
2629 +/* m68k/no-MMU-specific header files */
2630 +#ifndef _M68KNOMMU_KERNTYPES_H
2631 +#define _M68KNOMMU_KERNTYPES_H
2632 +
2633 +/* Use the default */
2634 +#include <asm-generic/kerntypes.h>
2635 +
2636 +#endif /* _M68KNOMMU_KERNTYPES_H */
2637 Index: linux-2.6.10/include/asm-v850/kerntypes.h
2638 ===================================================================
2639 --- linux-2.6.10.orig/include/asm-v850/kerntypes.h      2005-04-05 19:01:49.158500672 +0800
2640 +++ linux-2.6.10/include/asm-v850/kerntypes.h   2005-04-05 16:47:53.888213464 +0800
2641 @@ -0,0 +1,21 @@
2642 +/*
2643 + * asm-v850/kerntypes.h
2644 + *
2645 + * Arch-dependent header file that includes headers for all arch-specific 
2646 + * types of interest.
2647 + * The kernel type information is used by the lcrash utility when
2648 + * analyzing system crash dumps or the live system. Using the type
2649 + * information for the running system, rather than kernel header files,
2650 + * makes for a more flexible and robust analysis tool.
2651 + *
2652 + * This source code is released under the GNU GPL.
2653 + */
2654 +
2655 +/* V850-specific header files */
2656 +#ifndef _V850_KERNTYPES_H
2657 +#define _V850_KERNTYPES_H
2658 +
2659 +/* Use the default */
2660 +#include <asm-generic/kerntypes.h>
2661 +
2662 +#endif /* _V850_KERNTYPES_H */
2663 Index: linux-2.6.10/include/asm-x86_64/dump.h
2664 ===================================================================
2665 --- linux-2.6.10.orig/include/asm-x86_64/dump.h 2005-04-05 19:01:49.158500672 +0800
2666 +++ linux-2.6.10/include/asm-x86_64/dump.h      2005-04-05 16:47:53.868216504 +0800
2667 @@ -0,0 +1,93 @@
2668 +/*
2669 + * Kernel header file for Linux crash dumps.
2670 + *
2671 + * Created by: Matt Robinson (yakker@sgi.com)
2672 + *
2673 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
2674 + * x86_64 lkcd port Sachin Sant ( sachinp@in.ibm.com)
2675 + * This code is released under version 2 of the GNU GPL.
2676 + */
2677 +
2678 +/* This header file holds the architecture specific crash dump header */
2679 +#ifndef _ASM_DUMP_H
2680 +#define _ASM_DUMP_H
2681 +
2682 +/* necessary header files */
2683 +#include <asm/ptrace.h>                          /* for pt_regs             */
2684 +#include <linux/threads.h>
2685 +
2686 +/* definitions */
2687 +#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
2688 +#define DUMP_ASM_VERSION_NUMBER   0x2            /* version number          */
2689 +
2690 +
2691 +/*
2692 + * Structure: dump_header_asm_t
2693 + *  Function: This is the header for architecture-specific stuff.  It
2694 + *            follows right after the dump header.
2695 + */
2696 +struct __dump_header_asm {
2697 +
2698 +        /* the dump magic number -- unique to verify dump is valid */
2699 +        uint64_t             dha_magic_number;
2700 +
2701 +        /* the version number of this dump */
2702 +        uint32_t             dha_version;
2703 +
2704 +        /* the size of this header (in case we can't read it) */
2705 +        uint32_t             dha_header_size;
2706 +
2707 +       /* the dump registers */
2708 +       struct pt_regs       dha_regs;
2709 +
2710 +       /* smp specific */
2711 +       uint32_t             dha_smp_num_cpus;
2712 +       int                  dha_dumping_cpu;   
2713 +       struct pt_regs       dha_smp_regs[NR_CPUS];
2714 +       uint64_t             dha_smp_current_task[NR_CPUS];
2715 +       uint64_t             dha_stack[NR_CPUS];
2716 +       uint64_t             dha_stack_ptr[NR_CPUS];
2717 +} __attribute__((packed));
2718 +
2719 +#ifdef __KERNEL__
2720 +static inline void get_current_regs(struct pt_regs *regs)
2721 +{
2722 +       unsigned seg;
2723 +       __asm__ __volatile__("movq %%r15,%0" : "=m"(regs->r15));
2724 +       __asm__ __volatile__("movq %%r14,%0" : "=m"(regs->r14));
2725 +       __asm__ __volatile__("movq %%r13,%0" : "=m"(regs->r13));
2726 +       __asm__ __volatile__("movq %%r12,%0" : "=m"(regs->r12));
2727 +       __asm__ __volatile__("movq %%r11,%0" : "=m"(regs->r11));
2728 +       __asm__ __volatile__("movq %%r10,%0" : "=m"(regs->r10));
2729 +       __asm__ __volatile__("movq %%r9,%0" : "=m"(regs->r9));
2730 +       __asm__ __volatile__("movq %%r8,%0" : "=m"(regs->r8));
2731 +       __asm__ __volatile__("movq %%rbx,%0" : "=m"(regs->rbx));
2732 +       __asm__ __volatile__("movq %%rcx,%0" : "=m"(regs->rcx));
2733 +       __asm__ __volatile__("movq %%rdx,%0" : "=m"(regs->rdx));
2734 +       __asm__ __volatile__("movq %%rsi,%0" : "=m"(regs->rsi));
2735 +       __asm__ __volatile__("movq %%rdi,%0" : "=m"(regs->rdi));
2736 +       __asm__ __volatile__("movq %%rbp,%0" : "=m"(regs->rbp));
2737 +       __asm__ __volatile__("movq %%rax,%0" : "=m"(regs->rax));
2738 +       __asm__ __volatile__("movq %%rsp,%0" : "=m"(regs->rsp));
2739 +       __asm__ __volatile__("movl %%ss, %0" :"=r"(seg)); 
2740 +       regs->ss = (unsigned long)seg;
2741 +       __asm__ __volatile__("movl %%cs, %0" :"=r"(seg));
2742 +       regs->cs = (unsigned long)seg;
2743 +       __asm__ __volatile__("pushfq; popq %0" :"=m"(regs->eflags));
2744 +       regs->rip = (unsigned long)current_text_addr();
2745 +       
2746 +}
2747 +
2748 +extern volatile int dump_in_progress;
2749 +extern struct __dump_header_asm dump_header_asm;
2750 +
2751 +#ifdef CONFIG_SMP
2752 +
2753 +
2754 +extern void dump_send_ipi(void);
2755 +#else
2756 +#define dump_send_ipi() do { } while(0)
2757 +#endif
2758 +#endif /* __KERNEL__ */
2759 +
2760 +#endif /* _ASM_DUMP_H */
2761 Index: linux-2.6.10/include/asm-x86_64/kerntypes.h
2762 ===================================================================
2763 --- linux-2.6.10.orig/include/asm-x86_64/kerntypes.h    2005-04-05 19:01:49.158500672 +0800
2764 +++ linux-2.6.10/include/asm-x86_64/kerntypes.h 2005-04-05 16:47:53.869216352 +0800
2765 @@ -0,0 +1,21 @@
2766 +/*
2767 + * asm-x86_64/kerntypes.h
2768 + *
2769 + * Arch-dependent header file that includes headers for all arch-specific 
2770 + * types of interest.
2771 + * The kernel type information is used by the lcrash utility when
2772 + * analyzing system crash dumps or the live system. Using the type
2773 + * information for the running system, rather than kernel header files,
2774 + * makes for a more flexible and robust analysis tool.
2775 + *
2776 + * This source code is released under the GNU GPL.
2777 + */
2778 +
2779 +/* x86_64-specific header files */
2780 +#ifndef _X86_64_KERNTYPES_H
2781 +#define _X86_64_KERNTYPES_H
2782 +
2783 +/* Use the default */
2784 +#include <asm-generic/kerntypes.h>
2785 +
2786 +#endif /* _X86_64_KERNTYPES_H */
2787 Index: linux-2.6.10/include/asm-x86_64/hw_irq.h
2788 ===================================================================
2789 --- linux-2.6.10.orig/include/asm-x86_64/hw_irq.h       2004-12-25 05:35:39.000000000 +0800
2790 +++ linux-2.6.10/include/asm-x86_64/hw_irq.h    2005-04-05 16:47:53.869216352 +0800
2791 @@ -34,7 +34,6 @@
2792  
2793  #define IA32_SYSCALL_VECTOR    0x80
2794  
2795 -
2796  /*
2797   * Vectors 0x20-0x2f are used for ISA interrupts.
2798   */
2799 @@ -55,6 +54,7 @@
2800  #define TASK_MIGRATION_VECTOR  0xfb
2801  #define CALL_FUNCTION_VECTOR   0xfa
2802  #define KDB_VECTOR     0xf9
2803 +#define DUMP_VECTOR    0xf8
2804  
2805  #define THERMAL_APIC_VECTOR    0xf0
2806  
2807 Index: linux-2.6.10/include/asm-x86_64/kmap_types.h
2808 ===================================================================
2809 --- linux-2.6.10.orig/include/asm-x86_64/kmap_types.h   2004-12-25 05:35:23.000000000 +0800
2810 +++ linux-2.6.10/include/asm-x86_64/kmap_types.h        2005-04-05 16:47:53.868216504 +0800
2811 @@ -13,7 +13,8 @@
2812         KM_IRQ1,
2813         KM_SOFTIRQ0,
2814         KM_SOFTIRQ1,
2815 -       KM_TYPE_NR
2816 +       KM_DUMP,
2817 +       KM_TYPE_NR,
2818  };
2819  
2820  #endif
2821 Index: linux-2.6.10/include/asm-x86_64/smp.h
2822 ===================================================================
2823 --- linux-2.6.10.orig/include/asm-x86_64/smp.h  2004-12-25 05:33:48.000000000 +0800
2824 +++ linux-2.6.10/include/asm-x86_64/smp.h       2005-04-05 16:47:53.867216656 +0800
2825 @@ -41,6 +41,7 @@
2826  extern int pic_mode;
2827  extern int smp_num_siblings;
2828  extern void smp_flush_tlb(void);
2829 +extern void dump_send_ipi(void);
2830  extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
2831  extern void smp_send_reschedule(int cpu);
2832  extern void smp_invalidate_rcv(void);          /* Process an NMI */
2833 Index: linux-2.6.10/include/asm-s390/dump.h
2834 ===================================================================
2835 --- linux-2.6.10.orig/include/asm-s390/dump.h   2005-04-05 19:01:49.158500672 +0800
2836 +++ linux-2.6.10/include/asm-s390/dump.h        2005-04-05 16:47:53.865216960 +0800
2837 @@ -0,0 +1,10 @@
2838 +/*
2839 + * Kernel header file for Linux crash dumps.
2840 + */
2841 +
2842 +/* Nothing to be done here, we have proper hardware support */
2843 +#ifndef _ASM_DUMP_H
2844 +#define _ASM_DUMP_H
2845 +
2846 +#endif
2847 +
2848 Index: linux-2.6.10/include/asm-s390/kerntypes.h
2849 ===================================================================
2850 --- linux-2.6.10.orig/include/asm-s390/kerntypes.h      2005-04-05 19:01:49.158500672 +0800
2851 +++ linux-2.6.10/include/asm-s390/kerntypes.h   2005-04-05 16:47:53.866216808 +0800
2852 @@ -0,0 +1,46 @@
2853 +/*
2854 + * asm-s390/kerntypes.h
2855 + *
2856 + * Arch-dependent header file that includes headers for all arch-specific 
2857 + * types of interest.
2858 + * The kernel type information is used by the lcrash utility when
2859 + * analyzing system crash dumps or the live system. Using the type
2860 + * information for the running system, rather than kernel header files,
2861 + * makes for a more flexible and robust analysis tool.
2862 + *
2863 + * This source code is released under the GNU GPL.
2864 + */
2865 +
2866 +/* S/390 specific header files */
2867 +#ifndef _S390_KERNTYPES_H
2868 +#define _S390_KERNTYPES_H
2869 +
2870 +#include <asm/lowcore.h>
2871 +#include <asm/debug.h>
2872 +#include <asm/ccwdev.h>
2873 +#include <asm/ccwgroup.h>
2874 +#include <asm/qdio.h>
2875 +
2876 +/* channel subsystem driver */
2877 +#include "../../drivers/s390/cio/cio.h"
2878 +#include "../../drivers/s390/cio/chsc.h"
2879 +#include "../../drivers/s390/cio/css.h"
2880 +#include "../../drivers/s390/cio/device.h"
2881 +#include "../../drivers/s390/cio/qdio.h"
2882 +
2883 +/* dasd device driver */
2884 +#include "../../drivers/s390/block/dasd_int.h"
2885 +#include "../../drivers/s390/block/dasd_diag.h"
2886 +#include "../../drivers/s390/block/dasd_eckd.h"
2887 +#include "../../drivers/s390/block/dasd_fba.h"
2888 +
2889 +/* networking drivers */
2890 +#include "../../drivers/s390/net/fsm.h"
2891 +#include "../../drivers/s390/net/iucv.h"
2892 +#include "../../drivers/s390/net/lcs.h"
2893 +
2894 +/* zfcp device driver */
2895 +#include "../../drivers/s390/scsi/zfcp_def.h"
2896 +#include "../../drivers/s390/scsi/zfcp_fsf.h"
2897 +
2898 +#endif /* _S390_KERNTYPES_H */
2899 Index: linux-2.6.10/include/asm-sparc64/kerntypes.h
2900 ===================================================================
2901 --- linux-2.6.10.orig/include/asm-sparc64/kerntypes.h   2005-04-05 19:01:49.158500672 +0800
2902 +++ linux-2.6.10/include/asm-sparc64/kerntypes.h        2005-04-05 16:47:53.872215896 +0800
2903 @@ -0,0 +1,21 @@
2904 +/*
2905 + * asm-sparc64/kerntypes.h
2906 + *
2907 + * Arch-dependent header file that includes headers for all arch-specific 
2908 + * types of interest.
2909 + * The kernel type information is used by the lcrash utility when
2910 + * analyzing system crash dumps or the live system. Using the type
2911 + * information for the running system, rather than kernel header files,
2912 + * makes for a more flexible and robust analysis tool.
2913 + *
2914 + * This source code is released under the GNU GPL.
2915 + */
2916 +
2917 +/* SPARC64-specific header files */
2918 +#ifndef _SPARC64_KERNTYPES_H
2919 +#define _SPARC64_KERNTYPES_H
2920 +
2921 +/* Use the default */
2922 +#include <asm-generic/kerntypes.h>
2923 +
2924 +#endif /* _SPARC64_KERNTYPES_H */
2925 Index: linux-2.6.10/include/asm-mips/kerntypes.h
2926 ===================================================================
2927 --- linux-2.6.10.orig/include/asm-mips/kerntypes.h      2005-04-05 19:01:49.158500672 +0800
2928 +++ linux-2.6.10/include/asm-mips/kerntypes.h   2005-04-05 16:47:53.881214528 +0800
2929 @@ -0,0 +1,21 @@
2930 +/*
2931 + * asm-mips/kerntypes.h
2932 + *
2933 + * Arch-dependent header file that includes headers for all arch-specific 
2934 + * types of interest.
2935 + * The kernel type information is used by the lcrash utility when
2936 + * analyzing system crash dumps or the live system. Using the type
2937 + * information for the running system, rather than kernel header files,
2938 + * makes for a more flexible and robust analysis tool.
2939 + *
2940 + * This source code is released under the GNU GPL.
2941 + */
2942 +
2943 +/* MIPS-specific header files */
2944 +#ifndef _MIPS_KERNTYPES_H
2945 +#define _MIPS_KERNTYPES_H
2946 +
2947 +/* Use the default */
2948 +#include <asm-generic/kerntypes.h>
2949 +
2950 +#endif /* _MIPS_KERNTYPES_H */
2951 Index: linux-2.6.10/include/asm-m68k/kerntypes.h
2952 ===================================================================
2953 --- linux-2.6.10.orig/include/asm-m68k/kerntypes.h      2005-04-05 19:01:49.158500672 +0800
2954 +++ linux-2.6.10/include/asm-m68k/kerntypes.h   2005-04-05 16:47:53.875215440 +0800
2955 @@ -0,0 +1,21 @@
2956 +/*
2957 + * asm-m68k/kerntypes.h
2958 + *
2959 + * Arch-dependent header file that includes headers for all arch-specific 
2960 + * types of interest.
2961 + * The kernel type information is used by the lcrash utility when
2962 + * analyzing system crash dumps or the live system. Using the type
2963 + * information for the running system, rather than kernel header files,
2964 + * makes for a more flexible and robust analysis tool.
2965 + *
2966 + * This source code is released under the GNU GPL.
2967 + */
2968 +
2969 +/* m68k-specific header files */
2970 +#ifndef _M68K_KERNTYPES_H
2971 +#define _M68K_KERNTYPES_H
2972 +
2973 +/* Use the default */
2974 +#include <asm-generic/kerntypes.h>
2975 +
2976 +#endif /* _M68K_KERNTYPES_H */
2977 Index: linux-2.6.10/include/asm-generic/kerntypes.h
2978 ===================================================================
2979 --- linux-2.6.10.orig/include/asm-generic/kerntypes.h   2005-04-05 19:01:49.158500672 +0800
2980 +++ linux-2.6.10/include/asm-generic/kerntypes.h        2005-04-05 16:47:53.871216048 +0800
2981 @@ -0,0 +1,20 @@
2982 +/*
2983 + * asm-generic/kerntypes.h
2984 + *
2985 + * Arch-dependent header file that includes headers for all arch-specific 
2986 + * types of interest.
2987 + * The kernel type information is used by the lcrash utility when
2988 + * analyzing system crash dumps or the live system. Using the type
2989 + * information for the running system, rather than kernel header files,
2990 + * makes for a more flexible and robust analysis tool.
2991 + *
2992 + * This source code is released under the GNU GPL.
2993 + */
2994 +
2995 +/* Arch-independent header files */
2996 +#ifndef _GENERIC_KERNTYPES_H
2997 +#define _GENERIC_KERNTYPES_H
2998 +
2999 +#include <linux/pci.h>
3000 +
3001 +#endif /* _GENERIC_KERNTYPES_H */
3002 Index: linux-2.6.10/include/asm-i386/dump.h
3003 ===================================================================
3004 --- linux-2.6.10.orig/include/asm-i386/dump.h   2005-04-05 19:01:49.158500672 +0800
3005 +++ linux-2.6.10/include/asm-i386/dump.h        2005-04-05 16:47:53.886213768 +0800
3006 @@ -0,0 +1,90 @@
3007 +/*
3008 + * Kernel header file for Linux crash dumps.
3009 + *
3010 + * Created by: Matt Robinson (yakker@sgi.com)
3011 + *
3012 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
3013 + *
3014 + * This code is released under version 2 of the GNU GPL.
3015 + */
3016 +
3017 +/* This header file holds the architecture specific crash dump header */
3018 +#ifndef _ASM_DUMP_H
3019 +#define _ASM_DUMP_H
3020 +
3021 +/* necessary header files */
3022 +#include <asm/ptrace.h>
3023 +#include <asm/page.h>
3024 +#include <linux/threads.h>
3025 +#include <linux/mm.h>
3026 +
3027 +/* definitions */
3028 +#define DUMP_ASM_MAGIC_NUMBER  0xdeaddeadULL   /* magic number            */
3029 +#define DUMP_ASM_VERSION_NUMBER        0x3     /* version number          */
3030 +
3031 +/*
3032 + * Structure: __dump_header_asm
3033 + *  Function: This is the header for architecture-specific stuff.  It
3034 + *            follows right after the dump header.
3035 + */
3036 +struct __dump_header_asm {
3037 +       /* the dump magic number -- unique to verify dump is valid */
3038 +       u64             dha_magic_number;
3039 +
3040 +       /* the version number of this dump */
3041 +       u32             dha_version;
3042 +
3043 +       /* the size of this header (in case we can't read it) */
3044 +       u32             dha_header_size;
3045 +
3046 +       /* the esp for i386 systems */
3047 +       u32             dha_esp;
3048 +
3049 +       /* the eip for i386 systems */
3050 +       u32             dha_eip;
3051 +
3052 +       /* the dump registers */
3053 +       struct pt_regs  dha_regs;
3054 +
3055 +       /* smp specific */
3056 +       u32             dha_smp_num_cpus;
3057 +       u32             dha_dumping_cpu;
3058 +       struct pt_regs  dha_smp_regs[NR_CPUS];
3059 +       u32             dha_smp_current_task[NR_CPUS];
3060 +       u32             dha_stack[NR_CPUS];
3061 +       u32             dha_stack_ptr[NR_CPUS];
3062 +} __attribute__((packed));
3063 +
3064 +#ifdef __KERNEL__
3065 +
3066 +extern struct __dump_header_asm dump_header_asm;
3067 +
3068 +#ifdef CONFIG_SMP
3069 +extern cpumask_t irq_affinity[];
3070 +extern int (*dump_ipi_function_ptr)(struct pt_regs *);
3071 +extern void dump_send_ipi(void);
3072 +#else
3073 +#define dump_send_ipi() do { } while(0)
3074 +#endif
3075 +
3076 +static inline void get_current_regs(struct pt_regs *regs)
3077 +{
3078 +       __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
3079 +       __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
3080 +       __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
3081 +       __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
3082 +       __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
3083 +       __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
3084 +       __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
3085 +       __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
3086 +       __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
3087 +       __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
3088 +       __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
3089 +       __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
3090 +       __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
3091 +       regs->eip = (unsigned long)current_text_addr();
3092 +}
3093 +
3094 +#endif /* __KERNEL__ */
3095 +
3096 +#endif /* _ASM_DUMP_H */
3097 Index: linux-2.6.10/include/asm-i386/kerntypes.h
3098 ===================================================================
3099 --- linux-2.6.10.orig/include/asm-i386/kerntypes.h      2005-04-05 19:01:49.158500672 +0800
3100 +++ linux-2.6.10/include/asm-i386/kerntypes.h   2005-04-05 16:47:53.887213616 +0800
3101 @@ -0,0 +1,21 @@
3102 +/*
3103 + * asm-i386/kerntypes.h
3104 + *
3105 + * Arch-dependent header file that includes headers for all arch-specific 
3106 + * types of interest.
3107 + * The kernel type information is used by the lcrash utility when
3108 + * analyzing system crash dumps or the live system. Using the type
3109 + * information for the running system, rather than kernel header files,
3110 + * makes for a more flexible and robust analysis tool.
3111 + *
3112 + * This source code is released under the GNU GPL.
3113 + */
3114 +
3115 +/* ix86-specific header files */
3116 +#ifndef _I386_KERNTYPES_H
3117 +#define _I386_KERNTYPES_H
3118 +
3119 +/* Use the default */
3120 +#include <asm-generic/kerntypes.h>
3121 +
3122 +#endif /* _I386_KERNTYPES_H */
3123 Index: linux-2.6.10/include/asm-i386/kmap_types.h
3124 ===================================================================
3125 --- linux-2.6.10.orig/include/asm-i386/kmap_types.h     2004-12-25 05:35:23.000000000 +0800
3126 +++ linux-2.6.10/include/asm-i386/kmap_types.h  2005-04-05 16:47:53.886213768 +0800
3127 @@ -23,7 +23,8 @@
3128  D(10)  KM_IRQ1,
3129  D(11)  KM_SOFTIRQ0,
3130  D(12)  KM_SOFTIRQ1,
3131 -D(13)  KM_TYPE_NR
3132 +D(13)  KM_DUMP,
3133 +D(14)  KM_TYPE_NR
3134  };
3135  
3136  #undef D
3137 Index: linux-2.6.10/include/asm-i386/smp.h
3138 ===================================================================
3139 --- linux-2.6.10.orig/include/asm-i386/smp.h    2004-12-25 05:35:50.000000000 +0800
3140 +++ linux-2.6.10/include/asm-i386/smp.h 2005-04-05 16:47:53.885213920 +0800
3141 @@ -37,6 +37,7 @@
3142  extern cpumask_t cpu_sibling_map[];
3143  
3144  extern void smp_flush_tlb(void);
3145 +extern void dump_send_ipi(void);
3146  extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
3147  extern void smp_invalidate_rcv(void);          /* Process an NMI */
3148  extern void (*mtrr_hook) (void);
3149 Index: linux-2.6.10/include/asm-i386/mach-default/irq_vectors.h
3150 ===================================================================
3151 --- linux-2.6.10.orig/include/asm-i386/mach-default/irq_vectors.h       2004-12-25 05:34:26.000000000 +0800
3152 +++ linux-2.6.10/include/asm-i386/mach-default/irq_vectors.h    2005-04-05 16:47:53.887213616 +0800
3153 @@ -48,6 +48,7 @@
3154  #define INVALIDATE_TLB_VECTOR  0xfd
3155  #define RESCHEDULE_VECTOR      0xfc
3156  #define CALL_FUNCTION_VECTOR   0xfb
3157 +#define DUMP_VECTOR            0xfa
3158  
3159  #define THERMAL_APIC_VECTOR    0xf0
3160  /*
3161 Index: linux-2.6.10/include/asm-arm/kerntypes.h
3162 ===================================================================
3163 --- linux-2.6.10.orig/include/asm-arm/kerntypes.h       2005-04-05 19:01:49.158500672 +0800
3164 +++ linux-2.6.10/include/asm-arm/kerntypes.h    2005-04-05 16:47:53.873215744 +0800
3165 @@ -0,0 +1,21 @@
3166 +/*
3167 + * asm-arm/kerntypes.h
3168 + *
3169 + * Arch-dependent header file that includes headers for all arch-specific 
3170 + * types of interest.
3171 + * The kernel type information is used by the lcrash utility when
3172 + * analyzing system crash dumps or the live system. Using the type
3173 + * information for the running system, rather than kernel header files,
3174 + * makes for a more flexible and robust analysis tool.
3175 + *
3176 + * This source code is released under the GNU GPL.
3177 + */
3178 +
3179 +/* ARM-specific header files */
3180 +#ifndef _ARM_KERNTYPES_H
3181 +#define _ARM_KERNTYPES_H
3182 +
3183 +/* Use the default */
3184 +#include <asm-generic/kerntypes.h>
3185 +
3186 +#endif /* _ARM_KERNTYPES_H */
3187 Index: linux-2.6.10/include/asm-sparc/kerntypes.h
3188 ===================================================================
3189 --- linux-2.6.10.orig/include/asm-sparc/kerntypes.h     2005-04-05 19:01:49.158500672 +0800
3190 +++ linux-2.6.10/include/asm-sparc/kerntypes.h  2005-04-05 16:47:53.874215592 +0800
3191 @@ -0,0 +1,21 @@
3192 +/*
3193 + * asm-sparc/kerntypes.h
3194 + *
3195 + * Arch-dependent header file that includes headers for all arch-specific 
3196 + * types of interest.
3197 + * The kernel type information is used by the lcrash utility when
3198 + * analyzing system crash dumps or the live system. Using the type
3199 + * information for the running system, rather than kernel header files,
3200 + * makes for a more flexible and robust analysis tool.
3201 + *
3202 + * This source code is released under the GNU GPL.
3203 + */
3204 +
3205 +/* SPARC-specific header files */
3206 +#ifndef _SPARC_KERNTYPES_H
3207 +#define _SPARC_KERNTYPES_H
3208 +
3209 +/* Use the default */
3210 +#include <asm-generic/kerntypes.h>
3211 +
3212 +#endif /* _SPARC_KERNTYPES_H */
3213 Index: linux-2.6.10/include/asm-mips64/kerntypes.h
3214 ===================================================================
3215 --- linux-2.6.10.orig/include/asm-mips64/kerntypes.h    2005-04-05 19:01:49.158500672 +0800
3216 +++ linux-2.6.10/include/asm-mips64/kerntypes.h 2005-04-05 16:47:53.881214528 +0800
3217 @@ -0,0 +1,21 @@
3218 +/*
3219 + * asm-mips64/kerntypes.h
3220 + *
3221 + * Arch-dependent header file that includes headers for all arch-specific 
3222 + * types of interest.
3223 + * The kernel type information is used by the lcrash utility when
3224 + * analyzing system crash dumps or the live system. Using the type
3225 + * information for the running system, rather than kernel header files,
3226 + * makes for a more flexible and robust analysis tool.
3227 + *
3228 + * This source code is released under the GNU GPL.
3229 + */
3230 +
3231 +/* MIPS64-specific header files */
3232 +#ifndef _MIPS64_KERNTYPES_H
3233 +#define _MIPS64_KERNTYPES_H
3234 +
3235 +/* Use the default */
3236 +#include <asm-generic/kerntypes.h>
3237 +
3238 +#endif /* _MIPS64_KERNTYPES_H */
3239 Index: linux-2.6.10/net/Kconfig
3240 ===================================================================
3241 --- linux-2.6.10.orig/net/Kconfig       2005-04-05 16:29:27.896349784 +0800
3242 +++ linux-2.6.10/net/Kconfig    2005-04-05 16:47:53.895212400 +0800
3243 @@ -632,7 +632,7 @@
3244  endmenu
3245  
3246  config NETPOLL
3247 -       def_bool NETCONSOLE
3248 +       def_bool NETCONSOLE || CRASH_DUMP_NETDEV
3249  
3250  config NETPOLL_RX
3251         bool "Netpoll support for trapping incoming packets"
3252 Index: linux-2.6.10/scripts/mkcompile_h
3253 ===================================================================
3254 --- linux-2.6.10.orig/scripts/mkcompile_h       2004-12-25 05:35:50.000000000 +0800
3255 +++ linux-2.6.10/scripts/mkcompile_h    2005-04-05 16:47:53.950204040 +0800
3256 @@ -33,7 +33,7 @@
3257  
3258  UTS_LEN=64
3259  UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
3260 -
3261 +LINUX_COMPILE_VERSION_ID="__linux_compile_version_id__`hostname | tr -c '[0-9A-Za-z\n]' '__'`_`LANG=C date | tr -c '[0-9A-Za-z\n]' '_'`"
3262  # Generate a temporary compile.h
3263  
3264  ( echo /\* This file is auto generated, version $VERSION \*/
3265 @@ -55,6 +55,8 @@
3266    fi
3267  
3268    echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
3269 +  echo \#define LINUX_COMPILE_VERSION_ID $LINUX_COMPILE_VERSION_ID
3270 +  echo \#define LINUX_COMPILE_VERSION_ID_TYPE typedef char* "$LINUX_COMPILE_VERSION_ID""_t"
3271  ) > .tmpcompile
3272  
3273  # Only replace the real compile.h if the new one is different,
3274 Index: linux-2.6.10/mm/bootmem.c
3275 ===================================================================
3276 --- linux-2.6.10.orig/mm/bootmem.c      2004-12-25 05:34:30.000000000 +0800
3277 +++ linux-2.6.10/mm/bootmem.c   2005-04-05 16:47:53.903211184 +0800
3278 @@ -26,6 +26,7 @@
3279   */
3280  unsigned long max_low_pfn;
3281  unsigned long min_low_pfn;
3282 +EXPORT_SYMBOL(min_low_pfn);
3283  unsigned long max_pfn;
3284  
3285  EXPORT_SYMBOL(max_pfn);                /* This is exported so
3286 @@ -284,6 +285,7 @@
3287                                 if (j + 16 < BITS_PER_LONG)
3288                                         prefetchw(page + j + 16);
3289                                 __ClearPageReserved(page + j);
3290 +                               set_page_count(page + j, 1);
3291                         }
3292                         __free_pages(page, ffs(BITS_PER_LONG)-1);
3293                         i += BITS_PER_LONG;
3294 Index: linux-2.6.10/mm/page_alloc.c
3295 ===================================================================
3296 --- linux-2.6.10.orig/mm/page_alloc.c   2005-04-05 16:29:28.218300840 +0800
3297 +++ linux-2.6.10/mm/page_alloc.c        2005-04-05 16:47:53.902211336 +0800
3298 @@ -47,6 +47,11 @@
3299  EXPORT_SYMBOL(totalram_pages);
3300  EXPORT_SYMBOL(nr_swap_pages);
3301  
3302 +#ifdef CONFIG_CRASH_DUMP_MODULE
3303 +/* This symbol has to be exported to use 'for_each_pgdat' macro by modules. */
3304 +EXPORT_SYMBOL(pgdat_list);
3305 +#endif
3306 +
3307  /*
3308   * Used by page_zone() to look up the address of the struct zone whose
3309   * id is encoded in the upper bits of page->flags
3310 @@ -281,8 +286,11 @@
3311         arch_free_page(page, order);
3312  
3313         mod_page_state(pgfree, 1 << order);
3314 -       for (i = 0 ; i < (1 << order) ; ++i)
3315 +       for (i = 0 ; i < (1 << order) ; ++i){
3316 +               if (unlikely(i))
3317 +                   __put_page(page + i); 
3318                 free_pages_check(__FUNCTION__, page + i);
3319 +       }
3320         list_add(&page->lru, &list);
3321         kernel_map_pages(page, 1<<order, 0);
3322         free_pages_bulk(page_zone(page), 1, &list, order);
3323 @@ -322,44 +330,34 @@
3324         return page;
3325  }
3326  
3327 -static inline void set_page_refs(struct page *page, int order)
3328 -{
3329 -#ifdef CONFIG_MMU
3330 -       set_page_count(page, 1);
3331 -#else
3332 -       int i;
3333 -
3334 -       /*
3335 -        * We need to reference all the pages for this order, otherwise if
3336 -        * anyone accesses one of the pages with (get/put) it will be freed.
3337 -        */
3338 -       for (i = 0; i < (1 << order); i++)
3339 -               set_page_count(page+i, 1);
3340 -#endif /* CONFIG_MMU */
3341 -}
3342 -
3343  /*
3344   * This page is about to be returned from the page allocator
3345   */
3346 -static void prep_new_page(struct page *page, int order)
3347 +static void prep_new_page(struct page *_page, int order)
3348  {
3349 -       if (page->mapping || page_mapped(page) ||
3350 -           (page->flags & (
3351 -                       1 << PG_private |
3352 -                       1 << PG_locked  |
3353 -                       1 << PG_lru     |
3354 -                       1 << PG_active  |
3355 -                       1 << PG_dirty   |
3356 -                       1 << PG_reclaim |
3357 -                       1 << PG_swapcache |
3358 -                       1 << PG_writeback )))
3359 +        int i;
3360 +
3361 +       for(i = 0; i < (1 << order); i++){
3362 +           struct page *page = _page + i;
3363 +
3364 +           if (page->mapping || page_mapped(page) ||
3365 +                   (page->flags & (
3366 +                                   1 << PG_private     |
3367 +                                   1 << PG_locked      |
3368 +                                   1 << PG_lru |
3369 +                                   1 << PG_active      |
3370 +                                   1 << PG_dirty       |
3371 +                                   1 << PG_reclaim     |
3372 +                                   1 << PG_swapcache |
3373 +                                   1 << PG_writeback )))
3374                 bad_page(__FUNCTION__, page);
3375  
3376 -       page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
3377 -                       1 << PG_referenced | 1 << PG_arch_1 |
3378 -                       1 << PG_checked | 1 << PG_mappedtodisk);
3379 -       page->private = 0;
3380 -       set_page_refs(page, order);
3381 +           page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
3382 +                   1 << PG_referenced | 1 << PG_arch_1 |
3383 +                   1 << PG_checked | 1 << PG_mappedtodisk);
3384 +           page->private = 0;
3385 +           set_page_count(page, 1);
3386 +       }
3387  }
3388  
3389  /* 
3390 Index: linux-2.6.10/kernel/sched.c
3391 ===================================================================
3392 --- linux-2.6.10.orig/kernel/sched.c    2005-04-05 16:29:30.335978904 +0800
3393 +++ linux-2.6.10/kernel/sched.c 2005-04-05 16:47:53.901211488 +0800
3394 @@ -54,6 +54,10 @@
3395  #define cpu_to_node_mask(cpu) (cpu_online_map)
3396  #endif
3397  
3398 +/* used to soft spin in sched while dump is in progress */
3399 +unsigned long dump_oncpu;
3400 +EXPORT_SYMBOL(dump_oncpu);
3401 +
3402  /*
3403   * Convert user-nice values [ -20 ... 0 ... 19 ]
3404   * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
3405 @@ -184,109 +188,6 @@
3406  #define task_hot(p, now, sd) ((long long) ((now) - (p)->last_ran)      \
3407                                 < (long long) (sd)->cache_hot_time)
3408  
3409 -/*
3410 - * These are the runqueue data structures:
3411 - */
3412 -
3413 -#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
3414 -
3415 -typedef struct runqueue runqueue_t;
3416 -
3417 -struct prio_array {
3418 -       unsigned int nr_active;
3419 -       unsigned long bitmap[BITMAP_SIZE];
3420 -       struct list_head queue[MAX_PRIO];
3421 -};
3422 -
3423 -/*
3424 - * This is the main, per-CPU runqueue data structure.
3425 - *
3426 - * Locking rule: those places that want to lock multiple runqueues
3427 - * (such as the load balancing or the thread migration code), lock
3428 - * acquire operations must be ordered by ascending &runqueue.
3429 - */
3430 -struct runqueue {
3431 -       spinlock_t lock;
3432 -
3433 -       /*
3434 -        * nr_running and cpu_load should be in the same cacheline because
3435 -        * remote CPUs use both these fields when doing load calculation.
3436 -        */
3437 -       unsigned long nr_running;
3438 -#ifdef CONFIG_SMP
3439 -       unsigned long cpu_load;
3440 -#endif
3441 -       unsigned long long nr_switches;
3442 -
3443 -       /*
3444 -        * This is part of a global counter where only the total sum
3445 -        * over all CPUs matters. A task can increase this counter on
3446 -        * one CPU and if it got migrated afterwards it may decrease
3447 -        * it on another CPU. Always updated under the runqueue lock:
3448 -        */
3449 -       unsigned long nr_uninterruptible;
3450 -
3451 -       unsigned long expired_timestamp;
3452 -       unsigned long long timestamp_last_tick;
3453 -       task_t *curr, *idle;
3454 -       struct mm_struct *prev_mm;
3455 -       prio_array_t *active, *expired, arrays[2];
3456 -       int best_expired_prio;
3457 -       atomic_t nr_iowait;
3458 -
3459 -#ifdef CONFIG_SMP
3460 -       struct sched_domain *sd;
3461 -
3462 -       /* For active balancing */
3463 -       int active_balance;
3464 -       int push_cpu;
3465 -
3466 -       task_t *migration_thread;
3467 -       struct list_head migration_queue;
3468 -#endif
3469 -
3470 -#ifdef CONFIG_SCHEDSTATS
3471 -       /* latency stats */
3472 -       struct sched_info rq_sched_info;
3473 -
3474 -       /* sys_sched_yield() stats */
3475 -       unsigned long yld_exp_empty;
3476 -       unsigned long yld_act_empty;
3477 -       unsigned long yld_both_empty;
3478 -       unsigned long yld_cnt;
3479 -
3480 -       /* schedule() stats */
3481 -       unsigned long sched_noswitch;
3482 -       unsigned long sched_switch;
3483 -       unsigned long sched_cnt;
3484 -       unsigned long sched_goidle;
3485 -
3486 -       /* pull_task() stats */
3487 -       unsigned long pt_gained[MAX_IDLE_TYPES];
3488 -       unsigned long pt_lost[MAX_IDLE_TYPES];
3489 -
3490 -       /* active_load_balance() stats */
3491 -       unsigned long alb_cnt;
3492 -       unsigned long alb_lost;
3493 -       unsigned long alb_gained;
3494 -       unsigned long alb_failed;
3495 -
3496 -       /* try_to_wake_up() stats */
3497 -       unsigned long ttwu_cnt;
3498 -       unsigned long ttwu_attempts;
3499 -       unsigned long ttwu_moved;
3500 -
3501 -       /* wake_up_new_task() stats */
3502 -       unsigned long wunt_cnt;
3503 -       unsigned long wunt_moved;
3504 -
3505 -       /* sched_migrate_task() stats */
3506 -       unsigned long smt_cnt;
3507 -
3508 -       /* sched_balance_exec() stats */
3509 -       unsigned long sbe_cnt;
3510 -#endif
3511 -};
3512  
3513  static DEFINE_PER_CPU(struct runqueue, runqueues);
3514  
3515 @@ -2535,6 +2436,15 @@
3516         unsigned long run_time;
3517         int cpu, idx;
3518  
3519 +       /*
3520 +        * If crash dump is in progress, this other cpu's
3521 +        * need to wait until it completes.
3522 +        * NB: this code is optimized away for kernels without
3523 +        * dumping enabled.
3524 +        */
3525 +       if (unlikely(dump_oncpu))
3526 +               goto dump_scheduling_disabled;
3527 +
3528         /*
3529          * Test if we are atomic.  Since do_exit() needs to call into
3530          * schedule() atomically, we ignore that path for now.
3531 @@ -2698,6 +2608,16 @@
3532         preempt_enable_no_resched();
3533         if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
3534                 goto need_resched;
3535 +
3536 +       return;
3537 +
3538 + dump_scheduling_disabled:
3539 +       /* allow scheduling only if this is the dumping cpu */
3540 +       if (dump_oncpu != smp_processor_id()+1) {
3541 +               while (dump_oncpu)
3542 +                       cpu_relax();
3543 +       }
3544 +       return;
3545  }
3546  
3547  EXPORT_SYMBOL(schedule);
3548 Index: linux-2.6.10/kernel/panic.c
3549 ===================================================================
3550 --- linux-2.6.10.orig/kernel/panic.c    2004-12-25 05:35:29.000000000 +0800
3551 +++ linux-2.6.10/kernel/panic.c 2005-04-05 16:47:53.898211944 +0800
3552 @@ -18,12 +18,17 @@
3553  #include <linux/sysrq.h>
3554  #include <linux/interrupt.h>
3555  #include <linux/nmi.h>
3556 +#ifdef CONFIG_KEXEC
3557 +#include <linux/kexec.h>
3558 +#endif
3559  
3560  int panic_timeout;
3561  int panic_on_oops;
3562  int tainted;
3563 +void (*dump_function_ptr)(const char *, const struct pt_regs *) = 0;
3564  
3565  EXPORT_SYMBOL(panic_timeout);
3566 +EXPORT_SYMBOL(dump_function_ptr);
3567  
3568  struct notifier_block *panic_notifier_list;
3569  
3570 @@ -71,11 +76,12 @@
3571         printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
3572         bust_spinlocks(0);
3573  
3574 +        notifier_call_chain(&panic_notifier_list, 0, buf);
3575 +       
3576  #ifdef CONFIG_SMP
3577         smp_send_stop();
3578  #endif
3579  
3580 -       notifier_call_chain(&panic_notifier_list, 0, buf);
3581  
3582         if (!panic_blink)
3583                 panic_blink = no_blink;
3584 @@ -87,6 +93,18 @@
3585                  * We can't use the "normal" timers since we just panicked..
3586                  */
3587                 printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
3588 +#ifdef CONFIG_KEXEC
3589 +{              
3590 +               struct kimage *image;
3591 +               image = xchg(&kexec_image, 0);
3592 +               if (image) {
3593 +                       printk(KERN_EMERG "by starting a new kernel ..\n");
3594 +                       mdelay(panic_timeout*1000);
3595 +                       machine_kexec(image);
3596 +               }
3597 +}
3598 +#endif
3599 +
3600                 for (i = 0; i < panic_timeout*1000; ) {
3601                         touch_nmi_watchdog();
3602                         i += panic_blink(i);
3603 Index: linux-2.6.10/drivers/block/ll_rw_blk.c
3604 ===================================================================
3605 --- linux-2.6.10.orig/drivers/block/ll_rw_blk.c 2005-04-05 16:29:30.310982704 +0800
3606 +++ linux-2.6.10/drivers/block/ll_rw_blk.c      2005-04-05 16:47:53.949204192 +0800
3607 @@ -28,6 +28,7 @@
3608  #include <linux/slab.h>
3609  #include <linux/swap.h>
3610  #include <linux/writeback.h>
3611 +#include <linux/dump.h>
3612  
3613  /*
3614   * for max sense size
3615 @@ -2628,7 +2629,8 @@
3616         sector_t maxsector;
3617         int ret, nr_sectors = bio_sectors(bio);
3618  
3619 -       might_sleep();
3620 +       if (likely(!dump_oncpu))
3621 +           might_sleep();
3622         /* Test device or partition size, when known. */
3623         maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
3624         if (maxsector) {
3625 Index: linux-2.6.10/drivers/dump/dump_i386.c
3626 ===================================================================
3627 --- linux-2.6.10.orig/drivers/dump/dump_i386.c  2005-04-05 19:01:49.158500672 +0800
3628 +++ linux-2.6.10/drivers/dump/dump_i386.c       2005-04-05 16:47:53.940205560 +0800
3629 @@ -0,0 +1,372 @@
3630 +/*
3631 + * Architecture specific (i386) functions for Linux crash dumps.
3632 + *
3633 + * Created by: Matt Robinson (yakker@sgi.com)
3634 + *
3635 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
3636 + *
3637 + * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
3638 + * Copyright 2000 TurboLinux, Inc.  All rights reserved.
3639 + * 
3640 + * This code is released under version 2 of the GNU GPL.
3641 + */
3642 +
3643 +/*
3644 + * The hooks for dumping the kernel virtual memory to disk are in this
3645 + * file.  Any time a modification is made to the virtual memory mechanism,
3646 + * these routines must be changed to use the new mechanisms.
3647 + */
3648 +#include <linux/init.h>
3649 +#include <linux/types.h>
3650 +#include <linux/kernel.h>
3651 +#include <linux/smp.h>
3652 +#include <linux/fs.h>
3653 +#include <linux/vmalloc.h>
3654 +#include <linux/mm.h>
3655 +#include <linux/dump.h>
3656 +#include "dump_methods.h"
3657 +#include <linux/irq.h>
3658 +
3659 +#include <asm/processor.h>
3660 +#include <asm/e820.h>
3661 +#include <asm/hardirq.h>
3662 +#include <asm/nmi.h>
3663 +
3664 +static __s32        saved_irq_count;   /* saved preempt_count() flags */
3665 +
3666 +static int
3667 +alloc_dha_stack(void)
3668 +{
3669 +       int i;
3670 +       void *ptr;
3671 +       
3672 +       if (dump_header_asm.dha_stack[0])
3673 +               return 0;
3674 +
3675 +       ptr = vmalloc(THREAD_SIZE * num_online_cpus());
3676 +       if (!ptr) {
3677 +               printk("vmalloc for dha_stacks failed\n");
3678 +               return -ENOMEM;
3679 +       }
3680 +
3681 +       for (i = 0; i < num_online_cpus(); i++) {
3682 +               dump_header_asm.dha_stack[i] = (u32)((unsigned long)ptr +
3683 +                               (i * THREAD_SIZE));
3684 +       }
3685 +       return 0;
3686 +}
3687 +
3688 +static int
3689 +free_dha_stack(void) 
3690 +{
3691 +       if (dump_header_asm.dha_stack[0]) {
3692 +               vfree((void *)dump_header_asm.dha_stack[0]);    
3693 +               dump_header_asm.dha_stack[0] = 0;
3694 +       }
3695 +       return 0;
3696 +}
3697 +
3698 +
3699 +void 
3700 +__dump_save_regs(struct pt_regs *dest_regs, const struct pt_regs *regs)
3701 +{
3702 +       *dest_regs = *regs;
3703 +
3704 +       /* In case of panic dumps, we collects regs on entry to panic.
3705 +        * so, we shouldn't 'fix' ssesp here again. But it is hard to
3706 +        * tell just looking at regs whether ssesp need fixing. We make
3707 +        * this decision by looking at xss in regs. If we have better
3708 +        * means to determine that ssesp are valid (by some flag which
3709 +        * tells that we are here due to panic dump), then we can use
3710 +        * that instead of this kludge.
3711 +        */
3712 +       if (!user_mode(regs)) {
3713 +               if ((0xffff & regs->xss) == __KERNEL_DS) 
3714 +                       /* already fixed up */
3715 +                       return;
3716 +               dest_regs->esp = (unsigned long)&(regs->esp);
3717 +               __asm__ __volatile__ ("movw %%ss, %%ax;"
3718 +                       :"=a"(dest_regs->xss));
3719 +       }
3720 +}
3721 +
3722 +void
3723 +__dump_save_context(int cpu, const struct pt_regs *regs, 
3724 +       struct task_struct *tsk)
3725 +{
3726 +       dump_header_asm.dha_smp_current_task[cpu] = (unsigned long)tsk;
3727 +       __dump_save_regs(&dump_header_asm.dha_smp_regs[cpu], regs);
3728 +
3729 +       /* take a snapshot of the stack */
3730 +       /* doing this enables us to tolerate slight drifts on this cpu */
3731 +
3732 +       if (dump_header_asm.dha_stack[cpu]) {
3733 +               memcpy((void *)dump_header_asm.dha_stack[cpu],
3734 +                               STACK_START_POSITION(tsk),
3735 +                               THREAD_SIZE);
3736 +       }
3737 +       dump_header_asm.dha_stack_ptr[cpu] = (unsigned long)(tsk->thread_info);
3738 +}
3739 +
3740 +#ifdef CONFIG_SMP
3741 +extern cpumask_t irq_affinity[];
3742 +extern irq_desc_t irq_desc[];
3743 +extern void dump_send_ipi(void);
3744 +
3745 +static int dump_expect_ipi[NR_CPUS];
3746 +static atomic_t waiting_for_dump_ipi;
3747 +static cpumask_t saved_affinity[NR_IRQS];
3748 +
3749 +extern void stop_this_cpu(void *); /* exported by i386 kernel */
3750 +
3751 +static int
3752 +dump_nmi_callback(struct pt_regs *regs, int cpu) 
3753 +{
3754 +       if (!dump_expect_ipi[cpu])
3755 +               return 0;
3756 +
3757 +       dump_expect_ipi[cpu] = 0;
3758 +       
3759 +       dump_save_this_cpu(regs);
3760 +       atomic_dec(&waiting_for_dump_ipi);
3761 +
3762 + level_changed:
3763 +       switch (dump_silence_level) {
3764 +       case DUMP_HARD_SPIN_CPUS:       /* Spin until dump is complete */
3765 +               while (dump_oncpu) {
3766 +                       barrier();      /* paranoia */
3767 +                       if (dump_silence_level != DUMP_HARD_SPIN_CPUS)
3768 +                               goto level_changed;
3769 +
3770 +                       cpu_relax();    /* kill time nicely */
3771 +               }
3772 +               break;
3773 +
3774 +       case DUMP_HALT_CPUS:            /* Execute halt */
3775 +               stop_this_cpu(NULL);
3776 +               break;
3777 +               
3778 +       case DUMP_SOFT_SPIN_CPUS:
3779 +               /* Mark the task so it spins in schedule */
3780 +               set_tsk_thread_flag(current, TIF_NEED_RESCHED);
3781 +               break;
3782 +       }
3783 +
3784 +       return 1;
3785 +}
3786 +
3787 +/* save registers on other processors */
3788 +void 
3789 +__dump_save_other_cpus(void)
3790 +{
3791 +       int i, cpu = smp_processor_id();
3792 +       int other_cpus = num_online_cpus()-1;
3793 +       
3794 +       if (other_cpus > 0) {
3795 +               atomic_set(&waiting_for_dump_ipi, other_cpus);
3796 +
3797 +               for (i = 0; i < NR_CPUS; i++) {
3798 +                       dump_expect_ipi[i] = (i != cpu && cpu_online(i));
3799 +               }
3800 +
3801 +               /* short circuit normal NMI handling temporarily */
3802 +               set_nmi_callback(dump_nmi_callback);
3803 +               wmb();
3804 +
3805 +               dump_send_ipi();
3806 +               /* may be we dont need to wait for NMI to be processed. 
3807 +                  just write out the header at the end of dumping, if
3808 +                  this IPI is not processed until then, there probably
3809 +                  is a problem and we just fail to capture state of 
3810 +                  other cpus. */
3811 +               while(atomic_read(&waiting_for_dump_ipi) > 0) {
3812 +                       cpu_relax();
3813 +               }
3814 +
3815 +               unset_nmi_callback();
3816 +       }
3817 +}
3818 +
3819 +/*
3820 + * Routine to save the old irq affinities and change affinities of all irqs to
3821 + * the dumping cpu.
3822 + */
3823 +static void 
3824 +set_irq_affinity(void)
3825 +{
3826 +       int i;
3827 +       cpumask_t cpu = CPU_MASK_NONE;
3828 +
3829 +       cpu_set(smp_processor_id(), cpu);
3830 +       memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long));
3831 +       for (i = 0; i < NR_IRQS; i++) {
3832 +               if (irq_desc[i].handler == NULL)
3833 +                       continue;
3834 +               irq_affinity[i] = cpu;
3835 +               if (irq_desc[i].handler->set_affinity != NULL)
3836 +                       irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
3837 +       }
3838 +}
3839 +
3840 +/*
3841 + * Restore old irq affinities.
3842 + */
3843 +static void 
3844 +reset_irq_affinity(void)
3845 +{
3846 +       int i;
3847 +
3848 +       memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
3849 +       for (i = 0; i < NR_IRQS; i++) {
3850 +               if (irq_desc[i].handler == NULL)
3851 +                       continue;
3852 +               if (irq_desc[i].handler->set_affinity != NULL)
3853 +                       irq_desc[i].handler->set_affinity(i, saved_affinity[i]);
3854 +       }
3855 +}
3856 +
3857 +#else /* !CONFIG_SMP */
3858 +#define set_irq_affinity()     do { } while (0)
3859 +#define reset_irq_affinity()   do { } while (0)
3860 +#define save_other_cpu_states() do { } while (0)
3861 +#endif /* !CONFIG_SMP */
3862 +
3863 +/* 
3864 + * Kludge - dump from interrupt context is unreliable (Fixme)
3865 + *
3866 + * We do this so that softirqs initiated for dump i/o 
3867 + * get processed and we don't hang while waiting for i/o
3868 + * to complete or in any irq synchronization attempt.
3869 + *
3870 + * This is not quite legal of course, as it has the side 
3871 + * effect of making all interrupts & softirqs triggered 
3872 + * while dump is in progress complete before currently 
3873 + * pending softirqs and the currently executing interrupt 
3874 + * code. 
3875 + */
3876 +static inline void
3877 +irq_bh_save(void)
3878 +{
3879 +       saved_irq_count = irq_count();
3880 +       preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
3881 +}
3882 +
3883 +static inline void
3884 +irq_bh_restore(void)
3885 +{
3886 +       preempt_count() |= saved_irq_count;
3887 +}
3888 +
3889 +/*
3890 + * Name: __dump_irq_enable
3891 + * Func: Reset system so interrupts are enabled.
3892 + *      This is used for dump methods that require interrupts
3893 + *      Eventually, all methods will have interrupts disabled
3894 + *      and this code can be removed.
3895 + *
3896 + *     Change irq affinities
3897 + *     Re-enable interrupts
3898 + */
3899 +int
3900 +__dump_irq_enable(void)
3901 +{
3902 +       set_irq_affinity();
3903 +       irq_bh_save();
3904 +       local_irq_enable();
3905 +       return 0;
3906 +}
3907 +
3908 +/*
3909 + * Name: __dump_irq_restore
3910 + * Func: Resume the system state in an architecture-specific way.
3911 +
3912 + */
3913 +void 
3914 +__dump_irq_restore(void)
3915 +{
3916 +       local_irq_disable();
3917 +       reset_irq_affinity();
3918 +       irq_bh_restore();
3919 +}
3920 +
3921 +/*
3922 + * Name: __dump_configure_header()
3923 + * Func: Meant to fill in arch specific header fields except per-cpu state
3924 + * already captured via __dump_save_context for all CPUs.
3925 + */
3926 +int
3927 +__dump_configure_header(const struct pt_regs *regs)
3928 +{
3929 +       return (0);
3930 +}
3931 +
3932 +/*
3933 + * Name: __dump_init()
3934 + * Func: Initialize the dumping routine process.
3935 + */
3936 +void
3937 +__dump_init(uint64_t local_memory_start)
3938 +{
3939 +       return;
3940 +}
3941 +
3942 +/*
3943 + * Name: __dump_open()
3944 + * Func: Open the dump device (architecture specific).
3945 + */
3946 +void
3947 +__dump_open(void)
3948 +{
3949 +       alloc_dha_stack();
3950 +}
3951 +
3952 +/*
3953 + * Name: __dump_cleanup()
3954 + * Func: Free any architecture specific data structures. This is called
3955 + *       when the dump module is being removed.
3956 + */
3957 +void
3958 +__dump_cleanup(void)
3959 +{
3960 +       free_dha_stack();
3961 +}
3962 +
3963 +extern int pfn_is_ram(unsigned long);
3964 +
3965 +/*
3966 + * Name: __dump_page_valid()
3967 + * Func: Check if page is valid to dump.
3968 + */ 
3969 +int 
3970 +__dump_page_valid(unsigned long index)
3971 +{
3972 +       if (!pfn_valid(index))
3973 +               return 0;
3974 +
3975 +       return pfn_is_ram(index);
3976 +}
3977 +
3978 +/* 
3979 + * Name: manual_handle_crashdump()
3980 + * Func: Interface for the lkcd dump command. Calls dump_execute()
3981 + */
3982 +int
3983 +manual_handle_crashdump(void) {
3984 +
3985 +       struct pt_regs regs;
3986 +       
3987 +       get_current_regs(&regs);
3988 +       dump_execute("manual", &regs);
3989 +       return 0;
3990 +}
3991 +
3992 +/*
3993 + * Name: __dump_clean_irq_state()
3994 + * Func: Clean up from the previous IRQ handling state. Such as oops from 
3995 + *       interrupt handler or bottom half.
3996 + */
3997 +void
3998 +__dump_clean_irq_state(void)
3999 +{
4000 +    return;
4001 +}
4002 Index: linux-2.6.10/drivers/dump/dump_ia64.c
4003 ===================================================================
4004 --- linux-2.6.10.orig/drivers/dump/dump_ia64.c  2005-04-05 19:01:49.158500672 +0800
4005 +++ linux-2.6.10/drivers/dump/dump_ia64.c       2005-04-05 16:47:53.928207384 +0800
4006 @@ -0,0 +1,458 @@
4007 +/*
4008 + * Architecture specific (ia64) functions for Linux crash dumps.
4009 + *
4010 + * Created by: Matt Robinson (yakker@sgi.com)
4011 + * Contributions from SGI, IBM, and others.
4012 + *
4013 + * 2.4  kernel modifications by:  Matt D. Robinson (yakker@alacritech.com)
4014 + * ia64 kernel modifications by: Piet Delaney (piet@www.piet.net)
4015 + *
4016 + * Copyright (C) 2001 - 2002 Matt D. Robinson (yakker@alacritech.com)
4017 + * Copyright (C) 2002 Silicon Graphics, Inc. All rights reserved.
4018 + * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
4019 + *
4020 + * This code is released under version 2 of the GNU GPL.
4021 + */
4022 +
4023 +/*
4024 + * The hooks for dumping the kernel virtual memory to disk are in this
4025 + * file.  Any time a modification is made to the virtual memory mechanism,
4026 + * these routines must be changed to use the new mechanisms.
4027 + */
4028 +#include <linux/init.h>
4029 +#include <linux/types.h>
4030 +#include <linux/kernel.h>
4031 +#include <linux/smp.h>
4032 +#include <linux/fs.h>
4033 +#include <linux/vmalloc.h>
4034 +#include <linux/dump.h>
4035 +#include "dump_methods.h"
4036 +#include <linux/mm.h>
4037 +#include <asm/processor.h>
4038 +#include <asm-ia64/dump.h>
4039 +#include <asm/hardirq.h>
4040 +#include <linux/irq.h>
4041 +#include <linux/delay.h>
4042 +
4043 +static __s32         saved_irq_count;   /* saved preempt_count() flags */
4044 +
4045 +
4046 +static int alloc_dha_stack(void)
4047 +{
4048 +       int i;
4049 +       void *ptr;
4050 +       
4051 +       if (dump_header_asm.dha_stack[0])
4052 +       {
4053 +               return 0;
4054 +       }
4055 +               ptr = vmalloc(THREAD_SIZE * num_online_cpus());
4056 +               if (!ptr) {
4057 +               printk("vmalloc for dha_stacks failed\n");
4058 +               return -ENOMEM;
4059 +       }
4060 +       bzero(ptr,THREAD_SIZE );
4061 +
4062 +       for (i = 0; i < num_online_cpus(); i++) {
4063 +               dump_header_asm.dha_stack[i] = (uint64_t)((unsigned long)ptr + (i * THREAD_SIZE));
4064 +       }
4065 +       return 0;
4066 +}
4067 +
4068 +static int free_dha_stack(void) 
4069 +{
4070 +       if (dump_header_asm.dha_stack[0])
4071 +       {
4072 +               vfree((void*)dump_header_asm.dha_stack[0]);
4073 +               dump_header_asm.dha_stack[0] = 0;
4074 +       }
4075 +       return 0;
4076 +}
4077 +
4078 +/* a structure to get arguments into the following callback routine */
4079 +struct unw_args {
4080 +       int cpu;
4081 +       struct task_struct *tsk;
4082 +};
4083 +
4084 +static void
4085 +do_save_sw(struct unw_frame_info *info, void *arg)
4086 +{
4087 +       struct unw_args *uwargs = (struct unw_args *)arg;
4088 +       int cpu = uwargs->cpu;
4089 +       struct task_struct *tsk = uwargs->tsk;
4090 +
4091 +       dump_header_asm.dha_stack_ptr[cpu] = (uint64_t)info->sw;
4092 +
4093 +       if (tsk && dump_header_asm.dha_stack[cpu]) {
4094 +               memcpy((void *)dump_header_asm.dha_stack[cpu],
4095 +                               STACK_START_POSITION(tsk),
4096 +                               THREAD_SIZE);
4097 +       }
4098 +}
4099 +
4100 +void
4101 +__dump_save_context(int cpu, const struct pt_regs *regs, 
4102 +       struct task_struct *tsk)
4103 +{
4104 +       struct unw_args uwargs;
4105 +
4106 +       dump_header_asm.dha_smp_current_task[cpu] = (unsigned long)tsk;
4107 +
4108 +       if (regs) {
4109 +               dump_header_asm.dha_smp_regs[cpu] = *regs;
4110 +       }
4111 +
4112 +       /* save a snapshot of the stack in a nice state for unwinding */
4113 +       uwargs.cpu = cpu;
4114 +       uwargs.tsk = tsk;
4115 +
4116 +       unw_init_running(do_save_sw, (void *)&uwargs);
4117 +}
4118 +
4119 +#ifdef CONFIG_SMP
4120 +
4121 +extern cpumask_t irq_affinity[];
4122 +#define irq_desc _irq_desc
4123 +extern irq_desc_t irq_desc[];
4124 +extern void dump_send_ipi(void);
4125 +static cpumask_t saved_affinity[NR_IRQS];
4126 +
4127 +/*
4128 + * Routine to save the old irq affinities and change affinities of all irqs to
4129 + * the dumping cpu.
4130 + */
4131 +static void
4132 +set_irq_affinity(void)
4133 +{
4134 +        int i;
4135 +       cpumask_t cpu = CPU_MASK_NONE;
4136 +
4137 +       cpu_set(smp_processor_id(), cpu);
4138 +        memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long));
4139 +        for (i = 0; i < NR_IRQS; i++) {
4140 +                if (irq_desc[i].handler == NULL)
4141 +                        continue;
4142 +               irq_affinity[i] = cpu;
4143 +                if (irq_desc[i].handler->set_affinity != NULL)
4144 +                        irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
4145 +        }
4146 +}
4147 +
4148 +/*
4149 + * Restore old irq affinities.
4150 + */
4151 +static void
4152 +reset_irq_affinity(void)
4153 +{
4154 +        int i;
4155 +
4156 +        memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
4157 +        for (i = 0; i < NR_IRQS; i++) {
4158 +                if (irq_desc[i].handler == NULL)
4159 +                        continue;
4160 +                if (irq_desc[i].handler->set_affinity != NULL)
4161 +                        irq_desc[i].handler->set_affinity(i, saved_affinity[i]);
4162 +        }
4163 +}
4164 +
4165 +#else /* !CONFIG_SMP */
4166 +#define set_irq_affinity()      do { } while (0)
4167 +#define reset_irq_affinity()    do { } while (0)
4168 +#define save_other_cpu_states() do { } while (0)
4169 +#endif /* !CONFIG_SMP */
4170 +
4171 +#ifdef CONFIG_SMP
4172 +static int dump_expect_ipi[NR_CPUS];
4173 +static atomic_t waiting_for_dump_ipi;
4174 +static int wait_for_dump_ipi = 2000; /* wait 2000 ms for ipi to be handled */
4175 +extern void (*dump_trace_ptr)(struct pt_regs *);
4176 +
4177 +
4178 +extern void stop_this_cpu(void);
4179 +
4180 +static int
4181 +dump_nmi_callback(struct pt_regs *regs, int cpu)
4182 +{
4183 +        if (!dump_expect_ipi[cpu])
4184 +                return 0;
4185 +
4186 +        dump_expect_ipi[cpu] = 0;
4187 +
4188 +        dump_save_this_cpu(regs);
4189 +        atomic_dec(&waiting_for_dump_ipi);
4190 +
4191 + level_changed:
4192 +        switch (dump_silence_level) {
4193 +        case DUMP_HARD_SPIN_CPUS:       /* Spin until dump is complete */
4194 +                while (dump_oncpu) {
4195 +                        barrier();      /* paranoia */
4196 +                        if (dump_silence_level != DUMP_HARD_SPIN_CPUS)
4197 +                                goto level_changed;
4198 +
4199 +                        cpu_relax();    /* kill time nicely */
4200 +                }
4201 +                break;
4202 +
4203 +        case DUMP_HALT_CPUS:            /* Execute halt */
4204 +                stop_this_cpu();
4205 +                break;
4206 +
4207 +        case DUMP_SOFT_SPIN_CPUS:
4208 +                /* Mark the task so it spins in schedule */
4209 +                set_tsk_thread_flag(current, TIF_NEED_RESCHED);
4210 +                break;
4211 +        }
4212 +
4213 +        return 1;
4214 +}
4215 +
4216 +int IPI_handler(struct pt_regs *regs)
4217 +{
4218 +       int cpu;
4219 +       cpu = task_cpu(current);
4220 +       return(dump_nmi_callback(regs, cpu));
4221 +}
4222 +
4223 +/* save registers on other processors */
4224 +void
4225 +__dump_save_other_cpus(void)
4226 +{
4227 +        int i, cpu = smp_processor_id();
4228 +        int other_cpus = num_online_cpus()-1;
4229 +       int wait_time = wait_for_dump_ipi;
4230 +
4231 +        if (other_cpus > 0) {
4232 +                atomic_set(&waiting_for_dump_ipi, other_cpus);
4233 +
4234 +                for (i = 0; i < NR_CPUS; i++) {
4235 +                        dump_expect_ipi[i] = (i != cpu && cpu_online(i));
4236 +                }
4237 +
4238 +               dump_ipi_function_ptr = IPI_handler;
4239 +               
4240 +                wmb();
4241 +
4242 +                dump_send_ipi();
4243 +                /* may be we dont need to wait for IPI to be processed.
4244 +                 * just write out the header at the end of dumping, if
4245 +                 * this IPI is not processed until then, there probably
4246 +                 * is a problem and we just fail to capture state of
4247 +                 * other cpus. */
4248 +                while(wait_time-- && (atomic_read(&waiting_for_dump_ipi) > 0)) {
4249 +                       barrier();
4250 +                       mdelay(1);
4251 +                }
4252 +               if (wait_time <= 0) {
4253 +                       printk("dump ipi timeout, proceeding...\n");
4254 +               }
4255 +        }
4256 +}
4257 +#endif
4258 +/*
4259 + * Kludge - dump from interrupt context is unreliable (Fixme)
4260 + *
4261 + * We do this so that softirqs initiated for dump i/o
4262 + * get processed and we don't hang while waiting for i/o
4263 + * to complete or in any irq synchronization attempt.
4264 + *
4265 + * This is not quite legal of course, as it has the side
4266 + * effect of making all interrupts & softirqs triggered
4267 + * while dump is in progress complete before currently
4268 + * pending softirqs and the currently executing interrupt
4269 + * code.
4270 + */
4271 +static inline void
4272 +irq_bh_save(void)
4273 +{
4274 +        saved_irq_count = irq_count();
4275 +        preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
4276 +}
4277 +
4278 +static inline void
4279 +irq_bh_restore(void)
4280 +{
4281 +        preempt_count() |= saved_irq_count;
4282 +}
4283 +
4284 +/*
4285 + * Name: __dump_configure_header()
4286 + * Func: Configure the dump header with all proper values.
4287 + */
4288 +int
4289 +__dump_configure_header(const struct pt_regs *regs)
4290 +{
4291 +       return (0);
4292 +}
4293 +
4294 +
4295 +#define dim(x) (sizeof(x)/sizeof(*(x)))
4296 +
4297 +/*
4298 + * Name: __dump_irq_enable
4299 + * Func: Reset system so interrupts are enabled.
4300 + *       This is used for dump methods that require interrupts
4301 + *       Eventually, all methods will have interrupts disabled
4302 + *       and this code can be removed.
4303 + *
4304 + *     Change irq affinities
4305 + *     Re-enable interrupts
4306 + */
4307 +int
4308 +__dump_irq_enable(void)
4309 +{
4310 +        set_irq_affinity();
4311 +        irq_bh_save();
4312 +       ia64_srlz_d();
4313 +       /* 
4314 +        * reduce the task priority level
4315 +        * to get disk interrupts
4316 +        */
4317 +       ia64_setreg(_IA64_REG_CR_TPR, 0);
4318 +       ia64_srlz_d();
4319 +        local_irq_enable();
4320 +       return 0;
4321 +}
4322 +
4323 +/*
4324 + * Name: __dump_irq_restore
4325 + * Func: Resume the system state in an architecture-specific way.
4326 +
4327 + */
4328 +void
4329 +__dump_irq_restore(void)
4330 +{
4331 +        local_irq_disable();
4332 +        reset_irq_affinity();
4333 +        irq_bh_restore();
4334 +}
4335 +
4336 +/*
4337 + * Name: __dump_page_valid()
4338 + * Func: Check if page is valid to dump.
4339 + */
4340 +int
4341 +__dump_page_valid(unsigned long index)
4342 +{
4343 +        if (!pfn_valid(index))
4344 +       {
4345 +                return 0;
4346 +       }
4347 +        return 1;
4348 +}
4349 +
4350 +/*
4351 + * Name: __dump_init()
4352 + * Func: Initialize the dumping routine process.  This is in case
4353 + *       it's necessary in the future.
4354 + */
4355 +void
4356 +__dump_init(uint64_t local_memory_start)
4357 +{
4358 +       return;
4359 +}
4360 +
4361 +/*
4362 + * Name: __dump_open()
4363 + * Func: Open the dump device (architecture specific).  This is in
4364 + *       case it's necessary in the future.
4365 + */
4366 +void
4367 +__dump_open(void)
4368 +{
4369 +       alloc_dha_stack();
4370 +       return;
4371 +}
4372 +
4373 +
4374 +/*
4375 + * Name: __dump_cleanup()
4376 + * Func: Free any architecture specific data structures. This is called
4377 + *       when the dump module is being removed.
4378 + */
4379 +void
4380 +__dump_cleanup(void)
4381 +{
4382 +       free_dha_stack();
4383 +
4384 +       return;
4385 +}
4386 +
4387 +
4388 +
4389 +int __dump_memcpy_mc_expected = 0;             /* Doesn't help yet */
4390 +
4391 +/*
4392 + * An ia64 version of memcpy() that trys to avoid machine checks.
4393 + *
4394 + * NB: 
4395 + *     By itself __dump_memcpy_mc_expected() ins't providing any
4396 + *     protection against Machine Checks. We are looking into the
4397 + *     possability of adding code to the arch/ia64/kernel/mca.c fuction
4398 + *     ia64_mca_ucmc_handler() to restore state so that a IA64_MCA_CORRECTED
4399 + *     can be returned to the firmware. Curently it always returns 
4400 + *     IA64_MCA_COLD_BOOT and reboots the machine.
4401 + */
4402 +/*
4403 +void * __dump_memcpy(void * dest, const void *src, size_t count)
4404 +{
4405 +       void *vp;
4406 +
4407 +       if (__dump_memcpy_mc_expected) {
4408 +               ia64_pal_mc_expected((u64) 1, 0);
4409 +       }
4410 +
4411 +       vp = memcpy(dest, src, count);
4412 +
4413 +       if (__dump_memcpy_mc_expected) {
4414 +               ia64_pal_mc_expected((u64) 0, 0);
4415 +       }
4416 +       return(vp);
4417 +}
4418 +*/
4419 +/*
4420 + * Name: manual_handle_crashdump()
4421 + * Func: Interface for the lkcd dump command. Calls dump_execute()
4422 + */
4423 +int
4424 +manual_handle_crashdump(void) {
4425 +
4426 +        struct pt_regs regs;
4427 +
4428 +        get_current_regs(&regs);
4429 +        dump_execute("manual", &regs);
4430 +        return 0;
4431 +}
4432 +
4433 +/*
4434 + * Name: __dump_clean_irq_state()
4435 + * Func: Clean up from the previous IRQ handling state. Such as oops from 
4436 + *       interrupt handler or bottom half.
4437 + */
4438 +void
4439 +__dump_clean_irq_state(void)
4440 +{
4441 +       unsigned long saved_tpr;
4442 +       unsigned long TPR_MASK = 0xFFFFFFFFFFFEFF0F;
4443 +       
4444 +       
4445 +       /* Get the processors task priority register */
4446 +       saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
4447 +       /* clear the mmi and mic bit's of the TPR to unmask interrupts */
4448 +       saved_tpr = saved_tpr & TPR_MASK; 
4449 +       ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
4450 +       ia64_srlz_d();
4451 +
4452 +       /* Tell the processor we're done with the interrupt
4453 +        * that got us here.
4454 +        */
4455 +       
4456 +       ia64_eoi();
4457 +
4458 +       /* local implementation of irq_exit(); */
4459 +       preempt_count() -= IRQ_EXIT_OFFSET;
4460 +       preempt_enable_no_resched();
4461 +
4462 +       return;
4463 +}
4464 +
4465 Index: linux-2.6.10/drivers/dump/dump_rle.c
4466 ===================================================================
4467 --- linux-2.6.10.orig/drivers/dump/dump_rle.c   2005-04-05 19:01:49.158500672 +0800
4468 +++ linux-2.6.10/drivers/dump/dump_rle.c        2005-04-05 16:47:53.935206320 +0800
4469 @@ -0,0 +1,176 @@
4470 +/*
4471 + * RLE Compression functions for kernel crash dumps.
4472 + *
4473 + * Created by: Matt Robinson (yakker@sourceforge.net)
4474 + * Copyright 2001 Matt D. Robinson.  All rights reserved.
4475 + *
4476 + * This code is released under version 2 of the GNU GPL.
4477 + */
4478 +
4479 +/* header files */
4480 +#include <linux/config.h>
4481 +#include <linux/module.h>
4482 +#include <linux/sched.h>
4483 +#include <linux/fs.h>
4484 +#include <linux/file.h>
4485 +#include <linux/init.h>
4486 +#include <linux/dump.h>
4487 +
4488 +/*
4489 + * Name: dump_compress_rle()
4490 + * Func: Compress a DUMP_PAGE_SIZE (hardware) page down to something more
4491 + *       reasonable, if possible.  This is the same routine we use in IRIX.
4492 + */
4493 +static u32
4494 +dump_compress_rle(const u8 *old, u32 oldsize, u8 *new, u32 newsize,
4495 +               unsigned long loc)
4496 +{
4497 +       u16 ri, wi, count = 0;
4498 +       u_char value = 0, cur_byte;
4499 +
4500 +       /*
4501 +        * If the block should happen to "compress" to larger than the
4502 +        * buffer size, allocate a larger one and change cur_buf_size.
4503 +        */
4504 +
4505 +       wi = ri = 0;
4506 +
4507 +       while (ri < oldsize) {
4508 +               if (!ri) {
4509 +                       cur_byte = value = old[ri];
4510 +                       count = 0;
4511 +               } else {
4512 +                       if (count == 255) {
4513 +                               if (wi + 3 > oldsize) {
4514 +                                       return oldsize;
4515 +                               }
4516 +                               new[wi++] = 0;
4517 +                               new[wi++] = count;
4518 +                               new[wi++] = value;
4519 +                               value = cur_byte = old[ri];
4520 +                               count = 0;
4521 +                       } else { 
4522 +                               if ((cur_byte = old[ri]) == value) {
4523 +                                       count++;
4524 +                               } else {
4525 +                                       if (count > 1) {
4526 +                                               if (wi + 3 > oldsize) {
4527 +                                                       return oldsize;
4528 +                                               }
4529 +                                               new[wi++] = 0;
4530 +                                               new[wi++] = count;
4531 +                                               new[wi++] = value;
4532 +                                       } else if (count == 1) {
4533 +                                               if (value == 0) {
4534 +                                                       if (wi + 3 > oldsize) {
4535 +                                                               return oldsize;
4536 +                                                       }
4537 +                                                       new[wi++] = 0;
4538 +                                                       new[wi++] = 1;
4539 +                                                       new[wi++] = 0;
4540 +                                               } else {
4541 +                                                       if (wi + 2 > oldsize) {
4542 +                                                               return oldsize;
4543 +                                                       }
4544 +                                                       new[wi++] = value;
4545 +                                                       new[wi++] = value;
4546 +                                               }
4547 +                                       } else { /* count == 0 */
4548 +                                               if (value == 0) {
4549 +                                                       if (wi + 2 > oldsize) {
4550 +                                                               return oldsize;
4551 +                                                       }
4552 +                                                       new[wi++] = value;
4553 +                                                       new[wi++] = value;
4554 +                                               } else {
4555 +                                                       if (wi + 1 > oldsize) {
4556 +                                                               return oldsize;
4557 +                                                       }
4558 +                                                       new[wi++] = value;
4559 +                                               }
4560 +                                       } /* if count > 1 */
4561 +
4562 +                                       value = cur_byte;
4563 +                                       count = 0;
4564 +
4565 +                               } /* if byte == value */
4566 +
4567 +                       } /* if count == 255 */
4568 +
4569 +               } /* if ri == 0 */
4570 +               ri++;
4571 +
4572 +       }
4573 +       if (count > 1) {
4574 +               if (wi + 3 > oldsize) {
4575 +                       return oldsize;
4576 +               }
4577 +               new[wi++] = 0;
4578 +               new[wi++] = count;
4579 +               new[wi++] = value;
4580 +       } else if (count == 1) {
4581 +               if (value == 0) {
4582 +                       if (wi + 3 > oldsize)
4583 +                               return oldsize;
4584 +                       new[wi++] = 0;
4585 +                       new[wi++] = 1;
4586 +                       new[wi++] = 0;
4587 +               } else {
4588 +                       if (wi + 2 > oldsize)
4589 +                               return oldsize;
4590 +                       new[wi++] = value;
4591 +                       new[wi++] = value;
4592 +               }
4593 +       } else { /* count == 0 */
4594 +               if (value == 0) {
4595 +                       if (wi + 2 > oldsize)
4596 +                               return oldsize;
4597 +                       new[wi++] = value;
4598 +                       new[wi++] = value;
4599 +               } else {
4600 +                       if (wi + 1 > oldsize)
4601 +                               return oldsize;
4602 +                       new[wi++] = value;
4603 +               }
4604 +       } /* if count > 1 */
4605 +
4606 +       value = cur_byte;
4607 +       count = 0;
4608 +       return wi;
4609 +}
4610 +
4611 +/* setup the rle compression functionality */
4612 +static struct __dump_compress dump_rle_compression = {
4613 +       .compress_type = DUMP_COMPRESS_RLE,
4614 +       .compress_func = dump_compress_rle,
4615 +       .compress_name = "RLE",
4616 +};
4617 +
4618 +/*
4619 + * Name: dump_compress_rle_init()
4620 + * Func: Initialize rle compression for dumping.
4621 + */
4622 +static int __init
4623 +dump_compress_rle_init(void)
4624 +{
4625 +       dump_register_compression(&dump_rle_compression);
4626 +       return 0;
4627 +}
4628 +
4629 +/*
4630 + * Name: dump_compress_rle_cleanup()
4631 + * Func: Remove rle compression for dumping.
4632 + */
4633 +static void __exit
4634 +dump_compress_rle_cleanup(void)
4635 +{
4636 +       dump_unregister_compression(DUMP_COMPRESS_RLE);
4637 +}
4638 +
4639 +/* module initialization */
4640 +module_init(dump_compress_rle_init);
4641 +module_exit(dump_compress_rle_cleanup);
4642 +
4643 +MODULE_LICENSE("GPL");
4644 +MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
4645 +MODULE_DESCRIPTION("RLE compression module for crash dump driver");
4646 Index: linux-2.6.10/drivers/dump/dump_execute.c
4647 ===================================================================
4648 --- linux-2.6.10.orig/drivers/dump/dump_execute.c       2005-04-05 19:01:49.158500672 +0800
4649 +++ linux-2.6.10/drivers/dump/dump_execute.c    2005-04-05 16:47:53.943205104 +0800
4650 @@ -0,0 +1,144 @@
4651 +/*
4652 + * The file has the common/generic dump execution code 
4653 + *
4654 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
4655 + *     Split and rewrote high level dump execute code to make use 
4656 + *     of dump method interfaces.
4657 + *
4658 + * Derived from original code in dump_base.c created by 
4659 + *     Matt Robinson <yakker@sourceforge.net>)
4660 + *     
4661 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
4662 + * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
4663 + * Copyright (C) 2002 International Business Machines Corp. 
4664 + *
4665 + * Assumes dumper and dump config settings are in place
4666 + * (invokes corresponding dumper specific routines as applicable)
4667 + *
4668 + * This code is released under version 2 of the GNU GPL.
4669 + */
4670 +#include <linux/kernel.h>
4671 +#include <linux/notifier.h>
4672 +#include <linux/dump.h>
4673 +#include <linux/delay.h>
4674 +#include <linux/reboot.h>
4675 +#include "dump_methods.h"
4676 +
4677 +struct notifier_block *dump_notifier_list; /* dump started/ended callback */
4678 +
4679 +extern int panic_timeout;
4680 +
4681 +/* Dump progress indicator */
4682 +void 
4683 +dump_speedo(int i)
4684 +{
4685 +       static const char twiddle[4] =  { '|', '\\', '-', '/' };
4686 +       printk("%c\b", twiddle[i&3]);
4687 +}
4688 +
4689 +/* Make the device ready and write out the header */
4690 +int dump_begin(void)
4691 +{
4692 +       int err = 0;
4693 +
4694 +       /* dump_dev = dump_config.dumper->dev; */
4695 +       dumper_reset();
4696 +       if ((err = dump_dev_silence())) {
4697 +               /* quiesce failed, can't risk continuing */
4698 +               /* Todo/Future: switch to alternate dump scheme if possible */
4699 +               printk("dump silence dev failed ! error %d\n", err);
4700 +               return err;
4701 +       }
4702 +
4703 +       pr_debug("Writing dump header\n");
4704 +       if ((err = dump_update_header())) {
4705 +               printk("dump update header failed ! error %d\n", err);
4706 +               dump_dev_resume();
4707 +               return err;
4708 +       }
4709 +
4710 +       dump_config.dumper->curr_offset = DUMP_BUFFER_SIZE;
4711 +
4712 +       return 0;
4713 +}
4714 +
4715 +/* 
4716 + * Write the dump terminator, a final header update and let go of 
4717 + * exclusive use of the device for dump.
4718 + */
4719 +int dump_complete(void)
4720 +{
4721 +       int ret = 0;
4722 +
4723 +       if (dump_config.level != DUMP_LEVEL_HEADER) {
4724 +               if ((ret = dump_update_end_marker())) {
4725 +                       printk("dump update end marker error %d\n", ret);
4726 +               }
4727 +               if ((ret = dump_update_header())) {
4728 +                       printk("dump update header error %d\n", ret);
4729 +               }
4730 +       }
4731 +       ret = dump_dev_resume();
4732 +
4733 +       if ((panic_timeout > 0) && (!(dump_config.flags & (DUMP_FLAGS_SOFTBOOT | DUMP_FLAGS_NONDISRUPT)))) {
4734 +               mdelay(panic_timeout * 1000);
4735 +               machine_restart(NULL);
4736 +       }
4737 +
4738 +       return ret;
4739 +}
4740 +
4741 +/* Saves all dump data */
4742 +int dump_execute_savedump(void)
4743 +{
4744 +       int ret = 0, err = 0;
4745 +
4746 +       if ((ret = dump_begin()))  {
4747 +               return ret;
4748 +       }
4749 +
4750 +       if (dump_config.level != DUMP_LEVEL_HEADER) { 
4751 +               ret = dump_sequencer();
4752 +       }
4753 +       if ((err = dump_complete())) {
4754 +               printk("Dump complete failed. Error %d\n", err);
4755 +       }
4756 +
4757 +       return ret;
4758 +}
4759 +
4760 +extern void dump_calc_bootmap_pages(void);
4761 +
4762 +/* Does all the real work:  Capture and save state */
4763 +int dump_generic_execute(const char *panic_str, const struct pt_regs *regs)
4764 +{
4765 +       int ret = 0;
4766 +
4767 +#ifdef CONFIG_DISCONTIGMEM
4768 +        printk(KERN_INFO "Reconfiguring memory bank information....\n");
4769 +        printk(KERN_INFO "This may take a while....\n");
4770 +        dump_reconfigure_mbanks();
4771 +#endif
4772 +
4773 +       if ((ret = dump_configure_header(panic_str, regs))) {
4774 +               printk("dump config header failed ! error %d\n", ret);
4775 +               return ret;     
4776 +       }
4777 +
4778 +       dump_calc_bootmap_pages();
4779 +       /* tell interested parties that a dump is about to start */
4780 +       notifier_call_chain(&dump_notifier_list, DUMP_BEGIN, 
4781 +               &dump_config.dump_device);
4782 +
4783 +       if (dump_config.level != DUMP_LEVEL_NONE)
4784 +               ret = dump_execute_savedump();
4785 +
4786 +       pr_debug("dumped %ld blocks of %d bytes each\n", 
4787 +               dump_config.dumper->count, DUMP_BUFFER_SIZE);
4788 +       
4789 +       /* tell interested parties that a dump has completed */
4790 +       notifier_call_chain(&dump_notifier_list, DUMP_END, 
4791 +               &dump_config.dump_device);
4792 +
4793 +       return ret;
4794 +}
4795 Index: linux-2.6.10/drivers/dump/dump_netdev.c
4796 ===================================================================
4797 --- linux-2.6.10.orig/drivers/dump/dump_netdev.c        2005-04-05 19:01:49.158500672 +0800
4798 +++ linux-2.6.10/drivers/dump/dump_netdev.c     2005-04-05 16:47:53.936206168 +0800
4799 @@ -0,0 +1,566 @@
4800 +/*
4801 + * Implements the dump driver interface for saving a dump via network
4802 + * interface. 
4803 + *
4804 + * Some of this code has been taken/adapted from Ingo Molnar's netconsole
4805 + * code. LKCD team expresses its thanks to Ingo.
4806 + *
4807 + * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
4808 + *     Adapted netconsole code to implement LKCD dump over the network.
4809 + *
4810 + * Nov 2002 - Bharata B. Rao <bharata@in.ibm.com>
4811 + *     Innumerable code cleanups, simplification and some fixes.
4812 + *     Netdump configuration done by ioctl instead of using module parameters.
4813 + * Oct 2003 - Prasanna S Panchamukhi <prasanna@in.ibm.com>
4814 + *     Netdump code modified to use Netpoll API's.
4815 + *
4816 + * Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
4817 + * Copyright (C) 2002 International Business Machines Corp. 
4818 + *
4819 + *  This code is released under version 2 of the GNU GPL.
4820 + */
4821 +
4822 +#include <net/tcp.h>
4823 +#include <net/udp.h>
4824 +#include <linux/delay.h>
4825 +#include <linux/random.h>
4826 +#include <linux/reboot.h>
4827 +#include <linux/module.h>
4828 +#include <linux/dump.h>
4829 +#include <linux/dump_netdev.h>
4830 +
4831 +#include <asm/unaligned.h>
4832 +
4833 +static int startup_handshake;
4834 +static int page_counter;
4835 +static unsigned long flags_global;
4836 +static int netdump_in_progress;
4837 +
4838 +/*
4839 + * security depends on the trusted path between the netconsole
4840 + * server and netconsole client, since none of the packets are
4841 + * encrypted. The random magic number protects the protocol
4842 + * against spoofing.
4843 + */
4844 +static u64 dump_magic;
4845 +
4846 +/*
4847 + * We maintain a small pool of fully-sized skbs,
4848 + * to make sure the message gets out even in
4849 + * extreme OOM situations.
4850 + */
4851 +
4852 +static void rx_hook(struct netpoll *np, int port, char *msg, int size);
4853 +int new_req = 0;
4854 +static req_t req;
4855 +
4856 +static void rx_hook(struct netpoll *np, int port, char *msg, int size)
4857 +{
4858 +       req_t * __req = (req_t *) msg;
4859 +       /* 
4860 +        * First check if were are dumping or doing startup handshake, if
4861 +        * not quickly return.
4862 +        */
4863 +
4864 +       if (!netdump_in_progress)
4865 +               return ;
4866 +
4867 +       if ((ntohl(__req->command) != COMM_GET_MAGIC) &&
4868 +           (ntohl(__req->command) != COMM_HELLO) &&
4869 +           (ntohl(__req->command) != COMM_START_WRITE_NETDUMP_ACK) &&
4870 +           (ntohl(__req->command) != COMM_START_NETDUMP_ACK) &&
4871 +           (memcmp(&__req->magic, &dump_magic, sizeof(dump_magic)) != 0))
4872 +               goto out;
4873 +
4874 +       req.magic = ntohl(__req->magic);
4875 +       req.command = ntohl(__req->command);
4876 +       req.from = ntohl(__req->from);
4877 +       req.to = ntohl(__req->to);
4878 +       req.nr = ntohl(__req->nr);
4879 +       new_req = 1;
4880 +out:
4881 +       return ;
4882 +}
4883 +static char netdump_membuf[1024 + HEADER_LEN + 1];
4884 +/*
4885 + * Fill the netdump_membuf with the header information from reply_t structure 
4886 + * and send it down to netpoll_send_udp() routine.
4887 + */
4888 +static void 
4889 +netdump_send_packet(struct netpoll *np, reply_t *reply, size_t data_len) {
4890 +       char *b;
4891 +
4892 +       b = &netdump_membuf[1];
4893 +       netdump_membuf[0] = NETCONSOLE_VERSION;
4894 +       put_unaligned(htonl(reply->nr), (u32 *) b);
4895 +       put_unaligned(htonl(reply->code), (u32 *) (b + sizeof(reply->code)));
4896 +       put_unaligned(htonl(reply->info), (u32 *) (b + sizeof(reply->code) + 
4897 +               sizeof(reply->info)));
4898 +       netpoll_send_udp(np, netdump_membuf, data_len + HEADER_LEN);
4899 +}
4900 +
4901 +static void
4902 +dump_send_mem(struct netpoll *np, req_t *req, const char* buff, size_t len)
4903 +{
4904 +       int i;
4905 +
4906 +       int nr_chunks = len/1024;
4907 +       reply_t reply;
4908 +
4909 +       reply.nr = req->nr;
4910 +       reply.code = REPLY_MEM;
4911 +        if ( nr_chunks <= 0)
4912 +                nr_chunks = 1;
4913 +       for (i = 0; i < nr_chunks; i++) {
4914 +               unsigned int offset = i*1024;
4915 +               reply.info = offset;
4916 +               memcpy((netdump_membuf + HEADER_LEN), (buff + offset), 1024);
4917 +               netdump_send_packet(np, &reply, 1024);
4918 +       }
4919 +}
4920 +
4921 +/*
4922 + * This function waits for the client to acknowledge the receipt
4923 + * of the netdump startup reply, with the possibility of packets
4924 + * getting lost. We resend the startup packet if no ACK is received,
4925 + * after a 1 second delay.
4926 + *
4927 + * (The client can test the success of the handshake via the HELLO
4928 + * command, and send ACKs until we enter netdump mode.)
4929 + */
4930 +static int
4931 +dump_handshake(struct dump_dev *net_dev)
4932 +{
4933 +       reply_t reply;
4934 +       int i, j;
4935 +       size_t str_len;
4936 +
4937 +       if (startup_handshake) {
4938 +               sprintf((netdump_membuf + HEADER_LEN), 
4939 +                       "NETDUMP start, waiting for start-ACK.\n");
4940 +               reply.code = REPLY_START_NETDUMP;
4941 +               reply.nr = 0;
4942 +               reply.info = 0;
4943 +       } else {
4944 +               sprintf((netdump_membuf + HEADER_LEN), 
4945 +                       "NETDUMP start, waiting for start-ACK.\n");
4946 +               reply.code = REPLY_START_WRITE_NETDUMP;
4947 +               reply.nr = net_dev->curr_offset;
4948 +               reply.info = net_dev->curr_offset;
4949 +       }
4950 +       str_len = strlen(netdump_membuf + HEADER_LEN);
4951 +       
4952 +       /* send 300 handshake packets before declaring failure */
4953 +       for (i = 0; i < 300; i++) {
4954 +               netdump_send_packet(&net_dev->np, &reply, str_len);
4955 +
4956 +               /* wait 1 sec */
4957 +               for (j = 0; j < 10000; j++) {
4958 +                       udelay(100);
4959 +                       netpoll_poll(&net_dev->np);
4960 +                       if (new_req)
4961 +                               break;
4962 +               }
4963 +
4964 +               /* 
4965 +                * if there is no new request, try sending the handshaking
4966 +                * packet again
4967 +                */
4968 +               if (!new_req)
4969 +                       continue;
4970 +
4971 +               /* 
4972 +                * check if the new request is of the expected type,
4973 +                * if so, return, else try sending the handshaking
4974 +                * packet again
4975 +                */
4976 +               if (startup_handshake) {
4977 +                       if (req.command == COMM_HELLO || req.command ==
4978 +                               COMM_START_NETDUMP_ACK) {
4979 +                               return 0;
4980 +                       } else {
4981 +                               new_req = 0;
4982 +                               continue;
4983 +                       }
4984 +               } else {
4985 +                       if (req.command == COMM_SEND_MEM) {
4986 +                               return 0;
4987 +                       } else {
4988 +                               new_req = 0;
4989 +                               continue;
4990 +                       }
4991 +               }
4992 +       }
4993 +       return -1;
4994 +}
4995 +
4996 +static ssize_t
4997 +do_netdump(struct dump_dev *net_dev, const char* buff, size_t len)
4998 +{
4999 +       reply_t reply;
5000 +       ssize_t  ret = 0;
5001 +       int repeatCounter, counter, total_loop;
5002 +       size_t str_len;
5003 +       
5004 +       netdump_in_progress = 1;
5005 +
5006 +       if (dump_handshake(net_dev) < 0) {
5007 +               printk("network dump failed due to handshake failure\n");
5008 +               goto out;
5009 +       }
5010 +
5011 +       /*
5012 +        * Ideally startup handshake should be done during dump configuration,
5013 +        * i.e., in dump_net_open(). This will be done when I figure out
5014 +        * the dependency between startup handshake, subsequent write and
5015 +        * various commands wrt to net-server.
5016 +        */
5017 +       if (startup_handshake)
5018 +               startup_handshake = 0;
5019 +
5020 +        counter = 0;
5021 +       repeatCounter = 0;
5022 +       total_loop = 0;
5023 +       while (1) {
5024 +                if (!new_req) {
5025 +                       netpoll_poll(&net_dev->np);
5026 +               }
5027 +               if (!new_req) {
5028 +                       repeatCounter++;
5029 +
5030 +                       if (repeatCounter > 5) {
5031 +                               counter++;
5032 +                               if (counter > 10000) {
5033 +                                       if (total_loop >= 100000) {
5034 +                                               printk("Time OUT LEAVE NOW\n");
5035 +                                               goto out;
5036 +                                       } else {
5037 +                                               total_loop++;
5038 +                                               printk("Try number %d out of "
5039 +                                                       "10 before Time Out\n",
5040 +                                                       total_loop);
5041 +                                       }
5042 +                               }
5043 +                               mdelay(1);
5044 +                               repeatCounter = 0;
5045 +                       }       
5046 +                       continue;
5047 +               }
5048 +               repeatCounter = 0;
5049 +               counter = 0;
5050 +               total_loop = 0;
5051 +               new_req = 0;
5052 +               switch (req.command) {
5053 +               case COMM_NONE:
5054 +                       break;
5055 +
5056 +               case COMM_SEND_MEM:
5057 +                       dump_send_mem(&net_dev->np, &req, buff, len);
5058 +                       break;
5059 +
5060 +               case COMM_EXIT:
5061 +                case COMM_START_WRITE_NETDUMP_ACK:
5062 +                       ret = len;
5063 +                       goto out;
5064 +
5065 +               case COMM_HELLO:
5066 +                       sprintf((netdump_membuf + HEADER_LEN), 
5067 +                               "Hello, this is netdump version " "0.%02d\n",
5068 +                                NETCONSOLE_VERSION);
5069 +                       str_len = strlen(netdump_membuf + HEADER_LEN);
5070 +                       reply.code = REPLY_HELLO;
5071 +                       reply.nr = req.nr;
5072 +                        reply.info = net_dev->curr_offset;
5073 +                       netdump_send_packet(&net_dev->np, &reply, str_len);
5074 +                       break;
5075 +
5076 +               case COMM_GET_PAGE_SIZE:
5077 +                       sprintf((netdump_membuf + HEADER_LEN), 
5078 +                               "PAGE_SIZE: %ld\n", PAGE_SIZE);
5079 +                       str_len = strlen(netdump_membuf + HEADER_LEN);
5080 +                       reply.code = REPLY_PAGE_SIZE;
5081 +                       reply.nr = req.nr;
5082 +                       reply.info = PAGE_SIZE;
5083 +                       netdump_send_packet(&net_dev->np, &reply, str_len);
5084 +                       break;
5085 +
5086 +               case COMM_GET_NR_PAGES:
5087 +                       reply.code = REPLY_NR_PAGES;
5088 +                       reply.nr = req.nr;
5089 +                       reply.info = num_physpages;
5090 +                       reply.info = page_counter;
5091 +                       sprintf((netdump_membuf + HEADER_LEN), 
5092 +                               "Number of pages: %ld\n", num_physpages);
5093 +                       str_len = strlen(netdump_membuf + HEADER_LEN);
5094 +                       netdump_send_packet(&net_dev->np, &reply, str_len);
5095 +                       break;
5096 +
5097 +               case COMM_GET_MAGIC:
5098 +                       reply.code = REPLY_MAGIC;
5099 +                       reply.nr = req.nr;
5100 +                       reply.info = NETCONSOLE_VERSION;
5101 +                       sprintf((netdump_membuf + HEADER_LEN), 
5102 +                               (char *)&dump_magic, sizeof(dump_magic));
5103 +                       str_len = strlen(netdump_membuf + HEADER_LEN);
5104 +                       netdump_send_packet(&net_dev->np, &reply, str_len);
5105 +                       break;
5106 +
5107 +               default:
5108 +                       reply.code = REPLY_ERROR;
5109 +                       reply.nr = req.nr;
5110 +                       reply.info = req.command;
5111 +                       sprintf((netdump_membuf + HEADER_LEN), 
5112 +                               "Got unknown command code %d!\n", req.command);
5113 +                       str_len = strlen(netdump_membuf + HEADER_LEN);
5114 +                       netdump_send_packet(&net_dev->np, &reply, str_len);
5115 +                       break;
5116 +               }
5117 +       }
5118 +out:
5119 +       netdump_in_progress = 0;
5120 +       return ret;
5121 +}
5122 +
5123 +static int
5124 +dump_validate_config(struct netpoll *np)
5125 +{
5126 +       if (!np->local_ip) {
5127 +               printk("network device %s has no local address, "
5128 +                               "aborting.\n", np->name);
5129 +               return -1;
5130 +       }
5131 +
5132 +#define IP(x) ((unsigned char *)&np->local_ip)[x]
5133 +       printk("Source %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
5134 +#undef IP
5135 +
5136 +       if (!np->local_port) {
5137 +               printk("source_port parameter not specified, aborting.\n");
5138 +               return -1;
5139 +       }
5140 +
5141 +       if (!np->remote_ip) {
5142 +               printk("target_ip parameter not specified, aborting.\n");
5143 +               return -1;
5144 +       }
5145 +
5146 +       np->remote_ip = ntohl(np->remote_ip);
5147 +#define IP(x) ((unsigned char *)&np->remote_ip)[x]
5148 +       printk("Target %d.%d.%d.%d", IP(0), IP(1), IP(2), IP(3));
5149 +#undef IP
5150 +
5151 +       if (!np->remote_port) {
5152 +               printk("target_port parameter not specified, aborting.\n");
5153 +               return -1;
5154 +       }
5155 +       printk("Target Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x",
5156 +               np->remote_mac[0], np->remote_mac[1], np->remote_mac[2], 
5157 +               np->remote_mac[3], np->remote_mac[4], np->remote_mac[5]);
5158 +
5159 +       if ((np->remote_mac[0] & np->remote_mac[1] & np->remote_mac[2] & 
5160 +               np->remote_mac[3] & np->remote_mac[4] & np->remote_mac[5]) == 255)
5161 +               printk("(Broadcast)");
5162 +       printk("\n");
5163 +       return 0;
5164 +}
5165 +
5166 +/*
5167 + * Prepares the dump device so we can take a dump later. 
5168 + * Validates the netdump configuration parameters.
5169 + *
5170 + * TODO: Network connectivity check should be done here.
5171 + */
5172 +static int
5173 +dump_net_open(struct dump_dev *net_dev, unsigned long arg)
5174 +{
5175 +       int retval = 0;
5176 +
5177 +       /* get the interface name */
5178 +       if (copy_from_user(net_dev->np.dev_name, (void *)arg, IFNAMSIZ))
5179 +               return -EFAULT;
5180 +       net_dev->np.rx_hook = rx_hook;  
5181 +       retval = netpoll_setup(&net_dev->np);
5182 +
5183 +       dump_validate_config(&net_dev->np);
5184 +       net_dev->curr_offset = 0;
5185 +       printk("Network device %s successfully configured for dumping\n",
5186 +                       net_dev->np.dev_name);
5187 +       return retval;
5188 +}
5189 +
5190 +/*
5191 + * Close the dump device and release associated resources
5192 + * Invoked when unconfiguring the dump device.
5193 + */
5194 +static int
5195 +dump_net_release(struct dump_dev *net_dev)
5196 +{
5197 +       netpoll_cleanup(&net_dev->np);
5198 +       return 0;
5199 +}
5200 +
5201 +/*
5202 + * Prepare the dump device for use (silence any ongoing activity
5203 + * and quiesce state) when the system crashes.
5204 + */
5205 +static int
5206 +dump_net_silence(struct dump_dev *net_dev)
5207 +{
5208 +       netpoll_set_trap(1);
5209 +       local_irq_save(flags_global);
5210 +        startup_handshake = 1;
5211 +       net_dev->curr_offset = 0;
5212 +       printk("Dumping to network device %s on CPU %d ...\n", net_dev->np.name,
5213 +                       smp_processor_id());
5214 +       return 0;
5215 +}
5216 +
5217 +/*
5218 + * Invoked when dumping is done. This is the time to put things back 
5219 + * (i.e. undo the effects of dump_block_silence) so the device is 
5220 + * available for normal use.
5221 + */
5222 +static int
5223 +dump_net_resume(struct dump_dev *net_dev)
5224 +{
5225 +       int indx;
5226 +       size_t str_len;
5227 +       reply_t reply;
5228 +
5229 +       sprintf((netdump_membuf + HEADER_LEN), "NETDUMP end.\n");
5230 +       str_len = strlen(netdump_membuf + HEADER_LEN);
5231 +       for( indx = 0; indx < 6; indx++) {
5232 +               reply.code = REPLY_END_NETDUMP;
5233 +               reply.nr = 0;
5234 +               reply.info = 0;
5235 +               netdump_send_packet(&net_dev->np, &reply, str_len);
5236 +       }
5237 +       printk("NETDUMP END!\n");
5238 +       local_irq_restore(flags_global);
5239 +       netpoll_set_trap(0);
5240 +       startup_handshake = 0;
5241 +       return 0;
5242 +}
5243 +
5244 +/*
5245 + * Seek to the specified offset in the dump device.
5246 + * Makes sure this is a valid offset, otherwise returns an error.
5247 + */
5248 +static  int
5249 +dump_net_seek(struct dump_dev *net_dev, loff_t off)
5250 +{
5251 +       net_dev->curr_offset = off;
5252 +       return 0;
5253 +}
5254 +
5255 +/*
5256 + *
5257 + */
5258 +static int
5259 +dump_net_write(struct dump_dev *net_dev, void *buf, unsigned long len)
5260 +{
5261 +       int cnt, i, off;
5262 +       ssize_t ret;
5263 +
5264 +       cnt = len/ PAGE_SIZE;
5265 +
5266 +       for (i = 0; i < cnt; i++) {
5267 +               off = i* PAGE_SIZE;
5268 +               ret = do_netdump(net_dev, buf+off, PAGE_SIZE);
5269 +               if (ret <= 0)
5270 +                       return -1;
5271 +               net_dev->curr_offset = net_dev->curr_offset + PAGE_SIZE;
5272 +       }
5273 +       return len;
5274 +}
5275 +
5276 +/*
5277 + * check if the last dump i/o is over and ready for next request
5278 + */
5279 +static int
5280 +dump_net_ready(struct dump_dev *net_dev, void *buf)
5281 +{
5282 +       return 0;
5283 +}
5284 +
5285 +/*
5286 + * ioctl function used for configuring network dump
5287 + */
5288 +static int
5289 +dump_net_ioctl(struct dump_dev *net_dev, unsigned int cmd, unsigned long arg)
5290 +{
5291 +       switch (cmd) {
5292 +       case DIOSTARGETIP:
5293 +               net_dev->np.remote_ip= arg;
5294 +               break;
5295 +       case DIOSTARGETPORT:
5296 +               net_dev->np.remote_port = (u16)arg;
5297 +               break;
5298 +       case DIOSSOURCEPORT:
5299 +               net_dev->np.local_port = (u16)arg;
5300 +               break;
5301 +       case DIOSETHADDR:
5302 +               return copy_from_user(net_dev->np.remote_mac, (void *)arg, 6);
5303 +               break;
5304 +       case DIOGTARGETIP:
5305 +       case DIOGTARGETPORT:
5306 +       case DIOGSOURCEPORT:
5307 +       case DIOGETHADDR:
5308 +               break;
5309 +       default:
5310 +               return -EINVAL;
5311 +       }
5312 +       return 0;
5313 +}
5314 +
5315 +struct dump_dev_ops dump_netdev_ops = {
5316 +       .open           = dump_net_open,
5317 +       .release        = dump_net_release,
5318 +       .silence        = dump_net_silence,
5319 +       .resume         = dump_net_resume,
5320 +       .seek           = dump_net_seek,
5321 +       .write          = dump_net_write,
5322 +       /* .read not implemented */
5323 +       .ready          = dump_net_ready,
5324 +       .ioctl          = dump_net_ioctl
5325 +};
5326 +
5327 +static struct dump_dev default_dump_netdev = {
5328 +       .type_name = "networkdev", 
5329 +       .ops = &dump_netdev_ops, 
5330 +       .curr_offset = 0,
5331 +       .np.name = "netdump",
5332 +       .np.dev_name = "eth0",
5333 +       .np.rx_hook = rx_hook,
5334 +       .np.local_port = 6688,
5335 +       .np.remote_port = 6688,
5336 +       .np.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
5337 +};
5338 +
5339 +static int __init
5340 +dump_netdev_init(void)
5341 +{
5342 +       default_dump_netdev.curr_offset = 0;
5343 +
5344 +       if (dump_register_device(&default_dump_netdev) < 0) {
5345 +               printk("network dump device driver registration failed\n");
5346 +               return -1;
5347 +       }
5348 +       printk("network device driver for LKCD registered\n");
5349
5350 +       get_random_bytes(&dump_magic, sizeof(dump_magic));
5351 +       return 0;
5352 +}
5353 +
5354 +static void __exit
5355 +dump_netdev_cleanup(void)
5356 +{
5357 +       dump_unregister_device(&default_dump_netdev);
5358 +}
5359 +
5360 +MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
5361 +MODULE_DESCRIPTION("Network Dump Driver for Linux Kernel Crash Dump (LKCD)");
5362 +MODULE_LICENSE("GPL");
5363 +
5364 +module_init(dump_netdev_init);
5365 +module_exit(dump_netdev_cleanup);
5366 Index: linux-2.6.10/drivers/dump/dump_x8664.c
5367 ===================================================================
5368 --- linux-2.6.10.orig/drivers/dump/dump_x8664.c 2005-04-05 19:01:49.158500672 +0800
5369 +++ linux-2.6.10/drivers/dump/dump_x8664.c      2005-04-05 16:47:53.932206776 +0800
5370 @@ -0,0 +1,362 @@
5371 +/*
5372 + * Architecture specific (x86-64) functions for Linux crash dumps.
5373 + *
5374 + * Created by: Matt Robinson (yakker@sgi.com)
5375 + *
5376 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
5377 + *
5378 + * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
5379 + * Copyright 2000 TurboLinux, Inc.  All rights reserved.
5380 + *
5381 + * x86-64 port Copyright 2002 Andi Kleen, SuSE Labs
5382 + * x86-64 port Sachin Sant ( sachinp@in.ibm.com )
5383 + * This code is released under version 2 of the GNU GPL.
5384 + */
5385 +
5386 +/*
5387 + * The hooks for dumping the kernel virtual memory to disk are in this
5388 + * file.  Any time a modification is made to the virtual memory mechanism,
5389 + * these routines must be changed to use the new mechanisms.
5390 + */
5391 +#include <linux/init.h>
5392 +#include <linux/types.h>
5393 +#include <linux/kernel.h>
5394 +#include <linux/smp.h>
5395 +#include <linux/fs.h>
5396 +#include <linux/vmalloc.h>
5397 +#include <linux/dump.h>
5398 +#include "dump_methods.h"
5399 +#include <linux/mm.h>
5400 +#include <linux/rcupdate.h>
5401 +#include <asm/processor.h>
5402 +#include <asm/hardirq.h>
5403 +#include <asm/kdebug.h>
5404 +#include <asm/uaccess.h>
5405 +#include <asm/nmi.h>
5406 +#include <asm/kdebug.h>
5407 +
5408 +static __s32   saved_irq_count; /* saved preempt_count() flag */
5409 +
5410 +void (*dump_trace_ptr)(struct pt_regs *);
5411 +
5412 +static int alloc_dha_stack(void)
5413 +{
5414 +       int i;
5415 +       void *ptr;
5416 +       
5417 +       if (dump_header_asm.dha_stack[0])
5418 +               return 0;
5419 +
5420 +               ptr = vmalloc(THREAD_SIZE * num_online_cpus());
5421 +       if (!ptr) {
5422 +               printk("vmalloc for dha_stacks failed\n");
5423 +               return -ENOMEM;
5424 +       }
5425 +
5426 +       for (i = 0; i < num_online_cpus(); i++) {
5427 +               dump_header_asm.dha_stack[i] = 
5428 +                       (uint64_t)((unsigned long)ptr + (i * THREAD_SIZE));
5429 +       }
5430 +       return 0;
5431 +}
5432 +
5433 +static int free_dha_stack(void) 
5434 +{
5435 +       if (dump_header_asm.dha_stack[0]) {
5436 +               vfree((void *)dump_header_asm.dha_stack[0]);    
5437 +               dump_header_asm.dha_stack[0] = 0;
5438 +       }       
5439 +       return 0;
5440 +}
5441 +
5442 +void
5443 +__dump_save_regs(struct pt_regs* dest_regs, const struct pt_regs* regs)
5444 +{
5445 +       if (regs)
5446 +               memcpy(dest_regs, regs, sizeof(struct pt_regs));
5447 +}
5448 +
5449 +void
5450 +__dump_save_context(int cpu, const struct pt_regs *regs, 
5451 +       struct task_struct *tsk)
5452 +{
5453 +       dump_header_asm.dha_smp_current_task[cpu] = (unsigned long)tsk;
5454 +       __dump_save_regs(&dump_header_asm.dha_smp_regs[cpu], regs);
5455 +
5456 +       /* take a snapshot of the stack */
5457 +       /* doing this enables us to tolerate slight drifts on this cpu */
5458 +
5459 +       if (dump_header_asm.dha_stack[cpu]) {
5460 +               memcpy((void *)dump_header_asm.dha_stack[cpu],
5461 +                               STACK_START_POSITION(tsk),
5462 +                               THREAD_SIZE);
5463 +       }
5464 +       dump_header_asm.dha_stack_ptr[cpu] = (unsigned long)(tsk->thread_info);
5465 +}
5466 +
5467 +#ifdef CONFIG_SMP
5468 +extern cpumask_t irq_affinity[];
5469 +extern irq_desc_t irq_desc[];
5470 +extern void dump_send_ipi(void);
5471 +static int dump_expect_ipi[NR_CPUS];
5472 +static atomic_t waiting_for_dump_ipi;
5473 +static unsigned long saved_affinity[NR_IRQS];
5474 +
5475 +extern void stop_this_cpu(void *);
5476 +
5477 +static int
5478 +dump_nmi_callback(struct pt_regs *regs, int cpu) 
5479 +{
5480 +       if (!dump_expect_ipi[cpu]) {
5481 +               return 0;
5482 +       }
5483 +       
5484 +       dump_expect_ipi[cpu] = 0;
5485 +
5486 +       dump_save_this_cpu(regs);
5487 +       atomic_dec(&waiting_for_dump_ipi);
5488 +
5489 +level_changed:
5490 +
5491 +       switch (dump_silence_level) {
5492 +        case DUMP_HARD_SPIN_CPUS:       /* Spin until dump is complete */
5493 +                while (dump_oncpu) {
5494 +                        barrier();      /* paranoia */
5495 +                        if (dump_silence_level != DUMP_HARD_SPIN_CPUS)
5496 +                                goto level_changed;
5497 +
5498 +                        cpu_relax();    /* kill time nicely */
5499 +                }
5500 +                break;
5501 +
5502 +        case DUMP_HALT_CPUS:            /* Execute halt */
5503 +                stop_this_cpu(NULL);
5504 +                break;
5505 +
5506 +        case DUMP_SOFT_SPIN_CPUS:
5507 +                /* Mark the task so it spins in schedule */
5508 +                set_tsk_thread_flag(current, TIF_NEED_RESCHED);
5509 +                break;
5510 +        }
5511 +
5512 +       return 1;
5513 +}
5514 +
5515 +/* save registers on other processors */
5516 +void 
5517 +__dump_save_other_cpus(void) 
5518 +{
5519 +       int i, cpu = smp_processor_id();
5520 +       int other_cpus = num_online_cpus() - 1;
5521 +
5522 +       if (other_cpus > 0) {
5523 +               atomic_set(&waiting_for_dump_ipi, other_cpus);
5524 +
5525 +               for (i = 0; i < NR_CPUS; i++)
5526 +                       dump_expect_ipi[i] = (i != cpu && cpu_online(i));
5527 +               
5528 +               set_nmi_callback(dump_nmi_callback);
5529 +               wmb();
5530 +
5531 +               dump_send_ipi();
5532 +
5533 +               /* may be we dont need to wait for NMI to be processed. 
5534 +                  just write out the header at the end of dumping, if
5535 +                  this IPI is not processed untill then, there probably
5536 +                  is a problem and we just fail to capture state of 
5537 +                  other cpus. */
5538 +               while(atomic_read(&waiting_for_dump_ipi) > 0)
5539 +                       cpu_relax();
5540 +
5541 +               unset_nmi_callback();
5542 +       }
5543 +       return;
5544 +}
5545 +
5546 +/*
5547 + * Routine to save the old irq affinities and change affinities of all irqs to
5548 + * the dumping cpu.
5549 + */
5550 +static void
5551 +set_irq_affinity(void)
5552 +{
5553 +       int i;
5554 +       cpumask_t cpu = CPU_MASK_NONE;
5555 +
5556 +       cpu_set(smp_processor_id(), cpu); 
5557 +       memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long));
5558 +       for (i = 0; i < NR_IRQS; i++) {
5559 +               if (irq_desc[i].handler == NULL)
5560 +                       continue;
5561 +               irq_affinity[i] = cpu;
5562 +               if (irq_desc[i].handler->set_affinity != NULL)
5563 +                       irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
5564 +       }
5565 +}
5566 +
5567 +/*
5568 + * Restore old irq affinities.
5569 + */
5570 +static void
5571 +reset_irq_affinity(void)
5572 +{
5573 +       int i;
5574 +
5575 +       memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
5576 +       for (i = 0; i < NR_IRQS; i++) {
5577 +               if (irq_desc[i].handler == NULL)
5578 +                       continue;
5579 +               if (irq_desc[i].handler->set_affinity != NULL)
5580 +                       irq_desc[i].handler->set_affinity(i, saved_affinity[i]);
5581 +       }
5582 +}
5583 +
5584 +#else /* !CONFIG_SMP */
5585 +#define set_irq_affinity()     do { } while (0)
5586 +#define reset_irq_affinity()   do { } while (0)
5587 +#define save_other_cpu_states() do { } while (0)
5588 +#endif /* !CONFIG_SMP */
5589 +
5590 +static inline void
5591 +irq_bh_save(void)
5592 +{
5593 +       saved_irq_count = irq_count();
5594 +       preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
5595 +}
5596 +
5597 +static inline void
5598 +irq_bh_restore(void)
5599 +{
5600 +       preempt_count() |= saved_irq_count;
5601 +}
5602 +
5603 +/*
5604 + * Name: __dump_irq_enable
5605 + * Func: Reset system so interrupts are enabled.
5606 + *       This is used for dump methods that require interrupts
5607 + *       Eventually, all methods will have interrupts disabled
5608 + *       and this code can be removed.
5609 + *
5610 + *     Change irq affinities
5611 + *     Re-enable interrupts
5612 + */
5613 +int
5614 +__dump_irq_enable(void)
5615 +{
5616 +        set_irq_affinity();
5617 +        irq_bh_save();
5618 +        local_irq_enable();
5619 +       return 0;
5620 +}
5621 +
5622 +/*
5623 + * Name: __dump_irq_restore
5624 + * Func: Resume the system state in an architecture-speeific way.
5625 + *
5626 + */
5627 +void
5628 +__dump_irq_restore(void)
5629 +{
5630 +        local_irq_disable();
5631 +        reset_irq_affinity();
5632 +        irq_bh_restore();
5633 +}
5634 +
5635 +/*
5636 + * Name: __dump_configure_header()
5637 + * Func: Configure the dump header with all proper values.
5638 + */
5639 +int
5640 +__dump_configure_header(const struct pt_regs *regs)
5641 +{
5642 +       /* Dummy function - return */
5643 +       return (0);
5644 +}
5645 +
5646 +static int notify(struct notifier_block *nb, unsigned long code, void *data)
5647 +{
5648 +       if (code == DIE_NMI_IPI && dump_oncpu)
5649 +               return NOTIFY_BAD; 
5650 +       return NOTIFY_DONE; 
5651 +} 
5652 +
5653 +static struct notifier_block dump_notifier = { 
5654 +       .notifier_call = notify,        
5655 +}; 
5656 +
5657 +/*
5658 + * Name: __dump_init()
5659 + * Func: Initialize the dumping routine process.
5660 + */
5661 +void
5662 +__dump_init(uint64_t local_memory_start)
5663 +{
5664 +       notifier_chain_register(&die_chain, &dump_notifier);
5665 +}
5666 +
5667 +/*
5668 + * Name: __dump_open()
5669 + * Func: Open the dump device (architecture specific).  This is in
5670 + *       case it's necessary in the future.
5671 + */
5672 +void
5673 +__dump_open(void)
5674 +{
5675 +       alloc_dha_stack();
5676 +       /* return */
5677 +       return;
5678 +}
5679 +
5680 +/*
5681 + * Name: __dump_cleanup()
5682 + * Func: Free any architecture specific data structures. This is called
5683 + *       when the dump module is being removed.
5684 + */
5685 +void
5686 +__dump_cleanup(void)
5687 +{
5688 +       free_dha_stack();
5689 +       notifier_chain_unregister(&die_chain, &dump_notifier);
5690 +       synchronize_kernel(); 
5691 +       return;
5692 +}
5693 +
5694 +extern int page_is_ram(unsigned long);
5695 +
5696 +/*
5697 + * Name: __dump_page_valid()
5698 + * Func: Check if page is valid to dump.
5699 + */
5700 +int
5701 +__dump_page_valid(unsigned long index)
5702 +{
5703 +       if (!pfn_valid(index))
5704 +               return 0;
5705 +
5706 +       return page_is_ram(index);
5707 +}
5708 +
5709 +/*
5710 + * Name: manual_handle_crashdump()
5711 + * Func: Interface for the lkcd dump command. Calls dump_execute()
5712 + */
5713 +int
5714 +manual_handle_crashdump(void) {
5715 +
5716 +        struct pt_regs regs;
5717 +
5718 +        get_current_regs(&regs);
5719 +        dump_execute("manual", &regs);
5720 +        return 0;
5721 +}
5722 +
5723 +/*
5724 + * Name: __dump_clean_irq_state()
5725 + * Func: Clean up from the previous IRQ handling state. Such as oops from 
5726 + *       interrupt handler or bottom half.
5727 + */
5728 +void
5729 +__dump_clean_irq_state(void)
5730 +{
5731 +    return;
5732 +}
5733 Index: linux-2.6.10/drivers/dump/dump_overlay.c
5734 ===================================================================
5735 --- linux-2.6.10.orig/drivers/dump/dump_overlay.c       2005-04-05 19:01:49.158500672 +0800
5736 +++ linux-2.6.10/drivers/dump/dump_overlay.c    2005-04-05 16:47:53.934206472 +0800
5737 @@ -0,0 +1,890 @@
5738 +/*
5739 + * Two-stage soft-boot based dump scheme methods (memory overlay
5740 + * with post soft-boot writeout)
5741 + *
5742 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
5743 + *
5744 + * This approach of saving the dump in memory and writing it 
5745 + * out after a softboot without clearing memory is derived from the 
5746 + * Mission Critical Linux dump implementation. Credits and a big
5747 + * thanks for letting the lkcd project make use of the excellent 
5748 + * piece of work and also for helping with clarifications and 
5749 + * tips along the way are due to:
5750 + *     Dave Winchell <winchell@mclx.com> (primary author of mcore)
5751 + *     and also to
5752 + *     Jeff Moyer <moyer@mclx.com>
5753 + *     Josh Huber <huber@mclx.com>
5754 + * 
5755 + * For those familiar with the mcore implementation, the key 
5756 + * differences/extensions here are in allowing entire memory to be 
5757 + * saved (in compressed form) through a careful ordering scheme 
5758 + * on both the way down as well on the way up after boot, the latter
5759 + * for supporting the LKCD notion of passes in which most critical 
5760 + * data is the first to be saved to the dump device. Also the post 
5761 + * boot writeout happens from within the kernel rather than driven 
5762 + * from userspace.
5763 + *
5764 + * The sequence is orchestrated through the abstraction of "dumpers",
5765 + * one for the first stage which then sets up the dumper for the next 
5766 + * stage, providing for a smooth and flexible reuse of the singlestage 
5767 + * dump scheme methods and a handle to pass dump device configuration 
5768 + * information across the soft boot. 
5769 + *
5770 + * Copyright (C) 2002 International Business Machines Corp. 
5771 + *
5772 + * This code is released under version 2 of the GNU GPL.
5773 + */
5774 +
5775 +/*
5776 + * Disruptive dumping using the second kernel soft-boot option
5777 + * for issuing dump i/o operates in 2 stages:
5778 + * 
5779 + * (1) - Saves the (compressed & formatted) dump in memory using a 
5780 + *       carefully ordered overlay scheme designed to capture the 
5781 + *       entire physical memory or selective portions depending on 
5782 + *       dump config settings, 
5783 + *     - Registers the stage 2 dumper and 
5784 + *     - Issues a soft reboot w/o clearing memory. 
5785 + *
5786 + *     The overlay scheme starts with a small bootstrap free area
5787 + *     and follows a reverse ordering of passes wherein it 
5788 + *     compresses and saves data starting with the least critical 
5789 + *     areas first, thus freeing up the corresponding pages to 
5790 + *     serve as destination for subsequent data to be saved, and
5791 + *     so on. With a good compression ratio, this makes it feasible
5792 + *     to capture an entire physical memory dump without significantly
5793 + *     reducing memory available during regular operation.
5794 + *
5795 + * (2) Post soft-reboot, runs through the saved memory dump and
5796 + *     writes it out to disk, this time around, taking care to
5797 + *     save the more critical data first (i.e. pages which figure 
5798 + *     in early passes for a regular dump). Finally issues a 
5799 + *     clean reboot.
5800 + *     
5801 + *     Since the data was saved in memory after selection/filtering
5802 + *     and formatted as per the chosen output dump format, at this 
5803 + *     stage the filter and format actions are just dummy (or
5804 + *     passthrough) actions, except for influence on ordering of
5805 + *     passes.
5806 + */
5807 +
5808 +#include <linux/types.h>
5809 +#include <linux/kernel.h>
5810 +#include <linux/highmem.h>
5811 +#include <linux/bootmem.h>
5812 +#include <linux/dump.h>
5813 +#ifdef CONFIG_KEXEC
5814 +#include <linux/delay.h>
5815 +#include <linux/reboot.h>
5816 +#include <linux/kexec.h>
5817 +#endif
5818 +#include "dump_methods.h"
5819 +
5820 +extern struct list_head dumper_list_head;
5821 +extern struct dump_memdev *dump_memdev;
5822 +extern struct dumper dumper_stage2;
5823 +struct dump_config_block *dump_saved_config = NULL;
5824 +extern struct dump_blockdev *dump_blockdev;
5825 +static struct dump_memdev *saved_dump_memdev = NULL;
5826 +static struct dumper *saved_dumper = NULL;
5827 +
5828 +#ifdef CONFIG_KEXEC
5829 +extern int panic_timeout;
5830 +#endif
5831 +
5832 +/* For testing 
5833 +extern void dump_display_map(struct dump_memdev *);
5834 +*/
5835 +
5836 +struct dumper *dumper_by_name(char *name)
5837 +{
5838 +#ifdef LATER
5839 +       struct dumper *dumper;
5840 +       list_for_each_entry(dumper, &dumper_list_head, dumper_list)
5841 +               if (!strncmp(dumper->name, name, 32))
5842 +                       return dumper;
5843 +
5844 +       /* not found */
5845 +       return NULL; 
5846 +#endif
5847 +       /* Temporary proof of concept */
5848 +       if (!strncmp(dumper_stage2.name, name, 32))
5849 +               return &dumper_stage2;
5850 +       else
5851 +               return NULL;
5852 +}
5853 +
5854 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
5855 +extern void dump_early_reserve_map(struct dump_memdev *);
5856 +
5857 +void crashdump_reserve(void)
5858 +{
5859 +       extern unsigned long crashdump_addr;
5860 +
5861 +       if (crashdump_addr == 0xdeadbeef) 
5862 +               return;
5863 +
5864 +       /* reserve dump config and saved dump pages */
5865 +       dump_saved_config = (struct dump_config_block *)crashdump_addr;
5866 +       /* magic verification */
5867 +       if (dump_saved_config->magic != DUMP_MAGIC_LIVE) {
5868 +               printk("Invalid dump magic. Ignoring dump\n");
5869 +               dump_saved_config = NULL;
5870 +               return;
5871 +       }
5872 +                       
5873 +       printk("Dump may be available from previous boot\n");
5874 +
5875 +#ifdef CONFIG_X86_64
5876 +       reserve_bootmem_node(NODE_DATA(0), 
5877 +               virt_to_phys((void *)crashdump_addr), 
5878 +               PAGE_ALIGN(sizeof(struct dump_config_block)));
5879 +#else
5880 +       reserve_bootmem(virt_to_phys((void *)crashdump_addr), 
5881 +               PAGE_ALIGN(sizeof(struct dump_config_block)));
5882 +#endif
5883 +       dump_early_reserve_map(&dump_saved_config->memdev);
5884 +
5885 +}
5886 +#endif
5887 +
5888 +/* 
5889 + * Loads the dump configuration from a memory block saved across soft-boot
5890 + * The ops vectors need fixing up as the corresp. routines may have 
5891 + * relocated in the new soft-booted kernel.
5892 + */
5893 +int dump_load_config(struct dump_config_block *config)
5894 +{
5895 +       struct dumper *dumper;
5896 +       struct dump_data_filter *filter_table, *filter;
5897 +       struct dump_dev *dev;
5898 +       int i;
5899 +
5900 +       if (config->magic != DUMP_MAGIC_LIVE)
5901 +               return -ENOENT; /* not a valid config */
5902 +
5903 +       /* initialize generic config data */
5904 +       memcpy(&dump_config, &config->config, sizeof(dump_config));
5905 +
5906 +       /* initialize dumper state */
5907 +       if (!(dumper = dumper_by_name(config->dumper.name)))  {
5908 +               printk("dumper name mismatch\n");
5909 +               return -ENOENT; /* dumper mismatch */
5910 +       }
5911 +       
5912 +       /* verify and fixup schema */
5913 +       if (strncmp(dumper->scheme->name, config->scheme.name, 32)) {
5914 +               printk("dumper scheme mismatch\n");
5915 +               return -ENOENT; /* mismatch */
5916 +       }
5917 +       config->scheme.ops = dumper->scheme->ops;
5918 +       config->dumper.scheme = &config->scheme;
5919 +       
5920 +       /* verify and fixup filter operations */
5921 +       filter_table = dumper->filter;
5922 +       for (i = 0, filter = config->filter_table; 
5923 +               ((i < MAX_PASSES) && filter_table[i].selector); 
5924 +               i++, filter++) {
5925 +               if (strncmp(filter_table[i].name, filter->name, 32)) {
5926 +                       printk("dump filter mismatch\n");
5927 +                       return -ENOENT; /* filter name mismatch */
5928 +               }
5929 +               filter->selector = filter_table[i].selector;
5930 +       }
5931 +       config->dumper.filter = config->filter_table;
5932 +
5933 +       /* fixup format */
5934 +       if (strncmp(dumper->fmt->name, config->fmt.name, 32)) {
5935 +               printk("dump format mismatch\n");
5936 +               return -ENOENT; /* mismatch */
5937 +       }
5938 +       config->fmt.ops = dumper->fmt->ops;
5939 +       config->dumper.fmt = &config->fmt;
5940 +
5941 +       /* fixup target device */
5942 +       dev = (struct dump_dev *)(&config->dev[0]);
5943 +       if (dumper->dev == NULL) {
5944 +               pr_debug("Vanilla dumper - assume default\n");
5945 +               if (dump_dev == NULL)
5946 +                       return -ENODEV;
5947 +               dumper->dev = dump_dev;
5948 +       }
5949 +
5950 +       if (strncmp(dumper->dev->type_name, dev->type_name, 32)) { 
5951 +               printk("dump dev type mismatch %s instead of %s\n",
5952 +                               dev->type_name, dumper->dev->type_name);
5953 +               return -ENOENT; /* mismatch */
5954 +       }
5955 +       dev->ops = dumper->dev->ops; 
5956 +       config->dumper.dev = dev;
5957 +       
5958 +       /* fixup memory device containing saved dump pages */
5959 +       /* assume statically init'ed dump_memdev */
5960 +       config->memdev.ddev.ops = dump_memdev->ddev.ops; 
5961 +       /* switch to memdev from prev boot */
5962 +       saved_dump_memdev = dump_memdev; /* remember current */
5963 +       dump_memdev = &config->memdev;
5964 +
5965 +       /* Make this the current primary dumper */
5966 +       dump_config.dumper = &config->dumper;
5967 +
5968 +       return 0;
5969 +}
5970 +
5971 +/* Saves the dump configuration in a memory block for use across a soft-boot */
5972 +int dump_save_config(struct dump_config_block *config)
5973 +{
5974 +       printk("saving dump config settings\n");
5975 +
5976 +       /* dump config settings */
5977 +       memcpy(&config->config, &dump_config, sizeof(dump_config));
5978 +
5979 +       /* dumper state */
5980 +       memcpy(&config->dumper, dump_config.dumper, sizeof(struct dumper));
5981 +       memcpy(&config->scheme, dump_config.dumper->scheme, 
5982 +               sizeof(struct dump_scheme));
5983 +       memcpy(&config->fmt, dump_config.dumper->fmt, sizeof(struct dump_fmt));
5984 +       memcpy(&config->dev[0], dump_config.dumper->dev, 
5985 +               sizeof(struct dump_anydev));
5986 +       memcpy(&config->filter_table, dump_config.dumper->filter, 
5987 +               sizeof(struct dump_data_filter)*MAX_PASSES);
5988 +
5989 +       /* handle to saved mem pages */
5990 +       memcpy(&config->memdev, dump_memdev, sizeof(struct dump_memdev));
5991 +
5992 +       config->magic = DUMP_MAGIC_LIVE;
5993 +       
5994 +       return 0;
5995 +}
5996 +
5997 +int dump_init_stage2(struct dump_config_block *saved_config)
5998 +{
5999 +       int err = 0;
6000 +
6001 +       pr_debug("dump_init_stage2\n");
6002 +       /* Check if dump from previous boot exists */
6003 +       if (saved_config) {
6004 +               printk("loading dumper from previous boot \n");
6005 +               /* load and configure dumper from previous boot */
6006 +               if ((err = dump_load_config(saved_config)))
6007 +                       return err;
6008 +
6009 +               if (!dump_oncpu) {
6010 +                       if ((err = dump_configure(dump_config.dump_device))) {
6011 +                               printk("Stage 2 dump configure failed\n");
6012 +                               return err;
6013 +                       }
6014 +               }
6015 +
6016 +               dumper_reset();
6017 +               dump_dev = dump_config.dumper->dev;
6018 +               /* write out the dump */
6019 +               err = dump_generic_execute(NULL, NULL);
6020 +               
6021 +               dump_saved_config = NULL;
6022 +
6023 +               if (!dump_oncpu) {
6024 +                       dump_unconfigure(); 
6025 +               }
6026 +               
6027 +               return err;
6028 +
6029 +       } else {
6030 +               /* no dump to write out */
6031 +               printk("no dumper from previous boot \n");
6032 +               return 0;
6033 +       }
6034 +}
6035 +
6036 +extern void dump_mem_markpages(struct dump_memdev *);
6037 +
6038 +int dump_switchover_stage(void)
6039 +{
6040 +       int ret = 0;
6041 +
6042 +       /* trigger stage 2 rightaway - in real life would be after soft-boot */
6043 +       /* dump_saved_config would be a boot param */
6044 +       saved_dump_memdev = dump_memdev;
6045 +       saved_dumper = dump_config.dumper;
6046 +       ret = dump_init_stage2(dump_saved_config);
6047 +       dump_memdev = saved_dump_memdev;
6048 +       dump_config.dumper = saved_dumper;
6049 +       return ret;
6050 +}
6051 +
6052 +int dump_activate_softboot(void) 
6053 +{
6054 +        int err = 0;
6055 +#ifdef CONFIG_KEXEC
6056 +        int num_cpus_online = 0;
6057 +        struct kimage *image;
6058 +#endif
6059 +
6060 +        /* temporary - switchover to writeout previously saved dump */
6061 +#ifndef CONFIG_KEXEC
6062 +        err = dump_switchover_stage(); /* non-disruptive case */
6063 +        if (dump_oncpu)
6064 +                       dump_config.dumper = &dumper_stage1; /* set things back */
6065 +
6066 +        return err;
6067 +#else
6068 +
6069 +        dump_silence_level = DUMP_HALT_CPUS;
6070 +        /* wait till we become the only cpu */
6071 +        /* maybe by checking for online cpus ? */
6072 +
6073 +        while((num_cpus_online = num_online_cpus()) > 1);
6074 +
6075 +        /* now call into kexec */
6076 +
6077 +        image = xchg(&kexec_image, 0);
6078 +        if (image) {
6079 +                       mdelay(panic_timeout*1000);
6080 +                               machine_kexec(image);
6081 +                               }
6082 +
6083 +
6084 +        /* TBD/Fixme:
6085 +        *          * should we call reboot notifiers ? inappropriate for panic ?
6086 +        *                   * what about device_shutdown() ?
6087 +        *                            * is explicit bus master disabling needed or can we do that
6088 +        *                                     * through driverfs ?
6089 +        *                                              */
6090 +        return 0;
6091 +#endif
6092 +}
6093 +
6094 +/* --- DUMP SCHEME ROUTINES  --- */
6095 +
6096 +static inline int dump_buf_pending(struct dumper *dumper)
6097 +{
6098 +       return (dumper->curr_buf - dumper->dump_buf);
6099 +}
6100 +
6101 +/* Invoked during stage 1 of soft-reboot based dumping */
6102 +int dump_overlay_sequencer(void)
6103 +{
6104 +       struct dump_data_filter *filter = dump_config.dumper->filter;
6105 +       struct dump_data_filter *filter2 = dumper_stage2.filter;
6106 +       int pass = 0, err = 0, save = 0;
6107 +       int (*action)(unsigned long, unsigned long);
6108 +
6109 +       /* Make sure gzip compression is being used */
6110 +       if (dump_config.dumper->compress->compress_type != DUMP_COMPRESS_GZIP) {
6111 +               printk(" Please set GZIP compression \n");
6112 +               return -EINVAL;
6113 +       }
6114 +
6115 +       /* start filling in dump data right after the header */
6116 +       dump_config.dumper->curr_offset = 
6117 +               PAGE_ALIGN(dump_config.dumper->header_len);
6118 +
6119 +       /* Locate the last pass */
6120 +       for (;filter->selector; filter++, pass++);
6121 +       
6122 +       /* 
6123 +        * Start from the end backwards: overlay involves a reverse 
6124 +        * ordering of passes, since less critical pages are more
6125 +        * likely to be reusable as scratch space once we are through
6126 +        * with them. 
6127 +        */
6128 +       for (--pass, --filter; pass >= 0; pass--, filter--)
6129 +       {
6130 +               /* Assumes passes are exclusive (even across dumpers) */
6131 +               /* Requires care when coding the selection functions */
6132 +               if ((save = filter->level_mask & dump_config.level))
6133 +                       action = dump_save_data;
6134 +               else
6135 +                       action = dump_skip_data;
6136 +
6137 +               /* Remember the offset where this pass started */
6138 +               /* The second stage dumper would use this */
6139 +               if (dump_buf_pending(dump_config.dumper) & (PAGE_SIZE - 1)) {
6140 +                       pr_debug("Starting pass %d with pending data\n", pass);
6141 +                       pr_debug("filling dummy data to page-align it\n");
6142 +                       dump_config.dumper->curr_buf = (void *)PAGE_ALIGN(
6143 +                               (unsigned long)dump_config.dumper->curr_buf);
6144 +               }
6145 +               
6146 +               filter2[pass].start[0] = dump_config.dumper->curr_offset
6147 +                       + dump_buf_pending(dump_config.dumper);
6148 +
6149 +               err = dump_iterator(pass, action, filter);
6150 +
6151 +               filter2[pass].end[0] = dump_config.dumper->curr_offset
6152 +                       + dump_buf_pending(dump_config.dumper);
6153 +               filter2[pass].num_mbanks = 1;
6154 +
6155 +               if (err < 0) {
6156 +                       printk("dump_overlay_seq: failure %d in pass %d\n", 
6157 +                               err, pass);
6158 +                       break;
6159 +               }       
6160 +               printk("\n %d overlay pages %s of %d each in pass %d\n", 
6161 +               err, save ? "saved" : "skipped", DUMP_PAGE_SIZE, pass);
6162 +       }
6163 +
6164 +       return err;
6165 +}
6166 +
6167 +/* from dump_memdev.c */
6168 +extern struct page *dump_mem_lookup(struct dump_memdev *dev, unsigned long loc);
6169 +extern struct page *dump_mem_next_page(struct dump_memdev *dev);
6170 +
6171 +static inline struct page *dump_get_saved_page(loff_t loc)
6172 +{
6173 +       return (dump_mem_lookup(dump_memdev, loc >> PAGE_SHIFT));
6174 +}
6175 +
6176 +static inline struct page *dump_next_saved_page(void)
6177 +{
6178 +       return (dump_mem_next_page(dump_memdev));
6179 +}
6180 +
6181 +/* 
6182 + * Iterates over list of saved dump pages. Invoked during second stage of 
6183 + * soft boot dumping
6184 + *
6185 + * Observation: If additional selection is desired at this stage then
6186 + * a different iterator could be written which would advance 
6187 + * to the next page header everytime instead of blindly picking up
6188 + * the data. In such a case loc would be interpreted differently. 
6189 + * At this moment however a blind pass seems sufficient, cleaner and
6190 + * faster.
6191 + */
6192 +int dump_saved_data_iterator(int pass, int (*action)(unsigned long, 
6193 +       unsigned long), struct dump_data_filter *filter)
6194 +{
6195 +       loff_t loc, end;
6196 +       struct page *page;
6197 +       unsigned long count = 0;
6198 +       int i, err = 0;
6199 +       unsigned long sz;
6200 +
6201 +       for (i = 0; i < filter->num_mbanks; i++) {
6202 +               loc  = filter->start[i];
6203 +               end = filter->end[i];
6204 +               printk("pass %d, start off 0x%llx end offset 0x%llx\n", pass,
6205 +                       loc, end);
6206 +
6207 +               /* loc will get treated as logical offset into stage 1 */
6208 +               page = dump_get_saved_page(loc);
6209 +                       
6210 +               for (; loc < end; loc += PAGE_SIZE) {
6211 +                       dump_config.dumper->curr_loc = loc;
6212 +                       if (!page) {
6213 +                               printk("no more saved data for pass %d\n", 
6214 +                                       pass);
6215 +                               break;
6216 +                       }
6217 +                       sz = (loc + PAGE_SIZE > end) ? end - loc : PAGE_SIZE;
6218 +
6219 +                       if (page && filter->selector(pass, (unsigned long)page, 
6220 +                               PAGE_SIZE))  {
6221 +                               pr_debug("mem offset 0x%llx\n", loc);
6222 +                               if ((err = action((unsigned long)page, sz))) 
6223 +                                       break;
6224 +                               else
6225 +                                       count++;
6226 +                               /* clear the contents of page */
6227 +                               /* fixme: consider using KM_DUMP instead */
6228 +                               clear_highpage(page);
6229 +                       
6230 +                       }
6231 +                       page = dump_next_saved_page();
6232 +               }
6233 +       }
6234 +
6235 +       return err ? err : count;
6236 +}
6237 +
6238 +static inline int dump_overlay_pages_done(struct page *page, int nr)
6239 +{
6240 +       int ret=0;
6241 +
6242 +       for (; nr ; page++, nr--) {
6243 +               if (dump_check_and_free_page(dump_memdev, page))
6244 +                       ret++;
6245 +       }
6246 +       return ret;
6247 +}
6248 +
6249 +int dump_overlay_save_data(unsigned long loc, unsigned long len)
6250 +{
6251 +       int err = 0;
6252 +       struct page *page = (struct page *)loc;
6253 +       static unsigned long cnt = 0;
6254 +
6255 +       if ((err = dump_generic_save_data(loc, len)))
6256 +               return err;
6257 +
6258 +       if (dump_overlay_pages_done(page, len >> PAGE_SHIFT)) {
6259 +               cnt++;
6260 +               if (!(cnt & 0x7f))
6261 +                       pr_debug("released page 0x%lx\n", page_to_pfn(page));
6262 +       }
6263 +       
6264 +       return err;
6265 +}
6266 +
6267 +
6268 +int dump_overlay_skip_data(unsigned long loc, unsigned long len)
6269 +{
6270 +       struct page *page = (struct page *)loc;
6271 +
6272 +       dump_overlay_pages_done(page, len >> PAGE_SHIFT);
6273 +       return 0;
6274 +}
6275 +
6276 +int dump_overlay_resume(void)
6277 +{
6278 +       int err = 0;
6279 +
6280 +       /* 
6281 +        * switch to stage 2 dumper, save dump_config_block
6282 +        * and then trigger a soft-boot
6283 +        */
6284 +       dumper_stage2.header_len = dump_config.dumper->header_len;
6285 +       dump_config.dumper = &dumper_stage2;
6286 +       if ((err = dump_save_config(dump_saved_config)))
6287 +               return err;
6288 +
6289 +       dump_dev = dump_config.dumper->dev;
6290 +
6291 +#ifdef CONFIG_KEXEC
6292 +        /* If we are doing a disruptive dump, activate softboot now */
6293 +        if((panic_timeout > 0) && (!(dump_config.flags & DUMP_FLAGS_NONDISRUPT)))
6294 +        err = dump_activate_softboot();
6295 +#endif
6296 +               
6297 +       return err;
6298 +       err = dump_switchover_stage();  /* plugs into soft boot mechanism */
6299 +       dump_config.dumper = &dumper_stage1; /* set things back */
6300 +       return err;
6301 +}
6302 +
6303 +int dump_overlay_configure(unsigned long devid)
6304 +{
6305 +       struct dump_dev *dev;
6306 +       struct dump_config_block *saved_config = dump_saved_config;
6307 +       int err = 0;
6308 +
6309 +       /* If there is a previously saved dump, write it out first */
6310 +       if (saved_config) {
6311 +               printk("Processing old dump pending writeout\n");
6312 +               err = dump_switchover_stage();
6313 +               if (err) {
6314 +                       printk("failed to writeout saved dump\n");
6315 +                       return err;
6316 +               }
6317 +               dump_free_mem(saved_config); /* testing only: not after boot */
6318 +       }
6319 +
6320 +       dev = dumper_stage2.dev = dump_config.dumper->dev;
6321 +       /* From here on the intermediate dump target is memory-only */
6322 +       dump_dev = dump_config.dumper->dev = &dump_memdev->ddev;
6323 +       if ((err = dump_generic_configure(0))) {
6324 +               printk("dump generic configure failed: err %d\n", err);
6325 +               return err;
6326 +       }
6327 +       /* temporary */
6328 +       dumper_stage2.dump_buf = dump_config.dumper->dump_buf;
6329 +
6330 +       /* Sanity check on the actual target dump device */
6331 +       if (!dev || (err = dev->ops->open(dev, devid))) {
6332 +               return err;
6333 +       }
6334 +       /* TBD: should we release the target if this is soft-boot only ? */
6335 +
6336 +       /* alloc a dump config block area to save across reboot */
6337 +       if (!(dump_saved_config = dump_alloc_mem(sizeof(struct 
6338 +               dump_config_block)))) {
6339 +               printk("dump config block alloc failed\n");
6340 +               /* undo configure */
6341 +               dump_generic_unconfigure();
6342 +               return -ENOMEM;
6343 +       }
6344 +       dump_config.dump_addr = (unsigned long)dump_saved_config;
6345 +       printk("Dump config block of size %d set up at 0x%lx\n", 
6346 +               sizeof(*dump_saved_config), (unsigned long)dump_saved_config);
6347 +       return 0;
6348 +}
6349 +
6350 +int dump_overlay_unconfigure(void)
6351 +{
6352 +       struct dump_dev *dev = dumper_stage2.dev;
6353 +       int err = 0;
6354 +
6355 +       pr_debug("dump_overlay_unconfigure\n");
6356 +       /* Close the secondary device */
6357 +       dev->ops->release(dev); 
6358 +       pr_debug("released secondary device\n");
6359 +
6360 +       err = dump_generic_unconfigure();
6361 +       pr_debug("Unconfigured generic portions\n");
6362 +       dump_free_mem(dump_saved_config);
6363 +       dump_saved_config = NULL;
6364 +       pr_debug("Freed saved config block\n");
6365 +       dump_dev = dump_config.dumper->dev = dumper_stage2.dev;
6366 +
6367 +       printk("Unconfigured overlay dumper\n");
6368 +       return err;
6369 +}
6370 +
6371 +int dump_staged_unconfigure(void)
6372 +{
6373 +       int err = 0;
6374 +       struct dump_config_block *saved_config = dump_saved_config;
6375 +       struct dump_dev *dev;
6376 +
6377 +       pr_debug("dump_staged_unconfigure\n");
6378 +       err = dump_generic_unconfigure();
6379 +
6380 +       /* now check if there is a saved dump waiting to be written out */
6381 +       if (saved_config) {
6382 +               printk("Processing saved dump pending writeout\n");
6383 +               if ((err = dump_switchover_stage())) {
6384 +                       printk("Error in commiting saved dump at 0x%lx\n", 
6385 +                               (unsigned long)saved_config);
6386 +                       printk("Old dump may hog memory\n");
6387 +               } else {
6388 +                       dump_free_mem(saved_config);
6389 +                       pr_debug("Freed saved config block\n");
6390 +               }
6391 +               dump_saved_config = NULL;
6392 +       } else {
6393 +               dev = &dump_memdev->ddev;
6394 +               dev->ops->release(dev);
6395 +       }
6396 +       printk("Unconfigured second stage dumper\n");
6397 +
6398 +       return 0;
6399 +}
6400 +
6401 +/* ----- PASSTHRU FILTER ROUTINE --------- */
6402 +
6403 +/* transparent - passes everything through */
6404 +int dump_passthru_filter(int pass, unsigned long loc, unsigned long sz)
6405 +{
6406 +       return 1;
6407 +}
6408 +
6409 +/* ----- PASSTRU FORMAT ROUTINES ---- */
6410 +
6411 +
6412 +int dump_passthru_configure_header(const char *panic_str, const struct pt_regs *regs)
6413 +{
6414 +       dump_config.dumper->header_dirty++;
6415 +       return 0;
6416 +}
6417 +
6418 +/* Copies bytes of data from page(s) to the specified buffer */
6419 +int dump_copy_pages(void *buf, struct page *page, unsigned long sz)
6420 +{
6421 +       unsigned long len = 0, bytes;
6422 +       void *addr;
6423 +
6424 +       while (len < sz) {
6425 +               addr = kmap_atomic(page, KM_DUMP);
6426 +               bytes = (sz > len + PAGE_SIZE) ? PAGE_SIZE : sz - len;  
6427 +               memcpy(buf, addr, bytes); 
6428 +               kunmap_atomic(addr, KM_DUMP);
6429 +               buf += bytes;
6430 +               len += bytes;
6431 +               page++;
6432 +       }
6433 +       /* memset(dump_config.dumper->curr_buf, 0x57, len); temporary */
6434 +
6435 +       return sz - len;
6436 +}
6437 +
6438 +int dump_passthru_update_header(void)
6439 +{
6440 +       long len = dump_config.dumper->header_len;
6441 +       struct page *page;
6442 +       void *buf = dump_config.dumper->dump_buf;
6443 +       int err = 0;
6444 +
6445 +       if (!dump_config.dumper->header_dirty)
6446 +               return 0;
6447 +
6448 +       pr_debug("Copying header of size %ld bytes from memory\n", len);
6449 +       if (len > DUMP_BUFFER_SIZE) 
6450 +               return -E2BIG;
6451 +
6452 +       page = dump_mem_lookup(dump_memdev, 0);
6453 +       for (; (len > 0) && page; buf += PAGE_SIZE, len -= PAGE_SIZE) {
6454 +               if ((err = dump_copy_pages(buf, page, PAGE_SIZE)))
6455 +                       return err;
6456 +               page = dump_mem_next_page(dump_memdev);
6457 +       }
6458 +       if (len > 0) {
6459 +               printk("Incomplete header saved in mem\n");
6460 +               return -ENOENT;
6461 +       }
6462 +
6463 +       if ((err = dump_dev_seek(0))) {
6464 +               printk("Unable to seek to dump header offset\n");
6465 +               return err;
6466 +       }
6467 +       err = dump_ll_write(dump_config.dumper->dump_buf, 
6468 +               buf - dump_config.dumper->dump_buf);
6469 +       if (err < dump_config.dumper->header_len)
6470 +               return (err < 0) ? err : -ENOSPC;
6471 +
6472 +       dump_config.dumper->header_dirty = 0;
6473 +       return 0;
6474 +}
6475 +
6476 +static loff_t next_dph_offset = 0;
6477 +
6478 +static int dph_valid(struct __dump_page *dph)
6479 +{
6480 +       if ((dph->dp_address & (PAGE_SIZE - 1)) || (dph->dp_flags 
6481 +             > DUMP_DH_COMPRESSED) || (!dph->dp_flags) ||
6482 +               (dph->dp_size > PAGE_SIZE)) {
6483 +       printk("dp->address = 0x%llx, dp->size = 0x%x, dp->flag = 0x%x\n",
6484 +               dph->dp_address, dph->dp_size, dph->dp_flags);
6485 +               return 0;
6486 +       }
6487 +       return 1;
6488 +}
6489 +
6490 +int dump_verify_lcrash_data(void *buf, unsigned long sz)
6491 +{
6492 +       struct __dump_page *dph;
6493 +
6494 +       /* sanity check for page headers */
6495 +       while (next_dph_offset + sizeof(*dph) < sz) {
6496 +               dph = (struct __dump_page *)(buf + next_dph_offset);
6497 +               if (!dph_valid(dph)) {
6498 +                       printk("Invalid page hdr at offset 0x%llx\n",
6499 +                               next_dph_offset);
6500 +                       return -EINVAL;
6501 +               }
6502 +               next_dph_offset += dph->dp_size + sizeof(*dph);
6503 +       }
6504 +
6505 +       next_dph_offset -= sz;  
6506 +       return 0;
6507 +}
6508 +
6509 +/* 
6510 + * TBD/Later: Consider avoiding the copy by using a scatter/gather 
6511 + * vector representation for the dump buffer
6512 + */
6513 +int dump_passthru_add_data(unsigned long loc, unsigned long sz)
6514 +{
6515 +       struct page *page = (struct page *)loc;
6516 +       void *buf = dump_config.dumper->curr_buf;
6517 +       int err = 0;
6518 +
6519 +       if ((err = dump_copy_pages(buf, page, sz))) {
6520 +               printk("dump_copy_pages failed");
6521 +               return err;
6522 +       }
6523 +
6524 +       if ((err = dump_verify_lcrash_data(buf, sz))) {
6525 +               printk("dump_verify_lcrash_data failed\n");
6526 +               printk("Invalid data for pfn 0x%lx\n", page_to_pfn(page));
6527 +               printk("Page flags 0x%lx\n", page->flags);
6528 +               printk("Page count 0x%x\n", page_count(page));
6529 +               return err;
6530 +       }
6531 +
6532 +       dump_config.dumper->curr_buf = buf + sz;
6533 +
6534 +       return 0;
6535 +}
6536 +
6537 +
6538 +/* Stage 1 dumper: Saves compressed dump in memory and soft-boots system */
6539 +
6540 +/* Scheme to overlay saved data in memory for writeout after a soft-boot */
6541 +struct dump_scheme_ops dump_scheme_overlay_ops = {
6542 +       .configure      = dump_overlay_configure,
6543 +       .unconfigure    = dump_overlay_unconfigure,
6544 +       .sequencer      = dump_overlay_sequencer,
6545 +       .iterator       = dump_page_iterator,
6546 +       .save_data      = dump_overlay_save_data,
6547 +       .skip_data      = dump_overlay_skip_data,
6548 +       .write_buffer   = dump_generic_write_buffer
6549 +};
6550 +
6551 +struct dump_scheme dump_scheme_overlay = {
6552 +       .name           = "overlay",
6553 +       .ops            = &dump_scheme_overlay_ops
6554 +};
6555 +
6556 +
6557 +/* Stage 1 must use a good compression scheme - default to gzip */
6558 +extern struct __dump_compress dump_gzip_compression;
6559 +
6560 +struct dumper dumper_stage1 = {
6561 +       .name           = "stage1",
6562 +       .scheme         = &dump_scheme_overlay,
6563 +       .fmt            = &dump_fmt_lcrash,
6564 +       .compress       = &dump_none_compression, /* needs to be gzip */
6565 +       .filter         = dump_filter_table,
6566 +       .dev            = NULL,
6567 +};             
6568 +
6569 +/* Stage 2 dumper: Activated after softboot to write out saved dump to device */
6570 +
6571 +/* Formatter that transfers data as is (transparent) w/o further conversion */
6572 +struct dump_fmt_ops dump_fmt_passthru_ops = {
6573 +       .configure_header       = dump_passthru_configure_header,
6574 +       .update_header          = dump_passthru_update_header,
6575 +       .save_context           = NULL, /* unused */
6576 +       .add_data               = dump_passthru_add_data,
6577 +       .update_end_marker      = dump_lcrash_update_end_marker
6578 +};
6579 +
6580 +struct dump_fmt dump_fmt_passthru = {
6581 +       .name   = "passthru",
6582 +       .ops    = &dump_fmt_passthru_ops
6583 +};
6584 +
6585 +/* Filter that simply passes along any data within the range (transparent)*/
6586 +/* Note: The start and end ranges in the table are filled in at run-time */
6587 +
6588 +extern int dump_filter_none(int pass, unsigned long loc, unsigned long sz);
6589 +
6590 +struct dump_data_filter dump_passthru_filtertable[MAX_PASSES] = {
6591 +{.name = "passkern", .selector = dump_passthru_filter, 
6592 +       .level_mask = DUMP_MASK_KERN },
6593 +{.name = "passuser", .selector = dump_passthru_filter, 
6594 +       .level_mask = DUMP_MASK_USED },
6595 +{.name = "passunused", .selector = dump_passthru_filter, 
6596 +       .level_mask = DUMP_MASK_UNUSED },
6597 +{.name = "none", .selector = dump_filter_none, 
6598 +       .level_mask = DUMP_MASK_REST }
6599 +};
6600 +
6601 +
6602 +/* Scheme to handle data staged / preserved across a soft-boot */
6603 +struct dump_scheme_ops dump_scheme_staged_ops = {
6604 +       .configure      = dump_generic_configure,
6605 +       .unconfigure    = dump_staged_unconfigure,
6606 +       .sequencer      = dump_generic_sequencer,
6607 +       .iterator       = dump_saved_data_iterator,
6608 +       .save_data      = dump_generic_save_data,
6609 +       .skip_data      = dump_generic_skip_data,
6610 +       .write_buffer   = dump_generic_write_buffer
6611 +};
6612 +
6613 +struct dump_scheme dump_scheme_staged = {
6614 +       .name           = "staged",
6615 +       .ops            = &dump_scheme_staged_ops
6616 +};
6617 +
6618 +/* The stage 2 dumper comprising all these */
6619 +struct dumper dumper_stage2 = {
6620 +       .name           = "stage2",
6621 +       .scheme         = &dump_scheme_staged,
6622 +       .fmt            = &dump_fmt_passthru,
6623 +       .compress       = &dump_none_compression,
6624 +       .filter         = dump_passthru_filtertable,
6625 +       .dev            = NULL,
6626 +};             
6627 +
6628 Index: linux-2.6.10/drivers/dump/dump_memdev.c
6629 ===================================================================
6630 --- linux-2.6.10.orig/drivers/dump/dump_memdev.c        2005-04-05 19:01:49.158500672 +0800
6631 +++ linux-2.6.10/drivers/dump/dump_memdev.c     2005-04-05 16:47:53.947204496 +0800
6632 @@ -0,0 +1,655 @@
6633 +/*
6634 + * Implements the dump driver interface for saving a dump in available
6635 + * memory areas. The saved pages may be written out to persistent storage  
6636 + * after a soft reboot.
6637 + *
6638 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
6639 + *
6640 + * Copyright (C) 2002 International Business Machines Corp. 
6641 + *
6642 + * This code is released under version 2 of the GNU GPL.
6643 + *
6644 + * The approach of tracking pages containing saved dump using map pages 
6645 + * allocated as needed has been derived from the Mission Critical Linux 
6646 + * mcore dump implementation. 
6647 + *
6648 + * Credits and a big thanks for letting the lkcd project make use of 
6649 + * the excellent piece of work and also helping with clarifications 
6650 + * and tips along the way are due to:
6651 + *     Dave Winchell <winchell@mclx.com> (primary author of mcore)
6652 + *     Jeff Moyer <moyer@mclx.com>
6653 + *     Josh Huber <huber@mclx.com>
6654 + *
6655 + * For those familiar with the mcore code, the main differences worth
6656 + * noting here (besides the dump device abstraction) result from enabling 
6657 + * "high" memory pages (pages not permanently mapped in the kernel 
6658 + * address space) to be used for saving dump data (because of which a 
6659 + * simple virtual address based linked list cannot be used anymore for 
6660 + * managing free pages), an added level of indirection for faster 
6661 + * lookups during the post-boot stage, and the idea of pages being 
6662 + * made available as they get freed up while dump to memory progresses 
6663 + * rather than one time before starting the dump. The last point enables 
6664 + * a full memory snapshot to be saved starting with an initial set of 
6665 + * bootstrap pages given a good compression ratio. (See dump_overlay.c)
6666 + *
6667 + */
6668 +
6669 +/*
6670 + * -----------------MEMORY LAYOUT ------------------
6671 + * The memory space consists of a set of discontiguous pages, and
6672 + * discontiguous map pages as well, rooted in a chain of indirect
6673 + * map pages (also discontiguous). Except for the indirect maps 
6674 + * (which must be preallocated in advance), the rest of the pages 
6675 + * could be in high memory.
6676 + *
6677 + * root
6678 + *  |    ---------    --------        --------
6679 + *  -->  | .  . +|--->|  .  +|------->| . .  |       indirect 
6680 + *       --|--|---    ---|----        --|-|---      maps
6681 + *         |  |          |                     | |     
6682 + *    ------  ------   -------     ------ -------
6683 + *    | .  |  | .  |   | .  . |    | .  | |  . . |   maps 
6684 + *    --|---  --|---   --|--|--    --|--- ---|-|--
6685 + *     page    page    page page   page   page page  data
6686 + *                                                   pages
6687 + *
6688 + * Writes to the dump device happen sequentially in append mode.
6689 + * The main reason for the existence of the indirect map is
6690 + * to enable a quick way to lookup a specific logical offset in
6691 + * the saved data post-soft-boot, e.g. to writeout pages
6692 + * with more critical data first, even though such pages
6693 + * would have been compressed and copied last, being the lowest
6694 + * ranked candidates for reuse due to their criticality.
6695 + * (See dump_overlay.c)
6696 + */
6697 +#include <linux/mm.h>
6698 +#include <linux/highmem.h>
6699 +#include <linux/bootmem.h>
6700 +#include <linux/dump.h>
6701 +#include "dump_methods.h"
6702 +
6703 +#define DUMP_MAP_SZ (PAGE_SIZE / sizeof(unsigned long)) /* direct map size */
6704 +#define DUMP_IND_MAP_SZ        DUMP_MAP_SZ - 1  /* indirect map size */
6705 +#define DUMP_NR_BOOTSTRAP      64  /* no of bootstrap pages */
6706 +
6707 +extern int dump_low_page(struct page *);
6708 +
6709 +/* check if the next entry crosses a page boundary */
6710 +static inline int is_last_map_entry(unsigned long *map)
6711 +{
6712 +       unsigned long addr = (unsigned long)(map + 1);
6713 +
6714 +       return (!(addr & (PAGE_SIZE - 1)));
6715 +}
6716 +
6717 +/* Todo: should have some validation checks */
6718 +/* The last entry in the indirect map points to the next indirect map */
6719 +/* Indirect maps are referred to directly by virtual address */
6720 +static inline unsigned long *next_indirect_map(unsigned long *map)
6721 +{
6722 +       return (unsigned long *)map[DUMP_IND_MAP_SZ];
6723 +}
6724 +
6725 +#ifdef CONFIG_CRASH_DUMP_SOFTBOOT
6726 +/* Called during early bootup - fixme: make this __init */
6727 +void dump_early_reserve_map(struct dump_memdev *dev)
6728 +{
6729 +       unsigned long *map1, *map2;
6730 +       loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
6731 +       int i, j;
6732 +       
6733 +       printk("Reserve bootmap space holding previous dump of %lld pages\n",
6734 +                       last);
6735 +       map1= (unsigned long *)dev->indirect_map_root;
6736 +
6737 +       while (map1 && (off < last)) {
6738 +#ifdef CONFIG_X86_64
6739 +               reserve_bootmem_node(NODE_DATA(0), virt_to_phys((void *)map1),
6740 +                                PAGE_SIZE);
6741 +#else
6742 +               reserve_bootmem(virt_to_phys((void *)map1), PAGE_SIZE);
6743 +#endif
6744 +               for (i=0;  (i < DUMP_MAP_SZ - 1) && map1[i] && (off < last); 
6745 +                       i++, off += DUMP_MAP_SZ) {
6746 +                       pr_debug("indirect map[%d] = 0x%lx\n", i, map1[i]);
6747 +                       if (map1[i] >= max_low_pfn)
6748 +                               continue;
6749 +#ifdef CONFIG_X86_64
6750 +                       reserve_bootmem_node(NODE_DATA(0), 
6751 +                                       map1[i] << PAGE_SHIFT, PAGE_SIZE);
6752 +#else
6753 +                       reserve_bootmem(map1[i] << PAGE_SHIFT, PAGE_SIZE);
6754 +#endif
6755 +                       map2 = pfn_to_kaddr(map1[i]);
6756 +                       for (j = 0 ; (j < DUMP_MAP_SZ) && map2[j] && 
6757 +                               (off + j < last); j++) {
6758 +                               pr_debug("\t map[%d][%d] = 0x%lx\n", i, j, 
6759 +                                       map2[j]);
6760 +                               if (map2[j] < max_low_pfn) {
6761 +#ifdef CONFIG_X86_64
6762 +                                       reserve_bootmem_node(NODE_DATA(0),
6763 +                                               map2[j] << PAGE_SHIFT,
6764 +                                               PAGE_SIZE);
6765 +#else
6766 +                                       reserve_bootmem(map2[j] << PAGE_SHIFT,
6767 +                                               PAGE_SIZE);
6768 +#endif
6769 +                               }
6770 +                       }
6771 +               }
6772 +               map1 = next_indirect_map(map1);
6773 +       }
6774 +       dev->nr_free = 0; /* these pages don't belong to this boot */
6775 +}
6776 +#endif
6777 +
6778 +/* mark dump pages so that they aren't used by this kernel */
6779 +void dump_mark_map(struct dump_memdev *dev)
6780 +{
6781 +       unsigned long *map1, *map2;
6782 +       loff_t off = 0, last = dev->last_used_offset >> PAGE_SHIFT;
6783 +       struct page *page;
6784 +       int i, j;
6785 +       
6786 +       printk("Dump: marking pages in use by previous dump\n");
6787 +       map1= (unsigned long *)dev->indirect_map_root;
6788 +
6789 +       while (map1 && (off < last)) {
6790 +               page = virt_to_page(map1);      
6791 +               set_page_count(page, 1);
6792 +               for (i=0;  (i < DUMP_MAP_SZ - 1) && map1[i] && (off < last); 
6793 +                       i++, off += DUMP_MAP_SZ) {
6794 +                       pr_debug("indirect map[%d] = 0x%lx\n", i, map1[i]);
6795 +                       page = pfn_to_page(map1[i]);
6796 +                       set_page_count(page, 1);
6797 +                       map2 = kmap_atomic(page, KM_DUMP);
6798 +                       for (j = 0 ; (j < DUMP_MAP_SZ) && map2[j] && 
6799 +                               (off + j < last); j++) {
6800 +                               pr_debug("\t map[%d][%d] = 0x%lx\n", i, j, 
6801 +                                       map2[j]);
6802 +                               page = pfn_to_page(map2[j]);
6803 +                               set_page_count(page, 1);
6804 +                       }
6805 +               }
6806 +               map1 = next_indirect_map(map1);
6807 +       }
6808 +}
6809 +       
6810 +
6811 +/* 
6812 + * Given a logical offset into the mem device lookup the 
6813 + * corresponding page 
6814 + *     loc is specified in units of pages 
6815 + * Note: affects curr_map (even in the case where lookup fails)
6816 + */
6817 +struct page *dump_mem_lookup(struct dump_memdev *dump_mdev, unsigned long loc)
6818 +{
6819 +       unsigned long *map;
6820 +       unsigned long i, index = loc / DUMP_MAP_SZ;
6821 +       struct page *page = NULL;
6822 +       unsigned long curr_pfn, curr_map, *curr_map_ptr = NULL;
6823 +
6824 +       map = (unsigned long *)dump_mdev->indirect_map_root;
6825 +       if (!map) 
6826 +               return NULL;
6827 +       if (loc > dump_mdev->last_offset >> PAGE_SHIFT)
6828 +               return NULL;
6829 +
6830 +       /* 
6831 +        * first locate the right indirect map 
6832 +        * in the chain of indirect maps 
6833 +        */
6834 +       for (i = 0; i + DUMP_IND_MAP_SZ < index ; i += DUMP_IND_MAP_SZ) {
6835 +               if (!(map = next_indirect_map(map))) 
6836 +                       return NULL;
6837 +       }
6838 +       /* then the right direct map */
6839 +       /* map entries are referred to by page index */
6840 +       if ((curr_map = map[index - i])) {
6841 +               page = pfn_to_page(curr_map);
6842 +               /* update the current traversal index */
6843 +               /* dump_mdev->curr_map = &map[index - i];*/
6844 +               curr_map_ptr = &map[index - i];
6845 +       }
6846 +
6847 +       if (page)
6848 +               map = kmap_atomic(page, KM_DUMP);
6849 +       else 
6850 +               return NULL;
6851 +
6852 +       /* and finally the right entry therein */
6853 +       /* data pages are referred to by page index */
6854 +       i = index * DUMP_MAP_SZ;
6855 +       if ((curr_pfn = map[loc - i])) {
6856 +               page = pfn_to_page(curr_pfn);
6857 +               dump_mdev->curr_map = curr_map_ptr;
6858 +               dump_mdev->curr_map_offset = loc - i;
6859 +               dump_mdev->ddev.curr_offset = loc << PAGE_SHIFT;
6860 +       } else {
6861 +               page = NULL;
6862 +       }
6863 +       kunmap_atomic(map, KM_DUMP);
6864 +
6865 +       return page;
6866 +}
6867 +                       
6868 +/* 
6869 + * Retrieves a pointer to the next page in the dump device 
6870 + * Used during the lookup pass post-soft-reboot 
6871 + */
6872 +struct page *dump_mem_next_page(struct dump_memdev *dev)
6873 +{
6874 +       unsigned long i; 
6875 +       unsigned long *map;     
6876 +       struct page *page = NULL;
6877 +
6878 +       if (dev->ddev.curr_offset + PAGE_SIZE >= dev->last_offset) {
6879 +               return NULL;
6880 +       }
6881 +
6882 +       if ((i = (unsigned long)(++dev->curr_map_offset)) >= DUMP_MAP_SZ) {
6883 +               /* move to next map */  
6884 +               if (is_last_map_entry(++dev->curr_map)) {
6885 +                       /* move to the next indirect map page */
6886 +                       printk("dump_mem_next_page: go to next indirect map\n");
6887 +                       dev->curr_map = (unsigned long *)*dev->curr_map;
6888 +                       if (!dev->curr_map)
6889 +                               return NULL;
6890 +               }
6891 +               i = dev->curr_map_offset = 0;
6892 +               pr_debug("dump_mem_next_page: next map 0x%lx, entry 0x%lx\n",
6893 +                               dev->curr_map, *dev->curr_map);
6894 +
6895 +       };
6896 +       
6897 +       if (*dev->curr_map) {
6898 +               map = kmap_atomic(pfn_to_page(*dev->curr_map), KM_DUMP);
6899 +               if (map[i])
6900 +                       page = pfn_to_page(map[i]);
6901 +               kunmap_atomic(map, KM_DUMP);
6902 +               dev->ddev.curr_offset += PAGE_SIZE;
6903 +       };
6904 +
6905 +       return page;
6906 +}
6907 +
6908 +/* Copied from dump_filters.c */
6909 +static inline int kernel_page(struct page *p)
6910 +{
6911 +       /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
6912 +       return (PageReserved(p) && !PageInuse(p)) || (!PageLRU(p) && PageInuse(p));
6913 +}
6914 +
6915 +static inline int user_page(struct page *p)
6916 +{
6917 +       return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
6918 +}
6919 +
6920 +int dump_reused_by_boot(struct page *page)
6921 +{
6922 +       /* Todo
6923 +        * Checks:
6924 +        * if PageReserved 
6925 +        * if < __end + bootmem_bootmap_pages for this boot + allowance 
6926 +        * if overwritten by initrd (how to check ?)
6927 +        * Also, add more checks in early boot code
6928 +        * e.g. bootmem bootmap alloc verify not overwriting dump, and if
6929 +        * so then realloc or move the dump pages out accordingly.
6930 +        */
6931 +
6932 +       /* Temporary proof of concept hack, avoid overwriting kern pages */
6933 +
6934 +       return (kernel_page(page) || dump_low_page(page) || user_page(page));
6935 +}
6936 +
6937 +
6938 +/* Uses the free page passed in to expand available space */
6939 +int dump_mem_add_space(struct dump_memdev *dev, struct page *page)
6940 +{
6941 +       struct page *map_page;
6942 +       unsigned long *map;     
6943 +       unsigned long i; 
6944 +
6945 +       if (!dev->curr_map)
6946 +               return -ENOMEM; /* must've exhausted indirect map */
6947 +
6948 +       if (!*dev->curr_map || dev->curr_map_offset >= DUMP_MAP_SZ) {
6949 +               /* add map space */
6950 +               *dev->curr_map = page_to_pfn(page);
6951 +               dev->curr_map_offset = 0;
6952 +               return 0;
6953 +       }
6954 +
6955 +       /* add data space */
6956 +       i = dev->curr_map_offset;
6957 +       map_page = pfn_to_page(*dev->curr_map);
6958 +       map = (unsigned long *)kmap_atomic(map_page, KM_DUMP);
6959 +       map[i] = page_to_pfn(page);
6960 +       kunmap_atomic(map, KM_DUMP);
6961 +       dev->curr_map_offset = ++i;
6962 +       dev->last_offset += PAGE_SIZE;
6963 +       if (i >= DUMP_MAP_SZ) {
6964 +               /* move to next map */
6965 +               if (is_last_map_entry(++dev->curr_map)) {
6966 +                       /* move to the next indirect map page */
6967 +                       pr_debug("dump_mem_add_space: using next"
6968 +                       "indirect map\n");
6969 +                       dev->curr_map = (unsigned long *)*dev->curr_map;
6970 +               }
6971 +       }               
6972 +       return 0;
6973 +}
6974 +
6975 +
6976 +/* Caution: making a dest page invalidates existing contents of the page */
6977 +int dump_check_and_free_page(struct dump_memdev *dev, struct page *page)
6978 +{
6979 +       int err = 0;
6980 +
6981 +       /* 
6982 +        * the page can be used as a destination only if we are sure
6983 +        * it won't get overwritten by the soft-boot, and is not
6984 +        * critical for us right now.
6985 +        */
6986 +       if (dump_reused_by_boot(page))
6987 +               return 0;
6988 +
6989 +       if ((err = dump_mem_add_space(dev, page))) {
6990 +               printk("Warning: Unable to extend memdev space. Err %d\n",
6991 +               err);
6992 +               return 0;
6993 +       }
6994 +
6995 +       dev->nr_free++;
6996 +       return 1;
6997 +}
6998 +
6999 +
7000 +/* Set up the initial maps and bootstrap space  */
7001 +/* Must be called only after any previous dump is written out */
7002 +int dump_mem_open(struct dump_dev *dev, unsigned long devid)
7003 +{
7004 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
7005 +       unsigned long nr_maps, *map, *prev_map = &dump_mdev->indirect_map_root;
7006 +       void *addr;
7007 +       struct page *page;
7008 +       unsigned long i = 0;
7009 +       int err = 0;
7010 +
7011 +       /* Todo: sanity check for unwritten previous dump */
7012 +
7013 +       /* allocate pages for indirect map (non highmem area) */
7014 +       nr_maps = num_physpages / DUMP_MAP_SZ; /* maps to cover entire mem */
7015 +       for (i = 0; i < nr_maps; i += DUMP_IND_MAP_SZ) {
7016 +               if (!(map = (unsigned long *)dump_alloc_mem(PAGE_SIZE))) {
7017 +                       printk("Unable to alloc indirect map %ld\n", 
7018 +                               i / DUMP_IND_MAP_SZ);
7019 +                       return -ENOMEM;
7020 +               }
7021 +               clear_page(map);
7022 +               *prev_map = (unsigned long)map;
7023 +               prev_map = &map[DUMP_IND_MAP_SZ];
7024 +       };
7025 +               
7026 +       dump_mdev->curr_map = (unsigned long *)dump_mdev->indirect_map_root;
7027 +       dump_mdev->curr_map_offset = 0; 
7028 +
7029 +       /* 
7030 +        * allocate a few bootstrap pages: at least 1 map and 1 data page
7031 +        * plus enough to save the dump header
7032 +        */
7033 +       i = 0;
7034 +       do {
7035 +               if (!(addr = dump_alloc_mem(PAGE_SIZE))) {
7036 +                       printk("Unable to alloc bootstrap page %ld\n", i);
7037 +                       return -ENOMEM;
7038 +               }
7039 +
7040 +               page = virt_to_page(addr);
7041 +               if (dump_low_page(page)) {
7042 +                       dump_free_mem(addr);
7043 +                       continue;
7044 +               }
7045 +
7046 +               if (dump_mem_add_space(dump_mdev, page)) {
7047 +                       printk("Warning: Unable to extend memdev "
7048 +                                       "space. Err %d\n", err);
7049 +                       dump_free_mem(addr);
7050 +                       continue;
7051 +               }
7052 +               i++;
7053 +       } while (i < DUMP_NR_BOOTSTRAP);
7054 +
7055 +       printk("dump memdev init: %ld maps, %ld bootstrap pgs, %ld free pgs\n",
7056 +               nr_maps, i, dump_mdev->last_offset >> PAGE_SHIFT);
7057 +       
7058 +       dump_mdev->last_bs_offset = dump_mdev->last_offset;
7059 +
7060 +       return 0;
7061 +}
7062 +
7063 +/* Releases all pre-alloc'd pages */
7064 +int dump_mem_release(struct dump_dev *dev)
7065 +{
7066 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
7067 +       struct page *page, *map_page;
7068 +       unsigned long *map, *prev_map;
7069 +       void *addr;
7070 +       int i;
7071 +
7072 +       if (!dump_mdev->nr_free)
7073 +               return 0;
7074 +
7075 +       pr_debug("dump_mem_release\n");
7076 +       page = dump_mem_lookup(dump_mdev, 0);
7077 +       for (i = 0; page && (i < DUMP_NR_BOOTSTRAP - 1); i++) {
7078 +               if (PageHighMem(page))
7079 +                       break;
7080 +               addr = page_address(page);
7081 +               if (!addr) {
7082 +                       printk("page_address(%p) = NULL\n", page);
7083 +                       break;
7084 +               }
7085 +               pr_debug("Freeing page at 0x%lx\n", addr); 
7086 +               dump_free_mem(addr);
7087 +               if (dump_mdev->curr_map_offset >= DUMP_MAP_SZ - 1) {
7088 +                       map_page = pfn_to_page(*dump_mdev->curr_map);
7089 +                       if (PageHighMem(map_page))
7090 +                               break;
7091 +                       page = dump_mem_next_page(dump_mdev);
7092 +                       addr = page_address(map_page);
7093 +                       if (!addr) {
7094 +                               printk("page_address(%p) = NULL\n", 
7095 +                                       map_page);
7096 +                               break;
7097 +                       }
7098 +                       pr_debug("Freeing map page at 0x%lx\n", addr);
7099 +                       dump_free_mem(addr);
7100 +                       i++;
7101 +               } else {
7102 +                       page = dump_mem_next_page(dump_mdev);
7103 +               }
7104 +       }
7105 +
7106 +       /* now for the last used bootstrap page used as a map page */
7107 +       if ((i < DUMP_NR_BOOTSTRAP) && (*dump_mdev->curr_map)) {
7108 +               map_page = pfn_to_page(*dump_mdev->curr_map);
7109 +               if ((map_page) && !PageHighMem(map_page)) {
7110 +                       addr = page_address(map_page);
7111 +                       if (!addr) {
7112 +                               printk("page_address(%p) = NULL\n", map_page);
7113 +                       } else {
7114 +                               pr_debug("Freeing map page at 0x%lx\n", addr);
7115 +                               dump_free_mem(addr);
7116 +                               i++;
7117 +                       }
7118 +               }
7119 +       }
7120 +
7121 +       printk("Freed %d bootstrap pages\n", i);
7122 +
7123 +       /* free the indirect maps */
7124 +       map = (unsigned long *)dump_mdev->indirect_map_root;
7125 +
7126 +       i = 0;
7127 +       while (map) {
7128 +               prev_map = map;
7129 +               map = next_indirect_map(map);
7130 +               dump_free_mem(prev_map);
7131 +               i++;
7132 +       }
7133 +
7134 +       printk("Freed %d indirect map(s)\n", i);
7135 +
7136 +       /* Reset the indirect map */
7137 +       dump_mdev->indirect_map_root = 0;
7138 +       dump_mdev->curr_map = 0;
7139 +
7140 +       /* Reset the free list */
7141 +       dump_mdev->nr_free = 0;
7142 +
7143 +       dump_mdev->last_offset = dump_mdev->ddev.curr_offset = 0;
7144 +       dump_mdev->last_used_offset = 0;
7145 +       dump_mdev->curr_map = NULL;
7146 +       dump_mdev->curr_map_offset = 0;
7147 +       return 0;
7148 +}
7149 +
7150 +/*
7151 + * Long term:
7152 + * It is critical for this to be very strict. Cannot afford
7153 + * to have anything running and accessing memory while we overwrite 
7154 + * memory (potential risk of data corruption).
7155 + * If in doubt (e.g if a cpu is hung and not responding) just give
7156 + * up and refuse to proceed with this scheme.
7157 + *
7158 + * Note: I/O will only happen after soft-boot/switchover, so we can 
7159 + * safely disable interrupts and force stop other CPUs if this is
7160 + * going to be a disruptive dump, no matter what they
7161 + * are in the middle of.
7162 + */
7163 +/* 
7164 + * ATM Most of this is already taken care of in the nmi handler 
7165 + * We may halt the cpus rightaway if we know this is going to be disruptive 
7166 + * For now, since we've limited ourselves to overwriting free pages we
7167 + * aren't doing much here. Eventually, we'd have to wait to make sure other
7168 + * cpus aren't using memory we could be overwriting
7169 + */
7170 +int dump_mem_silence(struct dump_dev *dev)
7171 +{
7172 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
7173 +
7174 +       if (dump_mdev->last_offset > dump_mdev->last_bs_offset) {
7175 +               /* prefer to run lkcd config & start with a clean slate */
7176 +               return -EEXIST;
7177 +       }
7178 +       return 0;
7179 +}
7180 +
7181 +extern int dump_overlay_resume(void);
7182 +
7183 +/* Trigger the next stage of dumping */
7184 +int dump_mem_resume(struct dump_dev *dev)
7185 +{
7186 +       dump_overlay_resume(); 
7187 +       return 0;
7188 +}
7189 +
7190 +/* 
7191 + * Allocate mem dev pages as required and copy buffer contents into it.
7192 + * Fails if the no free pages are available
7193 + * Keeping it simple and limited for starters (can modify this over time)
7194 + *  Does not handle holes or a sparse layout
7195 + *  Data must be in multiples of PAGE_SIZE
7196 + */
7197 +int dump_mem_write(struct dump_dev *dev, void *buf, unsigned long len)
7198 +{
7199 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
7200 +       struct page *page;
7201 +       unsigned long n = 0;
7202 +       void *addr;
7203 +       unsigned long *saved_curr_map, saved_map_offset;
7204 +       int ret = 0;
7205 +
7206 +       pr_debug("dump_mem_write: offset 0x%llx, size %ld\n", 
7207 +               dev->curr_offset, len);
7208 +
7209 +       if (dev->curr_offset + len > dump_mdev->last_offset)  {
7210 +               printk("Out of space to write\n");
7211 +               return -ENOSPC;
7212 +       }
7213 +       
7214 +       if ((len & (PAGE_SIZE - 1)) || (dev->curr_offset & (PAGE_SIZE - 1)))
7215 +               return -EINVAL; /* not aligned in units of page size */
7216 +
7217 +       saved_curr_map = dump_mdev->curr_map;
7218 +       saved_map_offset = dump_mdev->curr_map_offset;
7219 +       page = dump_mem_lookup(dump_mdev, dev->curr_offset >> PAGE_SHIFT);
7220 +
7221 +       for (n = len; (n > 0) && page; n -= PAGE_SIZE, buf += PAGE_SIZE ) {
7222 +               addr = kmap_atomic(page, KM_DUMP);
7223 +               /* memset(addr, 'x', PAGE_SIZE); */
7224 +               memcpy(addr, buf, PAGE_SIZE);
7225 +               kunmap_atomic(addr, KM_DUMP);
7226 +               /* dev->curr_offset += PAGE_SIZE; */
7227 +               page = dump_mem_next_page(dump_mdev);
7228 +       }
7229 +
7230 +       dump_mdev->curr_map = saved_curr_map;
7231 +       dump_mdev->curr_map_offset = saved_map_offset;
7232 +
7233 +       if (dump_mdev->last_used_offset < dev->curr_offset)
7234 +               dump_mdev->last_used_offset = dev->curr_offset;
7235 +
7236 +       return (len - n) ? (len - n) : ret ;
7237 +}
7238 +
7239 +/* dummy - always ready */
7240 +int dump_mem_ready(struct dump_dev *dev, void *buf)
7241 +{
7242 +       return 0;
7243 +}
7244 +
7245 +/* 
7246 + * Should check for availability of space to write upto the offset 
7247 + * affects only the curr_offset; last_offset untouched 
7248 + * Keep it simple: Only allow multiples of PAGE_SIZE for now 
7249 + */
7250 +int dump_mem_seek(struct dump_dev *dev, loff_t offset)
7251 +{
7252 +       struct dump_memdev *dump_mdev = DUMP_MDEV(dev);
7253 +
7254 +       if (offset & (PAGE_SIZE - 1))
7255 +               return -EINVAL; /* allow page size units only for now */
7256 +       
7257 +       /* Are we exceeding available space ? */
7258 +       if (offset > dump_mdev->last_offset) {
7259 +               printk("dump_mem_seek failed for offset 0x%llx\n",
7260 +                       offset);
7261 +               return -ENOSPC; 
7262 +       }
7263 +
7264 +       dump_mdev->ddev.curr_offset = offset;
7265 +       return 0;
7266 +}
7267 +
7268 +struct dump_dev_ops dump_memdev_ops = {
7269 +       .open           = dump_mem_open,
7270 +       .release        = dump_mem_release,
7271 +       .silence        = dump_mem_silence,
7272 +       .resume         = dump_mem_resume,
7273 +       .seek           = dump_mem_seek,
7274 +       .write          = dump_mem_write,
7275 +       .read           = NULL, /* not implemented at the moment */
7276 +       .ready          = dump_mem_ready
7277 +};
7278 +
7279 +static struct dump_memdev default_dump_memdev = {
7280 +       .ddev = {.type_name = "memdev", .ops = &dump_memdev_ops,
7281 +                .device_id = 0x14}
7282 +       /* assume the rest of the fields are zeroed by default */
7283 +};     
7284 +       
7285 +/* may be overwritten if a previous dump exists */
7286 +struct dump_memdev *dump_memdev = &default_dump_memdev;
7287 +
7288 Index: linux-2.6.10/drivers/dump/dump_blockdev.c
7289 ===================================================================
7290 --- linux-2.6.10.orig/drivers/dump/dump_blockdev.c      2005-04-05 19:01:49.158500672 +0800
7291 +++ linux-2.6.10/drivers/dump/dump_blockdev.c   2005-04-05 16:47:53.945204800 +0800
7292 @@ -0,0 +1,469 @@
7293 +/*
7294 + * Implements the dump driver interface for saving a dump to 
7295 + * a block device through the kernel's generic low level block i/o
7296 + * routines.
7297 + *
7298 + * Started: June 2002 - Mohamed Abbas <mohamed.abbas@intel.com>
7299 + *     Moved original lkcd kiobuf dump i/o code from dump_base.c
7300 + *     to use generic dump device interfaces
7301 + *
7302 + * Sept 2002 - Bharata B. Rao <bharata@in.ibm.com>
7303 + *     Convert dump i/o to directly use bio instead of kiobuf for 2.5
7304 + *
7305 + * Oct 2002  - Suparna Bhattacharya <suparna@in.ibm.com>
7306 + *     Rework to new dumpdev.h structures, implement open/close/
7307 + *     silence, misc fixes (blocknr removal, bio_add_page usage)  
7308 + *
7309 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
7310 + * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
7311 + * Copyright (C) 2002 International Business Machines Corp. 
7312 + *
7313 + * This code is released under version 2 of the GNU GPL.
7314 + */
7315 +
7316 +#include <linux/types.h>
7317 +#include <linux/proc_fs.h>
7318 +#include <linux/module.h>
7319 +#include <linux/init.h>
7320 +#include <linux/blkdev.h>
7321 +#include <linux/bio.h>
7322 +#include <asm/hardirq.h>
7323 +#include <linux/dump.h>
7324 +#include "dump_methods.h"
7325 +
7326 +extern void *dump_page_buf;
7327 +
7328 +/* The end_io callback for dump i/o completion */
7329 +static int
7330 +dump_bio_end_io(struct bio *bio, unsigned int bytes_done, int error)
7331 +{
7332 +       struct dump_blockdev *dump_bdev;
7333 +
7334 +       if (bio->bi_size) {
7335 +               /* some bytes still left to transfer */
7336 +               return 1; /* not complete */
7337 +       }
7338 +
7339 +       dump_bdev = (struct dump_blockdev *)bio->bi_private;
7340 +       if (error) {
7341 +               printk("IO error while writing the dump, aborting\n");
7342 +       }
7343 +
7344 +       dump_bdev->err = error;
7345 +
7346 +       /* no wakeup needed, since caller polls for completion */
7347 +       return 0;
7348 +}
7349 +
7350 +/* Check if the dump bio is already mapped to the specified buffer */
7351 +static int
7352 +dump_block_map_valid(struct dump_blockdev *dev, struct page *page, 
7353 +       int len) 
7354 +{
7355 +       struct bio *bio = dev->bio;
7356 +       unsigned long bsize = 0;
7357 +
7358 +       if (!bio->bi_vcnt)
7359 +               return 0; /* first time, not mapped */
7360 +
7361 +
7362 +       if ((bio_page(bio) != page) || (len > bio->bi_vcnt << PAGE_SHIFT))
7363 +               return 0; /* buffer not mapped */
7364 +
7365 +       bsize = bdev_hardsect_size(bio->bi_bdev);
7366 +       if ((len & (PAGE_SIZE - 1)) || (len & bsize))
7367 +               return 0; /* alignment checks needed */
7368 +
7369 +       /* quick check to decide if we need to redo bio_add_page */
7370 +       if (bdev_get_queue(bio->bi_bdev)->merge_bvec_fn)
7371 +               return 0; /* device may have other restrictions */
7372 +
7373 +       return 1; /* already mapped */
7374 +}
7375 +
7376 +/* 
7377 + * Set up the dump bio for i/o from the specified buffer 
7378 + * Return value indicates whether the full buffer could be mapped or not
7379 + */
7380 +static int
7381 +dump_block_map(struct dump_blockdev *dev, void *buf, int len)
7382 +{
7383 +       struct page *page = virt_to_page(buf);
7384 +       struct bio *bio = dev->bio;
7385 +       unsigned long bsize = 0;
7386 +
7387 +       bio->bi_bdev = dev->bdev;
7388 +       bio->bi_sector = (dev->start_offset + dev->ddev.curr_offset) >> 9;
7389 +       bio->bi_idx = 0; /* reset index to the beginning */
7390 +
7391 +       if (dump_block_map_valid(dev, page, len)) {
7392 +               /* already mapped and usable rightaway */
7393 +               bio->bi_size = len; /* reset size to the whole bio */
7394 +               bio->bi_vcnt = (len + PAGE_SIZE - 1) / PAGE_SIZE; /* Set the proper vector cnt */
7395 +       } else {
7396 +               /* need to map the bio */
7397 +               bio->bi_size = 0;
7398 +               bio->bi_vcnt = 0;
7399 +               bsize = bdev_hardsect_size(bio->bi_bdev);
7400 +
7401 +               /* first a few sanity checks */
7402 +               if (len < bsize) {
7403 +                       printk("map: len less than hardsect size \n");
7404 +                       return -EINVAL;
7405 +               }
7406 +
7407 +               if ((unsigned long)buf & bsize) {
7408 +                       printk("map: not aligned \n");
7409 +                       return -EINVAL;
7410 +               }
7411 +
7412 +               /* assume contig. page aligned low mem buffer( no vmalloc) */
7413 +               if ((page_address(page) != buf) || (len & (PAGE_SIZE - 1))) {
7414 +                       printk("map: invalid buffer alignment!\n");
7415 +                       return -EINVAL; 
7416 +               }
7417 +               /* finally we can go ahead and map it */
7418 +               while (bio->bi_size < len)
7419 +                       if (bio_add_page(bio, page++, PAGE_SIZE, 0) == 0) {
7420 +                               break;
7421 +                       }
7422 +
7423 +               bio->bi_end_io = dump_bio_end_io;
7424 +               bio->bi_private = dev;
7425 +       }
7426 +
7427 +       if (bio->bi_size != len) {
7428 +               printk("map: bio size = %d not enough for len = %d!\n",
7429 +                       bio->bi_size, len);
7430 +               return -E2BIG;
7431 +       }
7432 +       return 0;
7433 +}
7434 +
7435 +static void
7436 +dump_free_bio(struct bio *bio)
7437 +{
7438 +       if (bio)
7439 +               kfree(bio->bi_io_vec);
7440 +       kfree(bio);
7441 +}
7442 +
7443 +/*
7444 + * Prepares the dump device so we can take a dump later. 
7445 + * The caller is expected to have filled up the dev_id field in the 
7446 + * block dump dev structure.
7447 + *
7448 + * At dump time when dump_block_write() is invoked it will be too 
7449 + * late to recover, so as far as possible make sure obvious errors 
7450 + * get caught right here and reported back to the caller.
7451 + */
7452 +static int
7453 +dump_block_open(struct dump_dev *dev, unsigned long arg)
7454 +{
7455 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
7456 +       struct block_device *bdev;
7457 +       int retval = 0;
7458 +       struct bio_vec *bvec;
7459 +
7460 +       /* make sure this is a valid block device */
7461 +       if (!arg) {
7462 +               retval = -EINVAL;
7463 +               goto err;
7464 +       }
7465 +
7466 +       /* Convert it to the new dev_t format */
7467 +       arg = MKDEV((arg >> OLDMINORBITS), (arg & OLDMINORMASK));
7468 +       
7469 +       /* get a corresponding block_dev struct for this */
7470 +       bdev = bdget((dev_t)arg);
7471 +       if (!bdev) {
7472 +               retval = -ENODEV;
7473 +               goto err;
7474 +       }
7475 +
7476 +       /* get the block device opened */
7477 +       if ((retval = blkdev_get(bdev, O_RDWR | O_LARGEFILE, 0))) {
7478 +               goto err1;
7479 +       }
7480 +
7481 +       if ((dump_bdev->bio = kmalloc(sizeof(struct bio), GFP_KERNEL)) 
7482 +               == NULL) {
7483 +               printk("Cannot allocate bio\n");
7484 +               retval = -ENOMEM;
7485 +               goto err2;
7486 +       }
7487 +
7488 +       bio_init(dump_bdev->bio);
7489 +
7490 +       if ((bvec = kmalloc(sizeof(struct bio_vec) * 
7491 +               (DUMP_BUFFER_SIZE >> PAGE_SHIFT), GFP_KERNEL)) == NULL) {
7492 +               retval = -ENOMEM;
7493 +               goto err3;
7494 +       }
7495 +
7496 +       /* assign the new dump dev structure */
7497 +       dump_bdev->dev_id = (dev_t)arg;
7498 +       dump_bdev->bdev = bdev;
7499 +
7500 +       /* make a note of the limit */
7501 +       dump_bdev->limit = bdev->bd_inode->i_size;
7502 +       
7503 +       /* now make sure we can map the dump buffer */
7504 +       dump_bdev->bio->bi_io_vec = bvec;
7505 +       dump_bdev->bio->bi_max_vecs = DUMP_BUFFER_SIZE >> PAGE_SHIFT;
7506 +
7507 +       retval = dump_block_map(dump_bdev, dump_config.dumper->dump_buf, 
7508 +               DUMP_BUFFER_SIZE);
7509 +               
7510 +       if (retval) {
7511 +               printk("open: dump_block_map failed, ret %d\n", retval);
7512 +               goto err3;
7513 +       }
7514 +
7515 +       printk("Block device (%d,%d) successfully configured for dumping\n",
7516 +              MAJOR(dump_bdev->dev_id),
7517 +              MINOR(dump_bdev->dev_id));
7518 +
7519 +
7520 +       /* after opening the block device, return */
7521 +       return retval;
7522 +
7523 +err3:  dump_free_bio(dump_bdev->bio);
7524 +       dump_bdev->bio = NULL;
7525 +err2:  if (bdev) blkdev_put(bdev);
7526 +               goto err;
7527 +err1:  if (bdev) bdput(bdev);
7528 +       dump_bdev->bdev = NULL;
7529 +err:   return retval;
7530 +}
7531 +
7532 +/*
7533 + * Close the dump device and release associated resources
7534 + * Invoked when unconfiguring the dump device.
7535 + */
7536 +static int
7537 +dump_block_release(struct dump_dev *dev)
7538 +{
7539 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
7540 +
7541 +       /* release earlier bdev if present */
7542 +       if (dump_bdev->bdev) {
7543 +               blkdev_put(dump_bdev->bdev);
7544 +               dump_bdev->bdev = NULL;
7545 +       }
7546 +
7547 +       dump_free_bio(dump_bdev->bio);
7548 +       dump_bdev->bio = NULL;
7549 +
7550 +       return 0;
7551 +}
7552 +
7553 +
7554 +/*
7555 + * Prepare the dump device for use (silence any ongoing activity
7556 + * and quiesce state) when the system crashes.
7557 + */
7558 +static int
7559 +dump_block_silence(struct dump_dev *dev)
7560 +{
7561 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
7562 +       struct request_queue *q = bdev_get_queue(dump_bdev->bdev);
7563 +       int ret;
7564 +
7565 +       /* If we can't get request queue lock, refuse to take the dump */
7566 +       if (!spin_trylock(q->queue_lock))
7567 +               return -EBUSY;
7568 +
7569 +       ret = elv_queue_empty(q);
7570 +       spin_unlock(q->queue_lock);
7571 +
7572 +       /* For now we assume we have the device to ourselves */
7573 +       /* Just a quick sanity check */
7574 +       if (!ret) {
7575 +               /* Warn the user and move on */
7576 +               printk(KERN_ALERT "Warning: Non-empty request queue\n");
7577 +               printk(KERN_ALERT "I/O requests in flight at dump time\n");
7578 +       }
7579 +
7580 +       /* 
7581 +        * Move to a softer level of silencing where no spin_lock_irqs 
7582 +        * are held on other cpus
7583 +        */
7584 +       dump_silence_level = DUMP_SOFT_SPIN_CPUS;       
7585 +
7586 +       ret = __dump_irq_enable();
7587 +       if (ret) {
7588 +               return ret;
7589 +       }
7590 +
7591 +       printk("Dumping to block device (%d,%d) on CPU %d ...\n",
7592 +              MAJOR(dump_bdev->dev_id), MINOR(dump_bdev->dev_id),
7593 +              smp_processor_id());
7594 +       
7595 +       return 0;
7596 +}
7597 +
7598 +/*
7599 + * Invoked when dumping is done. This is the time to put things back 
7600 + * (i.e. undo the effects of dump_block_silence) so the device is 
7601 + * available for normal use.
7602 + */
7603 +static int
7604 +dump_block_resume(struct dump_dev *dev)
7605 +{
7606 +       __dump_irq_restore();
7607 +       return 0;
7608 +}
7609 +
7610 +
7611 +/*
7612 + * Seek to the specified offset in the dump device.
7613 + * Makes sure this is a valid offset, otherwise returns an error.
7614 + */
7615 +static int
7616 +dump_block_seek(struct dump_dev *dev, loff_t off)
7617 +{
7618 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
7619 +       loff_t offset = off + dump_bdev->start_offset;
7620 +       
7621 +       if (offset & ( PAGE_SIZE - 1)) {
7622 +               printk("seek: non-page aligned\n");
7623 +               return -EINVAL;
7624 +       }
7625 +
7626 +       if (offset & (bdev_hardsect_size(dump_bdev->bdev) - 1)) {
7627 +               printk("seek: not sector aligned \n");
7628 +               return -EINVAL;
7629 +       }
7630 +
7631 +       if (offset > dump_bdev->limit) {
7632 +               printk("seek: not enough space left on device!\n");
7633 +               return -ENOSPC; 
7634 +       }
7635 +       dev->curr_offset = off;
7636 +       return 0;
7637 +}
7638 +
7639 +/*
7640 + * Write out a buffer after checking the device limitations, 
7641 + * sector sizes, etc. Assumes the buffer is in directly mapped 
7642 + * kernel address space (not vmalloc'ed).
7643 + *
7644 + * Returns: number of bytes written or -ERRNO. 
7645 + */
7646 +static int
7647 +dump_block_write(struct dump_dev *dev, void *buf, 
7648 +       unsigned long len)
7649 +{
7650 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
7651 +       loff_t offset = dev->curr_offset + dump_bdev->start_offset;
7652 +       int retval = -ENOSPC;
7653 +
7654 +       if (offset >= dump_bdev->limit) {
7655 +               printk("write: not enough space left on device!\n");
7656 +               goto out;
7657 +       }
7658 +
7659 +       /* don't write more blocks than our max limit */
7660 +       if (offset + len > dump_bdev->limit) 
7661 +               len = dump_bdev->limit - offset;
7662 +
7663 +
7664 +       retval = dump_block_map(dump_bdev, buf, len);
7665 +       if (retval){
7666 +               printk("write: dump_block_map failed! err %d\n", retval);
7667 +               goto out;
7668 +       }
7669 +
7670 +       /*
7671 +        * Write out the data to disk.
7672 +        * Assumes the entire buffer mapped to a single bio, which we can
7673 +        * submit and wait for io completion. In the future, may consider
7674 +        * increasing the dump buffer size and submitting multiple bio s 
7675 +        * for better throughput.
7676 +        */
7677 +       dump_bdev->err = -EAGAIN;
7678 +       submit_bio(WRITE, dump_bdev->bio);
7679 +
7680 +       dump_bdev->ddev.curr_offset += len;
7681 +       retval = len;
7682 + out:
7683 +       return retval;
7684 +}
7685 +
7686 +/*
7687 + * Name: dump_block_ready()
7688 + * Func: check if the last dump i/o is over and ready for next request
7689 + */
7690 +static int
7691 +dump_block_ready(struct dump_dev *dev, void *buf)
7692 +{
7693 +       struct dump_blockdev *dump_bdev = DUMP_BDEV(dev);
7694 +       request_queue_t *q = bdev_get_queue(dump_bdev->bio->bi_bdev);
7695 +
7696 +       /* check for io completion */
7697 +       if (dump_bdev->err == -EAGAIN) {
7698 +               q->unplug_fn(q);
7699 +               return -EAGAIN;
7700 +       }
7701 +
7702 +       if (dump_bdev->err) {
7703 +               printk("dump i/o err\n");
7704 +               return dump_bdev->err;
7705 +       }
7706 +
7707 +       return 0;
7708 +}
7709 +
7710 +
7711 +struct dump_dev_ops dump_blockdev_ops = {
7712 +       .open           = dump_block_open,
7713 +       .release        = dump_block_release,
7714 +       .silence        = dump_block_silence,
7715 +       .resume         = dump_block_resume,
7716 +       .seek           = dump_block_seek,
7717 +       .write          = dump_block_write,
7718 +       /* .read not implemented */
7719 +       .ready          = dump_block_ready
7720 +};
7721 +
7722 +static struct dump_blockdev default_dump_blockdev = {
7723 +       .ddev = {.type_name = "blockdev", .ops = &dump_blockdev_ops, 
7724 +                       .curr_offset = 0},
7725 +       /* 
7726 +        * leave enough room for the longest swap header possibly written 
7727 +        * written by mkswap (likely the largest page size supported by
7728 +        * the arch
7729 +        */
7730 +       .start_offset   = DUMP_HEADER_OFFSET,
7731 +       .err            = 0
7732 +       /* assume the rest of the fields are zeroed by default */
7733 +};     
7734 +       
7735 +struct dump_blockdev *dump_blockdev = &default_dump_blockdev;
7736 +
7737 +static int __init
7738 +dump_blockdev_init(void)
7739 +{
7740 +       if (dump_register_device(&dump_blockdev->ddev) < 0) {
7741 +               printk("block device driver registration failed\n");
7742 +               return -1;
7743 +       }
7744 +               
7745 +       printk("block device driver for LKCD registered\n");
7746 +       return 0;
7747 +}
7748 +
7749 +static void __exit
7750 +dump_blockdev_cleanup(void)
7751 +{
7752 +       dump_unregister_device(&dump_blockdev->ddev);
7753 +       printk("block device driver for LKCD unregistered\n");
7754 +}
7755 +
7756 +MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
7757 +MODULE_DESCRIPTION("Block Dump Driver for Linux Kernel Crash Dump (LKCD)");
7758 +MODULE_LICENSE("GPL");
7759 +
7760 +module_init(dump_blockdev_init);
7761 +module_exit(dump_blockdev_cleanup);
7762 Index: linux-2.6.10/drivers/dump/dump_fmt.c
7763 ===================================================================
7764 --- linux-2.6.10.orig/drivers/dump/dump_fmt.c   2005-04-05 19:01:49.158500672 +0800
7765 +++ linux-2.6.10/drivers/dump/dump_fmt.c        2005-04-05 16:47:53.941205408 +0800
7766 @@ -0,0 +1,407 @@
7767 +/*
7768 + * Implements the routines which handle the format specific
7769 + * aspects of dump for the default dump format.
7770 + *
7771 + * Used in single stage dumping and stage 1 of soft-boot based dumping 
7772 + * Saves data in LKCD (lcrash) format 
7773 + *
7774 + * Previously a part of dump_base.c
7775 + *
7776 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
7777 + *     Split off and reshuffled LKCD dump format code around generic
7778 + *     dump method interfaces.
7779 + *
7780 + * Derived from original code created by 
7781 + *     Matt Robinson <yakker@sourceforge.net>)
7782 + *
7783 + * Contributions from SGI, IBM, HP, MCL, and others.
7784 + *
7785 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
7786 + * Copyright (C) 2000 - 2002 TurboLinux, Inc.  All rights reserved.
7787 + * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
7788 + * Copyright (C) 2002 International Business Machines Corp. 
7789 + *
7790 + * This code is released under version 2 of the GNU GPL.
7791 + */
7792 +
7793 +#include <linux/types.h>
7794 +#include <linux/kernel.h>
7795 +#include <linux/time.h>
7796 +#include <linux/sched.h>
7797 +#include <linux/ptrace.h>
7798 +#include <linux/utsname.h>
7799 +#include <linux/dump.h>
7800 +#include <asm/dump.h>
7801 +#include "dump_methods.h"
7802 +
7803 +/*
7804 + * SYSTEM DUMP LAYOUT
7805 + * 
7806 + * System dumps are currently the combination of a dump header and a set
7807 + * of data pages which contain the system memory.  The layout of the dump
7808 + * (for full dumps) is as follows:
7809 + *
7810 + *             +-----------------------------+
7811 + *             |     generic dump header     |
7812 + *             +-----------------------------+
7813 + *             |   architecture dump header  |
7814 + *             +-----------------------------+
7815 + *             |         page header         |
7816 + *             +-----------------------------+
7817 + *             |          page data          |
7818 + *             +-----------------------------+
7819 + *             |         page header         |
7820 + *             +-----------------------------+
7821 + *             |          page data          |
7822 + *             +-----------------------------+
7823 + *             |              |              |
7824 + *             |              |              |
7825 + *             |              |              |
7826 + *             |              |              |
7827 + *             |              V              |
7828 + *             +-----------------------------+
7829 + *             |        PAGE_END header      |
7830 + *             +-----------------------------+
7831 + *
7832 + * There are two dump headers, the first which is architecture
7833 + * independent, and the other which is architecture dependent.  This
7834 + * allows different architectures to dump different data structures
7835 + * which are specific to their chipset, CPU, etc.
7836 + *
7837 + * After the dump headers come a succession of dump page headers along
7838 + * with dump pages.  The page header contains information about the page
7839 + * size, any flags associated with the page (whether it's compressed or
7840 + * not), and the address of the page.  After the page header is the page
7841 + * data, which is either compressed (or not).  Each page of data is
7842 + * dumped in succession, until the final dump header (PAGE_END) is
7843 + * placed at the end of the dump, assuming the dump device isn't out
7844 + * of space.
7845 + *
7846 + * This mechanism allows for multiple compression types, different
7847 + * types of data structures, different page ordering, etc., etc., etc.
7848 + * It's a very straightforward mechanism for dumping system memory.
7849 + */
7850 +
7851 +struct __dump_header dump_header;  /* the primary dump header              */
7852 +struct __dump_header_asm dump_header_asm; /* the arch-specific dump header */
7853 +
7854 +/* Replace a runtime sanity check on the DUMP_BUFFER_SIZE with a 
7855 + * compile-time check.  The compile_time_assertions routine will not
7856 + * compile if the assertion is false. 
7857 + *
7858 + * If you fail this assert you are most likely on a large machine and 
7859 + * should use a special 6.0.0 version of LKCD or a version > 7.0.0. See
7860 + * the LKCD website for more information.
7861 + */
7862 +
7863 +#define COMPILE_TIME_ASSERT(const_expr) \
7864 +       switch(0){case 0: case (const_expr):;}
7865 +
7866 +static inline void compile_time_assertions(void)
7867 +{
7868 +       COMPILE_TIME_ASSERT((sizeof(struct __dump_header) +
7869 +               sizeof(struct __dump_header_asm)) <= DUMP_BUFFER_SIZE);
7870 +}
7871 +
7872 +/*
7873 + *  Set up common header fields (mainly the arch indep section) 
7874 + *  Per-cpu state is handled by lcrash_save_context
7875 + *  Returns the size of the header in bytes.
7876 + */
7877 +static int lcrash_init_dump_header(const char *panic_str)
7878 +{
7879 +       struct timeval dh_time;
7880 +       u64 temp_memsz = dump_header.dh_memory_size;
7881 +
7882 +       /* initialize the dump headers to zero */
7883 +       /* save dha_stack pointer because it may contains pointer for stack! */
7884 +       memset(&dump_header, 0, sizeof(dump_header));
7885 +       memset(&dump_header_asm, 0,
7886 +               offsetof(struct __dump_header_asm, dha_stack));
7887 +       memset(&dump_header_asm.dha_stack+1, 0,
7888 +               sizeof(dump_header_asm) -
7889 +               offsetof(struct __dump_header_asm, dha_stack) -
7890 +               sizeof(dump_header_asm.dha_stack));
7891 +       dump_header.dh_memory_size = temp_memsz;
7892 +
7893 +       /* configure dump header values */
7894 +       dump_header.dh_magic_number = DUMP_MAGIC_NUMBER;
7895 +       dump_header.dh_version = DUMP_VERSION_NUMBER;
7896 +       dump_header.dh_memory_start = PAGE_OFFSET;
7897 +       dump_header.dh_memory_end = DUMP_MAGIC_NUMBER;
7898 +       dump_header.dh_header_size = sizeof(struct __dump_header);
7899 +       dump_header.dh_page_size = PAGE_SIZE;
7900 +       dump_header.dh_dump_level = dump_config.level;
7901 +       dump_header.dh_current_task = (unsigned long) current;
7902 +       dump_header.dh_dump_compress = dump_config.dumper->compress->
7903 +               compress_type;
7904 +       dump_header.dh_dump_flags = dump_config.flags;
7905 +       dump_header.dh_dump_device = dump_config.dumper->dev->device_id; 
7906 +
7907 +#if DUMP_DEBUG >= 6
7908 +       dump_header.dh_num_bytes = 0;
7909 +#endif
7910 +       dump_header.dh_num_dump_pages = 0;
7911 +       do_gettimeofday(&dh_time);
7912 +       dump_header.dh_time.tv_sec = dh_time.tv_sec;
7913 +       dump_header.dh_time.tv_usec = dh_time.tv_usec;
7914 +
7915 +       memcpy((void *)&(dump_header.dh_utsname_sysname), 
7916 +               (const void *)&(system_utsname.sysname), __NEW_UTS_LEN + 1);
7917 +       memcpy((void *)&(dump_header.dh_utsname_nodename), 
7918 +               (const void *)&(system_utsname.nodename), __NEW_UTS_LEN + 1);
7919 +       memcpy((void *)&(dump_header.dh_utsname_release), 
7920 +               (const void *)&(system_utsname.release), __NEW_UTS_LEN + 1);
7921 +       memcpy((void *)&(dump_header.dh_utsname_version), 
7922 +               (const void *)&(system_utsname.version), __NEW_UTS_LEN + 1);
7923 +       memcpy((void *)&(dump_header.dh_utsname_machine), 
7924 +               (const void *)&(system_utsname.machine), __NEW_UTS_LEN + 1);
7925 +       memcpy((void *)&(dump_header.dh_utsname_domainname), 
7926 +               (const void *)&(system_utsname.domainname), __NEW_UTS_LEN + 1);
7927 +
7928 +       if (panic_str) {
7929 +               memcpy((void *)&(dump_header.dh_panic_string),
7930 +                       (const void *)panic_str, DUMP_PANIC_LEN);
7931 +       }
7932 +
7933 +        dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER;
7934 +        dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER;
7935 +        dump_header_asm.dha_header_size = sizeof(dump_header_asm);
7936 +#ifdef CONFIG_ARM
7937 +       dump_header_asm.dha_physaddr_start = PHYS_OFFSET;
7938 +#endif
7939 +
7940 +       dump_header_asm.dha_smp_num_cpus = num_online_cpus();
7941 +       pr_debug("smp_num_cpus in header %d\n", 
7942 +               dump_header_asm.dha_smp_num_cpus);
7943 +
7944 +       dump_header_asm.dha_dumping_cpu = smp_processor_id();
7945 +       
7946 +       return sizeof(dump_header) + sizeof(dump_header_asm);
7947 +}
7948 +
7949 +
7950 +int dump_lcrash_configure_header(const char *panic_str, 
7951 +       const struct pt_regs *regs)
7952 +{
7953 +       int retval = 0;
7954 +
7955 +       dump_config.dumper->header_len = lcrash_init_dump_header(panic_str);
7956 +
7957 +       /* capture register states for all processors */
7958 +       dump_save_this_cpu(regs);
7959 +       __dump_save_other_cpus(); /* side effect:silence cpus */
7960 +
7961 +       /* configure architecture-specific dump header values */
7962 +       if ((retval = __dump_configure_header(regs))) 
7963 +               return retval;
7964 +
7965 +       dump_config.dumper->header_dirty++;
7966 +       return 0;
7967 +}
7968 +/* save register and task context */
7969 +void dump_lcrash_save_context(int cpu, const struct pt_regs *regs, 
7970 +       struct task_struct *tsk)
7971 +{
7972 +       /* This level of abstraction might be redundantly redundant */
7973 +       __dump_save_context(cpu, regs, tsk);
7974 +}
7975 +
7976 +/* write out the header */
7977 +int dump_write_header(void)
7978 +{
7979 +       int retval = 0, size;
7980 +       void *buf = dump_config.dumper->dump_buf;
7981 +
7982 +       /* accounts for DUMP_HEADER_OFFSET if applicable */
7983 +       if ((retval = dump_dev_seek(0))) {
7984 +               printk("Unable to seek to dump header offset: %d\n", 
7985 +                       retval);
7986 +               return retval;
7987 +       }
7988 +
7989 +       memcpy(buf, (void *)&dump_header, sizeof(dump_header));
7990 +       size = sizeof(dump_header);
7991 +       memcpy(buf + size, (void *)&dump_header_asm, sizeof(dump_header_asm));
7992 +       size += sizeof(dump_header_asm);
7993 +       size = PAGE_ALIGN(size);
7994 +       retval = dump_ll_write(buf , size);
7995 +
7996 +       if (retval < size) 
7997 +               return (retval >= 0) ? ENOSPC : retval;
7998 +       return 0;
7999 +}
8000 +
8001 +int dump_generic_update_header(void)
8002 +{
8003 +       int err = 0;
8004 +
8005 +       if (dump_config.dumper->header_dirty) {
8006 +               if ((err = dump_write_header())) {
8007 +                       printk("dump write header failed !err %d\n", err);
8008 +               } else {
8009 +                       dump_config.dumper->header_dirty = 0;
8010 +               }
8011 +       }
8012 +
8013 +       return err;
8014 +}
8015 +
8016 +static inline int is_curr_stack_page(struct page *page, unsigned long size)
8017 +{
8018 +       unsigned long thread_addr = (unsigned long)current_thread_info();
8019 +       unsigned long addr = (unsigned long)page_address(page);
8020 +
8021 +       return !PageHighMem(page) && (addr < thread_addr + THREAD_SIZE)
8022 +               && (addr + size > thread_addr);
8023 +}
8024 +
8025 +static inline int is_dump_page(struct page *page, unsigned long size)
8026 +{
8027 +       unsigned long addr = (unsigned long)page_address(page);
8028 +       unsigned long dump_buf = (unsigned long)dump_config.dumper->dump_buf;
8029 +
8030 +       return !PageHighMem(page) && (addr < dump_buf + DUMP_BUFFER_SIZE)
8031 +               && (addr + size > dump_buf);
8032 +}
8033 +
8034 +int dump_allow_compress(struct page *page, unsigned long size)
8035 +{
8036 +       /*
8037 +        * Don't compress the page if any part of it overlaps
8038 +        * with the current stack or dump buffer (since the contents
8039 +        * in these could be changing while compression is going on)
8040 +        */
8041 +       return !is_curr_stack_page(page, size) && !is_dump_page(page, size);
8042 +}
8043 +
8044 +void lcrash_init_pageheader(struct __dump_page *dp, struct page *page, 
8045 +       unsigned long sz)
8046 +{
8047 +       memset(dp, sizeof(struct __dump_page), 0);
8048 +       dp->dp_flags = 0; 
8049 +       dp->dp_size = 0;
8050 +       if (sz > 0)
8051 +               dp->dp_address = (loff_t)page_to_pfn(page) << PAGE_SHIFT;
8052 +
8053 +#if DUMP_DEBUG > 6
8054 +       dp->dp_page_index = dump_header.dh_num_dump_pages;
8055 +       dp->dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE
8056 +               + DUMP_HEADER_OFFSET; /* ?? */
8057 +#endif /* DUMP_DEBUG */
8058 +}
8059 +
8060 +int dump_lcrash_add_data(unsigned long loc, unsigned long len)
8061 +{
8062 +       struct page *page = (struct page *)loc;
8063 +       void *addr, *buf = dump_config.dumper->curr_buf;
8064 +       struct __dump_page *dp = (struct __dump_page *)buf; 
8065 +       int bytes, size;
8066 +
8067 +       if (buf > dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE)
8068 +               return -ENOMEM;
8069 +
8070 +       lcrash_init_pageheader(dp, page, len);
8071 +       buf += sizeof(struct __dump_page);
8072 +
8073 +       while (len) {
8074 +               addr = kmap_atomic(page, KM_DUMP);
8075 +               size = bytes = (len > PAGE_SIZE) ? PAGE_SIZE : len;     
8076 +               /* check for compression */
8077 +               if (dump_allow_compress(page, bytes)) {
8078 +                       size = dump_compress_data((char *)addr, bytes, 
8079 +                               (char *)buf, loc);
8080 +               }
8081 +               /* set the compressed flag if the page did compress */
8082 +               if (size && (size < bytes)) {
8083 +                       dp->dp_flags |= DUMP_DH_COMPRESSED;
8084 +               } else {
8085 +                       /* compression failed -- default to raw mode */
8086 +                       dp->dp_flags |= DUMP_DH_RAW;
8087 +                       memcpy(buf, addr, bytes);
8088 +                       size = bytes;
8089 +               }
8090 +               /* memset(buf, 'A', size); temporary: testing only !! */
8091 +               kunmap_atomic(addr, KM_DUMP);
8092 +               dp->dp_size += size;
8093 +               buf += size;
8094 +               len -= bytes;
8095 +               page++;
8096 +       }
8097 +
8098 +       /* now update the header */
8099 +#if DUMP_DEBUG > 6
8100 +       dump_header.dh_num_bytes += dp->dp_size + sizeof(*dp);
8101 +#endif
8102 +       dump_header.dh_num_dump_pages++;
8103 +       dump_config.dumper->header_dirty++;
8104 +
8105 +       dump_config.dumper->curr_buf = buf;     
8106 +
8107 +       return len;
8108 +}
8109 +
8110 +int dump_lcrash_update_end_marker(void)
8111 +{
8112 +       struct __dump_page *dp = 
8113 +               (struct __dump_page *)dump_config.dumper->curr_buf;
8114 +       unsigned long left;
8115 +       int ret = 0;
8116 +               
8117 +       lcrash_init_pageheader(dp, NULL, 0);
8118 +       dp->dp_flags |= DUMP_DH_END; /* tbd: truncation test ? */
8119 +       
8120 +       /* now update the header */
8121 +#if DUMP_DEBUG > 6
8122 +       dump_header.dh_num_bytes += sizeof(*dp);
8123 +#endif
8124 +       dump_config.dumper->curr_buf += sizeof(*dp);
8125 +       left = dump_config.dumper->curr_buf - dump_config.dumper->dump_buf;
8126 +
8127 +       printk("\n");
8128 +
8129 +       while (left) {
8130 +               if ((ret = dump_dev_seek(dump_config.dumper->curr_offset))) {
8131 +                       printk("Seek failed at offset 0x%llx\n", 
8132 +                       dump_config.dumper->curr_offset);
8133 +                       return ret;
8134 +               }
8135 +
8136 +               if (DUMP_BUFFER_SIZE > left) 
8137 +                       memset(dump_config.dumper->curr_buf, 'm', 
8138 +                               DUMP_BUFFER_SIZE - left);
8139 +
8140 +               if ((ret = dump_ll_write(dump_config.dumper->dump_buf, 
8141 +                       DUMP_BUFFER_SIZE)) < DUMP_BUFFER_SIZE) {
8142 +                       return (ret < 0) ? ret : -ENOSPC;
8143 +               }
8144 +
8145 +               dump_config.dumper->curr_offset += DUMP_BUFFER_SIZE;
8146 +       
8147 +               if (left > DUMP_BUFFER_SIZE) {
8148 +                       left -= DUMP_BUFFER_SIZE;
8149 +                       memcpy(dump_config.dumper->dump_buf, 
8150 +                       dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE, left);
8151 +                       dump_config.dumper->curr_buf -= DUMP_BUFFER_SIZE;
8152 +               } else {
8153 +                       left = 0;
8154 +               }
8155 +       }
8156 +       return 0;
8157 +}
8158 +
8159 +
8160 +/* Default Formatter (lcrash) */
8161 +struct dump_fmt_ops dump_fmt_lcrash_ops = {
8162 +       .configure_header       = dump_lcrash_configure_header,
8163 +       .update_header          = dump_generic_update_header,
8164 +       .save_context           = dump_lcrash_save_context,
8165 +       .add_data               = dump_lcrash_add_data,
8166 +       .update_end_marker      = dump_lcrash_update_end_marker
8167 +};
8168 +
8169 +struct dump_fmt dump_fmt_lcrash = {
8170 +       .name   = "lcrash",
8171 +       .ops    = &dump_fmt_lcrash_ops
8172 +};
8173 +
8174 Index: linux-2.6.10/drivers/dump/dump_setup.c
8175 ===================================================================
8176 --- linux-2.6.10.orig/drivers/dump/dump_setup.c 2005-04-05 19:01:49.158500672 +0800
8177 +++ linux-2.6.10/drivers/dump/dump_setup.c      2005-04-05 16:47:53.939205712 +0800
8178 @@ -0,0 +1,923 @@
8179 +/*
8180 + * Standard kernel function entry points for Linux crash dumps.
8181 + *
8182 + * Created by: Matt Robinson (yakker@sourceforge.net)
8183 + * Contributions from SGI, IBM, HP, MCL, and others.
8184 + *
8185 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
8186 + * Copyright (C) 2000 - 2002 TurboLinux, Inc.  All rights reserved.
8187 + * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
8188 + * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
8189 + *
8190 + * This code is released under version 2 of the GNU GPL.
8191 + */
8192 +
8193 +/*
8194 + * -----------------------------------------------------------------------
8195 + *
8196 + * DUMP HISTORY
8197 + *
8198 + * This dump code goes back to SGI's first attempts at dumping system
8199 + * memory on SGI systems running IRIX.  A few developers at SGI needed
8200 + * a way to take this system dump and analyze it, and created 'icrash',
8201 + * or IRIX Crash.  The mechanism (the dumps and 'icrash') were used
8202 + * by support people to generate crash reports when a system failure
8203 + * occurred.  This was vital for large system configurations that
8204 + * couldn't apply patch after patch after fix just to hope that the
8205 + * problems would go away.  So the system memory, along with the crash
8206 + * dump analyzer, allowed support people to quickly figure out what the
8207 + * problem was on the system with the crash dump.
8208 + *
8209 + * In comes Linux.  SGI started moving towards the open source community,
8210 + * and upon doing so, SGI wanted to take its support utilities into Linux
8211 + * with the hopes that they would end up the in kernel and user space to
8212 + * be used by SGI's customers buying SGI Linux systems.  One of the first
8213 + * few products to be open sourced by SGI was LKCD, or Linux Kernel Crash
8214 + * Dumps.  LKCD comprises of a patch to the kernel to enable system
8215 + * dumping, along with 'lcrash', or Linux Crash, to analyze the system
8216 + * memory dump.  A few additional system scripts and kernel modifications
8217 + * are also included to make the dump mechanism and dump data easier to
8218 + * process and use.
8219 + *
8220 + * As soon as LKCD was released into the open source community, a number
8221 + * of larger companies started to take advantage of it.  Today, there are
8222 + * many community members that contribute to LKCD, and it continues to
8223 + * flourish and grow as an open source project.
8224 + */
8225 +
8226 +/*
8227 + * DUMP TUNABLES (read/write with ioctl, readonly with /proc)
8228 + *
8229 + * This is the list of system tunables (via /proc) that are available
8230 + * for Linux systems.  All the read, write, etc., functions are listed
8231 + * here.  Currently, there are a few different tunables for dumps:
8232 + *
8233 + * dump_device (used to be dumpdev):
8234 + *     The device for dumping the memory pages out to.  This 
8235 + *     may be set to the primary swap partition for disruptive dumps,
8236 + *     and must be an unused partition for non-disruptive dumps.
8237 + *     Todo: In the case of network dumps, this may be interpreted 
8238 + *     as the IP address of the netdump server to connect to.
8239 + *
8240 + * dump_compress (used to be dump_compress_pages):
8241 + *     This is the flag which indicates which compression mechanism
8242 + *     to use.  This is a BITMASK, not an index (0,1,2,4,8,16,etc.).
8243 + *     This is the current set of values:
8244 + *
8245 + *     0: DUMP_COMPRESS_NONE -- Don't compress any pages.
8246 + *     1: DUMP_COMPRESS_RLE  -- This uses RLE compression.
8247 + *     2: DUMP_COMPRESS_GZIP -- This uses GZIP compression.
8248 + *
8249 + * dump_level:
8250 + *     The amount of effort the dump module should make to save
8251 + *     information for post crash analysis.  This value is now
8252 + *     a BITMASK value, not an index:
8253 + *
8254 + *     0:   Do nothing, no dumping. (DUMP_LEVEL_NONE)
8255 + *
8256 + *     1:   Print out the dump information to the dump header, and
8257 + *          write it out to the dump_device. (DUMP_LEVEL_HEADER)
8258 + *
8259 + *     2:   Write out the dump header and all kernel memory pages.
8260 + *          (DUMP_LEVEL_KERN)
8261 + *
8262 + *     4:   Write out the dump header and all kernel and user
8263 + *          memory pages.  (DUMP_LEVEL_USED)
8264 + *
8265 + *     8:   Write out the dump header and all conventional/cached 
8266 + *         memory (RAM) pages in the system (kernel, user, free).  
8267 + *         (DUMP_LEVEL_ALL_RAM)
8268 + *
8269 + *    16:   Write out everything, including non-conventional memory
8270 + *         like firmware, proms, I/O registers, uncached memory.
8271 + *         (DUMP_LEVEL_ALL)
8272 + *
8273 + *     The dump_level will default to 1.
8274 + *
8275 + * dump_flags:
8276 + *     These are the flags to use when talking about dumps.  There
8277 + *     are lots of possibilities.  This is a BITMASK value, not an index.
8278 + * 
8279 + * -----------------------------------------------------------------------
8280 + */
8281 +
8282 +#include <linux/kernel.h>
8283 +#include <linux/delay.h>
8284 +#include <linux/reboot.h>
8285 +#include <linux/fs.h>
8286 +#include <linux/dump.h>
8287 +#include <linux/ioctl32.h>
8288 +#include <linux/syscalls.h>
8289 +#include "dump_methods.h"
8290 +#include <linux/proc_fs.h>
8291 +#include <linux/module.h>
8292 +#include <linux/utsname.h>
8293 +#include <linux/highmem.h>
8294 +#include <linux/miscdevice.h>
8295 +#include <linux/sysrq.h>
8296 +#include <linux/sysctl.h>
8297 +#include <linux/nmi.h>
8298 +#include <linux/init.h>
8299 +#include <asm/hardirq.h>
8300 +#include <asm/uaccess.h>
8301 +
8302 +
8303 +/*
8304 + * -----------------------------------------------------------------------
8305 + *                         V A R I A B L E S
8306 + * -----------------------------------------------------------------------
8307 + */
8308 +
8309 +/* Dump tunables */
8310 +struct dump_config dump_config = {
8311 +       .level          = 0,
8312 +       .flags          = 0,
8313 +       .dump_device    = 0,
8314 +       .dump_addr      = 0,
8315 +       .dumper         = NULL
8316 +};
8317 +#ifdef CONFIG_ARM 
8318 +static _dump_regs_t all_regs;
8319 +#endif
8320 +
8321 +/* Global variables used in dump.h */
8322 +/* degree of system freeze when dumping */
8323 +enum dump_silence_levels dump_silence_level = DUMP_HARD_SPIN_CPUS;      
8324 +
8325 +/* Other global fields */
8326 +extern struct __dump_header dump_header; 
8327 +struct dump_dev *dump_dev = NULL;  /* Active dump device                   */
8328 +static int dump_compress = 0;
8329 +
8330 +static u32 dump_compress_none(const u8 *old, u32 oldsize, u8 *new, u32 newsize,
8331 +                               unsigned long loc);
8332 +struct __dump_compress dump_none_compression = {
8333 +       .compress_type  = DUMP_COMPRESS_NONE,
8334 +       .compress_func  = dump_compress_none,
8335 +       .compress_name  = "none",
8336 +};
8337 +
8338 +/* our device operations and functions */
8339 +static int dump_ioctl(struct inode *i, struct file *f,
8340 +       unsigned int cmd, unsigned long arg);
8341 +
8342 +#ifdef CONFIG_COMPAT
8343 +static int dw_long(unsigned int, unsigned int, unsigned long, struct file*);
8344 +#endif
8345 +
8346 +static struct file_operations dump_fops = {
8347 +       .owner  = THIS_MODULE,
8348 +       .ioctl  = dump_ioctl,
8349 +};
8350 +
8351 +static struct miscdevice dump_miscdev = {
8352 +       .minor  = CRASH_DUMP_MINOR,
8353 +       .name   = "dump",
8354 +       .fops   = &dump_fops,
8355 +};
8356 +MODULE_ALIAS_MISCDEV(CRASH_DUMP_MINOR);
8357 +
8358 +/* static variables                                                    */
8359 +static int dump_okay = 0;              /* can we dump out to disk?     */
8360 +static spinlock_t dump_lock = SPIN_LOCK_UNLOCKED;
8361 +
8362 +/* used for dump compressors */
8363 +static struct list_head dump_compress_list = LIST_HEAD_INIT(dump_compress_list);
8364 +
8365 +/* list of registered dump targets */
8366 +static struct list_head dump_target_list = LIST_HEAD_INIT(dump_target_list);
8367 +
8368 +/* lkcd info structure -- this is used by lcrash for basic system data     */
8369 +struct __lkcdinfo lkcdinfo = {
8370 +       .ptrsz          = (sizeof(void *) * 8),
8371 +#if defined(__LITTLE_ENDIAN) 
8372 +       .byte_order     = __LITTLE_ENDIAN,
8373 +#else
8374 +       .byte_order     = __BIG_ENDIAN,
8375 +#endif
8376 +       .page_shift     = PAGE_SHIFT,
8377 +       .page_size      = PAGE_SIZE,
8378 +       .page_mask      = PAGE_MASK,
8379 +       .page_offset    = PAGE_OFFSET,
8380 +};
8381 +
8382 +/*
8383 + * -----------------------------------------------------------------------
8384 + *            / P R O C   T U N A B L E   F U N C T I O N S
8385 + * -----------------------------------------------------------------------
8386 + */
8387 +
8388 +static int proc_dump_device(ctl_table *ctl, int write, struct file *f,
8389 +                           void __user *buffer, size_t *lenp, loff_t *ppos);
8390 +
8391 +static int proc_doulonghex(ctl_table *ctl, int write, struct file *f,
8392 +                           void __user *buffer, size_t *lenp, loff_t *ppos);
8393 +/*
8394 + * sysctl-tuning infrastructure.
8395 + */
8396 +static ctl_table dump_table[] = {
8397 +       { .ctl_name = CTL_DUMP_LEVEL,
8398 +         .procname = DUMP_LEVEL_NAME, 
8399 +         .data = &dump_config.level,    
8400 +         .maxlen = sizeof(int),
8401 +         .mode = 0444,
8402 +         .proc_handler = proc_doulonghex, },
8403 +
8404 +       { .ctl_name = CTL_DUMP_FLAGS,
8405 +         .procname = DUMP_FLAGS_NAME,
8406 +         .data = &dump_config.flags,   
8407 +         .maxlen = sizeof(int),
8408 +         .mode = 0444,
8409 +         .proc_handler = proc_doulonghex, },
8410 +
8411 +       { .ctl_name = CTL_DUMP_COMPRESS,
8412 +         .procname = DUMP_COMPRESS_NAME,
8413 +         .data = &dump_compress, /* FIXME */
8414 +         .maxlen = sizeof(int),
8415 +         .mode = 0444,
8416 +         .proc_handler = proc_dointvec, },
8417 +         
8418 +       { .ctl_name = CTL_DUMP_DEVICE,
8419 +         .procname = DUMP_DEVICE_NAME,
8420 +         .mode = 0444,
8421 +         .data = &dump_config.dump_device, /* FIXME */
8422 +         .maxlen = sizeof(int),
8423 +         .proc_handler = proc_dump_device },
8424 +
8425 +#ifdef CONFIG_CRASH_DUMP_MEMDEV
8426 +       { .ctl_name = CTL_DUMP_ADDR,
8427 +         .procname = DUMP_ADDR_NAME,
8428 +         .mode = 0444,
8429 +         .data = &dump_config.dump_addr,
8430 +         .maxlen = sizeof(unsigned long),
8431 +         .proc_handler = proc_doulonghex },
8432 +#endif
8433 +
8434 +       { 0, }
8435 +};
8436 +
8437 +static ctl_table dump_root[] = {
8438 +       { .ctl_name = KERN_DUMP,
8439 +         .procname = "dump",
8440 +         .mode = 0555, 
8441 +         .child = dump_table },
8442 +       { 0, }
8443 +};
8444 +
8445 +static ctl_table kernel_root[] = {
8446 +       { .ctl_name = CTL_KERN,
8447 +         .procname = "kernel",
8448 +         .mode = 0555,
8449 +         .child = dump_root, },
8450 +       { 0, }
8451 +};
8452 +
8453 +static struct ctl_table_header *sysctl_header;
8454 +
8455 +/*
8456 + * -----------------------------------------------------------------------
8457 + *              C O M P R E S S I O N   F U N C T I O N S
8458 + * -----------------------------------------------------------------------
8459 + */
8460 +
8461 +/*
8462 + * Name: dump_compress_none()
8463 + * Func: Don't do any compression, period.
8464 + */
8465 +static u32
8466 +dump_compress_none(const u8 *old, u32 oldsize, u8 *new, u32 newsize,
8467 +               unsigned long loc)
8468 +{
8469 +       /* just return the old size */
8470 +       return oldsize;
8471 +}
8472 +
8473 +
8474 +/*
8475 + * Name: dump_execute()
8476 + * Func: Execute the dumping process.  This makes sure all the appropriate
8477 + *       fields are updated correctly, and calls dump_execute_memdump(),
8478 + *       which does the real work.
8479 + */
8480 +void
8481 +dump_execute(const char *panic_str, const struct pt_regs *regs)
8482 +{
8483 +       int state = -1;
8484 +       unsigned long flags;
8485 +
8486 +       /* make sure we can dump */
8487 +       if (!dump_okay) {
8488 +               pr_info("LKCD not yet configured, can't take dump now\n");
8489 +               return;
8490 +       }
8491 +
8492 +       /* Exclude multiple dumps at the same time,
8493 +        * and disable interrupts,  some drivers may re-enable
8494 +        * interrupts in with silence()
8495 +        *
8496 +        * Try and acquire spin lock. If successful, leave preempt
8497 +        * and interrupts disabled.  See spin_lock_irqsave in spinlock.h
8498 +        */
8499 +       local_irq_save(flags);
8500 +       if (!spin_trylock(&dump_lock)) {
8501 +               local_irq_restore(flags);
8502 +               pr_info("LKCD dump already in progress\n");
8503 +               return;
8504 +       }
8505 +
8506 +       /* What state are interrupts really in? */
8507 +       if (in_interrupt()){ 
8508 +               if(in_irq())
8509 +                   printk(KERN_ALERT "Dumping from interrupt handler!\n");
8510 +               else 
8511 +                   printk(KERN_ALERT "Dumping from bottom half!\n");
8512 +
8513 +               __dump_clean_irq_state();
8514 +       }
8515 +
8516 +
8517 +       /* Bring system into the strictest level of quiescing for min drift 
8518 +        * dump drivers can soften this as required in dev->ops->silence() 
8519 +        */
8520 +       dump_oncpu = smp_processor_id() + 1;
8521 +       dump_silence_level = DUMP_HARD_SPIN_CPUS; 
8522 +
8523 +       state = dump_generic_execute(panic_str, regs);
8524 +       
8525 +       dump_oncpu = 0;
8526 +       spin_unlock_irqrestore(&dump_lock, flags);
8527 +
8528 +       if (state < 0) {
8529 +               printk("Dump Incomplete or failed!\n");
8530 +       } else {
8531 +               printk("Dump Complete; %d dump pages saved.\n", 
8532 +                      dump_header.dh_num_dump_pages);
8533 +       }
8534 +}
8535 +
8536 +/*
8537 + * Name: dump_register_compression()
8538 + * Func: Register a dump compression mechanism.
8539 + */
8540 +void
8541 +dump_register_compression(struct __dump_compress *item)
8542 +{
8543 +       if (item)
8544 +               list_add(&(item->list), &dump_compress_list);
8545 +}
8546 +
8547 +/*
8548 + * Name: dump_unregister_compression()
8549 + * Func: Remove a dump compression mechanism, and re-assign the dump
8550 + *       compression pointer if necessary.
8551 + */
8552 +void
8553 +dump_unregister_compression(int compression_type)
8554 +{
8555 +       struct list_head *tmp;
8556 +       struct __dump_compress *dc;
8557 +
8558 +       /* let's make sure our list is valid */
8559 +       if (compression_type != DUMP_COMPRESS_NONE) {
8560 +               list_for_each(tmp, &dump_compress_list) {
8561 +                       dc = list_entry(tmp, struct __dump_compress, list);
8562 +                       if (dc->compress_type == compression_type) {
8563 +                               list_del(&(dc->list));
8564 +                               break;
8565 +                       }
8566 +               }
8567 +       }
8568 +}
8569 +
8570 +/*
8571 + * Name: dump_compress_init()
8572 + * Func: Initialize (or re-initialize) compression scheme.
8573 + */
8574 +static int
8575 +dump_compress_init(int compression_type)
8576 +{
8577 +       struct list_head *tmp;
8578 +       struct __dump_compress *dc;
8579 +
8580 +       /* try to remove the compression item */
8581 +       list_for_each(tmp, &dump_compress_list) {
8582 +               dc = list_entry(tmp, struct __dump_compress, list);
8583 +               if (dc->compress_type == compression_type) {
8584 +                       dump_config.dumper->compress = dc;
8585 +                       dump_compress = compression_type;
8586 +                       pr_debug("Dump Compress %s\n", dc->compress_name);
8587 +                       return 0;
8588 +               }
8589 +       }
8590 +
8591 +       /* 
8592 +        * nothing on the list -- return ENODATA to indicate an error 
8593 +        *
8594 +        * NB: 
8595 +        *      EAGAIN: reports "Resource temporarily unavailable" which
8596 +        *              isn't very enlightening.
8597 +        */
8598 +       printk("compression_type:%d not found\n", compression_type);
8599 +
8600 +       return -ENODATA;
8601 +}
8602 +
8603 +static int
8604 +dumper_setup(unsigned long flags, unsigned long devid)
8605 +{
8606 +       int ret = 0;
8607 +
8608 +       /* unconfigure old dumper if it exists */
8609 +       dump_okay = 0;
8610 +       if (dump_config.dumper) {
8611 +               pr_debug("Unconfiguring current dumper\n");
8612 +               dump_unconfigure();
8613 +       }
8614 +       /* set up new dumper */
8615 +       if (dump_config.flags & DUMP_FLAGS_SOFTBOOT) {
8616 +               printk("Configuring softboot based dump \n");
8617 +#ifdef CONFIG_CRASH_DUMP_MEMDEV
8618 +               dump_config.dumper = &dumper_stage1; 
8619 +#else
8620 +               printk("Requires CONFIG_CRASHDUMP_MEMDEV. Can't proceed.\n");
8621 +               return -1;
8622 +#endif
8623 +       } else {
8624 +               dump_config.dumper = &dumper_singlestage;
8625 +       }       
8626 +       dump_config.dumper->dev = dump_dev;
8627 +
8628 +       ret = dump_configure(devid);
8629 +       if (!ret) {
8630 +               dump_okay = 1;
8631 +               pr_debug("%s dumper set up for dev 0x%lx\n", 
8632 +                       dump_config.dumper->name, devid);
8633 +               dump_config.dump_device = devid;
8634 +       } else {
8635 +               printk("%s dumper set up failed for dev 0x%lx\n", 
8636 +                      dump_config.dumper->name, devid);
8637 +               dump_config.dumper = NULL;
8638 +       }
8639 +       return ret;
8640 +}
8641 +
8642 +static int
8643 +dump_target_init(int target)
8644 +{
8645 +       char type[20];
8646 +       struct list_head *tmp;
8647 +       struct dump_dev *dev;
8648 +       
8649 +       switch (target) {
8650 +               case DUMP_FLAGS_DISKDUMP:
8651 +                       strcpy(type, "blockdev"); break;
8652 +               case DUMP_FLAGS_NETDUMP:
8653 +                       strcpy(type, "networkdev"); break;
8654 +               default:
8655 +                       return -1;
8656 +       }
8657 +
8658 +       /*
8659 +        * This is a bit stupid, generating strings from flag
8660 +        * and doing strcmp. This is done because 'struct dump_dev'
8661 +        * has string 'type_name' and not interger 'type'.
8662 +        */
8663 +       list_for_each(tmp, &dump_target_list) {
8664 +               dev = list_entry(tmp, struct dump_dev, list);
8665 +               if (strcmp(type, dev->type_name) == 0) {
8666 +                       dump_dev = dev;
8667 +                       return 0;
8668 +               }
8669 +       }
8670 +       return -1;
8671 +}
8672 +
8673 +/*
8674 + * Name: dump_ioctl()
8675 + * Func: Allow all dump tunables through a standard ioctl() mechanism.
8676 + *       This is far better than before, where we'd go through /proc,
8677 + *       because now this will work for multiple OS and architectures.
8678 + */
8679 +static int
8680 +dump_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
8681 +{
8682 +       /* check capabilities */
8683 +       if (!capable(CAP_SYS_ADMIN))
8684 +               return -EPERM;
8685 +
8686 +       if (!dump_config.dumper && cmd == DIOSDUMPCOMPRESS)
8687 +               /* dump device must be configured first */
8688 +               return -ENODEV;
8689 +
8690 +       /*
8691 +        * This is the main mechanism for controlling get/set data
8692 +        * for various dump device parameters.  The real trick here
8693 +        * is setting the dump device (DIOSDUMPDEV).  That's what
8694 +        * triggers everything else.
8695 +        */
8696 +       switch (cmd) {
8697 +       case DIOSDUMPDEV:       /* set dump_device */
8698 +               pr_debug("Configuring dump device\n"); 
8699 +               if (!(f->f_flags & O_RDWR))
8700 +                       return -EPERM;
8701 +
8702 +               __dump_open();
8703 +               return dumper_setup(dump_config.flags, arg);
8704 +
8705 +               
8706 +       case DIOGDUMPDEV:       /* get dump_device */
8707 +               return put_user((long)dump_config.dump_device, (long *)arg);
8708 +
8709 +       case DIOSDUMPLEVEL:     /* set dump_level */
8710 +               if (!(f->f_flags & O_RDWR))
8711 +                       return -EPERM;
8712 +
8713 +               /* make sure we have a positive value */
8714 +               if (arg < 0)
8715 +                       return -EINVAL;
8716 +
8717 +               /* Fixme: clean this up */
8718 +               dump_config.level = 0;
8719 +               switch ((int)arg) {
8720 +                       case DUMP_LEVEL_ALL:
8721 +                       case DUMP_LEVEL_ALL_RAM:
8722 +                               dump_config.level |= DUMP_MASK_UNUSED;
8723 +                       case DUMP_LEVEL_USED:
8724 +                               dump_config.level |= DUMP_MASK_USED;
8725 +                       case DUMP_LEVEL_KERN:
8726 +                               dump_config.level |= DUMP_MASK_KERN;
8727 +                       case DUMP_LEVEL_HEADER:
8728 +                               dump_config.level |= DUMP_MASK_HEADER;
8729 +                       case DUMP_LEVEL_NONE:
8730 +                               break;
8731 +                       default:
8732 +                               return (-EINVAL);
8733 +                       }
8734 +               pr_debug("Dump Level 0x%lx\n", dump_config.level);
8735 +               break;
8736 +
8737 +       case DIOGDUMPLEVEL:     /* get dump_level */
8738 +               /* fixme: handle conversion */
8739 +               return put_user((long)dump_config.level, (long *)arg);
8740 +
8741 +               
8742 +       case DIOSDUMPFLAGS:     /* set dump_flags */
8743 +               /* check flags */
8744 +               if (!(f->f_flags & O_RDWR))
8745 +                       return -EPERM;
8746 +
8747 +               /* make sure we have a positive value */
8748 +               if (arg < 0)
8749 +                       return -EINVAL;
8750 +                       
8751 +               if (dump_target_init(arg & DUMP_FLAGS_TARGETMASK) < 0)
8752 +                       return -EINVAL; /* return proper error */
8753 +
8754 +               dump_config.flags = arg;
8755 +               
8756 +               pr_debug("Dump Flags 0x%lx\n", dump_config.flags);
8757 +               break;
8758 +               
8759 +       case DIOGDUMPFLAGS:     /* get dump_flags */
8760 +               return put_user((long)dump_config.flags, (long *)arg);
8761 +
8762 +       case DIOSDUMPCOMPRESS:  /* set the dump_compress status */
8763 +               if (!(f->f_flags & O_RDWR))
8764 +                       return -EPERM;
8765 +
8766 +               return dump_compress_init((int)arg);
8767 +
8768 +       case DIOGDUMPCOMPRESS:  /* get the dump_compress status */
8769 +               return put_user((long)(dump_config.dumper ? 
8770 +                       dump_config.dumper->compress->compress_type : 0), 
8771 +                       (long *)arg);
8772 +       case DIOGDUMPOKAY: /* check if dump is configured */
8773 +               return put_user((long)dump_okay, (long *)arg);
8774 +       
8775 +       case DIOSDUMPTAKE: /* Trigger a manual dump */
8776 +               /* Do not proceed if lkcd not yet configured */
8777 +               if(!dump_okay) {
8778 +                       printk("LKCD not yet configured. Cannot take manual dump\n");
8779 +                       return -ENODEV;
8780 +               }
8781 +
8782 +               /* Take the dump */
8783 +               return  manual_handle_crashdump();
8784 +                       
8785 +       default:
8786 +               /* 
8787 +                * these are network dump specific ioctls, let the
8788 +                * module handle them.
8789 +                */
8790 +               return dump_dev_ioctl(cmd, arg);
8791 +       }
8792 +       return 0;
8793 +}
8794 +
8795 +/*
8796 + * Handle special cases for dump_device 
8797 + * changing dump device requires doing an opening the device
8798 + */
8799 +static int 
8800 +proc_dump_device(ctl_table *ctl, int write, struct file *f,
8801 +                void __user *buffer, size_t *lenp, loff_t *ppos)
8802 +{
8803 +       int *valp = ctl->data;
8804 +       int oval = *valp;
8805 +       int ret = -EPERM;
8806 +
8807 +       /* same permission checks as ioctl */
8808 +       if (capable(CAP_SYS_ADMIN)) {
8809 +               ret = proc_doulonghex(ctl, write, f, buffer, lenp, ppos);
8810 +               if (ret == 0 && write && *valp != oval) {
8811 +                       /* need to restore old value to close properly */
8812 +                       dump_config.dump_device = (dev_t) oval;
8813 +                       __dump_open();
8814 +                       ret = dumper_setup(dump_config.flags, (dev_t) *valp);
8815 +               }
8816 +       }
8817 +
8818 +       return ret;
8819 +}
8820 +
8821 +/* All for the want of a proc_do_xxx routine which prints values in hex */
8822 +/* Write is not implemented correctly, so mode is set to 0444 above. */
8823 +static int 
8824 +proc_doulonghex(ctl_table *ctl, int write, struct file *f,
8825 +                void __user *buffer, size_t *lenp, loff_t *ppos)
8826 +{
8827 +#define TMPBUFLEN 21
8828 +       unsigned long *i;
8829 +       size_t len, left;
8830 +       char buf[TMPBUFLEN];
8831 +
8832 +       if (!ctl->data || !ctl->maxlen || !*lenp || (*ppos && !write)) {
8833 +               *lenp = 0;
8834 +               return 0;
8835 +       }
8836 +       
8837 +       i = (unsigned long *) ctl->data;
8838 +       left = *lenp;
8839 +       
8840 +       sprintf(buf, "0x%lx\n", (*i));
8841 +       len = strlen(buf);
8842 +       if (len > left)
8843 +               len = left;
8844 +       if(copy_to_user(buffer, buf, len))
8845 +               return -EFAULT;
8846 +       
8847 +       left -= len;
8848 +       *lenp -= left;
8849 +       *ppos += *lenp;
8850 +       return 0;
8851 +}
8852 +
8853 +/*
8854 + * -----------------------------------------------------------------------
8855 + *                     I N I T   F U N C T I O N S
8856 + * -----------------------------------------------------------------------
8857 + */
8858 +
8859 +#ifdef CONFIG_COMPAT
8860 +static int dw_long(unsigned int fd, unsigned int cmd, unsigned long arg,
8861 +                struct file *f)
8862 +{
8863 +        mm_segment_t old_fs = get_fs();
8864 +        int err;
8865 +        unsigned long val;
8866 +
8867 +        set_fs (KERNEL_DS);
8868 +        err = sys_ioctl(fd, cmd, (u64)&val);
8869 +        set_fs (old_fs);
8870 +        if (!err && put_user((unsigned int) val, (u32 *)arg))
8871 +               return -EFAULT;
8872 +        return err;
8873 +}
8874 +#endif
8875 +
8876 +/*
8877 + * These register and unregister routines are exported for modules
8878 + * to register their dump drivers (like block, net etc)
8879 + */
8880 +int
8881 +dump_register_device(struct dump_dev *ddev)
8882 +{
8883 +       struct list_head *tmp;
8884 +       struct dump_dev *dev;
8885 +
8886 +       list_for_each(tmp, &dump_target_list) {
8887 +               dev = list_entry(tmp, struct dump_dev, list);
8888 +               if (strcmp(ddev->type_name, dev->type_name) == 0) {
8889 +                       printk("Target type %s already registered\n",
8890 +                                       dev->type_name);
8891 +                       return -1; /* return proper error */
8892 +               }
8893 +       }
8894 +       list_add(&(ddev->list), &dump_target_list);
8895 +       
8896 +       return 0;
8897 +}
8898 +
8899 +void
8900 +dump_unregister_device(struct dump_dev *ddev)
8901 +{
8902 +       list_del(&(ddev->list));
8903 +       if (ddev != dump_dev)
8904 +               return;
8905 +
8906 +       dump_okay = 0;
8907 +
8908 +       if (dump_config.dumper)
8909 +               dump_unconfigure();
8910 +
8911 +       dump_config.flags &= ~DUMP_FLAGS_TARGETMASK;
8912 +       dump_okay = 0;
8913 +       dump_dev = NULL;
8914 +       dump_config.dumper = NULL;
8915 +}
8916 +
8917 +static int panic_event(struct notifier_block *this, unsigned long event,
8918 +                      void *ptr)
8919 +{
8920 +#ifdef CONFIG_ARM
8921 +       get_current_general_regs(&all_regs);
8922 +       get_current_cp14_regs(&all_regs);
8923 +       get_current_cp15_regs(&all_regs);
8924 +       dump_execute((const char *)ptr, &all_regs);
8925 +#else
8926 +       struct pt_regs regs;
8927 +       
8928 +       get_current_regs(&regs);
8929 +       dump_execute((const char *)ptr, &regs);
8930 +#endif
8931 +       return 0;
8932 +}
8933 +
8934 +extern struct notifier_block *panic_notifier_list;
8935 +static int panic_event(struct notifier_block *, unsigned long, void *);
8936 +static struct notifier_block panic_block = {
8937 +       .notifier_call = panic_event,
8938 +};
8939 +
8940 +#ifdef CONFIG_MAGIC_SYSRQ
8941 +/* Sysrq handler */
8942 +static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
8943 +               struct tty_struct *tty) {
8944 +       if(!pt_regs) {
8945 +               struct pt_regs regs;
8946 +               get_current_regs(&regs);
8947 +               dump_execute("sysrq", &regs);
8948 +
8949 +       } else {
8950 +               dump_execute("sysrq", pt_regs);
8951 +       }
8952 +}
8953 +
8954 +static struct sysrq_key_op sysrq_crashdump_op = {
8955 +       .handler        =       sysrq_handle_crashdump,
8956 +       .help_msg       =       "Dump",
8957 +       .action_msg     =       "Starting crash dump",
8958 +};
8959 +#endif
8960 +
8961 +static inline void
8962 +dump_sysrq_register(void) 
8963 +{
8964 +#ifdef CONFIG_MAGIC_SYSRQ
8965 +       register_sysrq_key(DUMP_SYSRQ_KEY, &sysrq_crashdump_op);
8966 +#endif
8967 +}
8968 +
8969 +static inline void
8970 +dump_sysrq_unregister(void)
8971 +{
8972 +#ifdef CONFIG_MAGIC_SYSRQ
8973 +       unregister_sysrq_key(DUMP_SYSRQ_KEY, &sysrq_crashdump_op);
8974 +#endif
8975 +}
8976 +
8977 +/*
8978 + * Name: dump_init()
8979 + * Func: Initialize the dump process.  This will set up any architecture
8980 + *       dependent code.  The big key is we need the memory offsets before
8981 + *       the page table is initialized, because the base memory offset
8982 + *       is changed after paging_init() is called.
8983 + */
8984 +static int __init
8985 +dump_init(void)
8986 +{
8987 +       struct sysinfo info;
8988 +       int err;
8989 +
8990 +       /* try to create our dump device */
8991 +       err = misc_register(&dump_miscdev);
8992 +       if (err) {
8993 +               printk("cannot register dump character device!\n");
8994 +               return err;
8995 +       }
8996 +
8997 +       __dump_init((u64)PAGE_OFFSET);
8998 +
8999 +#ifdef CONFIG_COMPAT
9000 +       err = register_ioctl32_conversion(DIOSDUMPDEV, NULL);
9001 +       err |= register_ioctl32_conversion(DIOGDUMPDEV, NULL);
9002 +       err |= register_ioctl32_conversion(DIOSDUMPLEVEL, NULL);
9003 +       err |= register_ioctl32_conversion(DIOGDUMPLEVEL, dw_long);
9004 +       err |= register_ioctl32_conversion(DIOSDUMPFLAGS, NULL);
9005 +       err |= register_ioctl32_conversion(DIOGDUMPFLAGS, dw_long);
9006 +       err |= register_ioctl32_conversion(DIOSDUMPCOMPRESS, NULL);
9007 +       err |= register_ioctl32_conversion(DIOGDUMPCOMPRESS, dw_long);
9008 +       err |= register_ioctl32_conversion(DIOSTARGETIP, NULL);
9009 +       err |= register_ioctl32_conversion(DIOGTARGETIP, NULL);
9010 +       err |= register_ioctl32_conversion(DIOSTARGETPORT, NULL);
9011 +       err |= register_ioctl32_conversion(DIOGTARGETPORT, NULL);
9012 +       err |= register_ioctl32_conversion(DIOSSOURCEPORT, NULL);
9013 +       err |= register_ioctl32_conversion(DIOGSOURCEPORT, NULL);
9014 +       err |= register_ioctl32_conversion(DIOSETHADDR, NULL);
9015 +       err |= register_ioctl32_conversion(DIOGETHADDR, NULL);
9016 +       err |= register_ioctl32_conversion(DIOGDUMPOKAY, dw_long);
9017 +       err |= register_ioctl32_conversion(DIOSDUMPTAKE, NULL);
9018 +       if (err) {
9019 +                printk(KERN_ERR "LKCD: registering ioctl32 translations failed\
9020 +");
9021 +       }
9022 +#endif
9023 +       /* set the dump_compression_list structure up */
9024 +       dump_register_compression(&dump_none_compression);
9025 +
9026 +       /* grab the total memory size now (not if/when we crash) */
9027 +       si_meminfo(&info);
9028 +
9029 +       /* set the memory size */
9030 +       dump_header.dh_memory_size = (u64)info.totalram;
9031 +
9032 +       sysctl_header = register_sysctl_table(kernel_root, 0);
9033 +       dump_sysrq_register();
9034 +
9035 +       notifier_chain_register(&panic_notifier_list, &panic_block);
9036 +       dump_function_ptr = dump_execute;
9037 +
9038 +       pr_info("Crash dump driver initialized.\n");
9039 +       return 0;
9040 +}
9041 +
9042 +static void __exit
9043 +dump_cleanup(void)
9044 +{
9045 +       int err;
9046 +       dump_okay = 0;
9047 +
9048 +       if (dump_config.dumper)
9049 +               dump_unconfigure();
9050 +
9051 +       /* arch-specific cleanup routine */
9052 +       __dump_cleanup();
9053 +
9054 +#ifdef CONFIG_COMPAT
9055 +       err = unregister_ioctl32_conversion(DIOSDUMPDEV);
9056 +       err |= unregister_ioctl32_conversion(DIOGDUMPDEV);
9057 +       err |= unregister_ioctl32_conversion(DIOSDUMPLEVEL);
9058 +       err |= unregister_ioctl32_conversion(DIOGDUMPLEVEL);
9059 +       err |= unregister_ioctl32_conversion(DIOSDUMPFLAGS);
9060 +       err |= unregister_ioctl32_conversion(DIOGDUMPFLAGS);
9061 +       err |= unregister_ioctl32_conversion(DIOSDUMPCOMPRESS);
9062 +       err |= unregister_ioctl32_conversion(DIOGDUMPCOMPRESS);
9063 +       err |= unregister_ioctl32_conversion(DIOSTARGETIP);
9064 +       err |= unregister_ioctl32_conversion(DIOGTARGETIP);
9065 +       err |= unregister_ioctl32_conversion(DIOSTARGETPORT);
9066 +       err |= unregister_ioctl32_conversion(DIOGTARGETPORT);
9067 +       err |= unregister_ioctl32_conversion(DIOSSOURCEPORT);
9068 +       err |= unregister_ioctl32_conversion(DIOGSOURCEPORT);
9069 +       err |= unregister_ioctl32_conversion(DIOSETHADDR);
9070 +       err |= unregister_ioctl32_conversion(DIOGETHADDR);
9071 +       err |= unregister_ioctl32_conversion(DIOGDUMPOKAY);
9072 +       err |= unregister_ioctl32_conversion(DIOSDUMPTAKE);
9073 +       if (err) {
9074 +               printk(KERN_ERR "LKCD: Unregistering ioctl32 translations failed\n");
9075 +       }
9076 +#endif
9077 +
9078 +       /* ignore errors while unregistering -- since can't do anything */
9079 +       unregister_sysctl_table(sysctl_header);
9080 +       misc_deregister(&dump_miscdev);
9081 +       dump_sysrq_unregister();
9082 +       notifier_chain_unregister(&panic_notifier_list, &panic_block);
9083 +       dump_function_ptr = NULL;
9084 +}
9085 +
9086 +EXPORT_SYMBOL(dump_register_compression);
9087 +EXPORT_SYMBOL(dump_unregister_compression);
9088 +EXPORT_SYMBOL(dump_register_device);
9089 +EXPORT_SYMBOL(dump_unregister_device);
9090 +EXPORT_SYMBOL(dump_config);
9091 +EXPORT_SYMBOL(dump_silence_level);
9092 +
9093 +EXPORT_SYMBOL(__dump_irq_enable);
9094 +EXPORT_SYMBOL(__dump_irq_restore);
9095 +
9096 +MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
9097 +MODULE_DESCRIPTION("Linux Kernel Crash Dump (LKCD) driver");
9098 +MODULE_LICENSE("GPL");
9099 +
9100 +module_init(dump_init);
9101 +module_exit(dump_cleanup);
9102 Index: linux-2.6.10/drivers/dump/dump_scheme.c
9103 ===================================================================
9104 --- linux-2.6.10.orig/drivers/dump/dump_scheme.c        2005-04-05 19:01:49.158500672 +0800
9105 +++ linux-2.6.10/drivers/dump/dump_scheme.c     2005-04-05 16:47:53.944204952 +0800
9106 @@ -0,0 +1,430 @@
9107 +/* 
9108 + * Default single stage dump scheme methods
9109 + *
9110 + * Previously a part of dump_base.c
9111 + *
9112 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
9113 + *     Split and rewrote LKCD dump scheme to generic dump method 
9114 + *     interfaces 
9115 + * Derived from original code created by
9116 + *     Matt Robinson <yakker@sourceforge.net>)
9117 + *
9118 + * Contributions from SGI, IBM, HP, MCL, and others.
9119 + *
9120 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
9121 + * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
9122 + * Copyright (C) 2002 International Business Machines Corp. 
9123 + *
9124 + * This code is released under version 2 of the GNU GPL.
9125 + */
9126 +
9127 +/*
9128 + * Implements the default dump scheme, i.e. single-stage gathering and 
9129 + * saving of dump data directly to the target device, which operates in
9130 + * a push mode, where the dumping system decides what data it saves
9131 + * taking into account pre-specified dump config options.
9132 + *
9133 + * Aside: The 2-stage dump scheme, where there is a soft-reset between
9134 + * the gathering and saving phases, also reuses some of these
9135 + * default routines (see dump_overlay.c) 
9136 + */ 
9137 +#include <linux/types.h>
9138 +#include <linux/kernel.h>
9139 +#include <linux/mm.h>
9140 +#include <linux/slab.h>
9141 +#include <linux/delay.h>
9142 +#include <linux/reboot.h>
9143 +#include <linux/nmi.h>
9144 +#include <linux/dump.h>
9145 +#include "dump_methods.h"
9146 +
9147 +extern int panic_timeout;  /* time before reboot */
9148 +
9149 +extern void dump_speedo(int);
9150 +
9151 +/* Default sequencer used during single stage dumping */
9152 +/* Also invoked during stage 2 of soft-boot based dumping */
9153 +int dump_generic_sequencer(void)
9154 +{
9155 +       struct dump_data_filter *filter = dump_config.dumper->filter;
9156 +       int pass = 0, err = 0, save = 0;
9157 +       int (*action)(unsigned long, unsigned long);
9158 +
9159 +       /* 
9160 +        * We want to save the more critical data areas first in 
9161 +        * case we run out of space, encounter i/o failures, or get
9162 +        * interrupted otherwise and have to give up midway
9163 +        * So, run through the passes in increasing order 
9164 +        */
9165 +       for (;filter->selector; filter++, pass++)
9166 +       {
9167 +               /* Assumes passes are exclusive (even across dumpers) */
9168 +               /* Requires care when coding the selection functions */
9169 +               if ((save = filter->level_mask & dump_config.level))
9170 +                       action = dump_save_data;
9171 +               else
9172 +                       action = dump_skip_data;
9173 +
9174 +               if ((err = dump_iterator(pass, action, filter)) < 0)
9175 +                       break;
9176 +
9177 +               printk("\n %d dump pages %s of %d each in pass %d\n", 
9178 +               err, save ? "saved" : "skipped", (int)DUMP_PAGE_SIZE, pass);
9179 +
9180 +       }
9181 +
9182 +       return (err < 0) ? err : 0;
9183 +}
9184 +
9185 +static inline struct page *dump_get_page(loff_t loc)
9186 +{
9187 +
9188 +       unsigned long page_index = loc >> PAGE_SHIFT;
9189 +
9190 +       /* todo: complete this  to account for ia64/discontig mem */
9191 +       /* todo: and to check for validity, ram page, no i/o mem etc */
9192 +       /* need to use pfn/physaddr equiv of kern_addr_valid */
9193 +
9194 +       /* Important:
9195 +        *   On ARM/XScale system, the physical address starts from 
9196 +        *   PHYS_OFFSET, and it maybe the situation that PHYS_OFFSET != 0. 
9197 +        *   For example on Intel's PXA250, PHYS_OFFSET = 0xa0000000. And the 
9198 +        *   page index starts from PHYS_PFN_OFFSET. When configuring
9199 +        *   filter, filter->start is assigned to 0 in dump_generic_configure.
9200 +        *   Here we want to adjust it by adding PHYS_PFN_OFFSET to it!
9201 +        */
9202 +#ifdef CONFIG_ARM
9203 +       page_index += PHYS_PFN_OFFSET;
9204 +#endif
9205 +       if (__dump_page_valid(page_index))
9206 +               return pfn_to_page(page_index);
9207 +       else
9208 +               return NULL;
9209 +
9210 +}
9211 +
9212 +/* Default iterator: for singlestage and stage 1 of soft-boot dumping */
9213 +/* Iterates over range of physical memory pages in DUMP_PAGE_SIZE increments */
9214 +int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned long), 
9215 +       struct dump_data_filter *filter)
9216 +{
9217 +       /* Todo : fix unit, type */
9218 +       loff_t loc, start, end;
9219 +       int i, count = 0, err = 0;
9220 +       struct page *page;
9221 +
9222 +       /* Todo: Add membanks code */
9223 +       /* TBD: Check if we need to address DUMP_PAGE_SIZE < PAGE_SIZE */       
9224 +
9225 +       for (i = 0; i < filter->num_mbanks; i++) {
9226 +               start = filter->start[i];
9227 +               end = filter->end[i];
9228 +               for (loc = start; loc < end; loc += DUMP_PAGE_SIZE) {
9229 +                       dump_config.dumper->curr_loc = loc;
9230 +                       page = dump_get_page(loc);
9231 +                       if (page && filter->selector(pass, 
9232 +                               (unsigned long) page, DUMP_PAGE_SIZE)) { 
9233 +                               if ((err = action((unsigned long)page, 
9234 +                                       DUMP_PAGE_SIZE))) {
9235 +                                       printk("dump_page_iterator: err %d for "
9236 +                                               "loc 0x%llx, in pass %d\n", 
9237 +                                               err, loc, pass);
9238 +                                       return err ? err : count;
9239 +                               } else
9240 +                                       count++;
9241 +                       }
9242 +               }
9243 +       }
9244 +
9245 +       return err ? err : count;
9246 +}
9247 +
9248 +/* 
9249 + * Base function that saves the selected block of data in the dump 
9250 + * Action taken when iterator decides that data needs to be saved 
9251 + */
9252 +int dump_generic_save_data(unsigned long loc, unsigned long sz)
9253 +{
9254 +       void *buf;
9255 +       void *dump_buf = dump_config.dumper->dump_buf;
9256 +       int left, bytes, ret;
9257 +
9258 +       if ((ret = dump_add_data(loc, sz))) {
9259 +               return ret;
9260 +       }
9261 +       buf = dump_config.dumper->curr_buf;
9262 +
9263 +       /* If we've filled up the buffer write it out */
9264 +       if ((left = buf - dump_buf) >= DUMP_BUFFER_SIZE) {
9265 +               bytes = dump_write_buffer(dump_buf, DUMP_BUFFER_SIZE);
9266 +               if (bytes < DUMP_BUFFER_SIZE) {
9267 +                       printk("dump_write_buffer failed %d\n", bytes);
9268 +                       return bytes ? -ENOSPC : bytes;
9269 +               }
9270 +
9271 +               left -= bytes;
9272 +               
9273 +               /* -- A few chores to do from time to time -- */
9274 +               dump_config.dumper->count++;
9275 +
9276 +               if (!(dump_config.dumper->count & 0x3f)) {
9277 +                       /* Update the header every one in a while */
9278 +                       memset((void *)dump_buf, 'b', DUMP_BUFFER_SIZE);
9279 +                       if ((ret = dump_update_header()) < 0) {
9280 +                               /* issue warning */
9281 +                               return ret;
9282 +                       }
9283 +                       printk(".");
9284 +
9285 +                       touch_nmi_watchdog();
9286 +               } else if (!(dump_config.dumper->count & 0x7)) {
9287 +                       /* Show progress so the user knows we aren't hung */
9288 +                       dump_speedo(dump_config.dumper->count >> 3); 
9289 +               }
9290 +               /* Todo: Touch/Refresh watchdog */
9291 +
9292 +               /* --- Done with periodic chores -- */
9293 +
9294 +               /* 
9295 +                * extra bit of copying to simplify verification  
9296 +                * in the second kernel boot based scheme
9297 +                */
9298 +               memcpy(dump_buf - DUMP_PAGE_SIZE, dump_buf + 
9299 +                       DUMP_BUFFER_SIZE - DUMP_PAGE_SIZE, DUMP_PAGE_SIZE);
9300 +
9301 +               /* now adjust the leftover bits back to the top of the page */
9302 +               /* this case would not arise during stage 2 (passthru) */
9303 +               memset(dump_buf, 'z', DUMP_BUFFER_SIZE);
9304 +               if (left) {
9305 +                       memcpy(dump_buf, dump_buf + DUMP_BUFFER_SIZE, left);
9306 +               }
9307 +               buf -= DUMP_BUFFER_SIZE;
9308 +               dump_config.dumper->curr_buf = buf;
9309 +       }
9310 +                               
9311 +       return 0;
9312 +}
9313 +
9314 +int dump_generic_skip_data(unsigned long loc, unsigned long sz)
9315 +{
9316 +       /* dummy by default */
9317 +       return 0;
9318 +}
9319 +
9320 +/* 
9321 + * Common low level routine to write a buffer to current dump device 
9322 + * Expects checks for space etc to have been taken care of by the caller 
9323 + * Operates serially at the moment for simplicity. 
9324 + * TBD/Todo: Consider batching for improved throughput
9325 + */
9326 +int dump_ll_write(void *buf, unsigned long len)
9327 +{
9328 +       long transferred = 0, last_transfer = 0;
9329 +       int ret = 0;
9330 +
9331 +       /* make sure device is ready */
9332 +       while ((ret = dump_dev_ready(NULL)) == -EAGAIN);
9333 +       if  (ret < 0) {
9334 +               printk("dump_dev_ready failed !err %d\n", ret);
9335 +               return ret;
9336 +       }
9337 +
9338 +       while (len) {
9339 +               if ((last_transfer = dump_dev_write(buf, len)) <= 0)  {
9340 +                       ret = last_transfer;
9341 +                       printk("dump_dev_write failed !err %d\n", 
9342 +                       ret);
9343 +                       break;
9344 +               }
9345 +               /* wait till complete */
9346 +               while ((ret = dump_dev_ready(buf)) == -EAGAIN)
9347 +                       cpu_relax();
9348 +
9349 +               if  (ret < 0) {
9350 +                       printk("i/o failed !err %d\n", ret);
9351 +                       break;
9352 +               }
9353 +
9354 +               len -= last_transfer;
9355 +               buf += last_transfer;
9356 +               transferred += last_transfer;
9357 +       }
9358 +       return (ret < 0) ? ret : transferred;
9359 +}
9360 +
9361 +/* default writeout routine for single dump device */
9362 +/* writes out the dump data ensuring enough space is left for the end marker */
9363 +int dump_generic_write_buffer(void *buf, unsigned long len)
9364 +{
9365 +       long written = 0;
9366 +       int err = 0;
9367 +
9368 +       /* check for space */
9369 +       if ((err = dump_dev_seek(dump_config.dumper->curr_offset + len + 
9370 +                       2*DUMP_BUFFER_SIZE)) < 0) {
9371 +               printk("dump_write_buffer: insuff space after offset 0x%llx\n",
9372 +                       dump_config.dumper->curr_offset);
9373 +               return err;
9374 +       }
9375 +       /* alignment check would happen as a side effect of this */
9376 +       if ((err = dump_dev_seek(dump_config.dumper->curr_offset)) < 0)
9377 +               return err; 
9378 +
9379 +       written = dump_ll_write(buf, len);
9380 +
9381 +       /* all or none */
9382 +
9383 +       if (written < len)
9384 +               written = written ? -ENOSPC : written;
9385 +       else
9386 +               dump_config.dumper->curr_offset += len;
9387 +
9388 +       return written;
9389 +}
9390 +
9391 +int dump_generic_configure(unsigned long devid)
9392 +{
9393 +       struct dump_dev *dev = dump_config.dumper->dev;
9394 +       struct dump_data_filter *filter;
9395 +       void *buf;
9396 +       int ret = 0;
9397 +
9398 +       /* Allocate the dump buffer and initialize dumper state */
9399 +       /* Assume that we get aligned addresses */
9400 +       if (!(buf = dump_alloc_mem(DUMP_BUFFER_SIZE + 3 * DUMP_PAGE_SIZE)))
9401 +               return -ENOMEM;
9402 +
9403 +       if ((unsigned long)buf & (PAGE_SIZE - 1)) {
9404 +               /* sanity check for page aligned address */
9405 +               dump_free_mem(buf);
9406 +               return -ENOMEM; /* fixme: better error code */
9407 +       }
9408 +
9409 +       /* Initialize the rest of the fields */
9410 +       dump_config.dumper->dump_buf = buf + DUMP_PAGE_SIZE;
9411 +       dumper_reset();
9412 +
9413 +       /* Open the dump device */
9414 +       if (!dev)
9415 +               return -ENODEV;
9416 +
9417 +       if ((ret = dev->ops->open(dev, devid))) {
9418 +              return ret;
9419 +       }
9420 +
9421 +       /* Initialise the memory ranges in the dump filter */
9422 +       for (filter = dump_config.dumper->filter ;filter->selector; filter++) {
9423 +               if (!filter->start[0] && !filter->end[0]) {
9424 +                       pg_data_t *pgdat;
9425 +                       int i = 0;
9426 +                       for_each_pgdat(pgdat) {
9427 +                               filter->start[i] = 
9428 +                                       (loff_t)pgdat->node_start_pfn << PAGE_SHIFT;
9429 +                               filter->end[i] =
9430 +                                       (loff_t)(pgdat->node_start_pfn + pgdat->node_spanned_pages) << PAGE_SHIFT;
9431 +                               i++;
9432 +                       }
9433 +                       filter->num_mbanks = i;
9434 +               }
9435 +       }
9436 +
9437 +       return 0;
9438 +}
9439 +
9440 +int dump_generic_unconfigure(void)
9441 +{
9442 +       struct dump_dev *dev = dump_config.dumper->dev;
9443 +       void *buf = dump_config.dumper->dump_buf;
9444 +       int ret = 0;
9445 +
9446 +       pr_debug("Generic unconfigure\n");
9447 +       /* Close the dump device */
9448 +       if (dev && (ret = dev->ops->release(dev)))
9449 +               return ret;
9450 +
9451 +       printk("Closed dump device\n");
9452 +       
9453 +       if (buf)
9454 +               dump_free_mem((buf - DUMP_PAGE_SIZE));
9455 +
9456 +       dump_config.dumper->curr_buf = dump_config.dumper->dump_buf = NULL;
9457 +       pr_debug("Released dump buffer\n");
9458 +
9459 +       return 0;
9460 +}
9461 +
9462 +#ifdef CONFIG_DISCONTIGMEM
9463 +
9464 +void dump_reconfigure_mbanks(void) 
9465 +{
9466 +        pg_data_t *pgdat;
9467 +        loff_t start, end, loc, loc_end;
9468 +        int i=0;
9469 +        struct dump_data_filter *filter = dump_config.dumper->filter;
9470 +
9471 +        for_each_pgdat(pgdat) {
9472 +
9473 +                start = (loff_t)(pgdat->node_start_pfn << PAGE_SHIFT);
9474 +                end = ((loff_t)(pgdat->node_start_pfn + pgdat->node_spanned_pages) << PAGE_SHIFT);
9475 +               for(loc = start; loc < end; loc += (DUMP_PAGE_SIZE)) {
9476 +
9477 +                        if(!(__dump_page_valid(loc >> PAGE_SHIFT)))
9478 +                                continue;
9479 +
9480 +                        /* We found a valid page. This is the start */
9481 +                        filter->start[i] = loc;
9482 +
9483 +                        /* Now loop here till you find the end */
9484 +                        for(loc_end = loc; loc_end < end; loc_end += (DUMP_PAGE_SIZE)) {
9485 +                                
9486 +                               if(__dump_page_valid(loc_end >> PAGE_SHIFT)) {
9487 +                                /* This page could very well be the last page */
9488 +                                        filter->end[i] = loc_end;
9489 +                                        continue;
9490 +                                }
9491 +                                break;
9492 +                        }
9493 +                        i++;
9494 +                        loc = loc_end;
9495 +                }
9496 +        }
9497 +        filter->num_mbanks = i;
9498 +
9499 +        /* Propagate memory bank information to other filters */
9500 +        for (filter = dump_config.dumper->filter, filter++ ;filter->selector; filter++) {
9501 +                for(i = 0; i < dump_config.dumper->filter->num_mbanks; i++) {
9502 +                        filter->start[i] = dump_config.dumper->filter->start[i];
9503 +                        filter->end[i] = dump_config.dumper->filter->end[i];
9504 +                        filter->num_mbanks = dump_config.dumper->filter->num_mbanks;
9505 +                }
9506 +        }
9507 +}
9508 +#endif
9509 +
9510 +/* Set up the default dump scheme */
9511 +
9512 +struct dump_scheme_ops dump_scheme_singlestage_ops = {
9513 +       .configure      = dump_generic_configure,
9514 +       .unconfigure    = dump_generic_unconfigure,
9515 +       .sequencer      = dump_generic_sequencer,
9516 +       .iterator       = dump_page_iterator,
9517 +       .save_data      = dump_generic_save_data,
9518 +       .skip_data      = dump_generic_skip_data,
9519 +       .write_buffer   = dump_generic_write_buffer,
9520 +};
9521 +
9522 +struct dump_scheme dump_scheme_singlestage = {
9523 +       .name           = "single-stage",
9524 +       .ops            = &dump_scheme_singlestage_ops
9525 +};
9526 +
9527 +/* The single stage dumper comprising all these */
9528 +struct dumper dumper_singlestage = {
9529 +       .name           = "single-stage",
9530 +       .scheme         = &dump_scheme_singlestage,
9531 +       .fmt            = &dump_fmt_lcrash,
9532 +       .compress       = &dump_none_compression,
9533 +       .filter         = dump_filter_table,
9534 +       .dev            = NULL,
9535 +};             
9536 +
9537 Index: linux-2.6.10/drivers/dump/dump_gzip.c
9538 ===================================================================
9539 --- linux-2.6.10.orig/drivers/dump/dump_gzip.c  2005-04-05 19:01:49.158500672 +0800
9540 +++ linux-2.6.10/drivers/dump/dump_gzip.c       2005-04-05 16:47:53.937206016 +0800
9541 @@ -0,0 +1,174 @@
9542 +/*
9543 + * GZIP Compression functions for kernel crash dumps.
9544 + *
9545 + * Created by: Matt Robinson (yakker@sourceforge.net)
9546 + * Copyright 2001 Matt D. Robinson.  All rights reserved.
9547 + *
9548 + * This code is released under version 2 of the GNU GPL.
9549 + */
9550 +
9551 +/* header files */
9552 +#include <linux/config.h>
9553 +#include <linux/module.h>
9554 +#include <linux/sched.h>
9555 +#include <linux/fs.h>
9556 +#include <linux/file.h>
9557 +#include <linux/init.h>
9558 +#include <linux/slab.h>
9559 +#include <linux/dump.h>
9560 +#include <linux/zlib.h>
9561 +#include <linux/vmalloc.h>
9562 +
9563 +static void *deflate_workspace;
9564 +static unsigned long workspace_paddr[2];
9565 +
9566 +static u8 *safety_buffer;
9567 +
9568 +/*
9569 + * Name: dump_compress_gzip()
9570 + * Func: Compress a DUMP_PAGE_SIZE page using gzip-style algorithms (the.
9571 + *       deflate functions similar to what's used in PPP).
9572 + */
9573 +static u32
9574 +dump_compress_gzip(const u8 *old, u32 oldsize, u8 *new, u32 newsize,
9575 +               unsigned long loc)
9576 +{
9577 +       /* error code and dump stream */
9578 +       int err;
9579 +       z_stream dump_stream;
9580 +       struct page *pg = (struct page *)loc;
9581 +       unsigned long paddr =  page_to_pfn(pg) << PAGE_SHIFT;
9582 +       static int warning = 0;
9583 +
9584 +       dump_stream.workspace = deflate_workspace;
9585 +       if ((paddr == workspace_paddr[0]) || (paddr == workspace_paddr[1])) {
9586 +               /* 
9587 +                * This page belongs to deflate_workspace used as temporary 
9588 +                * buffer for compression. Hence, dump them without compression.
9589 +                */
9590 +               return(0);
9591 +       }
9592 +       if ((err = zlib_deflateInit(&dump_stream, Z_BEST_COMPRESSION)) != Z_OK) {
9593 +               /* fall back to RLE compression */
9594 +               printk("dump_compress_gzip(): zlib_deflateInit() "
9595 +                       "failed (%d)!\n", err);
9596 +               return 0;
9597 +       }
9598 +
9599 +       /* copy the old page to the safety buffer */
9600 +       if (oldsize <= DUMP_PAGE_SIZE) {
9601 +               memcpy(safety_buffer, old, oldsize);
9602 +               dump_stream.next_in = (u8 *) safety_buffer;
9603 +       } else {
9604 +               if (!warning) {
9605 +                       printk("dump_compress_gzip oversize input: %d\n",
9606 +                                       oldsize);
9607 +                       warning++;
9608 +               }
9609 +               dump_stream.next_in = (u8 *) old;
9610 +       }
9611 +
9612 +       /* use old (page of memory) and size (DUMP_PAGE_SIZE) as in-streams */
9613 +       dump_stream.avail_in = oldsize;
9614 +
9615 +       /* out streams are new (dpcpage) and new size (DUMP_DPC_PAGE_SIZE) */
9616 +       dump_stream.next_out = new;
9617 +       dump_stream.avail_out = newsize;
9618 +
9619 +       /* deflate the page -- check for error */
9620 +       err = zlib_deflate(&dump_stream, Z_FINISH);
9621 +       if (err != Z_STREAM_END) {
9622 +               /* zero is return code here */
9623 +               (void)zlib_deflateEnd(&dump_stream);
9624 +               printk("dump_compress_gzip(): zlib_deflate() failed (%d)!\n",
9625 +                       err);
9626 +               return 0;
9627 +       }
9628 +
9629 +       /* let's end the deflated compression stream */
9630 +       if ((err = zlib_deflateEnd(&dump_stream)) != Z_OK) {
9631 +               printk("dump_compress_gzip(): zlib_deflateEnd() "
9632 +                       "failed (%d)!\n", err);
9633 +       }
9634 +
9635 +       /* return the compressed byte total (if it's smaller) */
9636 +       if (dump_stream.total_out >= oldsize) {
9637 +               return oldsize;
9638 +       }
9639 +       return dump_stream.total_out;
9640 +}
9641 +
9642 +/* setup the gzip compression functionality */
9643 +static struct __dump_compress dump_gzip_compression = {
9644 +       .compress_type = DUMP_COMPRESS_GZIP,
9645 +       .compress_func = dump_compress_gzip,
9646 +       .compress_name = "GZIP",
9647 +};
9648 +
9649 +/*
9650 + * Name: dump_compress_gzip_init()
9651 + * Func: Initialize gzip as a compression mechanism.
9652 + */
9653 +static int __init
9654 +dump_compress_gzip_init(void)
9655 +{
9656 +       struct page *pg;
9657 +
9658 +       deflate_workspace = vmalloc(zlib_deflate_workspacesize());
9659 +       if (!deflate_workspace) {
9660 +               printk("dump_compress_gzip_init(): Failed to "
9661 +                       "alloc %d bytes for deflate workspace\n",
9662 +                       zlib_deflate_workspacesize());
9663 +               return -ENOMEM;
9664 +       }
9665 +       /*
9666 +        * Need to find pages (workspace) that are used for compression.
9667 +        * Even though zlib_deflate_workspacesize() is 64 pages (approximately)
9668 +        * depends on the arch, we used only 2 pages. Hence, get the physical
9669 +        * addresses for these 2 pages and used them to not to compress those
9670 +        * pages.
9671 +        */
9672 +       pg = vmalloc_to_page(deflate_workspace);
9673 +       workspace_paddr[0] = page_to_pfn(pg) << PAGE_SHIFT;
9674 +       pg = vmalloc_to_page(deflate_workspace + DUMP_PAGE_SIZE);
9675 +       workspace_paddr[1] = page_to_pfn(pg) << PAGE_SHIFT;
9676 +
9677 +       /* Eliminate the possibility of real data getting a compression
9678 +        * failure.
9679 +        */
9680 +
9681 +       if (!(safety_buffer = (void *)__get_free_pages(GFP_KERNEL, 
9682 +                                       get_order(DUMP_PAGE_SIZE))))
9683 +               return -ENOMEM;
9684 +
9685 +       printk("dump gzip safety buffer: %p, %d\n", safety_buffer,
9686 +                       (int)DUMP_PAGE_SIZE);
9687 +
9688 +       dump_register_compression(&dump_gzip_compression);
9689 +       return 0;
9690 +}
9691 +
9692 +/*
9693 + * Name: dump_compress_gzip_cleanup()
9694 + * Func: Remove gzip as a compression mechanism.
9695 + */
9696 +static void __exit
9697 +dump_compress_gzip_cleanup(void)
9698 +{
9699 +       vfree(deflate_workspace);
9700 +       if (safety_buffer) {
9701 +               free_pages((unsigned long)safety_buffer, 
9702 +                               get_order(DUMP_PAGE_SIZE));
9703 +               safety_buffer = NULL;
9704 +       }
9705 +
9706 +       dump_unregister_compression(DUMP_COMPRESS_GZIP);
9707 +}
9708 +
9709 +/* module initialization */
9710 +module_init(dump_compress_gzip_init);
9711 +module_exit(dump_compress_gzip_cleanup);
9712 +
9713 +MODULE_LICENSE("GPL");
9714 +MODULE_AUTHOR("LKCD Development Team <lkcd-devel@lists.sourceforge.net>");
9715 +MODULE_DESCRIPTION("Gzip compression module for crash dump driver");
9716 Index: linux-2.6.10/drivers/dump/dump_filters.c
9717 ===================================================================
9718 --- linux-2.6.10.orig/drivers/dump/dump_filters.c       2005-04-05 19:01:49.158500672 +0800
9719 +++ linux-2.6.10/drivers/dump/dump_filters.c    2005-04-05 16:47:53.942205256 +0800
9720 @@ -0,0 +1,143 @@
9721 +/*
9722 + * Default filters to select data to dump for various passes.
9723 + *
9724 + * Started: Oct 2002 -  Suparna Bhattacharya <suparna@in.ibm.com>
9725 + *     Split and rewrote default dump selection logic to generic dump 
9726 + *     method interfaces 
9727 + * Derived from a portion of dump_base.c created by 
9728 + *     Matt Robinson <yakker@sourceforge.net>)
9729 + *
9730 + * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
9731 + * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
9732 + * Copyright (C) 2002 International Business Machines Corp. 
9733 + *
9734 + * Used during single-stage dumping and during stage 1 of the 2-stage scheme
9735 + * (Stage 2 of the 2-stage scheme uses the fully transparent filters
9736 + * i.e. passthru filters in dump_overlay.c)
9737 + *
9738 + * Future: Custom selective dump may involve a different set of filters.
9739 + *
9740 + * This code is released under version 2 of the GNU GPL.
9741 + */
9742 +
9743 +#include <linux/kernel.h>
9744 +#include <linux/bootmem.h>
9745 +#include <linux/mm.h>
9746 +#include <linux/slab.h>
9747 +#include <linux/dump.h>
9748 +#include "dump_methods.h"
9749 +
9750 +#define DUMP_PFN_SAFETY_MARGIN  1024  /* 4 MB */
9751 +static unsigned long bootmap_pages;
9752 +
9753 +/* Copied from mm/bootmem.c - FIXME */
9754 +/* return the number of _pages_ that will be allocated for the boot bitmap */
9755 +void dump_calc_bootmap_pages (void)
9756 +{
9757 +       unsigned long mapsize;
9758 +       unsigned long pages = num_physpages;
9759 +
9760 +       mapsize = (pages+7)/8;
9761 +       mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK;
9762 +       mapsize >>= PAGE_SHIFT;
9763 +       bootmap_pages = mapsize + DUMP_PFN_SAFETY_MARGIN + 1;
9764 +}
9765 +
9766 +
9767 +/* temporary */
9768 +extern unsigned long min_low_pfn;
9769 +
9770 +
9771 +int dump_low_page(struct page *p)
9772 +{
9773 +       return ((page_to_pfn(p) >= min_low_pfn) &&
9774 +               (page_to_pfn(p) < (min_low_pfn + bootmap_pages)));
9775 +}
9776 +
9777 +static inline int kernel_page(struct page *p)
9778 +{
9779 +       /* FIXME: Need to exclude hugetlb pages. Clue: reserved but inuse */
9780 +       return (PageReserved(p) && !PageInuse(p)) || (!PageLRU(p) && PageInuse(p));
9781 +}
9782 +
9783 +static inline int user_page(struct page *p)
9784 +{
9785 +       return PageInuse(p) && (!PageReserved(p) && PageLRU(p));
9786 +}
9787 +
9788 +static inline int unreferenced_page(struct page *p)
9789 +{
9790 +       return !PageInuse(p) && !PageReserved(p);
9791 +}
9792 +
9793 +
9794 +/* loc marks the beginning of a range of pages */
9795 +int dump_filter_kernpages(int pass, unsigned long loc, unsigned long sz)
9796 +{
9797 +       struct page *page = (struct page *)loc;
9798 +       /* if any of the pages is a kernel page, select this set */     
9799 +       while (sz) {
9800 +               if (dump_low_page(page) || kernel_page(page))
9801 +                       return 1;
9802 +               sz -= PAGE_SIZE;
9803 +               page++;
9804 +       }       
9805 +       return 0;
9806 +}
9807 +
9808 +
9809 +/* loc marks the beginning of a range of pages */
9810 +int dump_filter_userpages(int pass, unsigned long loc, unsigned long sz)
9811 +{
9812 +       struct page *page = (struct page *)loc;
9813 +       int ret = 0;
9814 +       /* select if the set has any user page, and no kernel pages  */ 
9815 +       while (sz) {
9816 +               if (user_page(page) && !dump_low_page(page)) {
9817 +                       ret = 1;
9818 +               } else if (kernel_page(page) || dump_low_page(page)) {
9819 +                       return 0;
9820 +               }
9821 +               page++;
9822 +               sz -= PAGE_SIZE;
9823 +       }       
9824 +       return ret;
9825 +}
9826 +
9827 +
9828 +
9829 +/* loc marks the beginning of a range of pages */
9830 +int dump_filter_unusedpages(int pass, unsigned long loc, unsigned long sz)
9831 +{
9832 +       struct page *page = (struct page *)loc;
9833 +
9834 +       /* select if the set does not have any used pages  */   
9835 +       while (sz) {
9836 +               if (!unreferenced_page(page) || dump_low_page(page)) {
9837 +                       return 0;
9838 +               }
9839 +               page++;
9840 +               sz -= PAGE_SIZE;
9841 +       }       
9842 +       return 1;
9843 +}
9844 +
9845 +/* dummy: last (non-existent) pass */
9846 +int dump_filter_none(int pass, unsigned long loc, unsigned long sz)
9847 +{
9848 +       return 0;
9849 +}
9850 +
9851 +/* TBD: resolve level bitmask ? */
9852 +struct dump_data_filter dump_filter_table[] = {
9853 +       { .name = "kern", .selector = dump_filter_kernpages, 
9854 +               .level_mask = DUMP_MASK_KERN},
9855 +       { .name = "user", .selector = dump_filter_userpages, 
9856 +               .level_mask = DUMP_MASK_USED},
9857 +       { .name = "unused", .selector = dump_filter_unusedpages, 
9858 +               .level_mask = DUMP_MASK_UNUSED},
9859 +       { .name = "none", .selector = dump_filter_none, 
9860 +               .level_mask = DUMP_MASK_REST},
9861 +       { .name = "", .selector = NULL, .level_mask = 0}
9862 +};
9863 +
9864 Index: linux-2.6.10/drivers/dump/dump_ppc64.c
9865 ===================================================================
9866 --- linux-2.6.10.orig/drivers/dump/dump_ppc64.c 2005-04-05 19:01:49.158500672 +0800
9867 +++ linux-2.6.10/drivers/dump/dump_ppc64.c      2005-04-05 16:47:53.931206928 +0800
9868 @@ -0,0 +1,410 @@
9869 +/*
9870 + * Architecture specific (ppc64) functions for Linux crash dumps.
9871 + *
9872 + * Created by: Matt Robinson (yakker@sgi.com)
9873 + *
9874 + * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
9875 + * 
9876 + * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
9877 + * Copyright 2000 TurboLinux, Inc.  All rights reserved.
9878 + * Copyright 2003, 2004 IBM Corporation
9879 + * 
9880 + * This code is released under version 2 of the GNU GPL.
9881 + */
9882 +
9883 +/*
9884 + * The hooks for dumping the kernel virtual memory to disk are in this
9885 + * file.  Any time a modification is made to the virtual memory mechanism,
9886 + * these routines must be changed to use the new mechanisms.
9887 + */
9888 +#include <linux/types.h>
9889 +#include <linux/fs.h>
9890 +#include <linux/dump.h>
9891 +#include <linux/mm.h>
9892 +#include <linux/vmalloc.h>
9893 +#include <linux/delay.h>
9894 +#include <linux/syscalls.h> 
9895 +#include <asm/hardirq.h>
9896 +#include "dump_methods.h"
9897 +#include <linux/irq.h>
9898 +#include <asm/machdep.h>
9899 +#include <asm/uaccess.h>
9900 +#include <asm/irq.h>
9901 +#include <asm/page.h>
9902 +#if defined(CONFIG_KDB) && !defined(CONFIG_DUMP_MODULE)
9903 +#include <linux/kdb.h>
9904 +#endif
9905 +
9906 +extern cpumask_t irq_affinity[];
9907 +
9908 +static cpumask_t saved_affinity[NR_IRQS];
9909 +
9910 +static __s32         saved_irq_count;   /* saved preempt_count() flags */
9911 +
9912 +static int alloc_dha_stack(void)
9913 +{
9914 +        int i;
9915 +        void *ptr;
9916 +
9917 +        if (dump_header_asm.dha_stack[0])
9918 +                return 0;
9919 +
9920 +        ptr = (void *)vmalloc(THREAD_SIZE * num_possible_cpus());
9921 +        if (!ptr) {
9922 +                return -ENOMEM;
9923 +        }
9924 +
9925 +        for (i = 0; i < num_possible_cpus(); i++) {
9926 +                dump_header_asm.dha_stack[i] = 
9927 +                       (uint64_t)((unsigned long)ptr + (i * THREAD_SIZE));
9928 +       }
9929 +       return 0;
9930 +}
9931 +
9932 +static int free_dha_stack(void)
9933 +{
9934 +        if (dump_header_asm.dha_stack[0]) {
9935 +                vfree((void*)dump_header_asm.dha_stack[0]);
9936 +               dump_header_asm.dha_stack[0] = 0;
9937 +       }
9938 +        return 0;
9939 +}
9940 +#ifdef CONFIG_SMP
9941 +static int dump_expect_ipi[NR_CPUS];
9942 +static atomic_t waiting_for_dump_ipi;
9943 +
9944 +extern void stop_this_cpu(void *);
9945 +static int
9946 +dump_ipi_handler(struct pt_regs *regs) 
9947 +{
9948 +       int cpu = smp_processor_id();
9949 +
9950 +       if (!dump_expect_ipi[cpu])
9951 +               return 0;
9952 +       dump_save_this_cpu(regs);
9953 +       atomic_dec(&waiting_for_dump_ipi);
9954 +
9955 + level_changed:
9956 +       switch (dump_silence_level) {
9957 +       case DUMP_HARD_SPIN_CPUS:       /* Spin until dump is complete */
9958 +               while (dump_oncpu) {
9959 +                       barrier();      /* paranoia */
9960 +                       if (dump_silence_level != DUMP_HARD_SPIN_CPUS)
9961 +                               goto level_changed;
9962 +                       cpu_relax();    /* kill time nicely */
9963 +               }
9964 +               break;
9965 +
9966 +       case DUMP_HALT_CPUS:            /* Execute halt */
9967 +               stop_this_cpu(NULL);
9968 +               break;
9969 +       
9970 +       case DUMP_SOFT_SPIN_CPUS:
9971 +               /* Mark the task so it spins in schedule */
9972 +               set_tsk_thread_flag(current, TIF_NEED_RESCHED);
9973 +               break;
9974 +       }
9975 +
9976 +       return 1;
9977 +}
9978 +
9979 +/* save registers on other processors
9980 + * If the other cpus don't respond we simply do not get their states.
9981 + */
9982 +void 
9983 +__dump_save_other_cpus(void)
9984 +{
9985 +       int i, cpu = smp_processor_id();
9986 +       int other_cpus = num_online_cpus()-1;
9987 +       
9988 +       if (other_cpus > 0) {
9989 +               atomic_set(&waiting_for_dump_ipi, other_cpus);
9990 +               for (i = 0; i < NR_CPUS; i++)
9991 +                       dump_expect_ipi[i] = (i != cpu && cpu_online(i));
9992 +
9993 +               printk(KERN_ALERT "sending IPI to other cpus...\n");
9994 +               dump_send_ipi(dump_ipi_handler);
9995 +               /*
9996 +                * may be we dont need to wait for IPI to be processed.
9997 +                * just write out the header at the end of dumping, if
9998 +                * this IPI is not processed until then, there probably
9999 +                * is a problem and we just fail to capture state of
10000 +                * other cpus.
10001 +                * However, we will wait 10 secs for other CPUs to respond. 
10002 +                * If not, proceed the dump process even though we failed
10003 +                * to capture other CPU states. 
10004 +                */
10005 +               i = 10000; /* wait max of 10 seconds */
10006 +               while ((atomic_read(&waiting_for_dump_ipi) > 0) && (--i > 0)) {
10007 +                       barrier();
10008 +                       mdelay(1);
10009 +               } 
10010 +               printk(KERN_ALERT "done waiting: %d cpus not responding\n",
10011 +                      atomic_read(&waiting_for_dump_ipi));
10012 +               dump_send_ipi(NULL);    /* clear handler */
10013 +       }
10014 +}
10015 +
10016 +/*
10017 + * Restore old irq affinities.
10018 + */
10019 +static void
10020 +__dump_reset_irq_affinity(void)
10021 +{
10022 +       int i;
10023 +       irq_desc_t *irq_d;
10024 +
10025 +       memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
10026 +
10027 +       for_each_irq(i) {
10028 +               irq_d = get_irq_desc(i);
10029 +               if (irq_d->handler == NULL) {
10030 +                       continue;
10031 +               }
10032 +               if (irq_d->handler->set_affinity != NULL) {
10033 +                       irq_d->handler->set_affinity(i, saved_affinity[i]);
10034 +               }
10035 +       }
10036 +}
10037 +
10038 +/*
10039 + * Routine to save the old irq affinities and change affinities of all irqs to
10040 + * the dumping cpu.
10041 + *
10042 + * NB: Need to be expanded to multiple nodes.
10043 + */
10044 +static void
10045 +__dump_set_irq_affinity(void)
10046 +{
10047 +       int i;
10048 +       cpumask_t cpu = CPU_MASK_NONE;
10049 +       irq_desc_t *irq_d;
10050 +
10051 +       cpu_set(smp_processor_id(), cpu);
10052 +
10053 +       memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long));
10054 +
10055 +       for_each_irq(i) {
10056 +               irq_d = get_irq_desc(i);
10057 +               if (irq_d->handler == NULL) {
10058 +                       continue;
10059 +               }
10060 +               irq_affinity[i] = cpu;
10061 +               if (irq_d->handler->set_affinity != NULL) {
10062 +                       irq_d->handler->set_affinity(i, irq_affinity[i]);
10063 +               }
10064 +       }
10065 +}
10066 +#else /* !CONFIG_SMP */
10067 +#define __dump_save_other_cpus() do { } while (0)
10068 +#define __dump_set_irq_affinity()      do { } while (0)
10069 +#define __dump_reset_irq_affinity()    do { } while (0)
10070 +#endif /* !CONFIG_SMP */
10071 +
10072 +void
10073 +__dump_save_regs(struct pt_regs *dest_regs, const struct pt_regs *regs)
10074 +{
10075 +       if (regs) {
10076 +               memcpy(dest_regs, regs, sizeof(struct pt_regs));
10077 +       } 
10078 +}
10079 +
10080 +void
10081 +__dump_save_context(int cpu, const struct pt_regs *regs, 
10082 +       struct task_struct *tsk)
10083 +{
10084 +       dump_header_asm.dha_smp_current_task[cpu] = (unsigned long)tsk;
10085 +       __dump_save_regs(&dump_header_asm.dha_smp_regs[cpu], regs);
10086 +
10087 +       /* take a snapshot of the stack */
10088 +       /* doing this enables us to tolerate slight drifts on this cpu */
10089 +
10090 +       if (dump_header_asm.dha_stack[cpu]) {
10091 +               memcpy((void *)dump_header_asm.dha_stack[cpu],
10092 +                               STACK_START_POSITION(tsk),
10093 +                               THREAD_SIZE);
10094 +       }
10095 +       dump_header_asm.dha_stack_ptr[cpu] = (unsigned long)(tsk->thread_info);
10096 +}
10097 +
10098 +/*
10099 + * Name: __dump_configure_header()
10100 + * Func: Configure the dump header with all proper values.
10101 + */
10102 +int
10103 +__dump_configure_header(const struct pt_regs *regs)
10104 +{
10105 +       return (0);
10106 +}
10107 +
10108 +#if defined(CONFIG_KDB) && !defined(CONFIG_DUMP_MODULE)
10109 +int
10110 +kdb_sysdump(int argc, const char **argv, const char **envp, struct pt_regs *regs)
10111 +{
10112 +       kdb_printf("Dumping to disk...\n");
10113 +       dump("dump from kdb", regs);
10114 +       kdb_printf("Dump Complete\n");
10115 +       return 0;
10116 +}
10117 +#endif
10118 +
10119 +/*
10120 + * Name: __dump_init()
10121 + * Func: Initialize the dumping routine process.  This is in case
10122 + *       it's necessary in the future.
10123 + */
10124 +void
10125 +__dump_init(uint64_t local_memory_start)
10126 +{
10127 +#if defined(FIXME) && defined(CONFIG_KDB) && !defined(CONFIG_DUMP_MODULE)
10128 +       /* This won't currently work because interrupts are off in kdb
10129 +        * and the dump process doesn't understand how to recover.
10130 +        */
10131 +       /* ToDo: add a command to query/set dump configuration */
10132 +       kdb_register_repeat("sysdump", kdb_sysdump, "", "use lkcd to dump the system to disk (if configured)", 0, KDB_REPEAT_NONE);
10133 +#endif
10134 +
10135 +       /* return */
10136 +       return;
10137 +}
10138 +
10139 +/*
10140 + * Name: __dump_open()
10141 + * Func: Open the dump device (architecture specific).  This is in
10142 + *       case it's necessary in the future.
10143 + */
10144 +void
10145 +__dump_open(void)
10146 +{
10147 +       alloc_dha_stack();
10148 +}
10149 +
10150 +
10151 +/*
10152 + * Name: __dump_cleanup()
10153 + * Func: Free any architecture specific data structures. This is called
10154 + *       when the dump module is being removed.
10155 + */
10156 +void
10157 +__dump_cleanup(void)
10158 +{
10159 +       free_dha_stack();
10160 +}
10161 +
10162 +/*
10163 + * Kludge - dump from interrupt context is unreliable (Fixme)
10164 + *
10165 + * We do this so that softirqs initiated for dump i/o
10166 + * get processed and we don't hang while waiting for i/o
10167 + * to complete or in any irq synchronization attempt.
10168 + *
10169 + * This is not quite legal of course, as it has the side
10170 + * effect of making all interrupts & softirqs triggered
10171 + * while dump is in progress complete before currently
10172 + * pending softirqs and the currently executing interrupt
10173 + * code.
10174 + */
10175 +static inline void
10176 +irq_bh_save(void)
10177 +{
10178 +       saved_irq_count = irq_count();
10179 +       preempt_count() &= ~(HARDIRQ_MASK|SOFTIRQ_MASK);
10180 +}
10181 +
10182 +static inline void
10183 +irq_bh_restore(void)
10184 +{
10185 +       preempt_count() |= saved_irq_count;
10186 +}
10187 +
10188 +/*
10189 + * Name: __dump_irq_enable
10190 + * Func: Reset system so interrupts are enabled.
10191 + * This is used for dump methods that require interrupts
10192 + * Eventually, all methods will have interrupts disabled
10193 + * and this code can be removed.
10194 + *
10195 + * Change irq affinities
10196 + * Re-enable interrupts
10197 + */
10198 +int
10199 +__dump_irq_enable(void)
10200 +{
10201 +       __dump_set_irq_affinity();
10202 +       irq_bh_save();
10203 +       local_irq_enable();
10204 +       return 0;
10205 +}
10206 +
10207 +/*
10208 + * Name: __dump_irq_restore
10209 + * Func: Resume the system state in an architecture-specific way.
10210 + */
10211 +void
10212 +__dump_irq_restore(void)
10213 +{
10214 +       local_irq_disable();
10215 +       __dump_reset_irq_affinity();
10216 +       irq_bh_restore(); 
10217 +}
10218 +
10219 +#if 0
10220 +/* Cheap progress hack.  It estimates pages to write and
10221 + * assumes all pages will go -- so it may get way off.
10222 + * As the progress is not displayed for other architectures, not used at this 
10223 + * moment.
10224 + */
10225 +void
10226 +__dump_progress_add_page(void)
10227 +{
10228 +       unsigned long total_pages = nr_free_pages() + nr_inactive_pages + nr_active_pages;
10229 +       unsigned int percent = (dump_header.dh_num_dump_pages * 100) / total_pages;
10230 +       char buf[30];
10231 +
10232 +       if (percent > last_percent && percent <= 100) {
10233 +               sprintf(buf, "Dump %3d%%     ", percent);
10234 +               ppc64_dump_msg(0x2, buf);
10235 +               last_percent = percent;
10236 +       }
10237 +
10238 +}
10239 +#endif
10240 +
10241 +extern int dump_page_is_ram(unsigned long);
10242 +/*
10243 + * Name: __dump_page_valid()
10244 + * Func: Check if page is valid to dump.
10245 + */
10246 +int
10247 +__dump_page_valid(unsigned long index)
10248 +{
10249 +       if (!pfn_valid(index))
10250 +               return 0;
10251 +
10252 +       return dump_page_is_ram(index);
10253 +}
10254 +
10255 +/*
10256 + * Name: manual_handle_crashdump()
10257 + * Func: Interface for the lkcd dump command. Calls dump_execute()
10258 + */
10259 +int
10260 +manual_handle_crashdump(void)
10261 +{
10262 +       struct pt_regs regs;
10263 +
10264 +       get_current_regs(&regs);
10265 +       dump_execute("manual", &regs);
10266 +       return 0;
10267 +}
10268 +
10269 +/*
10270 + * Name: __dump_clean_irq_state()
10271 + * Func: Clean up from the previous IRQ handling state. Such as oops from 
10272 + *       interrupt handler or bottom half.
10273 + */
10274 +void
10275 +__dump_clean_irq_state(void)
10276 +{
10277 +    return;
10278 +}
10279 Index: linux-2.6.10/drivers/dump/dump_methods.h
10280 ===================================================================
10281 --- linux-2.6.10.orig/drivers/dump/dump_methods.h       2005-04-05 19:01:49.158500672 +0800
10282 +++ linux-2.6.10/drivers/dump/dump_methods.h    2005-04-05 16:47:53.930207080 +0800
10283 @@ -0,0 +1,357 @@
10284 +/*
10285 + * Generic interfaces for flexible system dump 
10286 + *
10287 + * Started: Oct 2002 -  Suparna Bhattacharya (suparna@in.ibm.com)
10288 + *
10289 + * Copyright (C) 2002 International Business Machines Corp. 
10290 + *
10291 + * This code is released under version 2 of the GNU GPL.
10292 + */
10293 +
10294 +#ifndef _LINUX_DUMP_METHODS_H
10295 +#define _LINUX_DUMP_METHODS_H
10296 +
10297 +/*
10298 + * Inspired by Matt Robinson's suggestion of introducing dump 
10299 + * methods as a way to enable different crash dump facilities to 
10300 + * coexist where each employs its own scheme or dumping policy.
10301 + *
10302 + * The code here creates a framework for flexible dump by defining 
10303 + * a set of methods and providing associated helpers that differentiate
10304 + * between the underlying mechanism (how to dump), overall scheme 
10305 + * (sequencing of stages and data dumped and associated quiescing), 
10306 + * output format (what the dump output looks like), target type 
10307 + * (where to save the dump; see dumpdev.h), and selection policy 
10308 + * (state/data to dump).
10309 + * 
10310 + * These sets of interfaces can be mixed and matched to build a 
10311 + * dumper suitable for a given situation, allowing for 
10312 + * flexibility as well appropriate degree of code reuse.
10313 + * For example all features and options of lkcd (including
10314 + * granular selective dumping in the near future) should be
10315 + * available even when say, the 2 stage soft-boot based mechanism 
10316 + * is used for taking disruptive dumps.
10317 + *
10318 + * Todo: Additionally modules or drivers may supply their own
10319 + * custom dumpers which extend dump with module specific
10320 + * information or hardware state, and can even tweak the
10321 + * mechanism when it comes to saving state relevant to
10322 + * them.
10323 + */
10324 +
10325 +#include <linux/sched.h>
10326 +#include <linux/slab.h>
10327 +#include <linux/highmem.h>
10328 +#include <linux/dumpdev.h>
10329 +#include <asm/page.h>  /* get_order */
10330 +
10331 +#define MAX_PASSES     6
10332 +#define MAX_DEVS       4
10333 +
10334 +
10335 +/* To customise selection of pages to be dumped in a given pass/group */
10336 +struct dump_data_filter{
10337 +       char name[32];
10338 +       int (*selector)(int, unsigned long, unsigned long);
10339 +       ulong level_mask; /* dump level(s) for which this filter applies */
10340 +       loff_t start[MAX_NUMNODES], end[MAX_NUMNODES]; /* location range applicable */
10341 +       ulong num_mbanks;  /* Number of memory banks. Greater than one for discontig memory (NUMA) */
10342 +};
10343 +
10344 +
10345 +/* 
10346 + * Determined by the kind of dump mechanism and appropriate 
10347 + * overall scheme 
10348 + */ 
10349 +struct dump_scheme_ops {
10350 +       /* sets aside memory, inits data structures etc */
10351 +       int (*configure)(unsigned long devid); 
10352 +       /* releases  resources */
10353 +       int (*unconfigure)(void); 
10354 +
10355 +       /* ordering of passes, invoking iterator */
10356 +       int (*sequencer)(void); 
10357 +        /* iterates over system data, selects and acts on data to dump */
10358 +       int (*iterator)(int, int (*)(unsigned long, unsigned long), 
10359 +               struct dump_data_filter *); 
10360 +        /* action when data is selected for dump */
10361 +       int (*save_data)(unsigned long, unsigned long); 
10362 +        /* action when data is to be excluded from dump */
10363 +       int (*skip_data)(unsigned long, unsigned long); 
10364 +       /* policies for space, multiple dump devices etc */
10365 +       int (*write_buffer)(void *, unsigned long); 
10366 +};
10367 +
10368 +struct dump_scheme {
10369 +       /* the name serves as an anchor to locate the scheme after reboot */
10370 +       char name[32]; 
10371 +       struct dump_scheme_ops *ops;
10372 +       struct list_head list;
10373 +};
10374 +
10375 +/* Quiescing/Silence levels (controls IPI callback behaviour) */
10376 +extern enum dump_silence_levels {
10377 +       DUMP_SOFT_SPIN_CPUS     = 1,
10378 +       DUMP_HARD_SPIN_CPUS     = 2,
10379 +       DUMP_HALT_CPUS          = 3,
10380 +} dump_silence_level;
10381 +
10382 +/* determined by the dump (file) format */
10383 +struct dump_fmt_ops {
10384 +       /* build header */
10385 +       int (*configure_header)(const char *, const struct pt_regs *); 
10386 +       int (*update_header)(void); /* update header and write it out */
10387 +       /* save curr context  */
10388 +       void (*save_context)(int, const struct pt_regs *, 
10389 +               struct task_struct *); 
10390 +       /* typically called by the save_data action */
10391 +       /* add formatted data to the dump buffer */
10392 +       int (*add_data)(unsigned long, unsigned long); 
10393 +       int (*update_end_marker)(void);
10394 +};
10395 +
10396 +struct dump_fmt {
10397 +       unsigned long magic; 
10398 +       char name[32];  /* lcrash, crash, elf-core etc */
10399 +       struct dump_fmt_ops *ops;
10400 +       struct list_head list;
10401 +};
10402 +
10403 +/* 
10404 + * Modules will be able add their own data capture schemes by 
10405 + * registering their own dumpers. Typically they would use the 
10406 + * primary dumper as a template and tune it with their routines.
10407 + * Still Todo.
10408 + */
10409 +
10410 +/* The combined dumper profile (mechanism, scheme, dev, fmt) */
10411 +struct dumper {
10412 +       char name[32]; /* singlestage, overlay (stg1), passthru(stg2), pull */
10413 +       struct dump_scheme *scheme;
10414 +       struct dump_fmt *fmt;
10415 +       struct __dump_compress *compress;
10416 +       struct dump_data_filter *filter;
10417 +       struct dump_dev *dev; 
10418 +       /* state valid only for active dumper(s) - per instance */
10419 +       /* run time state/context */
10420 +       int curr_pass;
10421 +       unsigned long count;
10422 +       loff_t curr_offset; /* current logical offset into dump device */
10423 +       loff_t curr_loc; /* current memory location */
10424 +       void *curr_buf; /* current position in the dump buffer */
10425 +       void *dump_buf; /* starting addr of dump buffer */
10426 +       int header_dirty; /* whether the header needs to be written out */
10427 +       int header_len; 
10428 +       struct list_head dumper_list; /* links to other dumpers */
10429 +};     
10430 +
10431 +/* Starting point to get to the current configured state */
10432 +struct dump_config {
10433 +       ulong level;
10434 +       ulong flags;
10435 +       struct dumper *dumper;
10436 +       unsigned long dump_device;
10437 +       unsigned long dump_addr; /* relevant only for in-memory dumps */
10438 +       struct list_head dump_dev_list;
10439 +};     
10440 +
10441 +extern struct dump_config dump_config;
10442 +
10443 +/* Used to save the dump config across a reboot for 2-stage dumps: 
10444 + * 
10445 + * Note: The scheme, format, compression and device type should be 
10446 + * registered at bootup, for this config to be sharable across soft-boot. 
10447 + * The function addresses could have changed and become invalid, and
10448 + * need to be set up again.
10449 + */
10450 +struct dump_config_block {
10451 +       u64 magic; /* for a quick sanity check after reboot */
10452 +       struct dump_memdev memdev; /* handle to dump stored in memory */
10453 +       struct dump_config config;
10454 +       struct dumper dumper;
10455 +       struct dump_scheme scheme;
10456 +       struct dump_fmt fmt;
10457 +       struct __dump_compress compress;
10458 +       struct dump_data_filter filter_table[MAX_PASSES];
10459 +       struct dump_anydev dev[MAX_DEVS]; /* target dump device */
10460 +};
10461 +
10462 +
10463 +/* Wrappers that invoke the methods for the current (active) dumper */
10464 +
10465 +/* Scheme operations */
10466 +
10467 +static inline int dump_sequencer(void)
10468 +{
10469 +       return dump_config.dumper->scheme->ops->sequencer();
10470 +}
10471 +
10472 +static inline int dump_iterator(int pass, int (*action)(unsigned long, 
10473 +       unsigned long), struct dump_data_filter *filter)
10474 +{
10475 +       return dump_config.dumper->scheme->ops->iterator(pass, action, filter);
10476 +}
10477 +
10478 +#define dump_save_data dump_config.dumper->scheme->ops->save_data
10479 +#define dump_skip_data dump_config.dumper->scheme->ops->skip_data
10480 +
10481 +static inline int dump_write_buffer(void *buf, unsigned long len)
10482 +{
10483 +       return dump_config.dumper->scheme->ops->write_buffer(buf, len);
10484 +}
10485 +
10486 +static inline int dump_configure(unsigned long devid)
10487 +{
10488 +       return dump_config.dumper->scheme->ops->configure(devid);
10489 +}
10490 +
10491 +static inline int dump_unconfigure(void)
10492 +{
10493 +       return dump_config.dumper->scheme->ops->unconfigure();
10494 +}
10495 +
10496 +/* Format operations */
10497 +
10498 +static inline int dump_configure_header(const char *panic_str, 
10499 +       const struct pt_regs *regs)
10500 +{
10501 +       return dump_config.dumper->fmt->ops->configure_header(panic_str, regs);
10502 +}
10503 +
10504 +static inline void dump_save_context(int cpu, const struct pt_regs *regs, 
10505 +               struct task_struct *tsk)
10506 +{
10507 +       dump_config.dumper->fmt->ops->save_context(cpu, regs, tsk);
10508 +}
10509 +
10510 +static inline int dump_save_this_cpu(const struct pt_regs *regs)
10511 +{
10512 +       int cpu = smp_processor_id();
10513 +
10514 +       dump_save_context(cpu, regs, current);
10515 +       return 1;
10516 +}
10517 +
10518 +static inline int dump_update_header(void)
10519 +{
10520 +       return dump_config.dumper->fmt->ops->update_header();
10521 +}
10522 +
10523 +static inline int dump_update_end_marker(void)
10524 +{
10525 +       return dump_config.dumper->fmt->ops->update_end_marker();
10526 +}
10527 +
10528 +static inline int dump_add_data(unsigned long loc, unsigned long sz)
10529 +{
10530 +       return dump_config.dumper->fmt->ops->add_data(loc, sz);
10531 +}
10532 +
10533 +/* Compression operation */
10534 +static inline int dump_compress_data(char *src, int slen, char *dst,
10535 +               unsigned long loc)
10536 +{
10537 +       return dump_config.dumper->compress->compress_func(src, slen, 
10538 +               dst, DUMP_DPC_PAGE_SIZE, loc);
10539 +}
10540 +
10541 +
10542 +/* Prototypes of some default implementations of dump methods */
10543 +
10544 +extern struct __dump_compress dump_none_compression;
10545 +
10546 +/* Default scheme methods (dump_scheme.c) */
10547 +
10548 +extern int dump_generic_sequencer(void);
10549 +extern int dump_page_iterator(int pass, int (*action)(unsigned long, unsigned
10550 +       long), struct dump_data_filter *filter);
10551 +extern int dump_generic_save_data(unsigned long loc, unsigned long sz);
10552 +extern int dump_generic_skip_data(unsigned long loc, unsigned long sz);
10553 +extern int dump_generic_write_buffer(void *buf, unsigned long len);
10554 +extern int dump_generic_configure(unsigned long);
10555 +extern int dump_generic_unconfigure(void);
10556 +#ifdef CONFIG_DISCONTIGMEM
10557 +extern void dump_reconfigure_mbanks(void);
10558 +#endif
10559 +
10560 +/* Default scheme template */
10561 +extern struct dump_scheme dump_scheme_singlestage;
10562 +
10563 +/* Default dump format methods */
10564 +
10565 +extern int dump_lcrash_configure_header(const char *panic_str, 
10566 +       const struct pt_regs *regs);
10567 +extern void dump_lcrash_save_context(int  cpu, const struct pt_regs *regs, 
10568 +       struct task_struct *tsk);
10569 +extern int dump_generic_update_header(void);
10570 +extern int dump_lcrash_add_data(unsigned long loc, unsigned long sz);
10571 +extern int dump_lcrash_update_end_marker(void);
10572 +
10573 +/* Default format (lcrash) template */
10574 +extern struct dump_fmt dump_fmt_lcrash;
10575 +
10576 +/* Default dump selection filter table */
10577 +
10578 +/* 
10579 + * Entries listed in order of importance and correspond to passes
10580 + * The last entry (with a level_mask of zero) typically reflects data that 
10581 + * won't be dumped  -- this may for example be used to identify data 
10582 + * that will be skipped for certain so the corresponding memory areas can be 
10583 + * utilized as scratch space.
10584 + */   
10585 +extern struct dump_data_filter dump_filter_table[];
10586 +
10587 +/* Some pre-defined dumpers */
10588 +extern struct dumper dumper_singlestage;
10589 +extern struct dumper dumper_stage1;
10590 +extern struct dumper dumper_stage2;
10591 +
10592 +/* These are temporary */
10593 +#define DUMP_MASK_HEADER       DUMP_LEVEL_HEADER
10594 +#define DUMP_MASK_KERN         DUMP_LEVEL_KERN
10595 +#define DUMP_MASK_USED         DUMP_LEVEL_USED
10596 +#define DUMP_MASK_UNUSED       DUMP_LEVEL_ALL_RAM
10597 +#define DUMP_MASK_REST         0 /* dummy for now */
10598 +
10599 +/* Helpers - move these to dump.h later ? */
10600 +
10601 +int dump_generic_execute(const char *panic_str, const struct pt_regs *regs);
10602 +extern int dump_ll_write(void *buf, unsigned long len); 
10603 +int dump_check_and_free_page(struct dump_memdev *dev, struct page *page);
10604 +
10605 +static inline void dumper_reset(void)
10606 +{
10607 +       dump_config.dumper->curr_buf = dump_config.dumper->dump_buf;
10608 +       dump_config.dumper->curr_loc = 0;
10609 +       dump_config.dumper->curr_offset = 0;
10610 +       dump_config.dumper->count = 0;
10611 +       dump_config.dumper->curr_pass = 0;
10612 +}
10613 +
10614 +/* 
10615 + * May later be moulded to perform boot-time allocations so we can dump 
10616 + * earlier during bootup 
10617 + */
10618 +static inline void *dump_alloc_mem(unsigned long size)
10619 +{
10620 +       return (void *) __get_free_pages(GFP_KERNEL, get_order(size));
10621 +}
10622 +
10623 +static inline void dump_free_mem(void *buf)
10624 +{
10625 +       struct page *page;
10626 +
10627 +       /* ignore reserved pages (e.g. post soft boot stage) */
10628 +       if (buf && (page = virt_to_page(buf))) {
10629 +               if (PageReserved(page))
10630 +                       return;
10631 +       }
10632 +       /*
10633 +        * Allocated using __get_free_pages().
10634 +        */
10635 +       free_pages((unsigned long)buf, 
10636 +               get_order(DUMP_BUFFER_SIZE + 3 * DUMP_PAGE_SIZE));
10637 +}
10638 +
10639 +
10640 +#endif /*  _LINUX_DUMP_METHODS_H */
10641 Index: linux-2.6.10/drivers/dump/Makefile
10642 ===================================================================
10643 --- linux-2.6.10.orig/drivers/dump/Makefile     2005-04-05 19:01:49.158500672 +0800
10644 +++ linux-2.6.10/drivers/dump/Makefile  2005-04-05 16:47:53.947204496 +0800
10645 @@ -0,0 +1,22 @@
10646 +#
10647 +# Makefile for the dump device drivers.
10648 +#
10649 +
10650 +dump-y                                 := dump_setup.o dump_fmt.o dump_filters.o dump_scheme.o dump_execute.o
10651 +ifeq ($(CONFIG_X86_64),)
10652 +ifeq ($(CONFIG_X86),y)
10653 +dump-$(CONFIG_X86)                     += dump_i386.o
10654 +endif
10655 +endif
10656 +dump-$(CONFIG_ARM)                     += dump_arm.o
10657 +dump-$(CONFIG_PPC64)                    += dump_ppc64.o
10658 +dump-$(CONFIG_X86_64)                  += dump_x8664.o
10659 +dump-$(CONFIG_IA64)                    += dump_ia64.o
10660 +dump-$(CONFIG_CRASH_DUMP_MEMDEV)       += dump_memdev.o dump_overlay.o
10661 +dump-objs                              += $(dump-y)
10662 +
10663 +obj-$(CONFIG_CRASH_DUMP)               += dump.o 
10664 +obj-$(CONFIG_CRASH_DUMP_BLOCKDEV)      += dump_blockdev.o
10665 +obj-$(CONFIG_CRASH_DUMP_NETDEV)        += dump_netdev.o
10666 +obj-$(CONFIG_CRASH_DUMP_COMPRESS_RLE)  += dump_rle.o
10667 +obj-$(CONFIG_CRASH_DUMP_COMPRESS_GZIP) += dump_gzip.o
10668 Index: linux-2.6.10/drivers/Makefile
10669 ===================================================================
10670 --- linux-2.6.10.orig/drivers/Makefile  2004-12-25 05:36:00.000000000 +0800
10671 +++ linux-2.6.10/drivers/Makefile       2005-04-05 16:47:53.950204040 +0800
10672 @@ -60,3 +60,4 @@
10673  obj-$(CONFIG_CPU_FREQ)         += cpufreq/
10674  obj-$(CONFIG_MMC)              += mmc/
10675  obj-y                          += firmware/
10676 +obj-$(CONFIG_CRASH_DUMP)       += dump/