diff -urN linux-2.2.16/Documentation/Configure.help linux-2.2.16-mcore/Documentation/Configure.help
--- linux-2.2.16/Documentation/Configure.help	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/Documentation/Configure.help	Thu Jun 15 14:07:08 2000
@@ -11743,6 +11743,35 @@
 
   Saying M will compile this driver as a module (planb.o).
 
+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.2.16/Makefile linux-2.2.16-mcore/Makefile
--- linux-2.2.16/Makefile	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/Makefile	Thu Jun 15 14:07:08 2000
@@ -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 	=
 
@@ -87,7 +87,13 @@
 # standard CFLAGS
 #
 
-CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+CFLAGS = -Wall -Wstrict-prototypes -O2
+
+ifeq ($(CONFIG_MCL_COREDUMP),y)
+	CFLAGS += -g
+else
+	CFLAGS += -fomit-frame-pointer
+endif
 
 # use '-fno-strict-aliasing', but only if the compiler can take it
 CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi)
diff -urN linux-2.2.16/arch/alpha/config.in linux-2.2.16-mcore/arch/alpha/config.in
--- linux-2.2.16/arch/alpha/config.in	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/alpha/config.in	Thu Jun 15 14:07:08 2000
@@ -295,4 +295,5 @@
 fi
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Kernel Core Dump Facility' CONFIG_MCL_COREDUMP
 endmenu
diff -urN linux-2.2.16/arch/alpha/kernel/Makefile linux-2.2.16-mcore/arch/alpha/kernel/Makefile
--- linux-2.2.16/arch/alpha/kernel/Makefile	Wed May  3 20:16:30 2000
+++ linux-2.2.16-mcore/arch/alpha/kernel/Makefile	Thu Jun 15 14:07:08 2000
@@ -124,6 +124,10 @@
 
 endif # GENERIC
 
+ifdef CONFIG_MCL_COREDUMP
+O_OBJS += crash.o
+endif
+
 ifdef CONFIG_SMP
 O_OBJS   += smp.o
 endif
diff -urN linux-2.2.16/arch/alpha/kernel/crash.c linux-2.2.16-mcore/arch/alpha/kernel/crash.c
--- linux-2.2.16/arch/alpha/kernel/crash.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/arch/alpha/kernel/crash.c	Wed Jun 21 12:13:19 2000
@@ -0,0 +1,131 @@
+/*
+ *  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;
+
+extern unsigned long cpu_present_mask;
+
+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->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)
+{
+	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 __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.2.16/arch/alpha/kernel/head.S linux-2.2.16-mcore/arch/alpha/kernel/head.S
--- linux-2.2.16/arch/alpha/kernel/head.S	Sat Jun 12 14:52:52 1999
+++ linux-2.2.16-mcore/arch/alpha/kernel/head.S	Thu Jun 15 14:07:08 2000
@@ -54,6 +54,21 @@
 	.end __smp_callin
 #endif /* __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.2.16/arch/alpha/kernel/process.c linux-2.2.16-mcore/arch/alpha/kernel/process.c
--- linux-2.2.16/arch/alpha/kernel/process.c	Wed May  3 20:16:30 2000
+++ linux-2.2.16-mcore/arch/alpha/kernel/process.c	Thu Jun 15 14:07:08 2000
@@ -122,6 +122,7 @@
 	char *	restart_cmd;
 };
 
+extern char *panicmsg;
 static void
 halt_processor(void * generic_ptr)
 {
@@ -142,12 +143,14 @@
 	*flags &= ~0x00ff0001UL;
 
 #ifdef __SMP__
-	/* Secondaries halt here. */
-	if (cpuid != smp_boot_cpuid) {
-		*flags |= 0x00040000UL; /* "remain halted" */
-		clear_bit(cpuid, &cpu_present_mask);
-		halt();
-	}
+	if (how->mode != LINUX_REBOOT_CMD_COREDUMP) {
+		/* Secondaries halt here. */
+		if (cpuid != smp_boot_cpuid) {
+			*flags |= 0x00040000UL; /* "remain halted" */
+			clear_bit(cpuid, &cpu_present_mask);
+			halt();
+		}
+        }
 #endif /* __SMP__ */
 
 #ifdef CONFIG_RTC
@@ -166,7 +169,8 @@
 	}
 #endif /* CONFIG_RTC */
 
-	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" */
 			cpup->ipc_buffer[0] = 0;
@@ -190,11 +194,12 @@
 		*flags |=  0x00040000UL; /* "remain halted" */
 
 #ifdef __SMP__
-	/* Wait for the secondaries to halt. */
-	clear_bit(smp_boot_cpuid, &cpu_present_mask);
-	while (cpu_present_mask)
-		/* Make sure we sample memory and not a register. */
-		barrier();
+	if (how->mode != LINUX_REBOOT_CMD_COREDUMP) {
+		/* Wait for the secondaries to halt. */
+		clear_bit(smp_boot_cpuid, &cpu_present_mask);
+		while (cpu_present_mask)
+			barrier();
+	}
 #endif /* __SMP__ */
 
         /* If booted from SRM, reset some of the original environment. */
@@ -227,7 +232,8 @@
 	copy_of_args.restart_cmd = restart_cmd;
 #ifdef __SMP__
 	/* A secondary can't wait here for the primary to finish, can it now? */
-	smp_call_function(halt_processor, (void *)&copy_of_args, 1, 0);
+	if(!panicmsg)
+		smp_call_function(halt_processor, (void *)&copy_of_args, 1, 0);
 #endif /* __SMP__ */
 	halt_processor(&copy_of_args);
 }
@@ -235,7 +241,10 @@
 void
 machine_restart(char *restart_cmd)
 {
-	alpha_mv.kill_arch(LINUX_REBOOT_CMD_RESTART, restart_cmd);
+	if(panicmsg)
+		alpha_mv.kill_arch(LINUX_REBOOT_CMD_COREDUMP, restart_cmd);
+	else
+		alpha_mv.kill_arch(LINUX_REBOOT_CMD_RESTART, restart_cmd);
 }
 
 void
diff -urN linux-2.2.16/arch/alpha/kernel/smp.c linux-2.2.16-mcore/arch/alpha/kernel/smp.c
--- linux-2.2.16/arch/alpha/kernel/smp.c	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/alpha/kernel/smp.c	Thu Jun 15 14:07:08 2000
@@ -32,6 +32,9 @@
 #include "proto.h"
 #include "irq.h"
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <asm/crash.h>
+#endif
 
 #define DEBUG_SMP 0
 #if DEBUG_SMP
@@ -551,6 +554,15 @@
 	       ((bogosum + 2500) / 5000) % 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.2.16/arch/alpha/kernel/traps.c linux-2.2.16-mcore/arch/alpha/kernel/traps.c
--- linux-2.2.16/arch/alpha/kernel/traps.c	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/alpha/kernel/traps.c	Tue Jun 20 16:29:20 2000
@@ -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>
@@ -313,6 +317,10 @@
 		while (1);
 	}
 	current->tss.flags |= (1UL << 63);
+#ifdef CONFIG_MCL_COREDUMP
+	if(panic_on_oops)
+		panic("die_if_kernel");
+#endif
 	do_exit(SIGSEGV);
 }
 
diff -urN linux-2.2.16/arch/alpha/mm/init.c linux-2.2.16-mcore/arch/alpha/mm/init.c
--- linux-2.2.16/arch/alpha/mm/init.c	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/alpha/mm/init.c	Thu Jun 15 14:07:08 2000
@@ -19,6 +19,10 @@
 #include <linux/blk.h>
 #endif
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -320,6 +324,10 @@
 		set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
 		tmp += PAGE_SIZE;
 	}
+
+#ifdef CONFIG_MCL_COREDUMP
+	crash_mark_dump_reserved();
+#endif
 
 	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
 		if (tmp >= MAX_DMA_ADDRESS)
diff -urN linux-2.2.16/arch/i386/boot/compressed/head.S linux-2.2.16-mcore/arch/i386/boot/compressed/head.S
--- linux-2.2.16/arch/i386/boot/compressed/head.S	Wed May  3 20:16:30 2000
+++ linux-2.2.16-mcore/arch/i386/boot/compressed/head.S	Thu Jun 15 14:07:08 2000
@@ -36,6 +36,23 @@
 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 %ax,%ds
 	movl %ax,%es
@@ -135,5 +152,6 @@
  * so we set esp here.
  */
 	mov  $0x90000,%esp
-	ljmp $(__KERNEL_CS), $0x100000
+	movl $0x100000,%eax
+	jmpl *%eax
 move_routine_end:
diff -urN linux-2.2.16/arch/i386/boot/setup.S linux-2.2.16-mcore/arch/i386/boot/setup.S
--- linux-2.2.16/arch/i386/boot/setup.S	Wed May  3 20:16:30 2000
+++ linux-2.2.16-mcore/arch/i386/boot/setup.S	Thu Jun 15 14:07:08 2000
@@ -82,18 +82,29 @@
 					!	T=2 for bootsect-loader
 					!	T=3 for SYSLX
 					!	T=4 for ETHERBOOT
+					!	T=5 for Linux kernel (bootimg)
 					!       V = version
 loadflags:			! flags, unused bits must be zero (RFU)
 LOADED_HIGH	= 1		! bit within loadflags,
-				! if set, then the kernel is loaded high
+	 			! if set, then 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.
+				! can be used for heap purposes.
 				! Only the loader knows what is free!
-#ifndef __BIG_KERNEL__
-		.byte	0x00
+
+#if defined(CONFIG_BOOTIMG) && defined(__BIG_KERNEL__)
+		.byte LOADED_HIGH + RELOADS_GDT
 #else
-		.byte	LOADED_HIGH
+#ifdef CONFIG_BOOTIMG
+		.byte RELOADS_GDT
+#else
+#ifdef __BIG_KERNEL__
+		.byte LOADED_HIGH
+#endif
+#endif
 #endif
 
 setup_move_size: .word  0x8000	! size to move, when we (setup) are not
diff -urN linux-2.2.16/arch/i386/config.in linux-2.2.16-mcore/arch/i386/config.in
--- linux-2.2.16/arch/i386/config.in	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/i386/config.in	Wed Aug  9 13:47:37 2000
@@ -206,5 +206,12 @@
 
 #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
+    define_bool CONFIG_BOOTIMG y
+#    bool '  Reboot via bootimg (Turn this ON!)' CONFIG_BOOTIMG
+  fi
+fi
 endmenu
 
diff -urN linux-2.2.16/arch/i386/kernel/Makefile linux-2.2.16-mcore/arch/i386/kernel/Makefile
--- linux-2.2.16/arch/i386/kernel/Makefile	Wed Jan 20 13:18:53 1999
+++ linux-2.2.16-mcore/arch/i386/kernel/Makefile	Thu Jun 15 14:07:08 2000
@@ -50,6 +50,10 @@
 O_OBJS += visws_apic.o
 endif
 
+ifdef CONFIG_MCL_COREDUMP
+O_OBJS += crash.o
+endif
+
 head.o: head.S $(TOPDIR)/include/linux/tasks.h
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
 
diff -urN linux-2.2.16/arch/i386/kernel/crash.c linux-2.2.16-mcore/arch/i386/kernel/crash.c
--- linux-2.2.16/arch/i386/kernel/crash.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/arch/i386/kernel/crash.c	Wed Jun 21 13:14:55 2000
@@ -0,0 +1,161 @@
+/*
+ *  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>
+#include <linux/delay.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_X86_LOCAL_APIC
+/* stolen from 2.3/4.x kernels to clear/reset the local APICs */
+/* ---------------------------------------------------------- */
+
+extern void clear_IO_APIC (void);
+
+#define         APIC_LVTERR     0x370
+#define         APIC_LVR        0x30
+#define         GET_APIC_VERSION(x)     ((x)&0xFF)
+#define         GET_APIC_MAXLVT(x)      (((x)>>16)&0x0F)
+#define         APIC_INTEGRATED(x)      ((x)&0xF0)
+#define         APIC_LVTPC      0x340
+
+#ifdef CONFIG_X86_GOOD_APIC
+# define FORCE_READ_AROUND_WRITE 0
+# define apic_read_around(x)
+# define apic_write_around(x,y) apic_write((x),(y))
+#else
+# define FORCE_READ_AROUND_WRITE 1
+# define apic_read_around(x) apic_read(x)
+# define apic_write_around(x,y) apic_write_atomic((x),(y))
+#endif
+
+static int my_get_maxlvt(void)
+{
+        unsigned int v, ver, maxlvt;
+
+        v = apic_read(APIC_LVR);
+        ver = GET_APIC_VERSION(v);
+        /* 82489DXs do not report # of LVT entries. */
+        maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
+        return maxlvt;
+}
+
+static void my_clear_local_APIC(void)
+{
+        int maxlvt;
+        unsigned long v;
+
+        maxlvt = my_get_maxlvt();
+
+        /*
+         * Careful: we have to set masks only first to deassert
+         * any level-triggered sources.
+         */
+        v = apic_read(APIC_LVTT);
+        apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
+        v = apic_read(APIC_LVT0);
+        apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
+        v = apic_read(APIC_LVT1);
+        apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
+        if (maxlvt >= 3) {
+                v = apic_read(APIC_LVTERR);
+                apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
+        }
+        if (maxlvt >= 4) {
+                v = apic_read(APIC_LVTPC);
+                apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
+        }
+
+        /*
+         * Clean APIC state for other OSs:
+         */
+        apic_write_around(APIC_LVTT, APIC_LVT_MASKED);
+        apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
+        apic_write_around(APIC_LVT1, APIC_LVT_MASKED);
+        if (maxlvt >= 3)
+                apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
+        if (maxlvt >= 4)
+                apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
+}
+
+/* ---------------------------------------------------------- */
+/* end of stolen code! */
+#endif
+
+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->tss.esp));
+	tp->tss.eip = (u_long)crash_save_current_state;
+	panic_ksp[smp_processor_id()] = tp->tss.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_X86_LOCAL_APIC
+/*	my_clear_local_APIC(); */
+#endif
+#ifdef CONFIG_SMP
+	if (!boot_cpu) {
+		stop_this_cpu();
+		/* NOTREACHED */
+	}
+#endif
+
+	/* just have the boot cpu clear the IO apic */
+#ifdef CONFIG_X86_IO_APIC
+/*	clear_IO_APIC(); */
+#endif
+
+	machine_restart(NULL);
+}
+
+void crash_cleanup_smp_state(void)
+{
+	__cli();
+}
+
+/*
+ *  Core dump IPI
+ */
+void smp_crash_funnel_cpu(void)
+{
+	crash_save_current_state(current);
+}
diff -urN linux-2.2.16/arch/i386/kernel/head.S linux-2.2.16-mcore/arch/i386/kernel/head.S
--- linux-2.2.16/arch/i386/kernel/head.S	Fri Jan 15 01:57:25 1999
+++ linux-2.2.16-mcore/arch/i386/kernel/head.S	Thu Jun 15 14:07:08 2000
@@ -41,6 +41,18 @@
 ENTRY(_stext)
 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.2.16/arch/i386/kernel/io_apic.c linux-2.2.16-mcore/arch/i386/kernel/io_apic.c
--- linux-2.2.16/arch/i386/kernel/io_apic.c	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/i386/kernel/io_apic.c	Thu Jun 15 14:35:55 2000
@@ -218,7 +218,7 @@
 	io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
 }
 
-static void clear_IO_APIC (void)
+void clear_IO_APIC (void)
 {
 	int apic, pin;
 
diff -urN linux-2.2.16/arch/i386/kernel/process.c linux-2.2.16-mcore/arch/i386/kernel/process.c
--- linux-2.2.16/arch/i386/kernel/process.c	Wed May  3 20:16:31 2000
+++ linux-2.2.16-mcore/arch/i386/kernel/process.c	Thu Jun 15 14:07:10 2000
@@ -42,6 +42,9 @@
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
 
 #include "irq.h"
 
@@ -340,6 +343,21 @@
 
 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
 	/*
 	 * turn off the IO-APIC, so we can do a clean reboot
diff -urN linux-2.2.16/arch/i386/kernel/smp.c linux-2.2.16-mcore/arch/i386/kernel/smp.c
--- linux-2.2.16/arch/i386/kernel/smp.c	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/i386/kernel/smp.c	Thu Jun 15 14:07:10 2000
@@ -91,11 +91,15 @@
 /* Kernel spinlock */
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <asm/crash.h>
+#endif
+
 /*
  * function prototypes:
  */
 static void cache_APIC_registers (void);
-static void stop_this_cpu (void);
+void stop_this_cpu (void);
 
 static int smp_b_stepping = 0;				/* Set if we find a B stepping CPU			*/
 
@@ -2094,7 +2098,7 @@
 
 }
 
-static void stop_this_cpu (void)
+void stop_this_cpu (void)
 {
 	/*
 	 * Remove this CPU:
diff -urN linux-2.2.16/arch/i386/kernel/traps.c linux-2.2.16-mcore/arch/i386/kernel/traps.c
--- linux-2.2.16/arch/i386/kernel/traps.c	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/i386/kernel/traps.c	Thu Jun 15 14:07:10 2000
@@ -44,6 +44,10 @@
 
 #include "irq.h"
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
+
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
 
@@ -210,6 +214,10 @@
 	printk("%s: %04lx\n", str, err & 0xffff);
 	show_registers(regs);
 	spin_unlock_irq(&die_lock);
+#ifdef CONFIG_MCL_COREDUMP
+	if(panic_on_oops)
+		panic("die");
+#endif
 	do_exit(SIGSEGV);
 }
 
diff -urN linux-2.2.16/arch/i386/mm/init.c linux-2.2.16-mcore/arch/i386/mm/init.c
--- linux-2.2.16/arch/i386/mm/init.c	Tue Oct 26 20:53:39 1999
+++ linux-2.2.16-mcore/arch/i386/mm/init.c	Thu Jun 15 14:07:10 2000
@@ -426,6 +426,11 @@
 		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
 		start_mem += PAGE_SIZE;
 	}
+
+#ifdef CONFIG_MCL_COREDUMP
+	crash_mark_dump_reserved();
+#endif
+
 	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
 		if (tmp >= MAX_DMA_ADDRESS)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
diff -urN linux-2.2.16/arch/i386/vmlinux.lds.S linux-2.2.16-mcore/arch/i386/vmlinux.lds.S
--- linux-2.2.16/arch/i386/vmlinux.lds.S	Mon Aug  9 15:04:38 1999
+++ linux-2.2.16-mcore/arch/i386/vmlinux.lds.S	Thu Jun 15 14:07:10 2000
@@ -17,6 +17,13 @@
   .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.2.16/arch/ppc/config.in linux-2.2.16-mcore/arch/ppc/config.in
--- linux-2.2.16/arch/ppc/config.in	Wed Jun  7 17:26:42 2000
+++ linux-2.2.16-mcore/arch/ppc/config.in	Thu Jun 15 14:07:10 2000
@@ -195,4 +195,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.2.16/arch/ppc/kernel/Makefile linux-2.2.16-mcore/arch/ppc/kernel/Makefile
--- linux-2.2.16/arch/ppc/kernel/Makefile	Tue Jan  4 13:12:12 2000
+++ linux-2.2.16-mcore/arch/ppc/kernel/Makefile	Thu Jun 15 14:07:10 2000
@@ -29,6 +29,10 @@
 O_OBJS += sleep.o
 endif
 
+ifdef CONFIG_MCL_COREDUMP
+O_OBJS += crash.o
+endif
+
 ifeq ($(CONFIG_MBX),y)
 O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o
 else
diff -urN linux-2.2.16/arch/ppc/kernel/crash.c linux-2.2.16-mcore/arch/ppc/kernel/crash.c
--- linux-2.2.16/arch/ppc/kernel/crash.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/arch/ppc/kernel/crash.c	Wed Jun 21 12:12:10 2000
@@ -0,0 +1,94 @@
+/*
+ *  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>
+#include <linux/bootimg.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 = gprs;
+}
+
+/*
+ *  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.2.16/arch/ppc/mm/init.c linux-2.2.16-mcore/arch/ppc/mm/init.c
--- linux-2.2.16/arch/ppc/mm/init.c	Tue Jan  4 13:12:12 2000
+++ linux-2.2.16-mcore/arch/ppc/mm/init.c	Thu Jun 15 14:07:10 2000
@@ -56,6 +56,10 @@
 /* END APUS includes */
 #include <asm/gemini.h>
 
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.h>
+#endif
+
 int prom_trashed;
 atomic_t next_mmu_context;
 unsigned long *end_of_DRAM;
@@ -1233,6 +1237,10 @@
 	}
 
 	prom_trashed = 1;
+
+#ifdef CONFIG_MCL_COREDUMP
+	crash_mark_dump_reserved();
+#endif
 	
 	for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
 		if (PageReserved(mem_map + MAP_NR(addr))) {
diff -urN linux-2.2.16/drivers/char/sysrq.c linux-2.2.16-mcore/drivers/char/sysrq.c
--- linux-2.2.16/drivers/char/sysrq.c	Wed May  3 20:16:39 2000
+++ linux-2.2.16-mcore/drivers/char/sysrq.c	Thu Jun 15 14:07:10 2000
@@ -85,6 +85,11 @@
 		printk("Resetting\n");
 		machine_restart(NULL);
 		break;
+#ifdef CONFIG_MCL_COREDUMP
+	case 'c':
+		panic("sysrq");                             /* C -- crash and save core */
+		break;
+#endif
 	case 'o':					    /* O -- power off */
 		if (sysrq_power_off) {
 			printk("Power off\n");
@@ -143,6 +148,9 @@
 		printk("Boot ");
 		if (sysrq_power_off)
 			printk("Off ");
+#ifdef CONFIG_MCL_COREDUMP
+		printk("Crash ");
+#endif
 		printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n");
 		/* Don't use 'A' as it's handled specially on the Sparc */
 	}
diff -urN linux-2.2.16/include/asm-alpha/crash.h linux-2.2.16-mcore/include/asm-alpha/crash.h
--- linux-2.2.16/include/asm-alpha/crash.h	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/include/asm-alpha/crash.h	Thu Jun 15 14:07:10 2000
@@ -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.2.16/include/asm-i386/bootimg.h linux-2.2.16-mcore/include/asm-i386/bootimg.h
--- linux-2.2.16/include/asm-i386/bootimg.h	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/include/asm-i386/bootimg.h	Fri Jun 30 10:16:47 2000
@@ -0,0 +1,135 @@
+
+/* 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 <asm/hardirq.h>
+#include "../../arch/i386/kernel/irq.h" /* 2.2 irq.h is not in standard header location */
+#endif
+
+extern int get_maxlvt(void);
+extern void disable_local_APIC(void);
+
+/*
+ * 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();
+
+	init_pic_mode(); /* 2.2 version */
+#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))
+{
+	/* We must set bx to zero, because code in
+	   arch/i386/boot/compressed/head.S checks the value
+	   to determine if we are booting a secondary CPU
+	*/
+	__asm__ __volatile__ ("movl $0,%%ebx\n"
+			      : : : "ebx");
+	kernel_entry();
+}
+
+#endif
diff -urN linux-2.2.16/include/asm-i386/crash.h linux-2.2.16-mcore/include/asm-i386/crash.h
--- linux-2.2.16/include/asm-i386/crash.h	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/include/asm-i386/crash.h	Thu Jun 15 14:07:10 2000
@@ -0,0 +1,14 @@
+#ifndef __ASM_CRASH_H
+#define __ASM_CRASH_H
+
+#define UPPER_MEM_BACKUP 0
+#define LOWER_MEM_FORWARD 0
+
+/*
+ *  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.2.16/include/asm-ppc/crash.h linux-2.2.16-mcore/include/asm-ppc/crash.h
--- linux-2.2.16/include/asm-ppc/crash.h	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/include/asm-ppc/crash.h	Thu Jun 15 14:07:10 2000
@@ -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.2.16/include/linux/bootimg.h linux-2.2.16-mcore/include/linux/bootimg.h
--- linux-2.2.16/include/linux/bootimg.h	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/include/linux/bootimg.h	Thu Jun 15 14:07:10 2000
@@ -0,0 +1,87 @@
+/* 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 */
+extern unsigned long **bootimg_page_dir;
+
+/*
+ * 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);
+
+void enable_local_APIC(void); /* not in a header file in 2.2.x */
+
+#endif /* __KERNEL__ */
+
+#endif
diff -urN linux-2.2.16/include/linux/crash.h linux-2.2.16-mcore/include/linux/crash.h
--- linux-2.2.16/include/linux/crash.h	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/include/linux/crash.h	Fri Jun 30 10:16:32 2000
@@ -0,0 +1,128 @@
+#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>
+
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
+
+#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 crash_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);
+#define set_page_count(p,v)     atomic_set(&(p)->count, v)
+
+/*  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) (set_bit(PG_reserved,&mem_map[MAP_NR(addr)].flags));
+
+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.2.16/include/linux/mm.h linux-2.2.16-mcore/include/linux/mm.h
--- linux-2.2.16/include/linux/mm.h	Wed May  3 20:16:52 2000
+++ linux-2.2.16-mcore/include/linux/mm.h	Fri Jun 30 10:16:26 2000
@@ -144,6 +144,10 @@
 #define PG_Slab			 9
 #define PG_swap_cache		10
 #define PG_skip			11
+#define PG_free                 12
+#define PG_anon                 13
+#define PG_shm                  14
+/* bits 15-30 unused */
 #define PG_reserved		31
 
 /* Make it prettier to test the above... */
@@ -159,6 +163,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.2.16/include/linux/reboot.h linux-2.2.16-mcore/include/linux/reboot.h
--- linux-2.2.16/include/linux/reboot.h	Thu Aug 27 22:37:33 1998
+++ linux-2.2.16-mcore/include/linux/reboot.h	Thu Jun 15 14:07:10 2000
@@ -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.2.16/include/linux/sysctl.h linux-2.2.16-mcore/include/linux/sysctl.h
--- linux-2.2.16/include/linux/sysctl.h	Wed Jun  7 17:26:44 2000
+++ linux-2.2.16-mcore/include/linux/sysctl.h	Thu Jun 15 14:07:10 2000
@@ -106,6 +106,7 @@
 	KERN_SYSRQ=38,		/* int: Sysreq enable */
 	KERN_SHMALL=41,		/* int: maximum size of shared memory */
 	KERN_SPARC_STOP_A=44,	/* int: Sparc Stop-A enable */
+	KERN_PANIC_ON_OOPS,	/* int: do we panic on oops? */
 };
 
 
diff -urN linux-2.2.16/init/main.c linux-2.2.16-mcore/init/main.c
--- linux-2.2.16/init/main.c	Wed Jun  7 17:26:44 2000
+++ linux-2.2.16-mcore/init/main.c	Thu Jun 15 14:07:10 2000
@@ -58,6 +58,14 @@
 extern void nubus_init(void);
 #endif
 
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
+
+#ifdef CONFIG_MCL_COREDUMP
+#include <linux/crash.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.
@@ -408,8 +416,8 @@
 
 extern void time_init(void);
 
-static unsigned long memory_start = 0;
-static unsigned long memory_end = 0;
+unsigned long memory_start = 0;
+unsigned long memory_end = 0;
 
 int rows, cols;
 
@@ -1350,6 +1358,9 @@
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
+#ifdef CONFIG_MCL_COREDUMP
+	unsigned long crash_mem;
+#endif
 
 #ifdef __SMP__
 	static int boot_cpu = 1;
@@ -1365,7 +1376,20 @@
  */
 	printk(linux_banner);
 	setup_arch(&command_line, &memory_start, &memory_end);
-	memory_start = paging_init(memory_start,memory_end);
+#if CONFIG_MCL_COREDUMP
+	crash_mem = memory_start;
+	memory_start += crash_pages_needed() * PAGE_SIZE;
+#ifdef __alpha__
+	crash_console_sp = memory_start;
+	memory_start += PAGE_SIZE;
+#endif
+#endif
+
+        memory_start = paging_init(memory_start,memory_end);
+
+#if CONFIG_MCL_COREDUMP
+        crash_init((u_long)crash_mem);
+#endif
 	trap_init();
         memory_start = init_IRQ( memory_start );
 	sched_init();
@@ -1378,6 +1402,13 @@
 	 * this. But we do want output early, in case something goes wrong.
 	 */
 	memory_start = console_init(memory_start,memory_end);
+
+#ifdef CONFIG_BOOTIMG
+	unity_page = (void *)memory_start;
+	memory_start += PAGE_SIZE;
+	bootimg_page_dir = 0;
+	memset(&bootimg_dsc, 0, sizeof(struct bootimg_dsc));
+#endif
 #ifdef CONFIG_MODULES
 	init_modules();
 #endif
diff -urN linux-2.2.16/kernel/Makefile linux-2.2.16-mcore/kernel/Makefile
--- linux-2.2.16/kernel/Makefile	Wed May  6 14:01:46 1998
+++ linux-2.2.16-mcore/kernel/Makefile	Thu Jun 15 14:07:10 2000
@@ -25,6 +25,18 @@
 OX_OBJS  += ksyms.o
 endif
 
+ifndef CONFIG_IRDA_DEFLATE
+O_OBJS += zlib.o
+endif
+
+ifeq ($(CONFIG_BOOTIMG),y)
+O_OBJS += bootimg.o bootimg_pic.o
+endif
+
+ifeq ($(CONFIG_MCL_COREDUMP),y)
+O_OBJS += crash.o
+endif
+
 CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.16/kernel/bootimg.c linux-2.2.16-mcore/kernel/bootimg.c
--- linux-2.2.16/kernel/bootimg.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/kernel/bootimg.c	Thu Jun 15 14:07:11 2000
@@ -0,0 +1,259 @@
+/* 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>
+
+#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)
+{
+	pgd_t *pg_dir;
+
+	pg_dir = (pgd_t *)pgd_offset(current->mm, virt_to_phys(unity_page));
+	pgd_val(*pg_dir) =
+		((_KERNPG_TABLE + _PAGE_4M + (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;
+
+	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;
+
+	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
+			init_pic_mode();
+#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.2.16/kernel/bootimg_pic.c linux-2.2.16-mcore/kernel/bootimg_pic.c
--- linux-2.2.16/kernel/bootimg_pic.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/kernel/bootimg_pic.c	Thu Jun 15 14:07:11 2000
@@ -0,0 +1,95 @@
+/* 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/pgtable.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.2.16/kernel/crash.c linux-2.2.16-mcore/kernel/crash.c
--- linux-2.2.16/kernel/crash.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/kernel/crash.c	Tue Aug  8 10:36:27 2000
@@ -0,0 +1,869 @@
+#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 <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>
+
+#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 void crash_wait_cpus(void);
+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);
+
+/* for the /dev/crash interface */
+static int crash_init_chrdev(void);
+static int crashdev_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+#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 */
+
+#define PFN_DOWN(x)     ((x) >> PAGE_SHIFT)
+unsigned long max_low_pfn = 0;
+
+extern unsigned long memory_start, memory_end;
+
+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 crash_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\n");
+	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;
+
+	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("addresses: \n");
+	printk("    crash_dump_header = %lx\n", crash_dump_header);
+	printk("    crash_zalloc_cur  = %lx\n", crash_zalloc_cur);
+	printk("    crash_zalloc_end  = %lx\n", crash_zalloc_end);
+	printk("    crash_compr_buf   = %lx\n", crash_compr_buf);
+#endif
+
+	max_low_pfn = PFN_DOWN(virt_to_phys((void *)memory_end));
+
+	if (header->magic[0] == CRASH_MAGIC) {
+		printk("crash found\n");
+	} else {
+		memset(header, 0, sizeof(header));
+	}
+
+	crash_init_chrdev();
+}
+
+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 = (virt_to_phys((void *)memory_start) >> PAGE_SHIFT) + LOWER_MEM_FORWARD;
+	     i < (max_low_pfn - UPPER_MEM_BACKUP); i++) {
+		va = (u_long) phys_to_virt(PFN_PHYS(i));
+		page = mem_map + i;
+		if (PageLocked(page) || PageReserved(page))
+			continue;
+		if (page->inode || 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 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 (!(page->inode || 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 (addr < PAGE_OFFSET)
+		return FALSE;
+
+	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 = mem_map + MAP_NR(addr);
+	clear_bit(PG_reserved, &(page)->flags);
+
+	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 = mem_map + MAP_NR((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 = mem_map + MAP_NR(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 */
+struct file_operations crashdev_fops = {
+	NULL,			/* seek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* poll */
+	crashdev_ioctl,
+	NULL,			/* mmap */
+	crashdev_open,
+	NULL,			/* flush */
+	NULL,			/* close */
+	/* rest are NULL */
+};
+
+static struct miscdevice crash_miscdev = {
+	190, "crash", &crashdev_fops
+};
+
+static 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.2.16/kernel/panic.c linux-2.2.16-mcore/kernel/panic.c
--- linux-2.2.16/kernel/panic.c	Wed May  3 20:16:53 2000
+++ linux-2.2.16-mcore/kernel/panic.c	Wed Jun 21 12:09:11 2000
@@ -16,6 +16,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);
 extern int C_A_D;
@@ -38,18 +42,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 (current == task[0])
 		printk(KERN_EMERG "In swapper task - not syncing\n");
 	else if (in_interrupt())
 		printk(KERN_EMERG "In interrupt handler - not syncing\n");
+#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 __SMP__
 	smp_send_stop();
diff -urN linux-2.2.16/kernel/sysctl.c linux-2.2.16-mcore/kernel/sysctl.c
--- linux-2.2.16/kernel/sysctl.c	Wed Jun  7 17:26:44 2000
+++ linux-2.2.16-mcore/kernel/sysctl.c	Thu Jun 15 14:07:11 2000
@@ -29,6 +29,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. */
@@ -230,7 +234,11 @@
 #ifdef CONFIG_MAGIC_SYSRQ
 	{KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
 	 0644, NULL, &proc_dointvec},
-#endif	 
+#endif
+#ifdef CONFIG_MCL_COREDUMP
+	{KERN_PANIC_ON_OOPS, "panic_on_oops", &panic_on_oops, sizeof(int),
+	0644, NULL, &proc_dointvec},
+#endif
 	{0}
 };
 
diff -urN linux-2.2.16/kernel/zlib.c linux-2.2.16-mcore/kernel/zlib.c
--- linux-2.2.16/kernel/zlib.c	Wed Dec 31 19:00:00 1969
+++ linux-2.2.16-mcore/kernel/zlib.c	Thu Jun 15 14:07:11 2000
@@ -0,0 +1,5372 @@
+/*
+ * 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 more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * 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.
+         */
+   