diff -urN linux-2.4.7/Documentation/Configure.help linux-2.4.7-mcore/Documentation/Configure.help
--- linux-2.4.7/Documentation/Configure.help	Thu Jul 19 20:48:15 2001
+++ linux-2.4.7-mcore/Documentation/Configure.help	Fri Jul 27 14:58:14 2001
@@ -17569,6 +17569,35 @@
    boards supported by this driver, and for further information 
    on the use of this driver. 
 
+Boot kernel image support
+CONFIG_BOOTIMG
+  Add support for booting a new Linux kernel from a running Linux
+  system. You need to download the bootimg(8) utility from
+  ftp://icaftp.epfl.ch/pub/people/almesber/misc/bootimg-current.tar.gz
+  in order to use this functionality.
+
+Protect SMP configuration tables
+CONFIG_BOOTIMG_SMP
+  On SMP systems, the BIOS stores tables with configuration data in
+  memory and an SMP-enabled kernel reads these tables. However, a
+  kernel without SMP support will overwrite such tables. If a kernel
+  without SMP support used bootimg to boot an SMP-enabled kernel, the
+  latter will probably crash when trying to read the SMP tables. The
+  CONFIG_BOOTIMG_SMP option enables minimal support for scanning and
+  protecting of SMP configuration tables also for kernels without SMP
+  support.
+
+In-memory kernel core dump facility
+CONFIG_MCL_COREDUMP
+  In conjunction with bootimg, this allows you to get kernel core dumps
+  of your system at panic() time.  The panic call is modified so that it
+  calls the core dump facility and reboots the system.  On the way back 
+  up, the kernel dump image is written out to disk by the accompanying 
+  init script.  You can use the crash analysis tool to analyze the core 
+  dump.  This tool can be found at :
+
+	 http://www.missioncriticallinux.com/download
+
 #
 # ARM options
 #
diff -urN linux-2.4.7/Makefile linux-2.4.7-mcore/Makefile
--- linux-2.4.7/Makefile	Fri Jul 20 01:03:56 2001
+++ linux-2.4.7-mcore/Makefile	Fri Jul 27 15:00:19 2001
@@ -16,7 +16,7 @@
 FINDHPATH	= $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net
 
 HOSTCC  	= gcc
-HOSTCFLAGS	= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+HOSTCFLAGS	= -Wall -Wstrict-prototypes -O2 -g
 
 CROSS_COMPILE 	=
 
@@ -88,8 +88,14 @@
 CPPFLAGS := -D__KERNEL__ -I$(HPATH)
 
 CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
-	  -fomit-frame-pointer -fno-strict-aliasing -fno-common
+	  -fno-strict-aliasing -fno-common
 AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
+
+ifeq ($(CONFIG_MCL_COREDUMP),y)
+	CFLAGS += -g
+else
+	CFLAGS += -fomit-frame-pointer
+endif
 
 #
 # ROOT_DEV specifies the default root-device when making the image.
diff -urN linux-2.4.7/arch/alpha/config.in linux-2.4.7-mcore/arch/alpha/config.in
--- linux-2.4.7/arch/alpha/config.in	Tue Jul 10 23:08:51 2001
+++ linux-2.4.7-mcore/arch/alpha/config.in	Fri Jul 27 14:58:14 2001
@@ -364,5 +364,6 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 
 bool 'Legacy kernel start address' CONFIG_ALPHA_LEGACY_START_ADDRESS
+bool 'Kernel Core Dump Facility' CONFIG_MCL_COREDUMP
 
 endmenu
diff -urN linux-2.4.7/arch/alpha/kernel/Makefile linux-2.4.7-mcore/arch/alpha/kernel/Makefile
--- linux-2.4.7/arch/alpha/kernel/Makefile	Fri Feb  9 14:38:01 2001
+++ linux-2.4.7-mcore/arch/alpha/kernel/Makefile	Fri Jul 27 14:58:14 2001
@@ -45,6 +45,9 @@
 
 else
 
+# MCLX crash dump support
+obj-$(CONFIG_MCL_COREDUMP) += crash.o
+
 # Core logic support
 obj-$(CONFIG_ALPHA_APECS) += core_apecs.o
 obj-$(CONFIG_ALPHA_CIA) += core_cia.o
diff -urN linux-2.4.7/arch/alpha/kernel/crash.c linux-2.4.7-mcore/arch/alpha/kernel/crash.c
--- linux-2.4.7/arch/alpha/kernel/crash.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/arch/alpha/kernel/crash.c	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,130 @@
+/*
+ *  linux/arch/alpha/crash.c
+ *
+ *  Architecture dependant code for MCL in-memory core dump.
+ */
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/crash.h>
+#include <linux/reboot.h>
+#include <linux/bootimg.h>
+
+unsigned long crash_console_sp = 0;
+
+inline void crash_save_regs(void) {
+	static unsigned long gprs[32];
+
+	__asm__ __volatile__("stq $0,%0" : "=m"(gprs[0]));
+        __asm__ __volatile__("stq $1,%0" : "=m"(gprs[1]));
+        __asm__ __volatile__("stq $2,%0" : "=m"(gprs[2]));
+        __asm__ __volatile__("stq $3,%0" : "=m"(gprs[3]));
+        __asm__ __volatile__("stq $4,%0" : "=m"(gprs[4]));
+        __asm__ __volatile__("stq $5,%0" : "=m"(gprs[5]));
+        __asm__ __volatile__("stq $6,%0" : "=m"(gprs[6]));
+        __asm__ __volatile__("stq $7,%0" : "=m"(gprs[7]));
+        __asm__ __volatile__("stq $8,%0" : "=m"(gprs[8]));
+        __asm__ __volatile__("stq $9,%0" : "=m"(gprs[9]));
+        __asm__ __volatile__("stq $10,%0" : "=m"(gprs[10]));
+        __asm__ __volatile__("stq $11,%0" : "=m"(gprs[11]));
+        __asm__ __volatile__("stq $12,%0" : "=m"(gprs[12]));
+        __asm__ __volatile__("stq $13,%0" : "=m"(gprs[13]));
+        __asm__ __volatile__("stq $14,%0" : "=m"(gprs[14]));
+        __asm__ __volatile__("stq $15,%0" : "=m"(gprs[15]));
+        __asm__ __volatile__("stq $16,%0" : "=m"(gprs[16]));
+        __asm__ __volatile__("stq $17,%0" : "=m"(gprs[17]));
+        __asm__ __volatile__("stq $18,%0" : "=m"(gprs[18]));
+        __asm__ __volatile__("stq $19,%0" : "=m"(gprs[19]));
+        __asm__ __volatile__("stq $20,%0" : "=m"(gprs[20]));
+        __asm__ __volatile__("stq $21,%0" : "=m"(gprs[21]));
+        __asm__ __volatile__("stq $22,%0" : "=m"(gprs[22]));
+        __asm__ __volatile__("stq $23,%0" : "=m"(gprs[23]));
+        __asm__ __volatile__("stq $24,%0" : "=m"(gprs[24]));
+        __asm__ __volatile__("stq $25,%0" : "=m"(gprs[25]));
+        __asm__ __volatile__("stq $26,%0" : "=m"(gprs[26]));
+        __asm__ __volatile__("stq $27,%0" : "=m"(gprs[27]));
+        __asm__ __volatile__("stq $28,%0" : "=m"(gprs[28]));
+        __asm__ __volatile__("stq $29,%0" : "=m"(gprs[29]));
+        __asm__ __volatile__("stq $30,%0" : "=m"(gprs[30]));
+	__asm__ __volatile__("stq $31,%0" : "=m"(gprs[31]));
+
+	panic_regs = gprs;
+}
+
+/*
+ *  Save the current stack pointer.
+ */
+void crash_save_current_state(struct task_struct *tp)
+{
+	register unsigned long sp __asm__("$30");
+	tp->thread.ksp = sp;
+	panic_ksp[smp_processor_id()] = sp;
+	mb();
+	
+	save_core();
+
+	/* save_core only returns if we're running on the boot cpu */
+	crash_halt_or_reboot(1);
+}
+
+/*
+ *  If we are not the panicking thread, we simply halt.  Otherwise,
+ *  we take care of calling the reboot code.
+ */
+void crash_halt_or_reboot(int boot_cpu)
+{
+	unsigned long *pflags, flags;
+	struct percpu_struct *cpup;
+	int cpuid = smp_processor_id();
+
+	cpup = (struct percpu_struct *)
+			((unsigned long)hwrpb + hwrpb->processor_offset
+			 + hwrpb->processor_size * cpuid);
+
+	pflags = &cpup->flags;
+	flags = *pflags;
+
+#ifdef CONFIG_SMP
+	if (!boot_cpu) {
+		flags |= 0x00040000UL; /* "halt machine" */
+		*pflags = flags;
+		clear_bit(cpuid, &cpu_present_mask);
+		halt();
+	}
+	else {
+#else
+	{
+#endif
+		printk("crash_halt_or_reboot: ");
+		if (console_crash) {
+			printk("halting system.  Type 'b' to boot.\n");
+			halt();
+		}
+		printk("restarting system.\n");
+		machine_restart(NULL);
+	}
+}
+
+void crash_cleanup_smp_state(void)
+{
+	/*
+	 * Not much to be done here for alpha.
+	 */
+	__cli();
+}
+
+/*
+ *  Crash IPI
+ */
+void smp_crash_funnel_cpu(void)
+{
+	crash_save_current_state(current);
+}
+
+void crash_callin(void)
+{
+	console_crash = 1;
+	smp_call_function((void*)smp_crash_funnel_cpu,0,0,0);
+	crash_save_current_state(current);
+	/* NOTREACHED */
+}
diff -urN linux-2.4.7/arch/alpha/kernel/head.S linux-2.4.7-mcore/arch/alpha/kernel/head.S
--- linux-2.4.7/arch/alpha/kernel/head.S	Mon Apr 24 16:39:34 2000
+++ linux-2.4.7-mcore/arch/alpha/kernel/head.S	Fri Jul 27 14:58:14 2001
@@ -55,6 +55,21 @@
 	.end __smp_callin
 #endif /* CONFIG_SMP */
 
+#ifdef CONFIG_MCL_COREDUMP
+	.align 3
+	.globl  __crash_callin
+	.ent    __crash_callin
+__crash_callin:
+	.prologue 1
+	ldgp	$29,0($27)
+	lda	$9,crash_console_sp
+	ldq $10,0($9)
+	lda $30, 0x2000($10) /* one page of stack */
+	jsr $26,crash_callin
+	call_pal PAL_halt
+    .end __crash_callin
+
+#endif /* CONFIG_MCL_COREDUMP */
 	#
 	# The following two functions are needed for supporting SRM PALcode
 	# on the PC164 (at least), since that PALcode manages the interrupt
diff -urN linux-2.4.7/arch/alpha/kernel/process.c linux-2.4.7-mcore/arch/alpha/kernel/process.c
--- linux-2.4.7/arch/alpha/kernel/process.c	Wed Jun 20 14:10:27 2001
+++ linux-2.4.7-mcore/arch/alpha/kernel/process.c	Fri Jul 27 14:58:14 2001
@@ -119,16 +119,20 @@
 	flags &= ~0x00ff0001UL;
 
 #ifdef CONFIG_SMP
-	/* Secondaries halt here. */
-	if (cpuid != boot_cpuid) {
-		flags |= 0x00040000UL; /* "remain halted" */
-		*pflags = flags;
-		clear_bit(cpuid, &cpu_present_mask);
-		halt();
-	}
+	if (how->mode != LINUX_REBOOT_CMD_COREDUMP) {
+		/* Secondaries halt here. */
+		if (cpuid != boot_cpuid) {
+			flags |= 0x00040000UL; /* "remain halted" */
+			*pflags = flags;
+			clear_bit(cpuid, &cpu_present_mask);
+			halt();
+		}
+        }
 #endif
 
-	if (how->mode == LINUX_REBOOT_CMD_RESTART) {
+	if (how->mode == LINUX_REBOOT_CMD_RESTART ||
+		how->mode == LINUX_REBOOT_CMD_COREDUMP) {
+
 		if (!how->restart_cmd) {
 			flags |= 0x00020000UL; /* "cold bootstrap" */
 		} else {
@@ -148,10 +152,12 @@
 	*pflags = flags;
 
 #ifdef CONFIG_SMP
-	/* Wait for the secondaries to halt. */
-	clear_bit(boot_cpuid, &cpu_present_mask);
-	while (cpu_present_mask)
-		barrier();
+	if (how->mode != LINUX_REBOOT_CMD_COREDUMP) {
+		/* Wait for the secondaries to halt. */
+		clear_bit(boot_cpuid, &cpu_present_mask);
+		while (cpu_present_mask)
+			barrier();
+	}
 #endif
 
         /* If booted from SRM, reset some of the original environment. */
@@ -180,6 +186,7 @@
 	halt();
 }
 
+extern char *panicmsg;
 static void
 common_shutdown(int mode, char *restart_cmd)
 {
@@ -187,7 +194,8 @@
 	args.mode = mode;
 	args.restart_cmd = restart_cmd;
 #ifdef CONFIG_SMP
-	smp_call_function(common_shutdown_1, &args, 1, 0);
+	if(!panicmsg)
+		smp_call_function(common_shutdown_1, &args, 1, 0);
 #endif
 	common_shutdown_1(&args);
 }
@@ -195,6 +203,9 @@
 void
 machine_restart(char *restart_cmd)
 {
+	if (panicmsg)
+		common_shutdown(LINUX_REBOOT_CMD_COREDUMP, restart_cmd);
+	else
 	common_shutdown(LINUX_REBOOT_CMD_RESTART, restart_cmd);
 }
 
diff -urN linux-2.4.7/arch/alpha/kernel/setup.c linux-2.4.7-mcore/arch/alpha/kernel/setup.c
--- linux-2.4.7/arch/alpha/kernel/setup.c	Thu May 24 18:20:18 2001
+++ linux-2.4.7-mcore/arch/alpha/kernel/setup.c	Fri Jul 27 14:58:14 2001
@@ -56,6 +56,9 @@
 #include "proto.h"
 #include "pci_impl.h"
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
 
 struct hwrpb_struct *hwrpb;
 unsigned long srm_hae;
@@ -241,7 +244,7 @@
 	struct memdesc_struct * memdesc;
 	unsigned long start_kernel_pfn, end_kernel_pfn;
 	unsigned long bootmap_size, bootmap_pages, bootmap_start;
-	unsigned long start, end;
+	unsigned long start, end,  crash_pages=0;
 	int i;
 
 	/* Find free clusters, and init and free the bootmem accordingly.  */
@@ -286,6 +289,9 @@
 	bootmap_pages = bootmem_bootmap_pages(max_low_pfn);
 
 	/* Now find a good region where to allocate the bootmap.  */
+#ifdef CONFIG_MCL_COREDUMP
+	crash_pages = crash_pages_needed();
+#endif
 	for_each_mem_cluster(memdesc, cluster, i) {
 		if (cluster->usage & 3)
 			continue;
@@ -305,7 +311,7 @@
 				end = start_kernel_pfn;
 		} else if (start < end_kernel_pfn)
 			start = end_kernel_pfn;
-		if (end - start >= bootmap_pages) {
+		if (end - start >= (bootmap_pages + crash_pages)) {
 			bootmap_start = start;
 			break;
 		}
@@ -316,6 +322,11 @@
 		goto try_again;
 	}
 
+#ifdef CONFIG_MCL_COREDUMP
+	crash_init((u_long)phys_to_virt(PFN_PHYS(bootmap_start)),
+		   (u_long)phys_to_virt(PFN_PHYS(bootmap_start + bootmap_pages)),
+		   (u_long)phys_to_virt(PFN_PHYS(bootmap_start + bootmap_pages + crash_pages)));
+#endif
 	/* Allocate the bootmap and mark the whole MM as reserved.  */
 	bootmap_size = init_bootmem(bootmap_start, max_low_pfn);
 
@@ -349,8 +360,18 @@
 		printk("freeing pages %ld:%ld\n", start, end);
 	}
 
-	/* Reserve the bootmap memory.  */
+	/* Reserve the bootmap and crash memory.  */
+#ifndef CONFIG_MCL_COREDUMP
 	reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size);
+#else
+	reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size +
+			crash_pages * PAGE_SIZE);
+
+	/* reserve crash pages */
+	crash_mark_dump_reserved();
+	crash_console_sp = (unsigned long)alloc_bootmem(PAGE_SIZE) |
+					0xfffffc0000000000;
+#endif
 	printk("reserving pages %ld:%ld\n", bootmap_start, bootmap_start+PFN_UP(bootmap_size));
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff -urN linux-2.4.7/arch/alpha/kernel/smp.c linux-2.4.7-mcore/arch/alpha/kernel/smp.c
--- linux-2.4.7/arch/alpha/kernel/smp.c	Mon Jun 11 22:15:27 2001
+++ linux-2.4.7-mcore/arch/alpha/kernel/smp.c	Fri Jul 27 14:58:14 2001
@@ -35,6 +35,9 @@
 #include "proto.h"
 #include "irq_impl.h"
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <asm/crash.h>
+#endif
 
 #define DEBUG_SMP 0
 #if DEBUG_SMP
@@ -647,6 +650,15 @@
 	       ((bogosum + 2500) / (5000/HZ)) % 100);
 
 	smp_num_cpus = cpu_count;
+
+#ifdef CONFIG_MCL_COREDUMP
+	/*
+	 *  Here we set things up so we can get a crash from the SRM console.
+	 */
+	hwrpb->CPU_restart = __crash_callin; /*__smp_callin;*/
+	hwrpb->CPU_restart_data = (unsigned long) __crash_callin;/*__smp_callin;*/
+	hwrpb_update_checksum(hwrpb);
+#endif
 }
 
 /*
diff -urN linux-2.4.7/arch/alpha/kernel/traps.c linux-2.4.7-mcore/arch/alpha/kernel/traps.c
--- linux-2.4.7/arch/alpha/kernel/traps.c	Wed Jul  4 14:50:38 2001
+++ linux-2.4.7-mcore/arch/alpha/kernel/traps.c	Fri Jul 27 14:58:14 2001
@@ -15,6 +15,10 @@
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
+
 #include <asm/gentrap.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
@@ -536,6 +540,10 @@
 		while (1);
 	}
 	current->thread.flags |= (1UL << 63);
+#ifdef CONFIG_MCL_COREDUMP
+	if(panic_on_oops)
+		panic("die_if_kernel");
+#endif
 	do_exit(SIGSEGV);
 }
 
diff -urN linux-2.4.7/arch/i386/boot/compressed/head.S linux-2.4.7-mcore/arch/i386/boot/compressed/head.S
--- linux-2.4.7/arch/i386/boot/compressed/head.S	Wed Jul  5 15:03:12 2000
+++ linux-2.4.7-mcore/arch/i386/boot/compressed/head.S	Fri Jul 27 14:58:14 2001
@@ -31,6 +31,24 @@
 startup_32:
 	cld
 	cli
+
+/*
+ * GDT is invalid if we're booted by bootimg, so reload it now
+ */
+	lgdt	%cs:gdt_descr
+	ljmp	$(__KERNEL_CS),$1f
+
+gdt_descr:
+	.word	31
+	.long	gdt_table
+
+gdt_table: /* stolen from arch/i386/kernel/head.S */
+	.quad	0x0000000000000000	/* NULL descriptor */
+	.quad	0x0000000000000000	/* not used */
+	.quad	0x00cf9a000000ffff	/* 0x10 kernel 4GB code at 0x00000000 */
+	.quad	0x00cf92000000ffff	/* 0x18 kernel 4GB data at 0x00000000 */
+
+1:
 	movl $(__KERNEL_DS),%eax
 	movl %eax,%ds
 	movl %eax,%es
@@ -92,7 +110,6 @@
 	cld
 	rep
 	movsl
-
 	popl %esi	# discard the address
 	popl %ebx	# real mode pointer
 	popl %esi	# low_buffer_start
@@ -124,5 +141,6 @@
 	movsl
 	movl %ebx,%esi	# Restore setup pointer
 	xorl %ebx,%ebx
-	ljmp $(__KERNEL_CS), $0x100000
+        movl $0x100000,%eax
+        jmpl *%eax
 move_routine_end:
diff -urN linux-2.4.7/arch/i386/boot/setup.S linux-2.4.7-mcore/arch/i386/boot/setup.S
--- linux-2.4.7/arch/i386/boot/setup.S	Tue May  1 19:04:56 2001
+++ linux-2.4.7-mcore/arch/i386/boot/setup.S	Fri Jul 27 14:58:14 2001
@@ -97,16 +97,22 @@
 # flags, unused bits must be zero (RFU) bit within loadflags
 loadflags:
 LOADED_HIGH	= 1			# If set, the kernel is loaded high
+RELOADS_GDT	= 2			# if set, kernel reloads GDT, such that
+					# boot loader does not have to provide
+					# GDT in a "safe" memory location
 CAN_USE_HEAP	= 0x80			# If set, the loader also has set
 					# heap_end_ptr to tell how much
 					# space behind setup.S can be used for
 					# heap purposes.
 					# Only the loader knows what is free
-#ifndef __BIG_KERNEL__
-		.byte	0
-#else
-		.byte	LOADED_HIGH
+_FLAGS = 0
+#ifdef __BIG_KERNEL__
+		_FLAGS = _FLAGS | LOADED_HIGH
 #endif
+#ifdef CONFIG_BOOTIMG
+		_FLAGS = _FLAGS | RELOADS_GDT
+#endif
+		.byte _FLAGS
 
 setup_move_size: .word  0x8000		# size to move, when setup is not
 					# loaded at 0x90000. We will move setup 
diff -urN linux-2.4.7/arch/i386/config.in linux-2.4.7-mcore/arch/i386/config.in
--- linux-2.4.7/arch/i386/config.in	Sun Jul 15 19:15:44 2001
+++ linux-2.4.7-mcore/arch/i386/config.in	Fri Jul 27 14:58:14 2001
@@ -390,4 +390,10 @@
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   bool 'Kernel Core Dump Facility' CONFIG_MCL_COREDUMP
+   if [ "$CONFIG_MCL_COREDUMP" = "y" ]; then
+      bool '  Reboot using bootimg' CONFIG_BOOTIMG
+   fi
+fi
 endmenu
diff -urN linux-2.4.7/arch/i386/kernel/Makefile linux-2.4.7-mcore/arch/i386/kernel/Makefile
--- linux-2.4.7/arch/i386/kernel/Makefile	Fri Dec 29 17:35:47 2000
+++ linux-2.4.7-mcore/arch/i386/kernel/Makefile	Fri Jul 27 14:58:14 2001
@@ -40,5 +40,6 @@
 obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o mpparse.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
+obj-$(CONFIG_MCL_COREDUMP)	+= crash.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.7/arch/i386/kernel/crash.c linux-2.4.7-mcore/arch/i386/kernel/crash.c
--- linux-2.4.7/arch/i386/kernel/crash.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/arch/i386/kernel/crash.c	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,82 @@
+/*
+ *  linux/arch/i386/crash.c
+ *
+ *  Architecture dependant code for MCL in-memory core dump.
+ */
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/crash.h>
+#include <linux/reboot.h>
+#include <linux/bootimg.h>
+
+inline void crash_save_regs(void) {
+	static unsigned long regs[8];
+
+	__asm__ __volatile__("movl %%ebx,%0" : "=m"(regs[0]));
+	__asm__ __volatile__("movl %%ecx,%0" : "=m"(regs[1]));
+	__asm__ __volatile__("movl %%edx,%0" : "=m"(regs[2]));
+	__asm__ __volatile__("movl %%esi,%0" : "=m"(regs[3]));
+	__asm__ __volatile__("movl %%edi,%0" : "=m"(regs[4]));
+	__asm__ __volatile__("movl %%ebp,%0" : "=m"(regs[5]));
+	__asm__ __volatile__("movl %%eax,%0" : "=m"(regs[6]));
+	__asm__ __volatile__("movl %%esp,%0" : "=m"(regs[7]));
+
+	panic_regs = regs;
+}
+
+/*
+ *  Save the current stack pointer and EIP.
+ */
+void crash_save_current_state(struct task_struct *tp)
+{
+	/*
+	 *  Here we save ebp instead of esp just in case the compiler
+	 *  decides to put an extra push in before we execute this
+	 *  instruction (thus invalidating our frame pointer).
+	 */
+	asm volatile("movl %%ebp,%0":"=m" (*(u_long *)&tp->thread.esp));
+	tp->thread.eip = (u_long)crash_save_current_state;
+	panic_ksp[smp_processor_id()] = tp->thread.esp;
+	mb();
+
+	save_core();
+
+	crash_halt_or_reboot(1);
+}
+
+/*
+ *  If we are not the panicking thread, we simply halt.  Otherwise,
+ *  we take care of calling the reboot code.
+ */
+void crash_halt_or_reboot(int boot_cpu)
+{
+#ifdef CONFIG_SMP
+	if (!boot_cpu) {
+		stop_this_cpu(NULL);
+		/* NOTREACHED */
+	}
+#endif
+	machine_restart(NULL);
+}
+
+void crash_cleanup_smp_state(void)
+{
+	/*
+	 *  Here we duplicate smp_send_stop.  Crash_halt_or_reboot() calls
+	 *  stop_this_cpu.  We now know that we are the only one running, 
+	 *  so we finish off the smp_send_stop function.
+	 */
+	__cli();
+#ifdef CONFIG_SMP
+	disable_local_APIC();
+#endif
+}
+
+/*
+ *  Core dump IPI
+ */
+void smp_crash_funnel_cpu(void)
+{
+	crash_save_current_state(current);
+}
diff -urN linux-2.4.7/arch/i386/kernel/head.S linux-2.4.7-mcore/arch/i386/kernel/head.S
--- linux-2.4.7/arch/i386/kernel/head.S	Wed Jun 20 14:00:53 2001
+++ linux-2.4.7-mcore/arch/i386/kernel/head.S	Fri Jul 27 14:58:14 2001
@@ -43,6 +43,18 @@
  */
 startup_32:
 /*
+ * GDT is invalid if we're booted by bootimg, so reload it now
+ */
+	lgdt %cs:_gdt_descr-__PAGE_OFFSET
+	ljmp $(__KERNEL_CS),$1f-__PAGE_OFFSET
+
+_gdt_descr:
+	.word 31
+	.long SYMBOL_NAME(gdt_table)-__PAGE_OFFSET
+
+1:
+
+/*
  * Set segments to known values
  */
 	cld
diff -urN linux-2.4.7/arch/i386/kernel/process.c linux-2.4.7-mcore/arch/i386/kernel/process.c
--- linux-2.4.7/arch/i386/kernel/process.c	Wed Jul  4 17:41:33 2001
+++ linux-2.4.7-mcore/arch/i386/kernel/process.c	Fri Jul 27 14:58:14 2001
@@ -46,6 +46,9 @@
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
 
 #include <linux/irq.h>
 
@@ -345,6 +348,19 @@
 
 void machine_restart(char * __unused)
 {
+#ifdef CONFIG_MCL_COREDUMP
+	extern char *panicmsg;
+	/*
+	 *  Only call bootimg if we have a valid descriptor and
+	 *  we are in a panic() context.
+	 */
+	if (panicmsg)
+#endif
+#ifdef CONFIG_BOOTIMG
+		if (bootimg_dsc.page_dir)
+			boot_image();
+#endif
+
 #if CONFIG_SMP
 	/*
 	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
diff -urN linux-2.4.7/arch/i386/kernel/setup.c linux-2.4.7-mcore/arch/i386/kernel/setup.c
--- linux-2.4.7/arch/i386/kernel/setup.c	Wed Jul 11 12:31:44 2001
+++ linux-2.4.7-mcore/arch/i386/kernel/setup.c	Fri Jul 27 14:58:14 2001
@@ -104,6 +104,9 @@
 #include <asm/dma.h>
 #include <asm/mpspec.h>
 #include <asm/mmu_context.h>
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
 /*
  * Machine setup..
  */
@@ -768,6 +771,7 @@
 void __init setup_arch(char **cmdline_p)
 {
 	unsigned long bootmap_size, low_mem_size;
+	unsigned long bootmap_pages, crash_pages;
 	unsigned long start_pfn, max_pfn, max_low_pfn;
 	int i;
 
@@ -876,6 +880,21 @@
 			pages_to_mb(highend_pfn - highstart_pfn));
 	}
 #endif
+
+#ifdef CONFIG_MCL_COREDUMP
+	bootmap_pages = bootmem_bootmap_pages(max_low_pfn);
+	crash_pages = crash_pages_needed();
+
+	printk("start_pfn: %d, bootmap_pages: %d\n", start_pfn, bootmap_pages);
+
+	crash_init((u_long)phys_to_virt(PFN_PHYS(start_pfn)),
+		   (u_long)phys_to_virt(PFN_PHYS(LOW_OFFSET + start_pfn)),
+		   (u_long)phys_to_virt(PFN_PHYS(LOW_OFFSET + start_pfn +
+						 crash_pages)));
+
+	printk("new start_pfn: %08lx\n", PFN_PHYS(start_pfn));
+	printk("crash map starts at %lx\n",(start_pfn+bootmap_pages)*PAGE_SIZE);
+#endif
 	/*
 	 * Initialize the boot-time allocator (with low memory only):
 	 */
@@ -921,8 +940,8 @@
 	 * the (very unlikely) case of us accidentally initializing the
 	 * bootmem allocator with an invalid RAM area.
 	 */
-	reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) +
-			 bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
+	reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) + bootmap_size + 
+                    ((1+crash_pages)*PAGE_SIZE) + PAGE_SIZE-1) - (HIGH_MEMORY));
 
 	/*
 	 * reserve physical page 0 - it's a special BIOS page on many boxes,
@@ -930,6 +949,16 @@
 	 */
 	reserve_bootmem(0, PAGE_SIZE);
 
+#ifdef CONFIG_BOOTIMG
+	/*
+	 * bootimg(8) reads the old parameter block. Note that the copy in
+	 * empty_zero_page will vanish when mem_init runs. (Should we
+	 * memcpy(phys_to_virt(0x90000), PARAM, PAGE_SIZE);
+	 * now ?)
+	 */
+	reserve_bootmem(0x90000, PAGE_SIZE);
+#endif
+
 #ifdef CONFIG_SMP
 	/*
 	 * But first pinch a few for the stack/trampoline stuff
@@ -947,6 +976,12 @@
 	find_smp_config();
 #endif
 	paging_init();
+#ifdef CONFIG_MCL_COREDUMP
+	/* 
+         * Reserve crash pages.
+	 */
+	crash_mark_dump_reserved();
+#endif
 #ifdef CONFIG_X86_IO_APIC
 	/*
 	 * get boot-time SMP configuration:
@@ -959,6 +994,7 @@
 #endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
+	printk("caution: initrd may overwrite dump\n"); /* phro */
 	if (LOADER_TYPE && INITRD_START) {
 		if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
 			reserve_bootmem(INITRD_START, INITRD_SIZE);
diff -urN linux-2.4.7/arch/i386/kernel/smp.c linux-2.4.7-mcore/arch/i386/kernel/smp.c
--- linux-2.4.7/arch/i386/kernel/smp.c	Tue Feb 13 17:13:43 2001
+++ linux-2.4.7-mcore/arch/i386/kernel/smp.c	Fri Jul 27 14:58:14 2001
@@ -21,6 +21,9 @@
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <asm/crash.h>
+#endif
 /*
  *	Some notes on x86 processor bugs affecting SMP operation:
  *
@@ -483,7 +486,7 @@
 	return 0;
 }
 
-static void stop_this_cpu (void * dummy)
+void stop_this_cpu (void * dummy)
 {
 	/*
 	 * Remove this CPU:
diff -urN linux-2.4.7/arch/i386/kernel/traps.c linux-2.4.7-mcore/arch/i386/kernel/traps.c
--- linux-2.4.7/arch/i386/kernel/traps.c	Wed Jun 20 16:59:44 2001
+++ linux-2.4.7-mcore/arch/i386/kernel/traps.c	Fri Jul 27 14:58:14 2001
@@ -49,6 +49,10 @@
 
 #include <linux/irq.h>
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
+
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
 asmlinkage void lcall27(void);
@@ -222,7 +226,11 @@
 	show_registers(regs);
 
 	spin_unlock_irq(&die_lock);
-	do_exit(SIGSEGV);
+#ifdef CONFIG_MCL_COREDUMP 
+	if(panic_on_oops)
+		panic("die");
+#endif
+	do_exit(SIGSEGV);/* NOTREACHED */
 }
 
 static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
diff -urN linux-2.4.7/arch/i386/vmlinux.lds linux-2.4.7-mcore/arch/i386/vmlinux.lds
--- linux-2.4.7/arch/i386/vmlinux.lds	Mon Jul  2 17:40:14 2001
+++ linux-2.4.7-mcore/arch/i386/vmlinux.lds	Fri Jul 27 14:58:14 2001
@@ -20,6 +20,13 @@
   .rodata : { *(.rodata) *(.rodata.*) }
   .kstrtab : { *(.kstrtab) }
 
+  . = ALIGN(16);		/* Relocatable bootimage code */
+  __bootimg_start = .;
+  .bootimg : {
+	*(.bootimg)
+	}
+  __bootimg_end = .;
+
   . = ALIGN(16);		/* Exception table */
   __start___ex_table = .;
   __ex_table : { *(__ex_table) }
diff -urN linux-2.4.7/arch/ppc/config.in linux-2.4.7-mcore/arch/ppc/config.in
--- linux-2.4.7/arch/ppc/config.in	Wed Jul 18 10:14:01 2001
+++ linux-2.4.7-mcore/arch/ppc/config.in	Fri Jul 27 14:58:14 2001
@@ -376,4 +376,5 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 bool 'Include xmon kernel debugger' CONFIG_XMON
+bool 'Kernel Core Dump Facility' CONFIG_MCL_COREDUMP
 endmenu
diff -urN linux-2.4.7/arch/ppc/kernel/crash.c linux-2.4.7-mcore/arch/ppc/kernel/crash.c
--- linux-2.4.7/arch/ppc/kernel/crash.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/arch/ppc/kernel/crash.c	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,93 @@
+/*
+ *  linux/arch/ppc/crash.c
+ *
+ *  Architecture dependant code for MCL in-memory core dump.
+ */
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/crash.h>
+#include <linux/reboot.h>
+
+unsigned long crash_console_sp = 0;
+extern unsigned long cpu_present_mask;
+
+inline void crash_save_regs(void) {
+	static unsigned long gprs[32];
+
+        __asm__ __volatile__("stw %%r0,%0" :  "=m"(gprs[0]));
+        __asm__ __volatile__("stw %%r1,%0" :  "=m"(gprs[1]));
+        __asm__ __volatile__("stw %%r2,%0" :  "=m"(gprs[2]));
+        __asm__ __volatile__("stw %%r3,%0" :  "=m"(gprs[3]));
+        __asm__ __volatile__("stw %%r4,%0" :  "=m"(gprs[4]));
+        __asm__ __volatile__("stw %%r5,%0" :  "=m"(gprs[5]));
+        __asm__ __volatile__("stw %%r6,%0" :  "=m"(gprs[6]));
+        __asm__ __volatile__("stw %%r7,%0" :  "=m"(gprs[7]));
+        __asm__ __volatile__("stw %%r8,%0" :  "=m"(gprs[8]));
+        __asm__ __volatile__("stw %%r9,%0" :  "=m"(gprs[9]));
+        __asm__ __volatile__("stw %%r10,%0" : "=m"(gprs[10]));
+        __asm__ __volatile__("stw %%r11,%0" : "=m"(gprs[11]));
+        __asm__ __volatile__("stw %%r12,%0" : "=m"(gprs[12]));
+        __asm__ __volatile__("stw %%r13,%0" : "=m"(gprs[13]));
+        __asm__ __volatile__("stw %%r14,%0" : "=m"(gprs[14]));
+        __asm__ __volatile__("stw %%r16,%0" : "=m"(gprs[16]));
+        __asm__ __volatile__("stw %%r17,%0" : "=m"(gprs[17]));
+        __asm__ __volatile__("stw %%r18,%0" : "=m"(gprs[18]));
+        __asm__ __volatile__("stw %%r19,%0" : "=m"(gprs[19]));
+        __asm__ __volatile__("stw %%r20,%0" : "=m"(gprs[20]));
+        __asm__ __volatile__("stw %%r21,%0" : "=m"(gprs[21]));
+        __asm__ __volatile__("stw %%r22,%0" : "=m"(gprs[22]));
+        __asm__ __volatile__("stw %%r23,%0" : "=m"(gprs[23]));
+        __asm__ __volatile__("stw %%r24,%0" : "=m"(gprs[24]));
+        __asm__ __volatile__("stw %%r25,%0" : "=m"(gprs[25]));
+        __asm__ __volatile__("stw %%r26,%0" : "=m"(gprs[26]));
+        __asm__ __volatile__("stw %%r27,%0" : "=m"(gprs[27]));
+        __asm__ __volatile__("stw %%r28,%0" : "=m"(gprs[28]));
+        __asm__ __volatile__("stw %%r29,%0" : "=m"(gprs[29]));
+        __asm__ __volatile__("stw %%r30,%0" : "=m"(gprs[30]));
+        __asm__ __volatile__("stw %%r31,%0" : "=m"(gprs[31]));
+
+	panic_regs = regs;
+}
+
+/*
+ *  Save the current stack pointer.
+ */
+void crash_save_current_state(struct task_struct *tp)
+{
+	register unsigned long sp __asm__("%1");
+	tp->tss.ksp = sp;
+	panic_ksp[smp_processor_id()] = sp;
+	mb();
+
+	save_core();
+
+	crash_halt_or_reboot(1);
+}
+
+/*
+ *  If we are not the panicking thread, we simply halt.  Otherwise,
+ *  we take care of calling the reboot code.
+ */
+void crash_halt_or_reboot(int boot_cpu)
+{
+	printk("restarting system.\n");
+	machine_restart(NULL);
+}
+
+void crash_cleanup_smp_state(void)
+{
+	/*
+	 * Not much to be done here for ppc.
+	 */
+	__cli();
+}
+
+
+/*
+ *  Crash IPI
+ */
+void smp_crash_funnel_cpu(void)
+{
+	crash_save_current_state(current);
+}
diff -urN linux-2.4.7/arch/ppc/mm/init.c linux-2.4.7-mcore/arch/ppc/mm/init.c
--- linux-2.4.7/arch/ppc/mm/init.c	Mon Jul  2 17:34:57 2001
+++ linux-2.4.7-mcore/arch/ppc/mm/init.c	Fri Jul 27 14:58:14 2001
@@ -1000,7 +1000,7 @@
  */
 void __init do_init_bootmem(void)
 {
-	unsigned long start, size;
+	unsigned long start, size, crash_pages = 0;
 	int i;
 
 	/*
@@ -1010,6 +1010,11 @@
 	 * for 4GB of memory, using 4kB pages), plus 1 page
 	 * (in case the address isn't page-aligned).
 	 */
+
+#ifdef CONFIG_MCL_COREDUMP
+	crash_pages = crash_pages_needed();
+#endif
+
 	start = 0;
 	size = 0;
 	for (i = 0; i < phys_avail.n_regions; ++i) {
@@ -1019,7 +1024,7 @@
 			continue;
 		start = a;
 		size = s;
-		if (s >= 33 * PAGE_SIZE)
+		if (s >= (33 + crash_pages) * PAGE_SIZE)
 			break;
 	}
 	start = PAGE_ALIGN(start);
@@ -1027,13 +1032,24 @@
 	boot_mapsize = init_bootmem(start >> PAGE_SHIFT,
 				    total_lowmem >> PAGE_SHIFT);
 
-	/* remove the bootmem bitmap from the available memory */
-	mem_pieces_remove(&phys_avail, start, boot_mapsize, 1);
+#ifdef CONFIG_MCL_COREDUMP
+	crash_init((u_long)phys_to_virt(PFN_PHYS(start)),
+		   (u_long)phys_to_virt(PFN_PHYS(start + 33)),
+		   (u_long)phys_to_virt(PFN_PHYS(start + 33 + crash_pages)));
+#endif
+
+	/* remove the bootmem bitmap and crash memory from the available memory */
+	mem_pieces_remove(&phys_avail, start,
+			  boot_mapsize + crash_pages * PAGE_SIZE, 1);
 
 	/* add everything in phys_avail into the bootmem map */
 	for (i = 0; i < phys_avail.n_regions; ++i)
 		free_bootmem(phys_avail.regions[i].address,
 			     phys_avail.regions[i].size);
+
+#ifdef CONFIG_MCL_COREDUMP
+	crash_mark_dump_reserved();
+#endif
 
 	init_bootmem_done = 1;
 }
diff -urN linux-2.4.7/drivers/char/misc.c linux-2.4.7-mcore/drivers/char/misc.c
--- linux-2.4.7/drivers/char/misc.c	Thu May 24 18:14:08 2001
+++ linux-2.4.7-mcore/drivers/char/misc.c	Fri Jul 27 14:58:14 2001
@@ -76,6 +76,8 @@
 extern int pmu_device_init(void);
 extern int tosh_init(void);
 
+extern int crash_init_chrdev(void);
+
 static int misc_read_proc(char *buf, char **start, off_t offset,
 			  int len, int *eof, void *private)
 {
@@ -252,6 +254,9 @@
 int __init misc_init(void)
 {
 	create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL);
+#ifdef CONFIG_MCL_COREDUMP
+	crash_init_chrdev();
+#endif
 #ifdef CONFIG_MVME16x
 	rtc_MK48T08_init();
 #endif
diff -urN linux-2.4.7/drivers/char/sysrq.c linux-2.4.7-mcore/drivers/char/sysrq.c
--- linux-2.4.7/drivers/char/sysrq.c	Fri Feb  9 14:30:22 2001
+++ linux-2.4.7-mcore/drivers/char/sysrq.c	Fri Jul 27 14:58:14 2001
@@ -90,6 +90,9 @@
 		printk("Resetting\n");
 		machine_restart(NULL);
 		break;
+	case 'c':
+	        panic("sysrq");         /* C -- crash and save core */
+	        break;
 	case 'o':					    /* O -- power off */
 		if (sysrq_power_off) {
 			printk("Power off\n");
@@ -148,7 +151,7 @@
 		printk("Boot ");
 		if (sysrq_power_off)
 			printk("Off ");
-		printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n");
+		printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL Crash\n");
 		/* Don't use 'A' as it's handled specially on the Sparc */
 	}
 
diff -urN linux-2.4.7/include/asm-alpha/crash.h linux-2.4.7-mcore/include/asm-alpha/crash.h
--- linux-2.4.7/include/asm-alpha/crash.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/include/asm-alpha/crash.h	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,18 @@
+#ifndef __ASM_CRASH_H
+#define __ASM_CRASH_H
+
+#include <asm/hwrpb.h>
+
+/*
+ *  The alpha's console eats bits toward the end of memory.  Stay clear.
+ */
+#define UPPER_MEM_BACKUP 1000
+#define LOWER_MEM_FORWARD 0
+
+extern unsigned int console_crash;
+extern unsigned long crash_console_sp;
+
+void __crash_callin(void);
+void crash_callin(void);
+
+#endif
diff -urN linux-2.4.7/include/asm-i386/bootimg.h linux-2.4.7-mcore/include/asm-i386/bootimg.h
--- linux-2.4.7/include/asm-i386/bootimg.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/include/asm-i386/bootimg.h	Fri Jul 27 15:08:49 2001
@@ -0,0 +1,128 @@
+/* asm-i386/bootimg.h - Boot image, i386-specific code */
+
+/* Written 2000 by Werner Almesberger */
+
+/*
+ * When porting bootimg(2) to a new architcture, you need to adapt the
+ * functions and definitions in this file.
+ */
+
+
+#ifndef _ASM_I386_BOOTIMG_H
+#define _ASM_I386_BOOTIMG_H
+
+#include <linux/config.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_SMP
+#include <linux/smp.h>
+#include <linux/irq.h>
+#endif
+
+
+/*
+ * The memory page with the code currently executing has been copied from
+ * old_page to new_page. Jump there.
+ *
+ * Note: flush_icache_range has already been called on the new page.
+ */
+
+static inline void jump_relocated(unsigned long old_page,unsigned long new_page)
+{
+	int tmp;
+
+	__asm__ __volatile__(
+	"stc\n\t"
+	"call 1f\n"
+	"1:\tjnc 2f\n\t"
+	"popl %0\n\t"
+	"addl %1,%0\n\t"
+	"addl %1,%%esp\n\t"
+	"clc\n\t"
+	"jmp *%0\n"
+	"2:"
+	: "=&r" (tmp) : "r" (new_page-old_page));
+}
+
+
+/*
+ * Stop paging, such that
+ *  - page tables can be overwritten
+ *  - all physical memory can be accessed
+ *  - all physical memory is identity-mapped
+ *
+ * (Other rules are possible, but need to be encoded in bootimg(8).)
+ */
+
+static inline void stop_paging(void)
+{
+	unsigned long msw;
+
+	__asm__ __volatile__(
+	"movl %%cr0,%0\n\t"
+	"andl $0x7fffffff,%0\n\t"
+	"movl %0,%%cr0\n\t"
+	"jmp 1f\n\t"	/* i486 and such */
+	"1:"
+	: "=&r" (msw) : : "memory");
+}
+
+
+/*
+ * Stop any remaining concurrency in the system. If become_only_thread fails
+ * but the system is still usable, become_only_thread should return an error
+ * code. If no recovery is possible, it may as well panic.
+ */
+
+static inline int become_only_thread(void)
+{
+#ifdef CONFIG_SMP
+	smp_send_stop();
+	disable_IO_APIC();
+#endif
+	cli();
+	return 0;
+}
+
+
+/*
+ * A conservative estimate of the number of bytes relocate_and_jump allocated
+ * on the stack. This is only used for sanity checking before running code,
+ * because we can't recover from failure in relocate_and_jump.
+ */
+
+#define RESERVE_MIN_RELOC_STACK	256
+
+
+/*
+ * Change the stack pointer such that stack is at the end of the specified
+ * page. No data on the old stack will be accessed anymore, so no copying is
+ * required.
+ */
+
+static inline void stack_on_page(void *page)
+{
+	__asm__ __volatile__(
+	"push %%ds\n\t"
+	"pop %%ss\n\t"
+	"movl %0,%%esp\n\t"
+	"addl $0x1000,%%esp\n\t"
+	: : "r" (page));
+}
+
+/*
+ * Set up things such that the kernel will be comfortable (e.g. some
+ * architectures expect the boot loader to set registers in certain ways),
+ * and then jump to the kernel's entry address.
+ */
+
+static inline void jump_to_kernel(void (*kernel_entry)(void))
+{
+	__asm__ __volatile__(
+	"mov $0x90000,%%esi\n\t"
+	: : );
+
+	kernel_entry();
+}
+
+#endif
diff -urN linux-2.4.7/include/asm-i386/crash.h linux-2.4.7-mcore/include/asm-i386/crash.h
--- linux-2.4.7/include/asm-i386/crash.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/include/asm-i386/crash.h	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,15 @@
+#ifndef __ASM_CRASH_H
+#define __ASM_CRASH_H
+
+#define UPPER_MEM_BACKUP 0
+#define LOWER_MEM_FORWARD 0
+#define LOW_OFFSET 100
+
+/*
+ *  These two functions are inlined on alpha.  That's why they appear
+ *  in the arch dependent include file.
+ */
+void crash_save_current_state(struct task_struct *);
+void crash_halt_or_reboot(int);
+
+#endif
diff -urN linux-2.4.7/include/asm-ppc/crash.h linux-2.4.7-mcore/include/asm-ppc/crash.h
--- linux-2.4.7/include/asm-ppc/crash.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/include/asm-ppc/crash.h	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,18 @@
+#ifndef __ASM_CRASH_H
+#define __ASM_CRASH_H
+
+/* OF Eats memory but seems to stay clear from 0xc1700000-0xc7b2a004 */
+#define UPPER_MEM_BACKUP 1500
+#define LOWER_MEM_FORWARD 6000
+
+/*
+ *  These two functions are inlined on alpha.  That's why they appear
+ *  in the arch dependent include file.
+ */
+void crash_save_current_state(struct task_struct *);
+void crash_halt_or_reboot(int);
+
+extern unsigned int console_crash;
+extern unsigned long crash_console_sp;
+
+#endif
diff -urN linux-2.4.7/include/linux/bootimg.h linux-2.4.7-mcore/include/linux/bootimg.h
--- linux-2.4.7/include/linux/bootimg.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/include/linux/bootimg.h	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,84 @@
+/* linux/bootimg.h - Boot image, general definitions */
+
+/* Written 2000 by Werner Almesberger */
+
+
+#ifndef _LINUX_BOOTIMG_H
+#define _LINUX_BOOTIMG_H
+
+
+/*
+ * Constraints on image_map:
+ *  - each image_map[n] is the virtual address of a page-sized memory region
+ *    readable by the user
+ *  - currently, image_map[n] is not required to be page-aligned, but this may
+ *    change in the future if we want to map pages directly to lower memory
+ *    pressure (NB: mapping works for ELF and plain binary images, but usually
+ *    not for (b)zImages, because the prepended boot and setup sectors
+ *    mis-align them)
+ *
+ * Constraints on load_map:
+ *  - each load_map[] is the physical address of a page in RAM
+ */
+
+struct boot_image {
+	void **image_map;	/* pointers to image pages in user memory */
+	int pages;		/* length in pages */
+	unsigned long *load_map;/* list of destination pages (physical addr) */
+	unsigned long start;	/* jump to this physical address */
+	int flags;		/* for future use, must be zero for now */
+};
+
+
+#ifdef __KERNEL__
+
+#define __bootimg __attribute__ ((__section__ (".bootimg")))
+
+
+struct bootimg_dsc {
+	unsigned long self;		/* code page		ALL ADDRESSES */
+	unsigned long scratch;		/* scratch page		ARE PHYSICAL !*/
+	unsigned long **page_dir;	/* src & dst page tables              */
+	void (*jump_to)(void);		/* start address		      */
+	int pages;			/* number of pages */
+    unsigned long csum; /* Kernel Image checksum */
+};
+
+/*
+ * page_dir contains pointers to pages containing pointers to pages. We call
+ * page_dir a "directory" and the page page_dir[n] points to a "table". The
+ * first PAGES_PER_TABLE/2 entries of page_dir are for source pages, and other
+ * half are for destination pages.
+ */
+
+/*
+ * Note that the definitions used here do not necessarily correspond to the
+ * architecture-specific PTRS_PER_PTE, __pte_offset, etc.
+ */
+ 
+#define PAGES_PER_TABLE	(PAGE_SIZE/sizeof(void *))
+#define FROM_TABLE(i)	((i)/PAGES_PER_TABLE)
+#define TO_TABLE(i)	((i)/PAGES_PER_TABLE+PAGES_PER_TABLE/2)
+#define PAGE_NR(i)	((i) % PAGES_PER_TABLE)
+
+
+extern char __bootimg_start,__bootimg_end;	/* linker segment boundaries */
+extern unsigned long *unity_page; /* unity-mapped page for i386 */
+
+/*
+ * relocate_and_jump runs in its own page with its own stack. This makes it
+ * difficult to pass parameters. The solution chosen here is to use the global
+ * variable bootimg_dsc, which is copied into an "auto" variable by
+ * relocate_and_jump before any copying or relocation takes place.
+ */
+
+extern struct bootimg_dsc bootimg_dsc;
+
+typedef void (*relocate_and_jump_t)(void);
+
+void relocate_and_jump(void);
+int  boot_image(void);
+
+#endif /* __KERNEL__ */
+
+#endif
diff -urN linux-2.4.7/include/linux/crash.h linux-2.4.7-mcore/include/linux/crash.h
--- linux-2.4.7/include/linux/crash.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/include/linux/crash.h	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,119 @@
+#ifndef __LINUX_CRASH_H
+#define __LINUX_CRASH_H
+
+/* defines for interfacing with user-space (ioctls, etc) */
+struct ioctl_getdump {
+	unsigned long kva;
+	unsigned long buf;
+};
+
+#define CRASH_IOC_MAGIC 'C'
+
+#define CRASH_IOCFREEDUMP _IO(CRASH_IOC_MAGIC, 0)
+#define CRASH_IOCGETDUMP _IOWR(CRASH_IOC_MAGIC, 1, struct ioctl_getdump)
+#define CRASH_IOCBOOTIMG _IOWR(CRASH_IOC_MAGIC, 2, struct boot_image)
+#define CRASH_IOCVERSION _IO(CRASH_IOC_MAGIC, 3)
+
+/* kernel-only part of crash.h */
+#ifdef __KERNEL__
+#include <asm/crash.h>
+
+#define CRASH_K_MINOR (1)
+#define CRASH_K_MAJOR (0)
+
+/*
+ * Crash prototypes.
+ */
+void save_core(void);
+void crash_mark_dump_reserved(void);
+void crash_init(u_long bootmap_va, u_long crash_va, u_long end_alloc_va);
+u_long crash_pages_needed(void);
+void smp_crash_funnel_cpu(void);
+void crash_cleanup_smp_state(void);
+
+/*
+ *  Arch dependant crash.c funcs
+ */
+void crash_save_current_state(struct task_struct *);
+void crash_halt_or_reboot(int);
+inline void crash_save_regs(void);
+
+/*
+ * Crash globals
+ */
+extern u_long crash_dump_header;
+extern volatile u_long panic_ksp[];
+extern volatile int crash_release;
+extern int panic_on_oops;
+extern char *panicmsg;
+extern int panic_processor;
+extern int crash_perform_sync;
+extern unsigned long *panic_regs;
+
+/*
+ * symbols not exported by linux header files
+ */
+extern void stop_this_cpu(void *);
+
+/*  struct crash_map_hdr located at byte offset 0 */
+/* on-disk formats */
+
+#define trunc_page(x)   ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
+#define round_page(x)   trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
+
+#define CRASH_MAGIC 0x9a8bccdd
+#define CRASH_SOURCE_PAGES 128
+#define CRASH_SUB_MAP_BYTES ((u_long)round_page((CRASH_SOURCE_PAGES+1)*sizeof(u_long)))
+#define CRASH_SUB_MAP_PAGES (CRASH_SUB_MAP_BYTES / PAGE_SIZE)
+#define CRASH_UNCOMPR_BUF_PAGES (CRASH_SOURCE_PAGES + CRASH_SUB_MAP_PAGES)
+#define CRASH_COMPR_BUF_PAGES (CRASH_UNCOMPR_BUF_PAGES + (CRASH_UNCOMPR_BUF_PAGES/4))
+#define CRASH_COMPESS_PRIME_PAGES (2*CRASH_COMPR_BUF_PAGES)
+#define CRASH_ZALLOC_PAGES 16*5*2	/* 2 to handle crash in crash */
+#define CRASH_LOW_WATER_PAGES 100
+
+#define CRASH_CPU_TIMEOUT 5000	/* 5 sec wait for other cpus to stop */
+
+#define CRASH_MARK_RESERVED(addr) (set_bit(PG_reserved,&mem_map[MAP_NR(addr)].flags))
+#define CRASH_CLEAR_RESERVED(addr) (clear_bit(PG_reserved,&mem_map[MAP_NR(addr)].flags))
+#define CRASH_MARK_BOOT_RESERVED(addr) reserve_bootmem(virt_to_phys((void *)addr), PAGE_SIZE);
+
+typedef int boolean_t;
+
+#define TRUE 1
+#define FALSE 0
+
+/* mem structure */
+struct mem_crash_map_hdr {
+	long magic[4];		/* identify crash dump */
+	u_long map;		/* location of map */
+	u_long map_pages;
+	u_long data_pages;
+	u_long compr_units;
+	u_long boot_reserved_start;
+	u_long boot_reserved_end;
+};
+struct mem_crash_map_entry {
+	u_long src_va;		/* source start of larger non-contig 
+				 * block.  a src_va of -1 means that 
+				 * the dest_page_va is the location of 
+				 * the next map page */
+	u_long dest_page_va;	/* dest of this sub block */
+	u_long check_sum;	/* check_sum for dest data */
+};
+
+/* file structure */
+struct crash_map_hdr {
+	long magic[4];		/* identify crash dump */
+	int blk_size;		/* block size for this device */
+	int map_block;		/* location of map */
+	int map_blocks;		/* number of blocks for map */
+};
+struct crash_map_entry {
+	u_long start_va;	/* virtual address */
+	char *exp_data;		/* expanded data in memory */
+	int start_blk;		/* device location */
+	int num_blks;
+};
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_CRASH_H */
diff -urN linux-2.4.7/include/linux/mm.h linux-2.4.7-mcore/include/linux/mm.h
--- linux-2.4.7/include/linux/mm.h	Fri Jul 20 15:52:18 2001
+++ linux-2.4.7-mcore/include/linux/mm.h	Fri Jul 27 15:08:49 2001
@@ -282,6 +282,9 @@
 #define PG_inactive_clean	11
 #define PG_highmem		12
 #define PG_checked		13	/* kill me in 2.5.<early>. */
+#define PG_free			14
+#define PG_anon			15
+#define PG_shm			16
 				/* bits 21-29 unused */
 #define PG_arch_1		30
 #define PG_reserved		31
@@ -333,6 +336,9 @@
 #define PageSlab(page)		test_bit(PG_slab, &(page)->flags)
 #define PageSwapCache(page)	test_bit(PG_swap_cache, &(page)->flags)
 #define PageReserved(page)	test_bit(PG_reserved, &(page)->flags)
+#define PageFree(page)		(test_bit(PG_free, &(page)->flags))
+#define PageAnon(page)		(test_bit(PG_anon, &(page)->flags))
+#define PageShm(page)		(test_bit(PG_shm, &(page)->flags))
 
 #define PageSetSlab(page)	set_bit(PG_slab, &(page)->flags)
 #define PageSetSwapCache(page)	set_bit(PG_swap_cache, &(page)->flags)
diff -urN linux-2.4.7/include/linux/reboot.h linux-2.4.7-mcore/include/linux/reboot.h
--- linux-2.4.7/include/linux/reboot.h	Fri Feb  9 17:46:13 2001
+++ linux-2.4.7-mcore/include/linux/reboot.h	Fri Jul 27 14:58:14 2001
@@ -20,6 +20,7 @@
  * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.
  * POWER_OFF   Stop OS and remove all power from system, if possible.
  * RESTART2    Restart system using given command string.
+ * COREDUMP    We're taking a core dump, secondary cpus already stopped.
  */
 
 #define	LINUX_REBOOT_CMD_RESTART	0x01234567
@@ -28,7 +29,7 @@
 #define	LINUX_REBOOT_CMD_CAD_OFF	0x00000000
 #define	LINUX_REBOOT_CMD_POWER_OFF	0x4321FEDC
 #define	LINUX_REBOOT_CMD_RESTART2	0xA1B2C3D4
-
+#define LINUX_REBOOT_CMD_COREDUMP   0x9A8BCCDD
 
 #ifdef __KERNEL__
 
diff -urN linux-2.4.7/include/linux/sysctl.h linux-2.4.7-mcore/include/linux/sysctl.h
--- linux-2.4.7/include/linux/sysctl.h	Fri Jul 20 15:52:18 2001
+++ linux-2.4.7-mcore/include/linux/sysctl.h	Fri Jul 27 15:08:44 2001
@@ -118,7 +118,8 @@
 	KERN_SHMPATH=48,	/* string: path to shm fs */
 	KERN_HOTPLUG=49,	/* string: path to hotplug policy agent */
 	KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */
-	KERN_S390_USER_DEBUG_LOGGING=51  /* int: dumps of user faults */
+	KERN_S390_USER_DEBUG_LOGGING=51,  /* int: dumps of user faults */
+	KERN_PANIC_ON_OOPS=52	/* int: panic on oops enable */
 };
 
 
diff -urN linux-2.4.7/init/main.c linux-2.4.7-mcore/init/main.c
--- linux-2.4.7/init/main.c	Thu Jul  5 14:31:58 2001
+++ linux-2.4.7-mcore/init/main.c	Fri Jul 27 15:53:35 2001
@@ -70,6 +70,10 @@
 #include <asm/smp.h>
 #endif
 
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -526,10 +530,14 @@
 	char * command_line;
 	unsigned long mempages;
 	extern char saved_command_line[];
+#if defined(CONFIG_BOOTIMG) && defined(CONFIG_X86_LOCAL_APIC)
+	unsigned long value;
+#endif
 /*
  * Interrupts are still disabled. Do necessary setups, then
  * enable them
  */
+	printk("start_kernel\n");
 	lock_kernel();
 	printk(linux_banner);
 	setup_arch(&command_line);
@@ -547,6 +555,11 @@
 	 * this. But we do want output early, in case something goes wrong.
 	 */
 	console_init();
+
+#ifdef CONFIG_BOOTIMG
+	unity_page = alloc_bootmem_pages(PAGE_SIZE);
+	printk("unity_page addr: %p\n",unity_page);
+#endif
 #ifdef CONFIG_MODULES
 	init_modules();
 #endif
@@ -562,6 +575,15 @@
 
 	kmem_cache_init();
 	sti();
+#if defined(CONFIG_BOOTIMG) && defined(CONFIG_X86_LOCAL_APIC)
+	/* If we don't make sure the APIC is enabled, AND the LVT0
+	 * register is programmed properly, we won't get timer interrupts
+	 */
+	setup_local_APIC();
+	
+	value = apic_read(APIC_LVT0);
+	apic_write_around(APIC_LVT0, value & ~APIC_LVT_MASKED);
+#endif
 	calibrate_delay();
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start && !initrd_below_start_ok &&
diff -urN linux-2.4.7/kernel/Makefile linux-2.4.7-mcore/kernel/Makefile
--- linux-2.4.7/kernel/Makefile	Fri Dec 29 17:07:24 2000
+++ linux-2.4.7-mcore/kernel/Makefile	Fri Jul 27 14:58:14 2001
@@ -19,6 +19,12 @@
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
 obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_BOOTIMG) += bootimg.o bootimg_pic.o
+obj-$(CONFIG_MCL_COREDUMP) += crash.o
+
+ifneq ($(CONFIG_IRDA_DEFLATE),y)
+obj-y += zlib.o
+endif
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff -urN linux-2.4.7/kernel/bootimg.c linux-2.4.7-mcore/kernel/bootimg.c
--- linux-2.4.7/kernel/bootimg.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/kernel/bootimg.c	Fri Jul 27 15:53:15 2001
@@ -0,0 +1,260 @@
+/* bootimg.c - Boot another (kernel) image */
+
+/* Written 2000 by Werner Almesberger */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/capability.h>
+#include <linux/bootimg.h>
+#include <asm/bootimg.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <linux/delay.h>
+
+#if 0
+#define DPRINTK_CONT(format,args...) printk(format,##args)
+#else
+#define DPRINTK_CONT(format,args...)
+#endif
+#define DPRINTK(format,args...) DPRINTK_CONT(KERN_DEBUG format,##args)
+
+unsigned long **bootimg_page_dir;
+
+struct bootimg_dsc bootimg_dsc; /* communication with PIC */
+unsigned long *unity_page; /* unity-mapped page for i386 */
+
+static unsigned long cheese_checksum(unsigned long **page_dir, int num_pages)
+{
+	int i,csum=0;
+	
+	for (i = 0; i < num_pages; i++)
+		csum += *(unsigned long *)__va(bootimg_page_dir[0][i]);
+	return csum;
+}
+
+static unsigned long get_identity_mapped_page(void)
+{
+	set_pgd(pgd_offset(current->active_mm,virt_to_phys(unity_page)),
+		__pgd((_KERNPG_TABLE + _PAGE_PSE + (virt_to_phys(unity_page)&PGDIR_MASK))));
+	return (unsigned long)unity_page;
+}
+
+#if 0 /* Perhaps we'll need this in the future? */
+static void unmap_identity_mapped_page(void)
+{
+	set_pgd(pgd_offset(current->active_mm,virt_to_phys(unity_page)),__pgd(0));
+	__flush_tlb();
+}
+#endif
+
+static int fill_page_dir(unsigned long **page_dir,struct boot_image *image)
+{
+	int i, count=0;
+
+	memset(bootimg_page_dir,0,PAGE_SIZE);
+	for (i = 0; i < image->pages; i += PAGES_PER_TABLE) {
+		unsigned long **table;
+		int bytes_left;
+
+		table = bootimg_page_dir+FROM_TABLE(i);
+		*table = (unsigned long *) get_free_page(GFP_KERNEL);
+		if (!*table) return -ENOMEM;
+
+		memset(*table,0,PAGE_SIZE);
+		DPRINTK("page %d: from table %p @ %p\n",i,*table,table);
+		table = bootimg_page_dir+TO_TABLE(i);
+		*table = (unsigned long *) get_free_page(GFP_KERNEL);
+		if (!*table) return -ENOMEM;
+
+		bytes_left = (image->pages-i)*sizeof(unsigned long);
+		if (copy_from_user(*table,image->load_map+i,
+		    bytes_left > PAGE_SIZE ? PAGE_SIZE : bytes_left))
+			return -EFAULT;
+		DPRINTK("page %d: to table %p @ %p\n",i,*table,table);
+		count+=2; /* 2 pages per loop */
+	}
+
+	for (i = 0; i < image->pages; i++) {
+		unsigned long page = get_free_page(GFP_KERNEL);
+		void *src;
+
+		if (!page) return -ENOMEM;
+		count++;
+
+		bootimg_page_dir[FROM_TABLE(i)][PAGE_NR(i)] =
+		    virt_to_phys((void *) page);
+		if (get_user(src,image->image_map+i) ||
+		    copy_from_user((void *) page,src,PAGE_SIZE))
+			return -EFAULT;
+
+		DPRINTK("page %d: %p->%p->%p @ %p\n",i,src,(void *) page,
+		    (void *) bootimg_page_dir[FROM_TABLE(i)][PAGE_NR(i)],
+		    &bootimg_page_dir[FROM_TABLE(i)][PAGE_NR(i)]);
+	}
+
+	DPRINTK("fill_page_dir: %d pages allocated\n", count);
+
+	return 0;
+}
+
+
+static void free_page_dir(unsigned long **page_dir)
+{
+	int i,j,count=0;
+
+	for (i = 0; i < PAGES_PER_TABLE/2; i++)
+		if (bootimg_page_dir[i])
+			for (j = 0; j < PAGES_PER_TABLE; j++)
+				if (bootimg_page_dir[i][j]) {
+					free_page((unsigned long)
+					    phys_to_virt(bootimg_page_dir[i][j]));
+					count++;
+				}
+	for (i = 0; i < PAGES_PER_TABLE; i++)
+		if (bootimg_page_dir[i]) {
+			free_page((unsigned long) *bootimg_page_dir[i]);
+			count++;
+		}
+	DPRINTK("free_page_dir: %d pages freed\n", count);
+}
+
+
+static void convert_table_refs_to_phys(unsigned long **page_dir)
+{
+	int i;
+
+	DPRINTK("PAGES_PER_TABLE: %d\n",PAGES_PER_TABLE);
+	for (i = 0; i < PAGES_PER_TABLE; i++)
+		if (bootimg_page_dir[i]) {
+			DPRINTK("table %i: mapped %p -> ",i,bootimg_page_dir[i]);
+			bootimg_page_dir[i] = (unsigned long *)
+			    virt_to_phys(bootimg_page_dir[i]);
+			DPRINTK_CONT("%p\n",bootimg_page_dir[i]);
+		}
+}
+
+
+
+static int fill_bootimg_dsc(struct boot_image *image)
+{
+    	unsigned long scratch;
+	int error = -ENOMEM;
+
+	if(bootimg_page_dir) {
+		/* free previously allocated memory */
+		free_page_dir(bootimg_page_dir);
+		free_page((unsigned long) bootimg_page_dir);
+		DPRINTK("free_page (bootimg_page_dir)\n");
+	}
+
+	bootimg_page_dir = (unsigned long **) get_free_page(GFP_KERNEL);
+	if (!bootimg_page_dir) goto out0;
+	DPRINTK("get_free_page (bootimg_page_dir)\n");
+
+	error = fill_page_dir(bootimg_page_dir,image);
+	if (error) goto out1;
+
+	if(!bootimg_dsc.scratch) {
+		scratch = get_free_page(GFP_KERNEL);
+		DPRINTK("get_free_page (scratch)\n");
+	} else
+		scratch = 1; /* already allocated */
+
+	if (!scratch) goto out1;
+	/*
+	 * Not all architectures need the code to be identity-mapped, but it
+	 * can't hurt ...
+	 */
+	DPRINTK("bootimg_page_dir: mapped %p -> ",bootimg_page_dir);
+	bootimg_dsc.page_dir = (unsigned long **) virt_to_phys(bootimg_page_dir);
+	DPRINTK_CONT("%p\n",bootimg_dsc.page_dir);
+	if(!bootimg_dsc.scratch)
+		bootimg_dsc.scratch = virt_to_phys((void *) scratch);
+	bootimg_dsc.jump_to = (void (*)(void)) image->start;
+	bootimg_dsc.pages = image->pages;
+	bootimg_dsc.csum = cheese_checksum(bootimg_page_dir, image->pages);
+
+	return 0;
+
+out1:
+	free_page_dir(bootimg_page_dir);
+	free_page((unsigned long) bootimg_page_dir);
+	DPRINTK("free_page (bootimg_page_dir)\n");
+	bootimg_page_dir = 0;
+out0:
+	return error;
+}
+
+extern char *panicmsg;
+int boot_image()
+{
+	relocate_and_jump_t code;
+	unsigned long code_page;
+	int error = -ENOMEM;
+	int i;
+
+	if (cheese_checksum(__va(bootimg_dsc.page_dir),bootimg_dsc.pages) 
+		!= bootimg_dsc.csum)
+		printk("Checksum of kernel image failed.  Rebooting via BIOS\n");
+
+	code_page = get_identity_mapped_page();
+	if (!code_page) goto out3;
+	code = (relocate_and_jump_t) virt_to_phys((void *) code_page);
+	memcpy(code,&__bootimg_start,&__bootimg_end-&__bootimg_start);
+
+	bootimg_dsc.self = code_page;
+	printk(KERN_INFO "Running boot code at 0x%p\n",code);
+	
+	/*
+	 * The point of no return. Not even printk may work after a successful
+	 * return from become_only_thread.
+	 */
+
+	if (!panicmsg) {
+			error = become_only_thread();
+			if (error) goto out3;
+	} else {
+#ifdef CONFIG_SMP
+			disable_IO_APIC();
+#endif
+			__cli();
+	}
+
+	convert_table_refs_to_phys((unsigned long **)__va(bootimg_dsc.page_dir));
+	stack_on_page(code);
+
+	code();
+
+	panic("PIC code exec failed");
+out3:
+	printk("boot_image() failed!\n");
+	for(;;); 
+}
+
+/* changed from asmlinkage because we're called via an IOCTL on /dev/crash now */
+int sys_bootimg(struct boot_image *user_dsc)
+{
+	struct boot_image dsc;
+
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_MODULE)) return -EPERM;
+	if (&__bootimg_end-&__bootimg_start > PAGE_SIZE-RESERVE_MIN_RELOC_STACK)
+	   {
+		printk(KERN_ERR "boot_image: PIC too large (%d bytes)\n",
+		    &__bootimg_end-&__bootimg_start);
+		return -EIO;
+	}
+	if ((void *) relocate_and_jump != (void *) &__bootimg_start) {
+		printk(KERN_ERR "boot_image: relocate_and_jump is mis-placed"
+		    "(0x%p != 0x%p)\n",relocate_and_jump,&__bootimg_start);
+		return -EIO;
+	}
+	
+	if (copy_from_user(&dsc,user_dsc,sizeof(dsc))) return -EFAULT;
+	if (dsc.pages >= PAGES_PER_TABLE*PAGES_PER_TABLE/2) return -EFBIG;
+	if (dsc.flags) return -EINVAL; /* for future use */
+	return fill_bootimg_dsc(&dsc);
+}
diff -urN linux-2.4.7/kernel/bootimg_pic.c linux-2.4.7-mcore/kernel/bootimg_pic.c
--- linux-2.4.7/kernel/bootimg_pic.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/kernel/bootimg_pic.c	Fri Jul 27 14:58:14 2001
@@ -0,0 +1,93 @@
+/* bootimg_pic.c - Boot image, position-independent code */
+
+/* Written 2000 by Werner Almesberger */
+
+/*
+ * Strongly inspired by FiPaBoL designed mainly by Otfried Cheong and Roger
+ * Gammans, and written by the latter.
+ */
+
+/*
+ * This code is position-independent and must fit in a single page !
+ * Furthermore, everything (text+data+stack) has to go into the
+ * .bootimg segment.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/bootimg.h>
+#include <asm/bootimg.h>
+
+#include <asm/io.h>
+
+#define copy_and_swap(from,to) \
+    ( { my_copy_page(from,to); \
+    tmp = from; \
+    from = to; \
+    to = tmp; } )
+
+
+static inline void my_copy_page(unsigned long from,unsigned long to)
+{
+	unsigned long end = from+PAGE_SIZE;
+
+	do *((unsigned long *) to)++ = *((unsigned long *) from)++;
+	while (from != end);
+}
+
+
+void __bootimg relocate_and_jump(void)
+{
+	struct bootimg_dsc dsc = bootimg_dsc;
+	int i;
+
+	stop_paging();
+	for (i = 0; i < dsc.pages; i++) {
+		unsigned long from,to,tmp;
+
+		from = dsc.page_dir[FROM_TABLE(i)][PAGE_NR(i)];
+		to = dsc.page_dir[TO_TABLE(i)][PAGE_NR(i)];
+		if (from == to) continue;
+		if (to == dsc.self) {
+			copy_and_swap(dsc.self,dsc.scratch);
+			/* WARNING: flush_icache_range MUST BE INLINED !!! */
+			flush_icache_range(dsc.self,dsc.self+PAGE_SIZE-1);
+			jump_relocated(dsc.scratch,dsc.self);
+		}
+		else if (to == (unsigned long) dsc.page_dir)
+			copy_and_swap((unsigned long) dsc.page_dir,dsc.scratch);
+		else {
+			/*
+			 * O((n^2-n)/2), sigh ...
+			 */
+			unsigned long *table;
+			int j;
+
+			for (j = i+1; j < dsc.pages; j++) {
+				table = (unsigned long *)
+				    dsc.page_dir+FROM_TABLE(j);
+				if (*table == to) {
+					copy_and_swap(*table,dsc.scratch);
+					break;
+				}
+				if (table[PAGE_NR(j)] == to) {
+					copy_and_swap(table[PAGE_NR(j)],
+					    dsc.scratch);
+					break;
+				}
+				table = (unsigned long *)
+				    dsc.page_dir+TO_TABLE(j);
+				if (*table == to) {
+					copy_and_swap(*table,dsc.scratch);
+					break;
+				}
+			}
+		}
+		my_copy_page(from,to);
+		dsc.scratch = from;
+	}
+	jump_to_kernel(dsc.jump_to);
+}
diff -urN linux-2.4.7/kernel/crash.c linux-2.4.7-mcore/kernel/crash.c
--- linux-2.4.7/kernel/crash.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/kernel/crash.c	Fri Jul 27 15:53:05 2001
@@ -0,0 +1,882 @@
+#include <linux/locks.h>
+#include <linux/malloc.h>
+#include <linux/crash.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <asm/param.h>
+#include <asm/uaccess.h>
+#include "../drivers/net/zlib.h"
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/miscdevice.h>
+#include <linux/bootmem.h>
+
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
+
+static void crash_print_data_around(u_long p);
+static void crash_free_page(u_long addr);
+static int crash_chksum_page(u_long pg_addr, u_long * sum_addr);
+static void *czalloc(void *arg, unsigned int items, unsigned int size);
+static void czfree(void *arg, void *ptr);
+static u_long crash_alloc_dest_page(void);
+static void crash_free_dest_page(u_long dest);
+static void init_dest_page_alloc(void);
+static int crash_audit_maps(void);
+static u_long crash_get_source_page(void);
+static u_long crash_update_map(u_long map, u_long src_base, u_long dest, u_long * pages);
+static int crash_reset_stream(z_stream * stream);
+static boolean_t crash_is_kseg(u_long addr);
+static u_long *crash_link(u_long p);
+static int crash_chksum(u_long limit, u_long * sum_addr);
+static int crash_audit_map_page(u_long map);
+static void crash_wait_cpus(void);
+static int crash_is_dir_page(struct page *page);
+
+/* for the /dev/crash interface */
+int crash_init_chrdev(void);
+static int crashdev_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+#define CRASH_DEBUG 1
+
+#ifdef CONFIG_BOOTIMG
+extern int sys_bootimg(struct boot_image *);
+#endif
+
+static u_long crash_compr_buf;
+static u_long crash_uncompr_buf;
+static u_long crash_dump_header = 0;
+static u_long crash_dest_free_list = 0;
+static u_long crash_debug = 0;
+
+static u_long crash_cur_pfn;
+
+static u_long src_pages_skipped = 0;
+static u_long src_pages_saved = 0;
+static u_long dest_pages_free = 0;
+
+/* this information is saved from within panic() */
+char *panicmsg = (char *)0;
+int panic_processor = 0;
+int crash_perform_sync = 0;
+
+u_int console_crash = 0;	/* should be moved to alpha branch */
+
+typedef struct task_struct *task_t;
+
+/*
+ *  Threads active at time of panic:
+ */
+volatile task_t panic_threads[NR_CPUS];
+volatile unsigned long panic_ksp[NR_CPUS];
+unsigned long *panic_regs = NULL;
+
+int panic_on_oops;		/* for /proc/sys/kernel/panic_on_oops */
+
+extern unsigned long max_low_pfn;
+
+u_long crash_zalloc_start, crash_zalloc_end, crash_zalloc_cur;
+
+/* 
+ * Crash Kernel API functions below
+ * crash_pages_needed, computes pages needed for header and compression temp
+ * crash_init, partitions out the allocated pages, sets defaults and 
+ *             initializes the character device.
+ * crash_mark_dump_reserved, marks pages reserved from a previous dump.
+ * save_core, called at panic time to save a dump to memory.
+ */
+u_long crash_pages_needed(void)
+{
+	/* one for the header */
+	return (1 + CRASH_ZALLOC_PAGES + CRASH_UNCOMPR_BUF_PAGES + CRASH_COMPR_BUF_PAGES);
+}
+
+void crash_init(u_long bootmap_va, u_long crash_va, u_long end_alloc_va)
+{
+	struct mem_crash_map_hdr *header;
+	int i;
+
+	/* the default behavior is not NOT panic on a kernel OOPS */
+	panic_on_oops = 0;
+
+	printk("crash_init (crash_va: %08lx)\n", crash_va);
+	for (i = 0; i < NR_CPUS; i++)
+		panic_threads[i] = 0;
+	crash_dump_header = crash_va;
+	crash_va += PAGE_SIZE;
+	crash_zalloc_cur = crash_zalloc_start = crash_va;
+	crash_va += CRASH_ZALLOC_PAGES * PAGE_SIZE;
+	crash_zalloc_end = crash_uncompr_buf = crash_va;
+	crash_va += CRASH_UNCOMPR_BUF_PAGES * PAGE_SIZE;
+	crash_compr_buf = crash_va;
+	crash_va += CRASH_COMPR_BUF_PAGES * PAGE_SIZE;
+#if 0
+	if (crash_va != end_alloc_va)
+		panic("crash_init inconsistency-1\n");
+#endif
+
+	header = (struct mem_crash_map_hdr *)crash_dump_header;
+#ifdef CRASH_DEBUG
+	printk("crash_dump_header %p {\n", header);
+	printk("    magic[0]            = %lx\n", header->magic[0]);
+	printk("    map                 = %lx\n", header->map);
+	printk("    map_pages           = %lx\n", header->map_pages);
+	printk("    data_pages          = %lx\n", header->data_pages);
+	printk("    compr_units         = %lx\n", header->compr_units);
+	printk("    boot_reserved_start = %lx\n", header->boot_reserved_start);
+	printk("    boot_reserved_end   = %lx\n", header->boot_reserved_end);
+#endif
+
+	if (header->magic[0] == CRASH_MAGIC) {
+		printk("crash found\n");
+		if ((header->boot_reserved_start != bootmap_va) ||
+		    (header->boot_reserved_end != end_alloc_va)) {
+			/* crash audit will catch the corruption */
+			printk("crash_init inconsistency, dump may be corrupted\n");
+		}
+	} else {
+printk("memset...");
+		memset(header, 0, sizeof(*header));
+printk("done\n");
+	}
+
+	header->boot_reserved_start = bootmap_va;
+	header->boot_reserved_end = end_alloc_va;
+
+}
+
+void crash_mark_dump_reserved(void)
+{
+	struct mem_crash_map_hdr *header;
+	struct mem_crash_map_entry *m;
+
+	header = (struct mem_crash_map_hdr *)crash_dump_header;
+	if (header->magic[0] != CRASH_MAGIC)
+		return;
+	m = (struct mem_crash_map_entry *)header->map;
+#ifdef CRASH_DEBUG
+	printk("\n\n\ncrash_mark_dump_reserved\n\n");
+	printk("crash_dump_header %p {\n", header);
+	printk("    magic[0]            = %lx\n", header->magic[0]);
+	printk("    map                 = %lx\n", header->map);
+	printk("    map_pages           = %lx\n", header->map_pages);
+	printk("    data_pages          = %lx\n", header->data_pages);
+	printk("    compr_units         = %lx\n", header->compr_units);
+	printk("    boot_reserved_start = %lx\n", header->boot_reserved_start);
+	printk("    boot_reserved_end   = %lx\n", header->boot_reserved_end);
+	printk("mem_crash_map_entry %p {\n", m);
+	printk("    src_va              = %lx\n", m->src_va);
+	printk("    dest_page_va        = %lx\n", m->dest_page_va);
+	printk("    check_sum           = %lx\n", m->check_sum);
+#endif
+
+	if (crash_audit_maps()) {
+		header->magic[0] = 0;
+		return;
+	}
+
+	m = (struct mem_crash_map_entry *)header->map;
+ again:
+	CRASH_MARK_BOOT_RESERVED(m);
+	for (; m->src_va; m++) {
+		if (m->src_va == -1) {
+			m = (struct mem_crash_map_entry *)m->dest_page_va;
+			goto again;
+		}
+		CRASH_MARK_BOOT_RESERVED(m->dest_page_va);
+	}
+	return;
+}
+
+void save_core(void)
+{
+	int i, j, k;
+	z_stream stream;
+	int err;
+	struct task_struct *tp;
+	struct mem_crash_map_hdr *header;
+	u_long *sub_map;
+	u_long map;
+	u_long src, dest, unc, cp, src_base, comp_pages;
+
+	k = 0;
+	dest = 0;
+	__cli();
+	tp = current;
+	mb();
+	if (smp_processor_id() != 0) {	/* boot_cpu_id is always 0, i think */
+		panic_threads[smp_processor_id()] = tp;
+		crash_halt_or_reboot(0);
+	} else {
+		if (console_crash)
+			panic_threads[smp_processor_id()] = &init_task_union.task;
+		else
+			panic_threads[smp_processor_id()] = tp;
+
+		crash_wait_cpus();
+	}
+
+	printk("save_core: started on CPU%d\n", smp_processor_id());
+	if (!crash_dump_header) {
+		printk("save_core: not initialized\n");
+		return;
+	}
+
+	header = (struct mem_crash_map_hdr *)crash_dump_header;
+	header->magic[0] = 0;
+	header->map_pages = 0;
+	header->data_pages = 0;
+	header->compr_units = 0;
+	header->map = 0;
+
+	stream.zalloc = czalloc;
+	stream.zfree = czfree;
+	stream.opaque = (voidpf) 0;
+	stream.next_out = (Bytef *) crash_compr_buf;
+	stream.avail_out = (uInt) (CRASH_COMPR_BUF_PAGES * PAGE_SIZE);
+	stream.next_in = (Bytef *) crash_uncompr_buf;
+	stream.avail_in = (uInt) (CRASH_UNCOMPR_BUF_PAGES * PAGE_SIZE);
+	err = deflateInit(&stream, Z_BEST_SPEED);
+	if (err != Z_OK) {
+		printk("save_core: bad return %d from deflateInit\n", err);
+		return;
+	}
+
+	init_dest_page_alloc();
+	header->map = map = crash_update_map(0, 0, 0, &header->map_pages);
+	if (!map) {
+		printk("save_core: no dest pages\n");
+		return;
+	}
+	crash_cur_pfn = 0;
+	src_base = 0;
+	src = 0;
+	for (;;) {
+		sub_map = (u_long *) crash_uncompr_buf;
+		unc = crash_uncompr_buf + CRASH_SUB_MAP_PAGES * PAGE_SIZE;
+		for (i = 0; i < CRASH_SOURCE_PAGES; i++) {
+			src = crash_get_source_page();
+			if (!src)
+				break;
+			if (!i)
+				src_base = src;
+			if (!crash_is_kseg(unc) || !crash_is_kseg(src)) {
+				printk("unc = 0x%lx, src = 0x%lx, i = %d\n", unc, src, i);
+				i = src = 0;
+				break;
+			}
+			memcpy((void *)unc, (void *)src, PAGE_SIZE);
+			unc += PAGE_SIZE;
+			*sub_map++ = src;
+		}
+		*sub_map = 0;
+		if (!i && !src)
+			break;
+		err = deflate(&stream, Z_FINISH);
+		if (!(err == Z_STREAM_END)) {
+			deflateEnd(&stream);
+			printk("save_core: bad return %d from deflate, src_base = 0x%lx\n", err,
+			       src_base);
+			return;
+		}
+		comp_pages = (u_long) round_page(stream.total_out) / PAGE_SIZE;
+		if (crash_debug)
+			printk("src_base = 0x%lx compressed data in 0x%lx pages\n", src_base,
+			       comp_pages);
+
+		cp = crash_compr_buf;
+		j = 0;
+		if (crash_debug)
+			printk("\nsrc = %lx\n", src_base);
+		else {
+			printk(".");
+			if (!(k++ % 64))
+				printk("\n");
+		}
+		for (i = 0; i < comp_pages; i++) {
+			dest = crash_alloc_dest_page();
+			if (crash_debug) {
+				printk("%lx ", dest);
+				if (!(j++ % 8))
+					printk("\n");
+			}
+			header->data_pages++;
+			if (!dest) {
+				printk("save_core: no dest pages\n");
+				return;
+			}
+			if (!crash_is_kseg(dest) || !crash_is_kseg(cp)) {
+				printk("dest = 0x%lx, cp = 0x%lx, i = %d, comp_pages = 0x%lx\n",
+				       dest, cp, i, comp_pages);
+				src = 0;
+				break;
+			}
+			memcpy((void *)dest, (void *)cp, PAGE_SIZE);
+			cp += PAGE_SIZE;
+			map = crash_update_map(map, src_base, dest, &header->map_pages); /* links a new map page, if necessary */
+			if (!map) {
+				printk("save_core: no map\n");
+				return;
+			}
+		}
+		header->compr_units++;
+		if (!src)
+			break;
+		if (crash_reset_stream(&stream))
+			return;
+	}
+
+	map = crash_update_map(map, 0, 0, &header->map_pages);
+	header->magic[0] = CRASH_MAGIC;
+
+	if (crash_audit_maps()) {
+		header->magic[0] = 0;
+		return;
+	}
+
+	printk("\nsave_core: src pages skipped = 0x%lx src pages saved = 0x%lx\n",
+	       src_pages_skipped, src_pages_saved);
+	printk("save_core: data_pages = 0x%lx map_pages = 0x%lx\n", header->data_pages,
+	       header->map_pages);
+	printk("save_core: completed, crash_dump_header = 0x%lx\n", crash_dump_header);
+}
+
+/* helper functions private to this file */
+static int crash_reset_stream(z_stream * stream)
+{
+	int err;
+
+	stream->zalloc = czalloc;
+	stream->zfree = czfree;
+	stream->opaque = (voidpf) 0;
+	stream->next_out = (Bytef *) crash_compr_buf;
+	stream->avail_out = (uInt) (CRASH_COMPR_BUF_PAGES * PAGE_SIZE);
+	stream->next_in = (Bytef *) crash_uncompr_buf;
+	stream->avail_in = (uInt) (CRASH_UNCOMPR_BUF_PAGES * PAGE_SIZE);
+	err = deflateReset(stream);
+	if (err != Z_OK) {
+		printk("crash_reset_stream: bad return %d from deflateReset\n", err);
+		return 1;
+	}
+	return 0;
+}
+
+static u_long crash_alloc_dest_page(void)
+{
+	u_long addr;
+
+	addr = crash_dest_free_list;
+	if (addr) {
+		crash_dest_free_list = *(u_long *) addr;
+		dest_pages_free--;
+	} else
+		printk("crash_alloc_dest_page: free list empty\n");
+	return addr;
+}
+
+static void crash_free_dest_page(u_long dest)
+{
+	if (!dest) {
+		printk("crash_free_dest_page: freeing addr 0\n");
+		return;
+	}
+	dest_pages_free++;
+	dest = (u_long) trunc_page(dest);
+	*(u_long *) dest = crash_dest_free_list;
+	crash_dest_free_list = dest;
+}
+
+/*
+ *  Stolen from setup.c
+ */
+#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+
+static void init_dest_page_alloc(void)
+{
+	u_long va;
+	long i;
+	struct page *page;
+	struct mem_crash_map_hdr *header;
+
+	header = (struct mem_crash_map_hdr *)crash_dump_header;
+	for (i = ((1 << 24) >> PAGE_SHIFT) + LOWER_MEM_FORWARD;
+	     i < (max_low_pfn - UPPER_MEM_BACKUP); i++) {
+		va = (u_long) phys_to_virt(PFN_PHYS(i));
+		if ((va >= header->boot_reserved_start) && (va < header->boot_reserved_end))
+			continue;
+		page = mem_map + i;
+		if (PageLocked(page) || PageReserved(page))
+			continue;
+		if (PageFree(page) || PageAnon(page) || PageShm(page) || page->buffers)
+			crash_free_dest_page(va);
+	}
+	if (crash_debug)
+		printk("init_dest_page_alloc: dest_pages_free = 0x%lx\n", dest_pages_free);
+}
+
+static int crash_is_dir_page(struct page *page) {
+	struct inode *tmp_inode;
+
+	if(page->mapping && page->mapping->host) {
+		tmp_inode = (struct inode *)page->mapping->host;
+		if((tmp_inode->i_sb->s_magic == EXT2_SUPER_MAGIC) &&
+		   (S_ISDIR(tmp_inode->i_mode)))
+			return 1;
+	}
+
+	return 0;
+}
+
+static u_long crash_get_source_page(void)
+{
+	struct page *page;
+	u_long va;
+
+	while (crash_cur_pfn < max_low_pfn) {
+		page = mem_map + crash_cur_pfn;
+		if (!(PageFree(page) || PageAnon(page) || PageShm(page) || page->buffers))
+			break;
+		src_pages_skipped++;
+		crash_cur_pfn++;
+	}
+	if (crash_cur_pfn == max_low_pfn)
+		return 0;
+
+	va = (u_long) phys_to_virt(PFN_PHYS(crash_cur_pfn));
+	src_pages_saved++;
+	crash_cur_pfn++;
+	return va;
+}
+
+static u_long crash_update_map(u_long map, u_long src_base, u_long dest, u_long * pages)
+{
+	struct mem_crash_map_entry *m;
+
+
+	if (!map) {
+		(*pages)++;
+		return crash_alloc_dest_page();
+	}
+	m = (struct mem_crash_map_entry *)map;
+	m->src_va = src_base;
+	m->dest_page_va = dest;
+	if (dest)
+		if (crash_chksum_page(dest, &m->check_sum))
+			return 0;
+
+	map += sizeof(struct mem_crash_map_entry);
+
+	m = (struct mem_crash_map_entry *)map;
+	if (!src_base) {	/* end of list */
+		if (crash_chksum((u_long) m, &m->src_va))
+			return 0;
+	} else if ((map + 3 * sizeof(struct mem_crash_map_entry)) > (u_long) round_page(map)) {
+		m->src_va = -1;
+		map = m->dest_page_va = crash_alloc_dest_page();
+		if (crash_debug)
+			printk("\nm = 0x%lx m->src_va = 0x%lx m->dest_page_va = 0x%lx\n",
+			       (u_long) trunc_page(m), m->src_va, m->dest_page_va);
+		m++;
+		if (crash_chksum((u_long) m, &m->src_va))
+			return 0;
+		if (crash_debug)
+			printk("m = 0x%lx chksum =  m->src_va = 0x%lx\n", (u_long) trunc_page(m),
+			       m->src_va);
+		if (crash_audit_map_page((u_long) m))
+			return 0;
+		(*pages)++;
+	}
+	return map;
+}
+
+static int crash_chksum(u_long limit, u_long * sum_addr)
+{
+	u_long sum;
+	u_long *addr;
+
+	if (!crash_is_kseg(limit)) {
+		printk("bad addr = 0x%lx to crash_chksum\n", limit);
+		return 1;
+	}
+	sum = 0;
+	addr = (u_long *) trunc_page(limit);
+	for (; (u_long) addr < limit; addr++)
+		sum += *addr;
+	*sum_addr = sum;
+	return 0;
+}
+
+static int crash_chksum_page(u_long pg_addr, u_long * sum_addr)
+{
+	u_long sum, limit;
+	u_long *addr;
+
+	if (!crash_is_kseg(pg_addr)) {
+		printk("bad addr = 0x%lx to crash_chksum_page\n", pg_addr);
+		return 1;
+	}
+
+	sum = 0;
+	addr = (u_long *) trunc_page(pg_addr);
+	limit = (u_long) addr + PAGE_SIZE;
+	for (; (u_long) addr < limit; addr++)
+		sum += *addr;
+	*sum_addr = sum;
+	return 0;
+}
+
+static int crash_audit_maps(void)
+{
+	u_long m, count;
+	u_long *link_addr;
+	struct mem_crash_map_hdr *header;
+
+	header = (struct mem_crash_map_hdr *)crash_dump_header;
+	if (header->magic[0] != CRASH_MAGIC)
+		return 1;
+
+	link_addr = &header->map;
+	m = header->map;
+
+	count = 0;
+	for (;;) {
+		if (!crash_is_kseg(m)) {
+			printk("crash_audit_maps: bad link 0x%lx at 0x%lx\n", m,
+			       (u_long) link_addr);
+			return 1;
+		}
+		if (crash_audit_map_page(m)) {
+			printk("audit failed while on map page %ld\n", count);
+			return 1;
+		}
+		if (!crash_link(m))
+			break;
+		link_addr = crash_link(m);
+		m = *link_addr;
+
+		count++;
+	}
+	return 0;
+}
+
+static int crash_audit_map_page(u_long map)
+{
+	struct mem_crash_map_entry *m;
+	u_long sum;
+
+	if (!map || !crash_is_kseg(map)) {
+		printk("crash_audit_map_page: bad map = 0x%lx\n", map);
+		return 1;
+	}
+	map = (u_long) trunc_page((u_long) map);
+	m = (struct mem_crash_map_entry *)map;
+	for (;;) {
+		if ((m->src_va == -1) || (m->src_va == 0)) {
+			m++;
+			if (crash_chksum((u_long) m, &sum))
+				return 1;
+			if (m->src_va != sum) {
+				printk("crash_audit_map_page: checksum failure1\n");
+				printk("m = 0x%lx, sum = 0x%lx, m->src_va = 0x%lx\n",
+				       (u_long) m, (u_long) sum, (u_long) m->src_va);
+				crash_print_data_around((u_long) & m->src_va);
+				return 1;
+			} else {
+				return 0;
+			}
+		} else {
+			if (crash_chksum_page((u_long) m->dest_page_va, &sum)
+			    || (m->check_sum != sum)) {
+				printk("crash_audit_map_page: checksum failure2\n");
+				printk
+					("dest_page_va = 0x%lx, &dest_page_va = 0x%lx, sum = 0x%lx, m->check_sum = 0x%lx\n",
+					 (u_long) m->dest_page_va, (u_long) (&m->check_sum),
+					 (u_long) sum, (u_long) m->check_sum);
+				crash_print_data_around((u_long) & m->check_sum);
+				return 1;
+			}
+		}
+		m++;
+	}
+}
+
+static void crash_print_data_around(u_long p)
+{
+	u_long *a;
+	int i;
+
+	if (!crash_is_kseg(p)) {
+		printk("crash_print_data_around: p = 0x%lx not kseg\n", p);
+		return;
+	}
+	a = (u_long *) p;
+	a -= 20;
+	for (i = 0; i < 40; i++)
+		printk("%lx\n", *a++);
+}
+
+#ifdef CRASH_DEBUG
+static void crash_print_map_page(u_long map)
+{
+	struct mem_crash_map_entry *m;
+	int j = 0;
+	u_long sum;
+
+	map = (u_long) trunc_page((u_long) map);
+	m = (struct mem_crash_map_entry *)map;
+	for (;;) {
+		printk("%lx %lx %lx ", m->src_va, m->dest_page_va, m->check_sum);
+		if (!(j++ % 4))
+			printk("\n");
+		if ((m->src_va == -1) || (m->src_va == 0)) {
+			m++;
+			printk("%lx %lx ", m->src_va, m->dest_page_va);
+			if (crash_chksum((u_long) m, &sum));
+			else
+				printk("\nchksum = 0x%lx\n", sum);
+			return;
+		}
+		m++;
+	}
+}
+#endif /* CRASH_DEBUG */
+
+static void crash_wait_cpus(void)
+{
+	int i;
+	int msecs = 0;
+
+	for (i = 0; i < smp_num_cpus; i++) {
+		if (i != smp_processor_id()) {
+			while (!panic_threads[i]) {
+				msecs++;
+				mdelay(1);
+				if (msecs > CRASH_CPU_TIMEOUT) {
+					/* if other cpus are still running
+					 * we have to halt, otherwise we could
+					 * risk using buffer cache pages which
+					 * could subsequently get flushed to disk.
+					 */
+					printk("Unable to halt other CPUs, halting system.\n");
+					crash_halt_or_reboot(0);
+				}
+			}
+		}
+	}
+
+	crash_cleanup_smp_state();
+}
+
+
+static void *czalloc(void *arg, unsigned int items, unsigned int size)
+{
+	u_long nbytes;
+	u_long addr;
+
+	nbytes = (u_long) (items * size);
+	nbytes = (u_long) round_page(nbytes);
+	if ((crash_zalloc_cur + nbytes) > crash_zalloc_end)
+		return 0;
+	addr = crash_zalloc_cur;
+	crash_zalloc_cur += nbytes;
+	return ((void *)addr);
+}
+
+static void czfree(void *arg, void *ptr)
+{
+	printk("zfree: ptr = 0x%lx\n", (u_long) ptr);
+}
+
+static boolean_t crash_is_kseg(u_long addr)
+{
+	u_long phys;
+
+	phys = virt_to_phys((void *)addr);
+	if (phys < PFN_PHYS(max_low_pfn))
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static u_long *crash_link(u_long p)
+{
+	struct mem_crash_map_entry *m;
+
+	p = (u_long) trunc_page(p);
+	m = (struct mem_crash_map_entry *)p;
+	for (; m->src_va; m++)
+		if (m->src_va == -1)
+			return &m->dest_page_va;
+
+	return 0;
+}
+
+/* Call this after data written to disk. */
+static int crash_free_crashmem(void)
+{
+	struct mem_crash_map_hdr *header;
+	struct mem_crash_map_entry *m, *last_m;
+
+	if (crash_debug)
+		printk("crash_free_crashmem: \n");
+
+	header = (struct mem_crash_map_hdr *)crash_dump_header;
+	if (crash_audit_maps()) {
+		header->magic[0] = 0;
+		return 1;
+	}
+	m = (struct mem_crash_map_entry *)header->map;
+ again:
+	for (; m->src_va; m++) {
+		if (m->src_va == -1) {
+			last_m = m;
+			m = (struct mem_crash_map_entry *)m->dest_page_va;
+			crash_free_page((unsigned long)last_m);
+			goto again;
+		}
+		crash_free_page(m->dest_page_va);
+	}
+	if (crash_debug)
+		printk("crash_free_crashmem: 0x%lx freed\n",
+		       (header->data_pages + header->map_pages) * PAGE_SIZE);
+	header->magic[0] = 0;
+	return 0;
+}
+
+static void crash_free_page(u_long addr)
+{
+	struct page *page;
+
+	page = virt_to_page(addr);
+	ClearPageReserved(page);
+	set_page_count(page, 1);
+	__free_page(page);
+}
+
+static int get_dump_helper(u_long kva, u_long buf)
+{
+	struct page *page;
+	struct mem_crash_map_hdr *header;
+
+	header = (struct mem_crash_map_hdr *)crash_dump_header;
+	if (header->magic[0] != CRASH_MAGIC)
+		return 1;
+
+	if (!kva) {
+		if (crash_audit_maps()) {
+			printk("get_dump_helper: audit failure\n");
+			header->magic[0] = 0;
+			return 1;
+		}
+		page = virt_to_page((u_long) crash_dump_header);
+		if (!PageReserved(page)) {
+			printk("not reserved: crash_dump_header = 0x%lx\n", crash_dump_header);
+			return 1;
+		}
+		if (copy_to_user((char *)buf, (char *)crash_dump_header,
+				 sizeof(struct mem_crash_map_hdr))) {
+			printk("get_dump_helper: copy_to_user failed1\n");
+			return 1;
+		}
+	} else {
+		page = virt_to_page(kva);
+		if (!PageReserved(page)) {
+			printk("not reserved: kva = 0x%lx\n", kva);
+			return 1;
+		}
+		if (copy_to_user((char *)buf, (char *)trunc_page(kva), PAGE_SIZE)) {
+			printk("get_dump_helper: copy_to_user failed2\n");
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static void free_dump_helper(void)
+{
+	struct mem_crash_map_hdr *header;
+
+	header = (struct mem_crash_map_hdr *)crash_dump_header;
+	if (header->magic[0] != CRASH_MAGIC)
+		return;
+	if (crash_debug)
+		printk("free_dump_helper\n");
+	crash_free_crashmem();
+}
+
+static int crashdev_open(struct inode *inode, struct file *file)
+{
+	/* always return success -- nothing to do here */
+	return 0;
+}
+
+/* character device implementation */
+static struct file_operations crashdev_fops = {
+	ioctl:crashdev_ioctl,
+	open:crashdev_open,
+};
+
+static struct miscdevice crash_miscdev = {
+	190, "crash", &crashdev_fops
+};
+
+int crash_init_chrdev(void)
+{
+	int result;
+
+	result = misc_register(&crash_miscdev);
+
+	if (result < 0)
+		printk(KERN_WARNING "crash: can't register crash device (c 10 190)\n");
+
+	return result;
+}
+
+/* call the original syscalls, just to get things going */
+static int crashdev_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	switch (cmd) {
+	case CRASH_IOCFREEDUMP:
+		free_dump_helper();
+		break;
+
+	case CRASH_IOCGETDUMP:
+		if (crash_debug) {
+			printk("crashdev_ioctl: get dump\n");
+			printk("vals: %08lx %08lx\n",
+			       ((struct ioctl_getdump *)arg)->kva,
+			       ((struct ioctl_getdump *)arg)->buf);
+		}
+
+		retval = get_dump_helper((u_long) ((struct ioctl_getdump *)arg)->kva,
+					 (u_long) ((struct ioctl_getdump *)arg)->buf);
+		break;
+
+#ifdef CONFIG_BOOTIMG
+	case CRASH_IOCBOOTIMG:
+		if (crash_debug)
+			printk("crashdev_ioctl: bootimg\n");
+
+		retval = sys_bootimg((struct boot_image *)arg);
+		break;
+#endif
+
+	case CRASH_IOCVERSION:
+		if (crash_debug)
+			printk("crashdev_ioctl: version\n");
+		retval = CRASH_K_MINOR | (CRASH_K_MAJOR << 16);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return retval;
+}
diff -urN linux-2.4.7/kernel/panic.c linux-2.4.7-mcore/kernel/panic.c
--- linux-2.4.7/kernel/panic.c	Mon Oct 16 15:58:51 2000
+++ linux-2.4.7-mcore/kernel/panic.c	Fri Jul 27 14:58:14 2001
@@ -17,6 +17,10 @@
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
+
 asmlinkage void sys_sync(void);	/* it's really int */
 extern void unblank_console(void);
 
@@ -51,18 +55,41 @@
         unsigned long caller = (unsigned long) __builtin_return_address(0);
 #endif
 
+#ifdef CONFIG_MCL_COREDUMP
+	crash_save_regs();
+#endif
+
 	va_start(args, fmt);
 	vsprintf(buf, fmt, args);
 	va_end(args);
 	printk(KERN_EMERG "Kernel panic: %s\n",buf);
+
+#ifdef CONFIG_MCL_COREDUMP
+        if(!panicmsg) {
+		panicmsg = buf;
+		panic_processor = smp_processor_id();
+		printk("panic processor = %d\n", panic_processor);
+		mb();
+	}
+#endif
+
 	if (in_interrupt())
 		printk(KERN_EMERG "In interrupt handler - not syncing\n");
 	else if (!current->pid)
 		printk(KERN_EMERG "In idle task - not syncing\n");
-	else
+#ifdef CONFIG_MCL_COREDUMP
+        else if(crash_perform_sync)
+#else
+        else
+#endif
 		sys_sync();
 
 	unblank_console();
+
+#ifdef CONFIG_MCL_COREDUMP
+	smp_call_function((void*)smp_crash_funnel_cpu,0,0,0);
+	crash_save_current_state(current);	
+#endif
 
 #ifdef CONFIG_SMP
 	smp_send_stop();
diff -urN linux-2.4.7/kernel/sysctl.c linux-2.4.7-mcore/kernel/sysctl.c
--- linux-2.4.7/kernel/sysctl.c	Thu Apr 12 15:20:31 2001
+++ linux-2.4.7-mcore/kernel/sysctl.c	Fri Jul 27 14:58:14 2001
@@ -37,6 +37,10 @@
 #include <linux/nfs_fs.h>
 #endif
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
+
 #if defined(CONFIG_SYSCTL)
 
 /* External variables not in a header file. */
@@ -232,6 +236,10 @@
 	{KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
 	 0644, NULL, &proc_dointvec},
 #endif	 
+#ifdef CONFIG_MCL_COREDUMP
+	{KERN_PANIC_ON_OOPS, "panic_on_oops", &panic_on_oops, sizeof(int),
+	 0644, NULL, &proc_dointvec},
+#endif
 	{KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_RANDOM, "random", NULL, 0, 0555, random_table},
diff -urN linux-2.4.7/kernel/zlib.c linux-2.4.7-mcore/kernel/zlib.c
--- linux-2.4.7/kernel/zlib.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.7-mcore/kernel/zlib.c	Fri Jul 27 14:58:15 2001
@@ -0,0 +1,5371 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-1.0.4
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.  See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp and deflateOutputPending
+ * - allow strm->next_out to be NULL, meaning discard the output
+ *
+ * $Id: zlib.c,v 1.3 1997/12/23 10:47:42 paulus Exp $
+ */
+
+/* 
+ *  ==FILEVERSION 971210==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+#define NO_DUMMY_DECL
+#define NO_ZCFUNCS
+#define MY_ZCALLOC
+
+#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
+#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
+#endif
+
+
+/* +++ zutil.h */
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#if defined(KERNEL) || defined(_KERNEL)
+/* Assume this is a *BSD or SVR4 kernel */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#  define HAVE_MEMCPY
+#  define memcpy(d, s, n)	bcopy((s), (d), (n))
+#  define memset(d, v, n)	bzero((d), (n))
+#  define memcmp		bcmp
+
+#else
+#if defined(__KERNEL__)
+/* Assume this is a Linux kernel */
+#include <linux/string.h>
+#define HAVE_MEMCPY
+
+#else /* not kernel */
+
+#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
+#   include <stddef.h>
+#   include <errno.h>
+#else
+    extern int errno;
+#endif
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#endif /* __KERNEL__ */
+#endif /* _KERNEL || KERNEL */
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#ifdef MSDOS
+#  define OS_CODE  0x00
+#  ifdef __TURBOC__
+#    include <alloc.h>
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+#  define OS_CODE  0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define FOPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef MACOS
+#  define OS_CODE  0x07
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0F
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef FOPEN
+#  define FOPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#ifdef HAVE_STRERROR
+   extern char *strerror OF((int));
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
+   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+#  include <stdio.h>
+#  ifndef verbose
+#    define verbose 0
+#  endif
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
+/* --- zutil.h */
+
+/* +++ deflate.h */
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+/* #include "zutil.h" */
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct deflate_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    int   pending;       /* nb of bytes in the pending buffer */
+    int   noheader;      /* suppress zlib header and adler32 */
+    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    ulg compressed_len; /* total bit length of compressed file */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG_ZLIB
+    ulg bits_sent;      /* bit length of the compressed data */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+			  int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+void _tr_stored_type_only OF((deflate_state *));
+
+#endif
+/* --- deflate.h */
+
+/* +++ deflate.c */
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
+
+/* #include "deflate.h" */
+
+char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG_ZLIB
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+local config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+			 Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+		  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int noheader = 0;
+    static char* my_version = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+	return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+    if (strm->zalloc == Z_NULL) {
+	strm->zalloc = zcalloc;
+	strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+#endif
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+	return Z_STREAM_ERROR;
+
+    s = (deflate_state *) strm->state;
+    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+	length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+	dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    zmemcpy((charf *)s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+	INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+	level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+	return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+	/* Flush the last buffer: */
+	err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+	s->level = level;
+	s->max_lazy_match   = configuration_table[level].max_lazy;
+	s->good_match       = configuration_table[level].good_length;
+	s->nice_match       = configuration_table[level].nice_length;
+	s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}   
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    deflate_state *s = (deflate_state *) strm->state;
+    unsigned len = s->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    if (strm->next_out != Z_NULL) {
+	zmemcpy(strm->next_out, s->pending_out, len);
+	strm->next_out += len;
+    }
+    s->pending_out += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    s->pending -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+	flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) strm->state;
+
+    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
+	(s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+	if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        s->status = BUSY_STATE;
+        putShortMSB(s, header);
+
+	/* Save the adler32 of the preset dictionary: */
+	if (s->strstart != 0) {
+	    putShortMSB(s, (uInt)(strm->adler >> 16));
+	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+	}
+	strm->adler = 1L;
+    }
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+	    /* Since avail_out is 0, deflate will be called again with
+	     * more output space, but possibly with both pending and
+	     * avail_in equal to zero. There won't be anything to do,
+	     * but this is not an error situation so make sure we
+	     * return OK instead of BUF_ERROR at next call of deflate:
+             */
+	    s->last_flush = -1;
+	    return Z_OK;
+	}
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+	       flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+	bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+	    if (strm->avail_out == 0) {
+	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+	    }
+	    return Z_OK;
+	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+	     * of deflate should use the same flush parameter to make sure
+	     * that the flush is complete. So we don't have to output an
+	     * empty block here, this will be done at next call. This also
+	     * ensures that for a very small output buffer, we emit at most
+	     * one empty block.
+	     */
+	}
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+	    } else if (flush == Z_PACKET_FLUSH) {
+		/* Output just the 3-bit `stored' block type value,
+		   but not a zero length. */
+		_tr_stored_type_only(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+	    if (strm->avail_out == 0) {
+	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+	      return Z_OK;
+	    }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(s, (uInt)(strm->adler >> 16));
+    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    status = s->status;
+    if (status != INIT_STATE && status != BUSY_STATE &&
+	status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, s->pending_buf);
+    TRY_FREE(strm, s->head);
+    TRY_FREE(strm, s->prev);
+    TRY_FREE(strm, s->window);
+
+    ZFREE(strm, s);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ */
+int deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    ss = (deflate_state *) source->state;
+
+    *dest = *source;
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    *ds = *ss;
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+}
+
+/* ===========================================================================
+ * Return the number of bytes of output which are immediately available
+ * for output from the decompressor.
+ */
+int deflateOutputPending (strm)
+    z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
+    
+    return ((deflate_state *)(strm->state))->pending;
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    charf *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!((deflate_state *)(strm->state))->noheader) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check 