--- /dev/null
+? linux/.config
+? linux/include/linux/autoconf.h
+? linux/include/linux/modules
+Index: linux/Makefile
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/Makefile,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.1
+diff -u -r1.3.2.1 -r1.3.2.1.2.1
+--- linux/Makefile 12 Mar 2003 19:48:52 -0000 1.3.2.1
++++ linux/Makefile 1 Apr 2003 12:17:40 -0000 1.3.2.1.2.1
+@@ -99,6 +99,10 @@
+ CFLAGS += -fomit-frame-pointer
+ endif
+ AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
++ifeq ($(CONFIG_MCL_COREDUMP),y)
++ CFLAGS += -g
++endif
++
+
+ #
+ # ROOT_DEV specifies the default root-device when making the image.
+Index: linux/Documentation/Configure.help
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/Documentation/Configure.help,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.1
+diff -u -r1.3.2.1 -r1.3.2.1.2.1
+--- linux/Documentation/Configure.help 12 Mar 2003 19:48:52 -0000 1.3.2.1
++++ linux/Documentation/Configure.help 1 Apr 2003 12:17:40 -0000 1.3.2.1.2.1
+@@ -21660,6 +21660,35 @@
+ This option allows you to run the kernel with data cache disabled.
+ Say Y if you experience CPM lock-ups.
+
++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
++
+ #
+ # m68k-specific kernel options
+ # Documented by Chris Lawrence <mailto:quango@themall.net> et al.
+Index: linux/arch/i386/config.in
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/config.in,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.2
+diff -u -r1.3.2.1 -r1.3.2.1.2.2
+--- linux/arch/i386/config.in 12 Mar 2003 19:49:05 -0000 1.3.2.1
++++ linux/arch/i386/config.in 1 Apr 2003 19:35:12 -0000 1.3.2.1.2.2
+@@ -502,6 +502,12 @@
+ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
+ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+ bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
++ if [ "$CONFIG_FRAME_POINTER " != "n" ]; then
++ bool ' Kernel Core Dump Facility' CONFIG_MCL_COREDUMP
++ if [ "$CONFIG_MCL_COREDUMP" = "y" ]; then
++ bool ' Reboot using bootimg' CONFIG_BOOTIMG
++ fi
++ fi
+ fi
+
+ endmenu
+Index: linux/arch/i386/vmlinux.lds
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/vmlinux.lds,v
+retrieving revision 1.1.1.1.4.1
+retrieving revision 1.1.1.1.4.1.2.1
+diff -u -r1.1.1.1.4.1 -r1.1.1.1.4.1.2.1
+--- linux/arch/i386/vmlinux.lds 12 Mar 2003 19:49:05 -0000 1.1.1.1.4.1
++++ linux/arch/i386/vmlinux.lds 1 Apr 2003 12:17:40 -0000 1.1.1.1.4.1.2.1
+@@ -19,6 +19,13 @@
+ .rodata : { *(.rodata) *(.rodata.*) }
+ .kstrtab : { *(.kstrtab) }
+
++ . = ALIGN(16); /* Relocatable bootimage code */
++ __bootimg_start = .;
++ .bootimg : {
++ *(.bootimg)
++ }
++ __bootimg_end = .;
++
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+Index: linux/arch/i386/boot/setup.S
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/boot/setup.S,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.1.2.1
+diff -u -r1.2.2.1 -r1.2.2.1.2.1
+--- linux/arch/i386/boot/setup.S 12 Mar 2003 19:49:05 -0000 1.2.2.1
++++ linux/arch/i386/boot/setup.S 1 Apr 2003 12:17:40 -0000 1.2.2.1.2.1
+@@ -105,16 +105,22 @@
+ # flags, unused bits must be zero (RFU) bit within loadflags
+ loadflags:
+ LOADED_HIGH = 1 # If set, the kernel is loaded high
++RELOADS_GDT = 2 # if set, kernel reloads GDT, such that
++ # boot loader does not have to provide
++ # GDT in a "safe" memory location
+ CAN_USE_HEAP = 0x80 # If set, the loader also has set
+ # heap_end_ptr to tell how much
+ # space behind setup.S can be used for
+ # heap purposes.
+ # Only the loader knows what is free
+-#ifndef __BIG_KERNEL__
+- .byte 0
+-#else
+- .byte LOADED_HIGH
++_FLAGS = 0
++#ifdef __BIG_KERNEL__
++ _FLAGS = _FLAGS | LOADED_HIGH
+ #endif
++#ifdef CONFIG_BOOTIMG
++ _FLAGS = _FLAGS | RELOADS_GDT
++#endif
++ .byte _FLAGS
+
+ setup_move_size: .word 0x8000 # size to move, when setup is not
+ # loaded at 0x90000. We will move setup
+Index: linux/arch/i386/kernel/Makefile
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/kernel/Makefile,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.1.2.1
+diff -u -r1.2.2.1 -r1.2.2.1.2.1
+--- linux/arch/i386/kernel/Makefile 12 Mar 2003 19:49:05 -0000 1.2.2.1
++++ linux/arch/i386/kernel/Makefile 1 Apr 2003 12:17:40 -0000 1.2.2.1.2.1
+@@ -49,6 +49,7 @@
+ obj-$(CONFIG_X86_LONGRUN) += longrun.o
+ obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
+ obj-$(CONFIG_PROFILING) += profile.o
++obj-$(CONFIG_MCL_COREDUMP) += crash.o
+
+
+ include $(TOPDIR)/Rules.make
+Index: linux/arch/i386/kernel/crash.c
+===================================================================
+RCS file: linux/arch/i386/kernel/crash.c
+diff -N linux/arch/i386/kernel/crash.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ linux/arch/i386/kernel/crash.c 1 Apr 2003 12:17:40 -0000 1.1.6.1
+@@ -0,0 +1,82 @@
++/*
++ * linux/arch/i386/crash.c
++ *
++ * Architecture dependant code for MCL in-memory core dump.
++ */
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/smp.h>
++#include <linux/crash.h>
++#include <linux/reboot.h>
++#include <linux/bootimg.h>
++
++inline void crash_save_regs(void) {
++ static unsigned long regs[8];
++
++ __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs[0]));
++ __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs[1]));
++ __asm__ __volatile__("movl %%edx,%0" : "=m"(regs[2]));
++ __asm__ __volatile__("movl %%esi,%0" : "=m"(regs[3]));
++ __asm__ __volatile__("movl %%edi,%0" : "=m"(regs[4]));
++ __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs[5]));
++ __asm__ __volatile__("movl %%eax,%0" : "=m"(regs[6]));
++ __asm__ __volatile__("movl %%esp,%0" : "=m"(regs[7]));
++
++ panic_regs = regs;
++}
++
++/*
++ * Save the current stack pointer and EIP.
++ */
++void crash_save_current_state(struct task_struct *tp)
++{
++ /*
++ * Here we save ebp instead of esp just in case the compiler
++ * decides to put an extra push in before we execute this
++ * instruction (thus invalidating our frame pointer).
++ */
++ asm volatile("movl %%ebp,%0":"=m" (*(u_long *)&tp->thread.esp));
++ tp->thread.eip = (u_long)crash_save_current_state;
++ panic_ksp[smp_processor_id()] = tp->thread.esp;
++ mb();
++
++ save_core();
++
++ crash_halt_or_reboot(1);
++}
++
++/*
++ * If we are not the panicking thread, we simply halt. Otherwise,
++ * we take care of calling the reboot code.
++ */
++void crash_halt_or_reboot(int boot_cpu)
++{
++#ifdef CONFIG_SMP
++ if (!boot_cpu) {
++ stop_this_cpu(NULL);
++ /* NOTREACHED */
++ }
++#endif
++ machine_restart(NULL);
++}
++
++void crash_cleanup_smp_state(void)
++{
++ /*
++ * Here we duplicate smp_send_stop. Crash_halt_or_reboot() calls
++ * stop_this_cpu. We now know that we are the only one running,
++ * so we finish off the smp_send_stop function.
++ */
++ __cli();
++#ifdef CONFIG_SMP
++ disable_local_APIC();
++#endif
++}
++
++/*
++ * Core dump IPI
++ */
++void smp_crash_funnel_cpu(void)
++{
++ crash_save_current_state(current);
++}
+Index: linux/arch/i386/kernel/nmi.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/kernel/nmi.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.1.2.1
+diff -u -r1.2.2.1 -r1.2.2.1.2.1
+--- linux/arch/i386/kernel/nmi.c 12 Mar 2003 19:49:06 -0000 1.2.2.1
++++ linux/arch/i386/kernel/nmi.c 1 Apr 2003 12:17:40 -0000 1.2.2.1.2.1
+@@ -374,11 +374,18 @@
+ bust_spinlocks(1);
+ printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip);
+ show_registers(regs);
++#ifdef CONFIG_MCL_COREDUMP
++ spin_unlock(&nmi_print_lock);
++ bust_spinlocks(0);
++ panic("die");
++ /* NOTREACHED */
++#else
+ printk("console shuts up ...\n");
+ console_silent();
+ spin_unlock(&nmi_print_lock);
+ bust_spinlocks(0);
+ do_exit(SIGSEGV);
++#endif
+ }
+ } else {
+ last_irq_sums[cpu] = sum;
+Index: linux/arch/i386/kernel/process.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/kernel/process.c,v
+retrieving revision 1.2.2.2
+retrieving revision 1.2.2.2.2.1
+diff -u -r1.2.2.2 -r1.2.2.2.2.1
+--- linux/arch/i386/kernel/process.c 1 Apr 2003 02:11:17 -0000 1.2.2.2
++++ linux/arch/i386/kernel/process.c 1 Apr 2003 12:17:40 -0000 1.2.2.2.2.1
+@@ -50,6 +50,9 @@
+ #ifdef CONFIG_MATH_EMULATION
+ #include <asm/math_emu.h>
+ #endif
++#ifdef CONFIG_BOOTIMG
++#include <linux/bootimg.h>
++#endif
+
+ #include <linux/irq.h>
+
+@@ -377,7 +380,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
++{
+ int cpuid;
+
+ cpuid = GET_APIC_ID(apic_read(APIC_ID));
+@@ -413,6 +430,7 @@
+ if (!netdump_func)
+ smp_send_stop();
+ disable_IO_APIC();
++}
+ #endif
+
+ if(!reboot_thru_bios) {
+Index: linux/arch/i386/kernel/setup.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/kernel/setup.c,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.2
+diff -u -r1.3.2.1 -r1.3.2.1.2.2
+--- linux/arch/i386/kernel/setup.c 12 Mar 2003 19:49:06 -0000 1.3.2.1
++++ linux/arch/i386/kernel/setup.c 1 Apr 2003 17:55:35 -0000 1.3.2.1.2.2
+@@ -116,6 +116,9 @@
+ #include <asm/mpspec.h>
+ #include <asm/mmu_context.h>
+ #include <asm/edd.h>
++#ifdef CONFIG_MCL_COREDUMP
++#include <linux/crash.h>
++#endif
+ /*
+ * Machine setup..
+ */
+@@ -973,6 +976,7 @@
+ static unsigned long __init setup_memory(void)
+ {
+ unsigned long bootmap_size, start_pfn, max_low_pfn;
++ unsigned long bootmap_pages = 0UL, crash_pages = 0UL;
+
+ /*
+ * partially used pages are not usable - thus
+@@ -992,6 +996,21 @@
+ printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+ pages_to_mb(highend_pfn - highstart_pfn));
+ #endif
++
++#ifdef CONFIG_MCL_COREDUMP
++ bootmap_pages = bootmem_bootmap_pages(max_low_pfn);
++ crash_pages = crash_pages_needed();
++
++ printk("start_pfn: %d, bootmap_pages: %d\n", start_pfn, bootmap_pages);
++
++ crash_init((u_long)phys_to_virt(PFN_PHYS(start_pfn)),
++ (u_long)phys_to_virt(PFN_PHYS(LOW_OFFSET + start_pfn)),
++ (u_long)phys_to_virt(PFN_PHYS(LOW_OFFSET + start_pfn +
++ crash_pages)));
++
++ printk("new start_pfn: %08lx\n", PFN_PHYS(start_pfn));
++ printk("crash map starts at %lx\n",(start_pfn+bootmap_pages)*PAGE_SIZE);
++#endif
+ printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+ pages_to_mb(max_low_pfn));
+ /*
+@@ -1007,8 +1026,8 @@
+ * the (very unlikely) case of us accidentally initializing the
+ * bootmem allocator with an invalid RAM area.
+ */
+- reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) +
+- bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
++ reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) + bootmap_size +
++ ((1+crash_pages)*PAGE_SIZE) + PAGE_SIZE-1) - (HIGH_MEMORY));
+
+ /*
+ * reserve physical page 0 - it's a special BIOS page on many boxes,
+@@ -1016,6 +1035,16 @@
+ */
+ reserve_bootmem(0, PAGE_SIZE);
+
++#ifdef CONFIG_BOOTIMG
++ /*
++ * bootimg(8) reads the old parameter block. Note that the copy in
++ * empty_zero_page will vanish when mem_init runs. (Should we
++ * memcpy(phys_to_virt(0x90000), PARAM, PAGE_SIZE);
++ * now ?)
++ */
++ reserve_bootmem(0x90000, PAGE_SIZE);
++#endif
++
+ #ifdef CONFIG_SMP
+ /*
+ * But first pinch a few for the stack/trampoline stuff
+@@ -1032,6 +1061,7 @@
+ find_smp_config();
+ #endif
+ #ifdef CONFIG_BLK_DEV_INITRD
++ printk("caution: initrd may overwrite dump\n"); /* phro */
+ if (LOADER_TYPE && INITRD_START) {
+ if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
+ reserve_bootmem(INITRD_START, INITRD_SIZE);
+@@ -1172,6 +1202,12 @@
+ smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
+ #endif
+ paging_init();
++#ifdef CONFIG_MCL_COREDUMP
++ /*
++ * Reserve crash pages
++ */
++ crash_mark_dump_reserved();
++#endif
+ #ifdef CONFIG_X86_LOCAL_APIC
+ /*
+ * get boot-time SMP configuration:
+Index: linux/arch/i386/kernel/smp.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/kernel/smp.c,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.1
+diff -u -r1.3.2.1 -r1.3.2.1.2.1
+--- linux/arch/i386/kernel/smp.c 12 Mar 2003 19:49:06 -0000 1.3.2.1
++++ linux/arch/i386/kernel/smp.c 1 Apr 2003 12:17:40 -0000 1.3.2.1.2.1
+@@ -23,6 +23,9 @@
+ #include <asm/pgalloc.h>
+ #include <asm/smpboot.h>
+
++#ifdef CONFIG_MCL_COREDUMP
++#include <asm/crash.h>
++#endif
+ /*
+ * Some notes on x86 processor bugs affecting SMP operation:
+ *
+@@ -579,7 +582,7 @@
+ return 0;
+ }
+
+-static void stop_this_cpu (void * dummy)
++void stop_this_cpu (void * dummy)
+ {
+ /*
+ * Remove this CPU:
+Index: linux/arch/i386/kernel/traps.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/kernel/traps.c,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.1
+diff -u -r1.3.2.1 -r1.3.2.1.2.1
+--- linux/arch/i386/kernel/traps.c 12 Mar 2003 19:49:06 -0000 1.3.2.1
++++ linux/arch/i386/kernel/traps.c 1 Apr 2003 12:17:40 -0000 1.3.2.1.2.1
+@@ -52,6 +52,10 @@
+ #include <linux/irq.h>
+ #include <linux/module.h>
+
++#ifdef CONFIG_MCL_COREDUMP
++#include <linux/crash.h>
++#endif
++
+ asmlinkage int system_call(void);
+ asmlinkage void lcall7(void);
+ asmlinkage void lcall27(void);
+@@ -309,7 +313,11 @@
+ netdump_func(regs);
+ bust_spinlocks(0);
+ spin_unlock_irq(&die_lock);
+- do_exit(SIGSEGV);
++#ifdef CONFIG_MCL_COREDUMP
++ if(panic_on_oops)
++ panic("die");
++#endif
++ do_exit(SIGSEGV);/* NOTREACHED */
+ }
+
+ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+Index: linux/drivers/char/misc.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/drivers/char/misc.c,v
+retrieving revision 1.2
+retrieving revision 1.2.4.1
+diff -u -r1.2 -r1.2.4.1
+--- linux/drivers/char/misc.c 25 Sep 2002 17:11:05 -0000 1.2
++++ linux/drivers/char/misc.c 1 Apr 2003 12:17:41 -0000 1.2.4.1
+@@ -78,6 +78,8 @@
+ extern int i8k_init(void);
+ extern int lcd_init(void);
+
++extern int crash_init_chrdev(void);
++
+ static int misc_read_proc(char *buf, char **start, off_t offset,
+ int len, int *eof, void *private)
+ {
+@@ -255,6 +257,9 @@
+ int __init misc_init(void)
+ {
+ create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL);
++#ifdef CONFIG_MCL_COREDUMP
++ crash_init_chrdev();
++#endif
+ #ifdef CONFIG_MVME16x
+ rtc_MK48T08_init();
+ #endif
+Index: linux/drivers/char/sysrq.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/drivers/char/sysrq.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.1.2.2
+diff -u -r1.2.2.1 -r1.2.2.1.2.2
+--- linux/drivers/char/sysrq.c 12 Mar 2003 19:49:47 -0000 1.2.2.1
++++ linux/drivers/char/sysrq.c 1 Apr 2003 17:55:35 -0000 1.2.2.1.2.2
+@@ -97,7 +97,18 @@
+ action_msg: "Resetting",
+ };
+
+-
++#ifdef CONFIG_MCL_COREDUMP
++/* kernel core dump sysrq */
++static void sysrq_handle_coredump(int key, struct pt_regs *pt_regs,
++ struct kbd_struct *kbd, struct tty_struct *ttty) {
++ panic("sysrq");
++}
++static struct sysrq_key_op sysrq_coredump_op = {
++ handler: sysrq_handle_coredump,
++ help_msg: "Crash",
++ action_msg: "Dumping core",
++};
++#endif
+
+ /* SYNC SYSRQ HANDLERS BLOCK */
+
+@@ -334,7 +345,11 @@
+ it is handled specially on the spark
+ and will never arive */
+ /* b */ &sysrq_reboot_op,
++#ifdef CONFIG_MCL_COREDUMP
++/* c */ &sysrq_coredump_op,
++#else
+ /* c */ NULL,
++#endif
+ /* d */ NULL,
+ /* e */ &sysrq_term_op,
+ /* f */ NULL,
+Index: linux/include/asm-i386/bootimg.h
+===================================================================
+RCS file: linux/include/asm-i386/bootimg.h
+diff -N linux/include/asm-i386/bootimg.h
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ linux/include/asm-i386/bootimg.h 1 Apr 2003 12:17:41 -0000 1.1.6.1
+@@ -0,0 +1,141 @@
++/* asm-i386/bootimg.h - Boot image, i386-specific code */
++
++/* Written 2000 by Werner Almesberger */
++
++/*
++ * When porting bootimg(2) to a new architcture, you need to adapt the
++ * functions and definitions in this file.
++ */
++
++
++#ifndef _ASM_I386_BOOTIMG_H
++#define _ASM_I386_BOOTIMG_H
++
++#include <linux/config.h>
++#include <asm/system.h>
++
++#ifdef CONFIG_SMP
++#include <linux/smp.h>
++#include <linux/irq.h>
++#endif
++
++
++/*
++ * The memory page with the code currently executing has been copied from
++ * old_page to new_page. Jump there.
++ *
++ * Note: flush_icache_range has already been called on the new page.
++ */
++
++static inline void jump_relocated(unsigned long old_page,unsigned long new_page)
++{
++ int tmp;
++
++ __asm__ __volatile__(
++ "stc\n\t"
++ "call 1f\n"
++ "1:\tjnc 2f\n\t"
++ "popl %0\n\t"
++ "addl %1,%0\n\t"
++ "addl %1,%%esp\n\t"
++ "clc\n\t"
++ "jmp *%0\n"
++ "2:"
++ : "=&r" (tmp) : "r" (new_page-old_page));
++}
++
++
++/*
++ * Stop paging, such that
++ * - page tables can be overwritten
++ * - all physical memory can be accessed
++ * - all physical memory is identity-mapped
++ *
++ * (Other rules are possible, but need to be encoded in bootimg(8).)
++ */
++
++static inline void stop_paging(void)
++{
++ unsigned long msw;
++
++ __asm__ __volatile__(
++ "movl %%cr0,%0\n\t"
++ "andl $0x7fffffff,%0\n\t"
++ "movl %0,%%cr0\n\t"
++ "jmp 1f\n\t" /* i486 and such */
++ "1:"
++
++/* Clear the PAE bit in register %cr4 if we were in PAE mode. The initial
++ * page table set up by the new kernel's bootstrap code is non-PAE regardless
++ * of whether the new kernel is a PAE kernel. By clearing the PAE bit here,
++ * we make sure the bootstrap code doesn't accidentally enable PAE mode when
++ * it turns on address translation.
++ */
++#ifdef CONFIG_X86_PAE
++ "movl %%cr4,%0\n\t"
++ "andl $0xffffffdf,%0\n\t"
++ "movl %0,%%cr4\n\t"
++#endif
++
++ : "=&r" (msw) : : "memory");
++}
++
++
++/*
++ * Stop any remaining concurrency in the system. If become_only_thread fails
++ * but the system is still usable, become_only_thread should return an error
++ * code. If no recovery is possible, it may as well panic.
++ */
++
++static inline int become_only_thread(void)
++{
++#ifdef CONFIG_SMP
++ smp_send_stop();
++ disable_IO_APIC();
++#endif
++ cli();
++ return 0;
++}
++
++
++/*
++ * A conservative estimate of the number of bytes relocate_and_jump allocated
++ * on the stack. This is only used for sanity checking before running code,
++ * because we can't recover from failure in relocate_and_jump.
++ */
++
++#define RESERVE_MIN_RELOC_STACK 256
++
++
++/*
++ * Change the stack pointer such that stack is at the end of the specified
++ * page. No data on the old stack will be accessed anymore, so no copying is
++ * required.
++ */
++
++static inline void stack_on_page(void *page)
++{
++ __asm__ __volatile__(
++ "push %%ds\n\t"
++ "pop %%ss\n\t"
++ "movl %0,%%esp\n\t"
++ "addl $0x1000,%%esp\n\t"
++ : : "r" (page));
++}
++
++/*
++ * Set up things such that the kernel will be comfortable (e.g. some
++ * architectures expect the boot loader to set registers in certain ways),
++ * and then jump to the kernel's entry address.
++ */
++
++static inline void jump_to_kernel(void (*kernel_entry)(void))
++{
++ __asm__ __volatile__(
++ "mov $0x90000,%%esi\n\t"
++ : : );
++
++ kernel_entry();
++}
++
++#endif
+Index: linux/include/asm-i386/crash.h
+===================================================================
+RCS file: linux/include/asm-i386/crash.h
+diff -N linux/include/asm-i386/crash.h
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ linux/include/asm-i386/crash.h 1 Apr 2003 12:17:41 -0000 1.1.6.1
+@@ -0,0 +1,15 @@
++#ifndef __ASM_CRASH_H
++#define __ASM_CRASH_H
++
++#define UPPER_MEM_BACKUP 0
++#define LOWER_MEM_FORWARD 0
++#define LOW_OFFSET 100
++
++/*
++ * These two functions are inlined on alpha. That's why they appear
++ * in the arch dependent include file.
++ */
++void crash_save_current_state(struct task_struct *);
++void crash_halt_or_reboot(int);
++
++#endif
+Index: linux/include/linux/bootimg.h
+===================================================================
+RCS file: linux/include/linux/bootimg.h
+diff -N linux/include/linux/bootimg.h
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ linux/include/linux/bootimg.h 1 Apr 2003 12:17:41 -0000 1.1.6.1
+@@ -0,0 +1,84 @@
++/* linux/bootimg.h - Boot image, general definitions */
++
++/* Written 2000 by Werner Almesberger */
++
++
++#ifndef _LINUX_BOOTIMG_H
++#define _LINUX_BOOTIMG_H
++
++
++/*
++ * Constraints on image_map:
++ * - each image_map[n] is the virtual address of a page-sized memory region
++ * readable by the user
++ * - currently, image_map[n] is not required to be page-aligned, but this may
++ * change in the future if we want to map pages directly to lower memory
++ * pressure (NB: mapping works for ELF and plain binary images, but usually
++ * not for (b)zImages, because the prepended boot and setup sectors
++ * mis-align them)
++ *
++ * Constraints on load_map:
++ * - each load_map[] is the physical address of a page in RAM
++ */
++
++struct boot_image {
++ void **image_map; /* pointers to image pages in user memory */
++ int pages; /* length in pages */
++ unsigned long *load_map;/* list of destination pages (physical addr) */
++ unsigned long start; /* jump to this physical address */
++ int flags; /* for future use, must be zero for now */
++};
++
++
++#ifdef __KERNEL__
++
++#define __bootimg __attribute__ ((__section__ (".bootimg")))
++
++
++struct bootimg_dsc {
++ unsigned long self; /* code page ALL ADDRESSES */
++ unsigned long scratch; /* scratch page ARE PHYSICAL !*/
++ unsigned long **page_dir; /* src & dst page tables */
++ void (*jump_to)(void); /* start address */
++ int pages; /* number of pages */
++ unsigned long csum; /* Kernel Image checksum */
++};
++
++/*
++ * page_dir contains pointers to pages containing pointers to pages. We call
++ * page_dir a "directory" and the page page_dir[n] points to a "table". The
++ * first PAGES_PER_TABLE/2 entries of page_dir are for source pages, and other
++ * half are for destination pages.
++ */
++
++/*
++ * Note that the definitions used here do not necessarily correspond to the
++ * architecture-specific PTRS_PER_PTE, __pte_offset, etc.
++ */
++
++#define PAGES_PER_TABLE (PAGE_SIZE/sizeof(void *))
++#define FROM_TABLE(i) ((i)/PAGES_PER_TABLE)
++#define TO_TABLE(i) ((i)/PAGES_PER_TABLE+PAGES_PER_TABLE/2)
++#define PAGE_NR(i) ((i) % PAGES_PER_TABLE)
++
++
++extern char __bootimg_start,__bootimg_end; /* linker segment boundaries */
++extern unsigned long *unity_page; /* unity-mapped page for i386 */
++
++/*
++ * relocate_and_jump runs in its own page with its own stack. This makes it
++ * difficult to pass parameters. The solution chosen here is to use the global
++ * variable bootimg_dsc, which is copied into an "auto" variable by
++ * relocate_and_jump before any copying or relocation takes place.
++ */
++
++extern struct bootimg_dsc bootimg_dsc;
++
++typedef void (*relocate_and_jump_t)(void);
++
++void relocate_and_jump(void);
++int boot_image(void);
++
++#endif /* __KERNEL__ */
++
++#endif
+Index: linux/include/linux/crash.h
+===================================================================
+RCS file: linux/include/linux/crash.h
+diff -N linux/include/linux/crash.h
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ linux/include/linux/crash.h 1 Apr 2003 12:17:41 -0000 1.1.6.1
+@@ -0,0 +1,119 @@
++#ifndef __LINUX_CRASH_H
++#define __LINUX_CRASH_H
++
++/* defines for interfacing with user-space (ioctls, etc) */
++struct ioctl_getdump {
++ unsigned long kva;
++ unsigned long buf;
++};
++
++#define CRASH_IOC_MAGIC 'C'
++
++#define CRASH_IOCFREEDUMP _IO(CRASH_IOC_MAGIC, 0)
++#define CRASH_IOCGETDUMP _IOWR(CRASH_IOC_MAGIC, 1, struct ioctl_getdump)
++#define CRASH_IOCBOOTIMG _IOWR(CRASH_IOC_MAGIC, 2, struct boot_image)
++#define CRASH_IOCVERSION _IO(CRASH_IOC_MAGIC, 3)
++
++/* kernel-only part of crash.h */
++#ifdef __KERNEL__
++#include <asm/crash.h>
++
++#define CRASH_K_MINOR (1)
++#define CRASH_K_MAJOR (0)
++
++/*
++ * Crash prototypes.
++ */
++void save_core(void);
++void crash_mark_dump_reserved(void);
++void crash_init(u_long bootmap_va, u_long crash_va, u_long end_alloc_va);
++u_long crash_pages_needed(void);
++void smp_crash_funnel_cpu(void);
++void crash_cleanup_smp_state(void);
++
++/*
++ * Arch dependant crash.c funcs
++ */
++void crash_save_current_state(struct task_struct *);
++void crash_halt_or_reboot(int);
++inline void crash_save_regs(void);
++
++/*
++ * Crash globals
++ */
++extern u_long crash_dump_header;
++extern volatile u_long panic_ksp[];
++extern volatile int crash_release;
++extern int panic_on_oops;
++extern char *panicmsg;
++extern int panic_processor;
++extern int crash_perform_sync;
++extern unsigned long *panic_regs;
++
++/*
++ * symbols not exported by linux header files
++ */
++extern void stop_this_cpu(void *);
++
++/* struct crash_map_hdr located at byte offset 0 */
++/* on-disk formats */
++
++#define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
++#define round_page(x) trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
++
++#define CRASH_MAGIC 0x9a8bccdd
++#define CRASH_SOURCE_PAGES 128
++#define CRASH_SUB_MAP_BYTES ((u_long)round_page((CRASH_SOURCE_PAGES+1)*sizeof(u_long)))
++#define CRASH_SUB_MAP_PAGES (CRASH_SUB_MAP_BYTES / PAGE_SIZE)
++#define CRASH_UNCOMPR_BUF_PAGES (CRASH_SOURCE_PAGES + CRASH_SUB_MAP_PAGES)
++#define CRASH_COMPR_BUF_PAGES (CRASH_UNCOMPR_BUF_PAGES + (CRASH_UNCOMPR_BUF_PAGES/4))
++#define CRASH_COMPESS_PRIME_PAGES (2*CRASH_COMPR_BUF_PAGES)
++#define CRASH_ZALLOC_PAGES 16*5*2 /* 2 to handle crash in crash */
++#define CRASH_LOW_WATER_PAGES 100
++
++#define CRASH_CPU_TIMEOUT 5000 /* 5 sec wait for other cpus to stop */
++
++#define CRASH_MARK_RESERVED(addr) (set_bit(PG_reserved,&mem_map[MAP_NR(addr)].flags))
++#define CRASH_CLEAR_RESERVED(addr) (clear_bit(PG_reserved,&mem_map[MAP_NR(addr)].flags))
++#define CRASH_MARK_BOOT_RESERVED(addr) reserve_bootmem(virt_to_phys((void *)addr), PAGE_SIZE);
++
++typedef int boolean_t;
++
++#define TRUE 1
++#define FALSE 0
++
++/* mem structure */
++struct mem_crash_map_hdr {
++ long magic[4]; /* identify crash dump */
++ u_long map; /* location of map */
++ u_long map_pages;
++ u_long data_pages;
++ u_long compr_units;
++ u_long boot_reserved_start;
++ u_long boot_reserved_end;
++};
++struct mem_crash_map_entry {
++ u_long src_va; /* source start of larger non-contig
++ * block. a src_va of -1 means that
++ * the dest_page_va is the location of
++ * the next map page */
++ u_long dest_page_va; /* dest of this sub block */
++ u_long check_sum; /* check_sum for dest data */
++};
++
++/* file structure */
++struct crash_map_hdr {
++ long magic[4]; /* identify crash dump */
++ int blk_size; /* block size for this device */
++ int map_block; /* location of map */
++ int map_blocks; /* number of blocks for map */
++};
++struct crash_map_entry {
++ u_long start_va; /* virtual address */
++ char *exp_data; /* expanded data in memory */
++ int start_blk; /* device location */
++ int num_blks;
++};
++
++#endif /* __KERNEL__ */
++#endif /* __LINUX_CRASH_H */
+Index: linux/include/linux/mm.h
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/include/linux/mm.h,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.1.2.2
+diff -u -r1.2.2.1 -r1.2.2.1.2.2
+--- linux/include/linux/mm.h 12 Mar 2003 19:51:27 -0000 1.2.2.1
++++ linux/include/linux/mm.h 1 Apr 2003 17:55:35 -0000 1.2.2.1.2.2
+@@ -331,6 +331,11 @@
+ #define PG_lru 18
+ #define PG_active_cache 19
+ #define PG_fs_1 20 /* Filesystem specific */
++#ifdef CONFIG_MCL_COREDUMP
++#define PG_free 21
++#define PG_shm 22
++#define PG_anon 23
++#endif
+
+ /* Make it prettier to test the above... */
+ #define UnlockPage(page) unlock_page(page)
+@@ -452,6 +457,11 @@
+ #define PageSetSlab(page) set_bit(PG_slab, &(page)->flags)
+ #define PageClearSlab(page) clear_bit(PG_slab, &(page)->flags)
+ #define PageReserved(page) test_bit(PG_reserved, &(page)->flags)
++#ifdef CONFIG_MCL_COREDUMP
++#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))
++#endif
+
+ #define PageActiveAnon(page) test_bit(PG_active_anon, &(page)->flags)
+ #define SetPageActiveAnon(page) set_bit(PG_active_anon, &(page)->flags)
+Index: linux/include/linux/reboot.h
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/include/linux/reboot.h,v
+retrieving revision 1.1.1.1
+retrieving revision 1.1.1.1.10.2
+diff -u -r1.1.1.1 -r1.1.1.1.10.2
+--- linux/include/linux/reboot.h 7 May 2002 21:53:47 -0000 1.1.1.1
++++ linux/include/linux/reboot.h 1 Apr 2003 17:55:35 -0000 1.1.1.1.10.2
+@@ -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,9 @@
+ #define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
+ #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC
+ #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4
+-
++#ifdef CONFIG_MCL_COREDUMP
++#define LINUX_REBOOT_CMD_COREDUMP 0x9A8BCCDD
++#endif
+
+ #ifdef __KERNEL__
+
+Index: linux/include/linux/sysctl.h
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/include/linux/sysctl.h,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.1
+diff -u -r1.3.2.1 -r1.3.2.1.2.1
+--- linux/include/linux/sysctl.h 12 Mar 2003 19:51:30 -0000 1.3.2.1
++++ linux/include/linux/sysctl.h 1 Apr 2003 12:17:41 -0000 1.3.2.1.2.1
+@@ -126,6 +126,7 @@
+ KERN_CADPID=54, /* int: PID of the process to notify on CAD */
+ KERN_CORE_PATTERN=56, /* string: pattern for core-files */
+ KERN_PID_MAX=55, /* int: max PID value of processes */
++ KERN_PANIC_ON_OOPS /* int: panic on oops enabled */
+ };
+
+
+Index: linux/init/main.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/init/main.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.1.2.1
+diff -u -r1.2.2.1 -r1.2.2.1.2.1
+--- linux/init/main.c 12 Mar 2003 19:51:35 -0000 1.2.2.1
++++ linux/init/main.c 1 Apr 2003 12:17:41 -0000 1.2.2.1.2.1
+@@ -70,6 +70,10 @@
+ #include <asm/smp.h>
+ #endif
+
++#ifdef CONFIG_BOOTIMG
++#include <linux/bootimg.h>
++#endif
++
+ /*
+ * Versions of gcc older than that listed below may actually compile
+ * and link okay, but the end product can have subtle run time bugs.
+@@ -352,10 +356,14 @@
+ {
+ char * command_line;
+ extern char saved_command_line[];
++#if defined(CONFIG_BOOTIMG) && defined(CONFIG_X86_LOCAL_APIC)
++ unsigned long value;
++#endif
+ /*
+ * Interrupts are still disabled. Do necessary setups, then
+ * enable them
+ */
++ printk("start_kernel\n");
+ lock_kernel();
+ printk(linux_banner);
+ setup_arch(&command_line);
+@@ -373,12 +381,26 @@
+ * this. But we do want output early, in case something goes wrong.
+ */
+ console_init();
++
++#ifdef CONFIG_BOOTIMG
++ unity_page = alloc_bootmem_pages(PAGE_SIZE);
++ printk("unity_page addr: %p\n",unity_page);
++#endif
+ #ifdef CONFIG_MODULES
+ init_modules();
+ #endif
+ profile_init();
+ kmem_cache_init();
+ sti();
++#if defined(CONFIG_BOOTIMG) && defined(CONFIG_X86_LOCAL_APIC)
++ /* If we don't make sure the APIC is enabled, AND the LVT0
++ * register is programmed properly, we won't get timer interrupts
++ */
++ setup_local_APIC();
++
++ value = apic_read(APIC_LVT0);
++ apic_write_around(APIC_LVT0, value & ~APIC_LVT_MASKED);
++#endif
+ calibrate_delay();
+ #ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start && !initrd_below_start_ok &&
+Index: linux/kernel/Makefile
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/kernel/Makefile,v
+retrieving revision 1.1.1.1.4.1
+retrieving revision 1.1.1.1.4.1.2.1
+diff -u -r1.1.1.1.4.1 -r1.1.1.1.4.1.2.1
+--- linux/kernel/Makefile 12 Mar 2003 19:51:36 -0000 1.1.1.1.4.1
++++ linux/kernel/Makefile 1 Apr 2003 12:17:41 -0000 1.1.1.1.4.1.2.1
+@@ -22,7 +22,8 @@
+ obj-$(CONFIG_PM) += pm.o
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+ obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+-
++obj-$(CONFIG_BOOTIMG) += bootimg.o bootimg_pic.o
++obj-$(CONFIG_MCL_COREDUMP) += crash.o
+
+ ifneq ($(CONFIG_IA64),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+Index: linux/kernel/bootimg.c
+===================================================================
+RCS file: linux/kernel/bootimg.c
+diff -N linux/kernel/bootimg.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ linux/kernel/bootimg.c 1 Apr 2003 12:17:41 -0000 1.1.6.1
+@@ -0,0 +1,301 @@
++/* bootimg.c - Boot another (kernel) image */
++
++/* Written 2000 by Werner Almesberger */
++
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/capability.h>
++#include <linux/bootimg.h>
++#include <asm/bootimg.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <linux/delay.h>
++
++#if 0
++#define DPRINTK_CONT(format,args...) printk(format,##args)
++#else
++#define DPRINTK_CONT(format,args...)
++#endif
++#define DPRINTK(format,args...) DPRINTK_CONT(KERN_DEBUG format,##args)
++
++unsigned long **bootimg_page_dir;
++
++struct bootimg_dsc bootimg_dsc; /* communication with PIC */
++unsigned long *unity_page; /* unity-mapped page for i386 */
++
++static unsigned long bootimg_checksum(unsigned long **page_dir, int num_pages)
++{
++ unsigned long checksum, *page;
++ int i, j;
++
++ checksum = 0;
++
++ for (i = 0; i < num_pages; i++) {
++ page = __va((unsigned long *)
++ page_dir[FROM_TABLE(i)][PAGE_NR(i)]);
++
++ for (j = 0; j < PAGES_PER_TABLE; j++)
++ checksum ^= page[j];
++
++ checksum ^= page_dir[TO_TABLE(i)][PAGE_NR(i)];
++ }
++
++ return checksum;
++}
++
++#ifdef CONFIG_X86_PAE
++
++static unsigned long get_identity_mapped_page(void)
++{
++ pgd_t *pgd;
++ pmd_t *pmd;
++ unsigned long phys_addr, page_base;
++
++ /* Set up a 2 Mb identity-mapped page. */
++
++ phys_addr = virt_to_phys(unity_page);
++ pgd = pgd_offset(current->active_mm, phys_addr);
++ pmd = pmd_offset(pgd, phys_addr);
++
++ /* We hardcode this rather than using PMD_MASK just in case the PAE
++ * mode setup ever changes so that 2 Mb pages are no longer used.
++ */
++ page_base = phys_addr & ~((1 << 21) - 1);
++
++ set_pmd(pmd, __pmd(page_base | _PAGE_PSE | _KERNPG_TABLE));
++ __flush_tlb_one(phys_addr);
++
++ return (unsigned long) unity_page;
++}
++
++#else
++
++static unsigned long get_identity_mapped_page(void)
++{
++ set_pgd(pgd_offset(current->active_mm,virt_to_phys(unity_page)),
++ __pgd((_KERNPG_TABLE + _PAGE_PSE + (virt_to_phys(unity_page)&PGDIR_MASK))));
++ __flush_tlb_one(virt_to_phys(unity_page));
++ return (unsigned long)unity_page;
++}
++
++#endif
++
++#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(page_dir,0,PAGE_SIZE);
++ for (i = 0; i < image->pages; i += PAGES_PER_TABLE) {
++ unsigned long **table;
++ int bytes_left;
++
++ table = 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 = 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++;
++
++ 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 *) page_dir[FROM_TABLE(i)][PAGE_NR(i)],
++ &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 (page_dir[i])
++ for (j = 0; j < PAGES_PER_TABLE; j++)
++ if (page_dir[i][j]) {
++ free_page((unsigned long)
++ phys_to_virt(page_dir[i][j]));
++ count++;
++ }
++ for (i = 0; i < PAGES_PER_TABLE; i++)
++ if (page_dir[i]) {
++ free_page((unsigned long) *page_dir[i]);
++ count++;
++ }
++ DPRINTK("free_page_dir: %d pages freed\n", count);
++}
++
++
++static void convert_table_refs_to_phys(unsigned long **page_dir)
++{
++ int i;
++
++ DPRINTK("PAGES_PER_TABLE: %d\n",PAGES_PER_TABLE);
++ for (i = 0; i < PAGES_PER_TABLE; i++)
++ if (page_dir[i]) {
++ DPRINTK("table %i: mapped %p -> ",i,page_dir[i]);
++ page_dir[i] = (unsigned long *)
++ virt_to_phys(page_dir[i]);
++ DPRINTK_CONT("%p\n",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 = bootimg_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 (bootimg_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);
++ flush_icache_range(&__bootimg_start, &__bootimg_end-&__bootimg_start);
++
++ bootimg_dsc.self = (unsigned long) code;
++ printk(KERN_INFO "Running boot code at 0x%p\n",code);
++
++ /*
++ * The point of no return. Not even printk may work after a successful
++ * return from become_only_thread.
++ */
++
++ if (!panicmsg) {
++ error = become_only_thread();
++ if (error) goto out3;
++ } else {
++#ifdef CONFIG_SMP
++ disable_IO_APIC();
++#endif
++ __cli();
++ }
++
++ convert_table_refs_to_phys((unsigned long **)__va(bootimg_dsc.page_dir));
++ stack_on_page(code);
++
++ code();
++
++ panic("PIC code exec failed");
++out3:
++ printk("boot_image() failed!\n");
++ for(;;);
++}
++
++/* changed from asmlinkage because we're called via an IOCTL on /dev/crash now */
++int sys_bootimg(struct boot_image *user_dsc)
++{
++ struct boot_image dsc;
++
++ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_MODULE)) return -EPERM;
++ if (&__bootimg_end-&__bootimg_start > PAGE_SIZE-RESERVE_MIN_RELOC_STACK)
++ {
++ printk(KERN_ERR "boot_image: PIC too large (%d bytes)\n",
++ &__bootimg_end-&__bootimg_start);
++ return -EIO;
++ }
++ if ((void *) relocate_and_jump != (void *) &__bootimg_start) {
++ printk(KERN_ERR "boot_image: relocate_and_jump is mis-placed"
++ "(0x%p != 0x%p)\n",relocate_and_jump,&__bootimg_start);
++ return -EIO;
++ }
++
++ if (copy_from_user(&dsc,user_dsc,sizeof(dsc))) return -EFAULT;
++ if (dsc.pages >= PAGES_PER_TABLE*PAGES_PER_TABLE/2) return -EFBIG;
++ if (dsc.flags) return -EINVAL; /* for future use */
++ return fill_bootimg_dsc(&dsc);
++}
+Index: linux/kernel/bootimg_pic.c
+===================================================================
+RCS file: linux/kernel/bootimg_pic.c
+diff -N linux/kernel/bootimg_pic.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ linux/kernel/bootimg_pic.c 1 Apr 2003 12:17:41 -0000 1.1.6.1
+@@ -0,0 +1,91 @@
++/* bootimg_pic.c - Boot image, position-independent code */
++
++/* Written 2000 by Werner Almesberger */
++
++/*
++ * Strongly inspired by FiPaBoL designed mainly by Otfried Cheong and Roger
++ * Gammans, and written by the latter.
++ */
++
++/*
++ * This code is position-independent and must fit in a single page !
++ * Furthermore, everything (text+data+stack) has to go into the
++ * .bootimg segment.
++ */
++
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/bootimg.h>
++#include <asm/bootimg.h>
++
++#include <asm/io.h>
++
++#define copy_and_swap(from,to) \
++ ( { my_copy_page(from,to); \
++ tmp = from; \
++ from = to; \
++ to = tmp; } )
++
++
++static inline void my_copy_page(unsigned long from,unsigned long to)
++{
++ unsigned long end = from+PAGE_SIZE;
++
++ do *((unsigned long *) to)++ = *((unsigned long *) from)++;
++ while (from != end);
++}
++
++
++void __bootimg relocate_and_jump(void)
++{
++ struct bootimg_dsc dsc = bootimg_dsc;
++ int i;
++
++ stop_paging();
++ for (i = 0; i < dsc.pages; i++) {
++ unsigned long from,to,tmp;
++
++ from = dsc.page_dir[FROM_TABLE(i)][PAGE_NR(i)];
++ to = dsc.page_dir[TO_TABLE(i)][PAGE_NR(i)];
++ if (from == to) continue;
++ if (to == dsc.self) {
++ copy_and_swap(dsc.self,dsc.scratch);
++ /* WARNING: flush_icache_range MUST BE INLINED !!! */
++ flush_icache_range(dsc.self,dsc.self+PAGE_SIZE-1);
++ jump_relocated(dsc.scratch,dsc.self);
++ }
++ else if (to == (unsigned long) dsc.page_dir)
++ copy_and_swap((unsigned long) dsc.page_dir,dsc.scratch);
++ else {
++ /*
++ * O((n^2-n)/2), sigh ...
++ */
++ unsigned long **table;
++ int j;
++
++ for (j = i+1; j < dsc.pages; j++) {
++ table = dsc.page_dir+FROM_TABLE(j);
++ if (((unsigned long) *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 = dsc.page_dir+TO_TABLE(j);
++ if (((unsigned long) *table) == to) {
++ copy_and_swap(*table,dsc.scratch);
++ break;
++ }
++ }
++ }
++ my_copy_page(from,to);
++ dsc.scratch = from;
++ }
++ jump_to_kernel(dsc.jump_to);
++}
+Index: linux/kernel/crash.c
+===================================================================
+RCS file: linux/kernel/crash.c
+diff -N linux/kernel/crash.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ linux/kernel/crash.c 1 Apr 2003 12:17:41 -0000 1.1.6.1
+@@ -0,0 +1,886 @@
++#include <linux/locks.h>
++#include <linux/slab.h>
++#include <linux/crash.h>
++#include <linux/vmalloc.h>
++#include <linux/mm.h>
++#include <linux/fs.h>
++#include <linux/ext2_fs.h>
++#include <asm/param.h>
++#include <asm/uaccess.h>
++#include <linux/zlib.h>
++#include <linux/reboot.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include <linux/miscdevice.h>
++#include <linux/bootmem.h>
++
++#ifdef CONFIG_BOOTIMG
++#include <linux/bootimg.h>
++#endif
++
++static void crash_print_data_around(u_long p);
++static void crash_free_page(u_long addr);
++static int crash_chksum_page(u_long pg_addr, u_long * sum_addr);
++static void *czalloc(void *arg, unsigned int items, unsigned int size);
++static void czfree(void *arg, void *ptr);
++static u_long crash_alloc_dest_page(void);
++static void crash_free_dest_page(u_long dest);
++static void init_dest_page_alloc(void);
++static int crash_audit_maps(void);
++static u_long crash_get_source_page(void);
++static u_long crash_update_map(u_long map, u_long src_base, u_long dest, u_long * pages);
++static int crash_reset_stream(z_stream * stream);
++static boolean_t crash_is_kseg(u_long addr);
++static u_long *crash_link(u_long p);
++static int crash_chksum(u_long limit, u_long * sum_addr);
++static int crash_audit_map_page(u_long map);
++static void crash_wait_cpus(void);
++static int crash_is_dir_page(struct page *page);
++
++/* for the /dev/crash interface */
++int crash_init_chrdev(void);
++static int crashdev_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
++
++#define CRASH_DEBUG 1
++
++#ifdef CONFIG_BOOTIMG
++extern int sys_bootimg(struct boot_image *);
++#endif
++
++static u_long crash_compr_buf;
++static u_long crash_uncompr_buf;
++static u_long crash_dump_header = 0;
++static u_long crash_dest_free_list = 0;
++static u_long crash_debug = 0;
++
++static u_long crash_cur_pfn;
++
++static u_long src_pages_skipped = 0;
++static u_long src_pages_saved = 0;
++static u_long dest_pages_free = 0;
++
++/* this information is saved from within panic() */
++char *panicmsg = (char *)0;
++int panic_processor = 0;
++int crash_perform_sync = 0;
++
++u_int console_crash = 0; /* should be moved to alpha branch */
++
++// typedef struct task_struct *task_t;
++
++/*
++ * Threads active at time of panic:
++ */
++volatile task_t *panic_threads[NR_CPUS];
++volatile unsigned long panic_ksp[NR_CPUS];
++unsigned long *panic_regs = NULL;
++
++int panic_on_oops; /* for /proc/sys/kernel/panic_on_oops */
++
++extern unsigned long max_low_pfn;
++
++u_long crash_zalloc_start; // , crash_zalloc_end, crash_zalloc_cur;
++
++/*
++ * Crash Kernel API functions below
++ * crash_pages_needed, computes pages needed for header and compression temp
++ * crash_init, partitions out the allocated pages, sets defaults and
++ * initializes the character device.
++ * crash_mark_dump_reserved, marks pages reserved from a previous dump.
++ * save_core, called at panic time to save a dump to memory.
++ */
++u_long crash_pages_needed(void)
++{
++ /* one for the header */
++ return (1 + CRASH_ZALLOC_PAGES + CRASH_UNCOMPR_BUF_PAGES + CRASH_COMPR_BUF_PAGES);
++}
++
++void crash_init(u_long bootmap_va, u_long crash_va, u_long end_alloc_va)
++{
++ struct mem_crash_map_hdr *header;
++ int i;
++
++ /* the default behavior is not NOT panic on a kernel OOPS */
++ panic_on_oops = 0;
++
++ printk("crash_init (crash_va: %08lx)\n", crash_va);
++ for (i = 0; i < NR_CPUS; i++)
++ panic_threads[i] = 0;
++ crash_dump_header = crash_va;
++ crash_va += PAGE_SIZE;
++ crash_zalloc_start = crash_va;
++ crash_va += CRASH_ZALLOC_PAGES * PAGE_SIZE;
++ crash_uncompr_buf = crash_va;
++ crash_va += CRASH_UNCOMPR_BUF_PAGES * PAGE_SIZE;
++ crash_compr_buf = crash_va;
++ crash_va += CRASH_COMPR_BUF_PAGES * PAGE_SIZE;
++#if 0
++ if (crash_va != end_alloc_va)
++ panic("crash_init inconsistency-1\n");
++#endif
++
++ header = (struct mem_crash_map_hdr *)crash_dump_header;
++#ifdef CRASH_DEBUG
++ printk("crash_dump_header %p {\n", header);
++ printk(" magic[0] = %lx\n", header->magic[0]);
++ printk(" map = %lx\n", header->map);
++ printk(" map_pages = %lx\n", header->map_pages);
++ printk(" data_pages = %lx\n", header->data_pages);
++ printk(" compr_units = %lx\n", header->compr_units);
++ printk(" boot_reserved_start = %lx\n", header->boot_reserved_start);
++ printk(" boot_reserved_end = %lx\n", header->boot_reserved_end);
++#endif
++
++ if (header->magic[0] == CRASH_MAGIC) {
++ printk("crash found\n");
++ if ((header->boot_reserved_start != bootmap_va) ||
++ (header->boot_reserved_end != end_alloc_va)) {
++ /* crash audit will catch the corruption */
++ printk("crash_init inconsistency, dump may be corrupted\n");
++ }
++ } else {
++printk("memset...");
++ memset(header, 0, sizeof(*header));
++printk("done\n");
++ }
++
++ header->boot_reserved_start = bootmap_va;
++ header->boot_reserved_end = end_alloc_va;
++
++}
++
++void crash_mark_dump_reserved(void)
++{
++ struct mem_crash_map_hdr *header;
++ struct mem_crash_map_entry *m;
++
++ header = (struct mem_crash_map_hdr *)crash_dump_header;
++ if (header->magic[0] != CRASH_MAGIC)
++ return;
++ m = (struct mem_crash_map_entry *)header->map;
++#ifdef CRASH_DEBUG
++ printk("\n\n\ncrash_mark_dump_reserved\n\n");
++ printk("crash_dump_header %p {\n", header);
++ printk(" magic[0] = %lx\n", header->magic[0]);
++ printk(" map = %lx\n", header->map);
++ printk(" map_pages = %lx\n", header->map_pages);
++ printk(" data_pages = %lx\n", header->data_pages);
++ printk(" compr_units = %lx\n", header->compr_units);
++ printk(" boot_reserved_start = %lx\n", header->boot_reserved_start);
++ printk(" boot_reserved_end = %lx\n", header->boot_reserved_end);
++ printk("mem_crash_map_entry %p {\n", m);
++ printk(" src_va = %lx\n", m->src_va);
++ printk(" dest_page_va = %lx\n", m->dest_page_va);
++ printk(" check_sum = %lx\n", m->check_sum);
++#endif
++
++ if (crash_audit_maps()) {
++ header->magic[0] = 0;
++ return;
++ }
++
++ m = (struct mem_crash_map_entry *)header->map;
++ again:
++ CRASH_MARK_BOOT_RESERVED(m);
++ for (; m->src_va; m++) {
++ if (m->src_va == -1) {
++ m = (struct mem_crash_map_entry *)m->dest_page_va;
++ goto again;
++ }
++ CRASH_MARK_BOOT_RESERVED(m->dest_page_va);
++ }
++ return;
++}
++
++void save_core(void)
++{
++ int i, j, k;
++ z_stream stream;
++ int err;
++ struct task_struct *tp;
++ struct mem_crash_map_hdr *header;
++ u_long *sub_map;
++ u_long map;
++ u_long src, dest, unc, cp, src_base, comp_pages;
++
++ k = 0;
++ dest = 0;
++ __cli();
++ tp = current;
++ mb();
++ if (smp_processor_id() != 0) { /* boot_cpu_id is always 0, i think */
++ panic_threads[smp_processor_id()] = tp;
++ crash_halt_or_reboot(0);
++ } else {
++ if (console_crash)
++ panic_threads[smp_processor_id()] = &init_task_union.task;
++ else
++ panic_threads[smp_processor_id()] = tp;
++
++ crash_wait_cpus();
++ }
++
++ printk("save_core: started on CPU%d\n", smp_processor_id());
++ if (!crash_dump_header) {
++ printk("save_core: not initialized\n");
++ return;
++ }
++
++ header = (struct mem_crash_map_hdr *)crash_dump_header;
++ header->magic[0] = 0;
++ header->map_pages = 0;
++ header->data_pages = 0;
++ header->compr_units = 0;
++ header->map = 0;
++
++ stream.workspace=(void*)crash_zalloc_start;
++ // 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 = zlib_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 = zlib_deflate(&stream, Z_FINISH);
++ if (!(err == Z_STREAM_END)) {
++ zlib_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->workspace=(void*)crash_zalloc_start;
++ // 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 = zlib_deflateReset(stream);
++ if (err != Z_OK) {
++ printk("crash_reset_stream: bad return %d from deflateReset\n", err);
++ return 1;
++ }
++ return 0;
++}
++
++static u_long crash_alloc_dest_page(void)
++{
++ u_long addr;
++
++ addr = crash_dest_free_list;
++ if (addr) {
++ crash_dest_free_list = *(u_long *) addr;
++ dest_pages_free--;
++ } else
++ printk("crash_alloc_dest_page: free list empty\n");
++ return addr;
++}
++
++static void crash_free_dest_page(u_long dest)
++{
++ if (!dest) {
++ printk("crash_free_dest_page: freeing addr 0\n");
++ return;
++ }
++ dest_pages_free++;
++ dest = (u_long) trunc_page(dest);
++ *(u_long *) dest = crash_dest_free_list;
++ crash_dest_free_list = dest;
++}
++
++/*
++ * Stolen from setup.c
++ */
++#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
++
++static void init_dest_page_alloc(void)
++{
++ u_long va;
++ long i;
++ struct page *page;
++ struct mem_crash_map_hdr *header;
++
++ header = (struct mem_crash_map_hdr *)crash_dump_header;
++ for (i = ((1 << 24) >> PAGE_SHIFT) + LOWER_MEM_FORWARD;
++ i < (max_low_pfn - UPPER_MEM_BACKUP); i++) {
++ va = (u_long) phys_to_virt(PFN_PHYS(i));
++ if ((va >= header->boot_reserved_start) && (va < header->boot_reserved_end))
++ continue;
++ page = mem_map + i;
++ if (PageLocked(page) || PageReserved(page))
++ continue;
++ if (PageFree(page) || PageAnon(page) || PageShm(page) || page->buffers)
++ crash_free_dest_page(va);
++ }
++ if (crash_debug)
++ printk("init_dest_page_alloc: dest_pages_free = 0x%lx\n", dest_pages_free);
++}
++
++static int crash_is_dir_page(struct page *page) {
++ struct inode *tmp_inode;
++
++ if(page->mapping && page->mapping->host) {
++ tmp_inode = (struct inode *)page->mapping->host;
++ if((tmp_inode->i_sb->s_magic == EXT2_SUPER_MAGIC) &&
++ (S_ISDIR(tmp_inode->i_mode)))
++ return 1;
++ }
++
++ return 0;
++}
++
++static u_long crash_get_source_page(void)
++{
++ struct page *page;
++ u_long va;
++
++ while (crash_cur_pfn < max_low_pfn) {
++ page = mem_map + crash_cur_pfn;
++ if (!(PageFree(page) || PageAnon(page) || PageShm(page) || page->buffers))
++ break;
++ src_pages_skipped++;
++ crash_cur_pfn++;
++ }
++ if (crash_cur_pfn == max_low_pfn)
++ return 0;
++
++ va = (u_long) phys_to_virt(PFN_PHYS(crash_cur_pfn));
++ src_pages_saved++;
++ crash_cur_pfn++;
++ return va;
++}
++
++static u_long crash_update_map(u_long map, u_long src_base, u_long dest, u_long * pages)
++{
++ struct mem_crash_map_entry *m;
++
++
++ if (!map) {
++ (*pages)++;
++ return crash_alloc_dest_page();
++ }
++ m = (struct mem_crash_map_entry *)map;
++ m->src_va = src_base;
++ m->dest_page_va = dest;
++ if (dest)
++ if (crash_chksum_page(dest, &m->check_sum))
++ return 0;
++
++ map += sizeof(struct mem_crash_map_entry);
++
++ m = (struct mem_crash_map_entry *)map;
++ if (!src_base) { /* end of list */
++ if (crash_chksum((u_long) m, &m->src_va))
++ return 0;
++ } else if ((map + 3 * sizeof(struct mem_crash_map_entry)) > (u_long) round_page(map)) {
++ m->src_va = -1;
++ map = m->dest_page_va = crash_alloc_dest_page();
++ if (crash_debug)
++ printk("\nm = 0x%lx m->src_va = 0x%lx m->dest_page_va = 0x%lx\n",
++ (u_long) trunc_page(m), m->src_va, m->dest_page_va);
++ m++;
++ if (crash_chksum((u_long) m, &m->src_va))
++ return 0;
++ if (crash_debug)
++ printk("m = 0x%lx chksum = m->src_va = 0x%lx\n", (u_long) trunc_page(m),
++ m->src_va);
++ if (crash_audit_map_page((u_long) m))
++ return 0;
++ (*pages)++;
++ }
++ return map;
++}
++
++static int crash_chksum(u_long limit, u_long * sum_addr)
++{
++ u_long sum;
++ u_long *addr;
++
++ if (!crash_is_kseg(limit)) {
++ printk("bad addr = 0x%lx to crash_chksum\n", limit);
++ return 1;
++ }
++ sum = 0;
++ addr = (u_long *) trunc_page(limit);
++ for (; (u_long) addr < limit; addr++)
++ sum += *addr;
++ *sum_addr = sum;
++ return 0;
++}
++
++static int crash_chksum_page(u_long pg_addr, u_long * sum_addr)
++{
++ u_long sum, limit;
++ u_long *addr;
++
++ if (!crash_is_kseg(pg_addr)) {
++ printk("bad addr = 0x%lx to crash_chksum_page\n", pg_addr);
++ return 1;
++ }
++
++ sum = 0;
++ addr = (u_long *) trunc_page(pg_addr);
++ limit = (u_long) addr + PAGE_SIZE;
++ for (; (u_long) addr < limit; addr++)
++ sum += *addr;
++ *sum_addr = sum;
++ return 0;
++}
++
++static int crash_audit_maps(void)
++{
++ u_long m, count;
++ u_long *link_addr;
++ struct mem_crash_map_hdr *header;
++
++ header = (struct mem_crash_map_hdr *)crash_dump_header;
++ if (header->magic[0] != CRASH_MAGIC)
++ return 1;
++
++ link_addr = &header->map;
++ m = header->map;
++
++ count = 0;
++ for (;;) {
++ if (!crash_is_kseg(m)) {
++ printk("crash_audit_maps: bad link 0x%lx at 0x%lx\n", m,
++ (u_long) link_addr);
++ return 1;
++ }
++ if (crash_audit_map_page(m)) {
++ printk("audit failed while on map page %ld\n", count);
++ return 1;
++ }
++ if (!crash_link(m))
++ break;
++ link_addr = crash_link(m);
++ m = *link_addr;
++
++ count++;
++ }
++ return 0;
++}
++
++static int crash_audit_map_page(u_long map)
++{
++ struct mem_crash_map_entry *m;
++ u_long sum;
++
++ if (!map || !crash_is_kseg(map)) {
++ printk("crash_audit_map_page: bad map = 0x%lx\n", map);
++ return 1;
++ }
++ map = (u_long) trunc_page((u_long) map);
++ m = (struct mem_crash_map_entry *)map;
++ for (;;) {
++ if ((m->src_va == -1) || (m->src_va == 0)) {
++ m++;
++ if (crash_chksum((u_long) m, &sum))
++ return 1;
++ if (m->src_va != sum) {
++ printk("crash_audit_map_page: checksum failure1\n");
++ printk("m = 0x%lx, sum = 0x%lx, m->src_va = 0x%lx\n",
++ (u_long) m, (u_long) sum, (u_long) m->src_va);
++ crash_print_data_around((u_long) & m->src_va);
++ return 1;
++ } else {
++ return 0;
++ }
++ } else {
++ if (crash_chksum_page((u_long) m->dest_page_va, &sum)
++ || (m->check_sum != sum)) {
++ printk("crash_audit_map_page: checksum failure2\n");
++ printk
++ ("dest_page_va = 0x%lx, &dest_page_va = 0x%lx, sum = 0x%lx, m->check_sum = 0x%lx\n",
++ (u_long) m->dest_page_va, (u_long) (&m->check_sum),
++ (u_long) sum, (u_long) m->check_sum);
++ crash_print_data_around((u_long) & m->check_sum);
++ return 1;
++ }
++ }
++ m++;
++ }
++}
++
++static void crash_print_data_around(u_long p)
++{
++ u_long *a;
++ int i;
++
++ if (!crash_is_kseg(p)) {
++ printk("crash_print_data_around: p = 0x%lx not kseg\n", p);
++ return;
++ }
++ a = (u_long *) p;
++ a -= 20;
++ for (i = 0; i < 40; i++)
++ printk("%lx\n", *a++);
++}
++
++#ifdef CRASH_DEBUG
++static void crash_print_map_page(u_long map)
++{
++ struct mem_crash_map_entry *m;
++ int j = 0;
++ u_long sum;
++
++ map = (u_long) trunc_page((u_long) map);
++ m = (struct mem_crash_map_entry *)map;
++ for (;;) {
++ printk("%lx %lx %lx ", m->src_va, m->dest_page_va, m->check_sum);
++ if (!(j++ % 4))
++ printk("\n");
++ if ((m->src_va == -1) || (m->src_va == 0)) {
++ m++;
++ printk("%lx %lx ", m->src_va, m->dest_page_va);
++ if (crash_chksum((u_long) m, &sum));
++ else
++ printk("\nchksum = 0x%lx\n", sum);
++ return;
++ }
++ m++;
++ }
++}
++#endif /* CRASH_DEBUG */
++
++static void crash_wait_cpus(void)
++{
++ int i;
++ int msecs = 0;
++
++ for (i = 0; i < smp_num_cpus; i++) {
++ if (i != smp_processor_id()) {
++ while (!panic_threads[i]) {
++ msecs++;
++ mdelay(1);
++ if (msecs > CRASH_CPU_TIMEOUT) {
++ /* if other cpus are still running
++ * we have to halt, otherwise we could
++ * risk using buffer cache pages which
++ * could subsequently get flushed to disk.
++ */
++ printk("Unable to halt other CPUs, halting system.\n");
++ crash_halt_or_reboot(0);
++ }
++ }
++ }
++ }
++
++ crash_cleanup_smp_state();
++}
++
++
++#if 0
++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);
++}
++#endif
++
++static boolean_t crash_is_kseg(u_long addr)
++{
++ u_long phys;
++
++ phys = virt_to_phys((void *)addr);
++ if (phys < PFN_PHYS(max_low_pfn))
++ return TRUE;
++ else
++ return FALSE;
++}
++
++static u_long *crash_link(u_long p)
++{
++ struct mem_crash_map_entry *m;
++
++ p = (u_long) trunc_page(p);
++ m = (struct mem_crash_map_entry *)p;
++ for (; m->src_va; m++)
++ if (m->src_va == -1)
++ return &m->dest_page_va;
++
++ return 0;
++}
++
++/* Call this after data written to disk. */
++static int crash_free_crashmem(void)
++{
++ struct mem_crash_map_hdr *header;
++ struct mem_crash_map_entry *m, *last_m;
++
++ if (crash_debug)
++ printk("crash_free_crashmem: \n");
++
++ header = (struct mem_crash_map_hdr *)crash_dump_header;
++ if (crash_audit_maps()) {
++ header->magic[0] = 0;
++ return 1;
++ }
++ m = (struct mem_crash_map_entry *)header->map;
++ again:
++ for (; m->src_va; m++) {
++ if (m->src_va == -1) {
++ last_m = m;
++ m = (struct mem_crash_map_entry *)m->dest_page_va;
++ crash_free_page((unsigned long)last_m);
++ goto again;
++ }
++ crash_free_page(m->dest_page_va);
++ }
++ if (crash_debug)
++ printk("crash_free_crashmem: 0x%lx freed\n",
++ (header->data_pages + header->map_pages) * PAGE_SIZE);
++ header->magic[0] = 0;
++ return 0;
++}
++
++static void crash_free_page(u_long addr)
++{
++ struct page *page;
++
++ page = virt_to_page(addr);
++ ClearPageReserved(page);
++ set_page_count(page, 1);
++ __free_page(page);
++}
++
++static int get_dump_helper(u_long kva, u_long buf)
++{
++ struct page *page;
++ struct mem_crash_map_hdr *header;
++
++ header = (struct mem_crash_map_hdr *)crash_dump_header;
++ if (header->magic[0] != CRASH_MAGIC)
++ return 1;
++
++ if (!kva) {
++ if (crash_audit_maps()) {
++ printk("get_dump_helper: audit failure\n");
++ header->magic[0] = 0;
++ return 1;
++ }
++ page = virt_to_page((u_long) crash_dump_header);
++ if (!PageReserved(page)) {
++ printk("not reserved: crash_dump_header = 0x%lx\n", crash_dump_header);
++ return 1;
++ }
++ if (copy_to_user((char *)buf, (char *)crash_dump_header,
++ sizeof(struct mem_crash_map_hdr))) {
++ printk("get_dump_helper: copy_to_user failed1\n");
++ return 1;
++ }
++ } else {
++ page = virt_to_page(kva);
++ if (!PageReserved(page)) {
++ printk("not reserved: kva = 0x%lx\n", kva);
++ return 1;
++ }
++ if (copy_to_user((char *)buf, (char *)trunc_page(kva), PAGE_SIZE)) {
++ printk("get_dump_helper: copy_to_user failed2\n");
++ return 1;
++ }
++ }
++ return 0;
++}
++
++static void free_dump_helper(void)
++{
++ struct mem_crash_map_hdr *header;
++
++ header = (struct mem_crash_map_hdr *)crash_dump_header;
++ if (header->magic[0] != CRASH_MAGIC)
++ return;
++ if (crash_debug)
++ printk("free_dump_helper\n");
++ crash_free_crashmem();
++}
++
++static int crashdev_open(struct inode *inode, struct file *file)
++{
++ /* always return success -- nothing to do here */
++ return 0;
++}
++
++/* character device implementation */
++static struct file_operations crashdev_fops = {
++ ioctl:crashdev_ioctl,
++ open:crashdev_open,
++};
++
++static struct miscdevice crash_miscdev = {
++ 190, "crash", &crashdev_fops
++};
++
++int crash_init_chrdev(void)
++{
++ int result;
++
++ result = misc_register(&crash_miscdev);
++
++ if (result < 0)
++ printk(KERN_WARNING "crash: can't register crash device (c 10 190)\n");
++
++ return result;
++}
++
++/* call the original syscalls, just to get things going */
++static int crashdev_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int retval = 0;
++
++ switch (cmd) {
++ case CRASH_IOCFREEDUMP:
++ free_dump_helper();
++ break;
++
++ case CRASH_IOCGETDUMP:
++ if (crash_debug) {
++ printk("crashdev_ioctl: get dump\n");
++ printk("vals: %08lx %08lx\n",
++ ((struct ioctl_getdump *)arg)->kva,
++ ((struct ioctl_getdump *)arg)->buf);
++ }
++
++ retval = get_dump_helper((u_long) ((struct ioctl_getdump *)arg)->kva,
++ (u_long) ((struct ioctl_getdump *)arg)->buf);
++ break;
++
++#ifdef CONFIG_BOOTIMG
++ case CRASH_IOCBOOTIMG:
++ if (crash_debug)
++ printk("crashdev_ioctl: bootimg\n");
++
++ retval = sys_bootimg((struct boot_image *)arg);
++ break;
++#endif
++
++ case CRASH_IOCVERSION:
++ if (crash_debug)
++ printk("crashdev_ioctl: version\n");
++ retval = CRASH_K_MINOR | (CRASH_K_MAJOR << 16);
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return retval;
++}
+Index: linux/kernel/module.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/kernel/module.c,v
+retrieving revision 1.1.1.1.4.1
+retrieving revision 1.1.1.1.4.1.2.1
+diff -u -r1.1.1.1.4.1 -r1.1.1.1.4.1.2.1
+--- linux/kernel/module.c 12 Mar 2003 19:51:36 -0000 1.1.1.1.4.1
++++ linux/kernel/module.c 1 Apr 2003 12:17:41 -0000 1.1.1.1.4.1.2.1
+@@ -311,7 +311,14 @@
+ error = -EEXIST;
+ goto err1;
+ }
++#if defined(CONFIG_MCL_COREDUMP)
++ /* Call vmalloc_32 instead of module_map (vmalloc for i386)
++ * to avoid being mapped in highmem where mcore can't see us.
++ */
++ if ((mod = (struct module *)vmalloc_32(size)) == NULL) {
++#else
+ if ((mod = (struct module *)module_map(size)) == NULL) {
++#endif
+ error = -ENOMEM;
+ goto err1;
+ }
+Index: linux/kernel/panic.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/kernel/panic.c,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.1
+diff -u -r1.3.2.1 -r1.3.2.1.2.1
+--- linux/kernel/panic.c 12 Mar 2003 19:51:36 -0000 1.3.2.1
++++ linux/kernel/panic.c 1 Apr 2003 12:17:41 -0000 1.3.2.1.2.1
+@@ -19,6 +19,10 @@
+ #include <linux/vt_kern.h>
+ #include <linux/pc_keyb.h>
+
++#ifdef CONFIG_MCL_COREDUMP
++#include <linux/crash.h>
++#endif
++
+ asmlinkage void sys_sync(void); /* it's really int */
+
+ int panic_timeout;
+@@ -197,20 +201,43 @@
+ unsigned long caller = (unsigned long) __builtin_return_address(0);
+ #endif
+
++#ifdef CONFIG_MCL_COREDUMP
++ crash_save_regs();
++#endif
++
+ bust_spinlocks(1);
+ 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();
++ mb();
++ }
++#endif
++
+ if (netdump_func)
+ BUG();
+ if (in_interrupt())
+ printk(KERN_EMERG "In interrupt handler - not syncing\n");
+ else if (!current->pid)
+ printk(KERN_EMERG "In idle task - not syncing\n");
++#ifdef CONFIG_MCL_COREDUMP
++ else if (crash_perform_sync)
++#else
+ else
++#endif
+ sys_sync();
++
+ bust_spinlocks(0);
++
++#ifdef CONFIG_MCL_COREDUMP
++ smp_call_function((void *)smp_crash_funnel_cpu,0,0,0);
++ crash_save_current_state(current);
++#endif
+
+ #ifdef CONFIG_SMP
+ smp_send_stop();
+Index: linux/kernel/sysctl.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/kernel/sysctl.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.1.2.1
+diff -u -r1.2.2.1 -r1.2.2.1.2.1
+--- linux/kernel/sysctl.c 12 Mar 2003 19:51:36 -0000 1.2.2.1
++++ linux/kernel/sysctl.c 1 Apr 2003 12:17:41 -0000 1.2.2.1.2.1
+@@ -37,6 +37,10 @@
+ #include <linux/nfs_fs.h>
+ #endif
+
++#ifdef CONFIG_MCL_COREDUMP
++#include <linux/crash.h>
++#endif
++
+ #if defined(CONFIG_SYSCTL)
+
+ /* External variables not in a header file. */
+@@ -247,6 +251,10 @@
+ {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
+ 0644, NULL, &proc_dointvec},
+ #endif
++#ifdef CONFIG_MCL_COREDUMP
++ {KERN_PANIC_ON_OOPS, "panic_on_oops", &panic_on_oops, sizeof(int),
++ 0644, NULL, &proc_dointvec},
++#endif
+ {KERN_CADPID, "cad_pid", &cad_pid, sizeof (int),
+ 0600, NULL, &proc_dointvec},
+ {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
+Index: linux/lib/Config.in
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/lib/Config.in,v
+retrieving revision 1.2
+retrieving revision 1.2.4.1
+diff -u -r1.2 -r1.2.4.1
+--- linux/lib/Config.in 14 Feb 2003 22:59:23 -0000 1.2
++++ linux/lib/Config.in 1 Apr 2003 12:17:41 -0000 1.2.4.1
+@@ -23,12 +23,14 @@
+ fi
+ fi
+
+-if [ "$CONFIG_PPP_DEFLATE" = "y" -o \
++if [ "$CONFIG_MCL_COREDUMP" = "y" -o \
++ "$CONFIG_PPP_DEFLATE" = "y" -o \
+ "$CONFIG_JFFS2_FS" = "y" ]; then
+ define_tristate CONFIG_ZLIB_DEFLATE y
+ else
+ if [ "$CONFIG_PPP_DEFLATE" = "m" -o \
+- "$CONFIG_JFFS2_FS" = "m" ]; then
++ "$CONFIG_JFFS2_FS" = "m" -o \
++ "$CONFIG_MCL_COREDUMP" = "m" ]; then
+ define_tristate CONFIG_ZLIB_DEFLATE m
+ else
+ tristate 'zlib compression support' CONFIG_ZLIB_DEFLATE
+Index: linux/mm/memory.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/mm/memory.c,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.1
+diff -u -r1.3.2.1 -r1.3.2.1.2.1
+--- linux/mm/memory.c 12 Mar 2003 19:51:37 -0000 1.3.2.1
++++ linux/mm/memory.c 1 Apr 2003 12:17:41 -0000 1.3.2.1.2.1
+@@ -1381,6 +1381,10 @@
+ }
+ lock_page(page);
+
++#ifdef CONFIG_MCL_COREDUMP
++ set_bit(PG_anon, &page->flags);
++#endif
++
+ /*
+ * Back out if somebody else faulted in this pte while we
+ * released the page table lock.
+@@ -1470,6 +1474,9 @@
+ mm->rss++;
+ flush_page_to_ram(page);
+ entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
++#ifdef CONFIG_MCL_COREDUMP
++ set_bit(PG_anon, &page->flags);
++#endif
+ lru_cache_add(page);
+ }
+
+Index: linux/mm/page_alloc.c
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/mm/page_alloc.c,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.1.2.1
+diff -u -r1.3.2.1 -r1.3.2.1.2.1
+--- linux/mm/page_alloc.c 12 Mar 2003 19:51:37 -0000 1.3.2.1
++++ linux/mm/page_alloc.c 1 Apr 2003 12:17:41 -0000 1.3.2.1.2.1
+@@ -95,6 +95,10 @@
+ struct page *base;
+ per_cpu_t *per_cpu;
+ zone_t *zone;
++#ifdef CONFIG_MCL_COREDUMP
++ struct page *pagemap;
++ int count = 1<<order;
++#endif
+
+ /*
+ * Yes, think what happens when other parts of the kernel take
+@@ -163,6 +167,15 @@
+
+ spin_lock(&zone->lock);
+
++#ifdef CONFIG_MCL_COREDUMP
++ pagemap = page;
++ do {
++ pagemap->flags |= (1<<PG_free);
++ pagemap->flags &= ~((1<<PG_anon)|(1<<PG_shm));
++ pagemap++;
++ } while(--count);
++#endif
++
+ zone->free_pages -= mask;
+
+ while (mask + (1 << (MAX_ORDER-1))) {
+@@ -268,6 +281,16 @@
+ zone->free_pages -= 1UL << order;
+
+ page = expand(zone, page, index, order, curr_order, area);
++#ifdef CONFIG_MCL_COREDUMP
++ {
++ struct page *pagemap = page;
++ int count = 1<<order;
++ do {
++ pagemap->flags &= ~(1<<PG_free);
++ pagemap++;
++ } while (--count);
++ }
++#endif
+ spin_unlock_irqrestore(&zone->lock, flags);
+
+ set_page_count(page, 1);
+Index: linux/arch/i386//boot/compressed/head.S
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/boot/compressed/head.S,v
+retrieving revision 1.1.1.1
+retrieving revision 1.1.1.1.12.6
+diff -u -r1.1.1.1 -r1.1.1.1.12.6
+--- linux/arch/i386//boot/compressed/head.S 7 May 2002 21:53:54 -0000 1.1.1.1
++++ linux/arch/i386//boot/compressed/head.S 5 Apr 2003 05:51:27 -0000 1.1.1.1.12.6
+@@ -23,6 +23,7 @@
+ */
+ .text
+
++#include <linux/config.h>
+ #include <linux/linkage.h>
+ #include <asm/segment.h>
+
+@@ -31,6 +32,55 @@
+ startup_32:
+ cld
+ cli
++
++#ifdef CONFIG_BOOTIMG
++/*
++ * GDT is invalid if we're booted by bootimg, so reload it now
++ */
++ lgdt %cs:gdt_descr
++ ljmp $(__KERNEL_CS),$1f
++
++gdt_table_limit = gdt_table_end - gdt_table - 1
++gdt_descr:
++ .word gdt_table_limit
++ .long gdt_table
++
++gdt_table: /* stolen from arch/i386/kernel/head.S */
++ .quad 0x0000000000000000 /* NULL descriptor */
++ .quad 0x0000000000000000 /* 0x0b reserved */
++ .quad 0x0000000000000000 /* 0x13 reserved */
++ .quad 0x0000000000000000 /* 0x1b reserved */
++ .quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */
++ .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */
++ .quad 0x0000000000000000 /* 0x33 TLS entry 1 */
++ .quad 0x0000000000000000 /* 0x3b TLS entry 2 */
++ .quad 0x0000000000000000 /* 0x43 TLS entry 3 */
++ .quad 0x0000000000000000 /* 0x4b reserved */
++ .quad 0x0000000000000000 /* 0x53 reserved */
++ .quad 0x0000000000000000 /* 0x5b reserved */
++
++ .quad 0x00cf9a000000ffff /* 0x60 kernel 4GB code at 0x00000000 */
++ .quad 0x00cf92000000ffff /* 0x68 kernel 4GB data at 0x00000000 */
++ .quad 0x0000000000000000 /* 0x70 TSS descriptor */
++ .quad 0x0000000000000000 /* 0x78 LDT descriptor */
++
++ /* Segments used for calling PnP BIOS */
++ .quad 0x00c09a0000000000 /* 0x80 32-bit code */
++ .quad 0x00809a0000000000 /* 0x88 16-bit code */
++ .quad 0x0080920000000000 /* 0x90 16-bit data */
++ .quad 0x0080920000000000 /* 0x98 16-bit data */
++ .quad 0x0080920000000000 /* 0xa0 16-bit data */
++ /*
++ * The APM segments have byte granularity and their bases
++ * and limits are set at run time.
++ */
++ .quad 0x00409a0000000000 /* 0xa8 APM CS code */
++ .quad 0x00009a0000000000 /* 0xb0 APM CS 16 code (16 bit) */
++ .quad 0x0040920000000000 /* 0xb8 APM DS data */
++gdt_table_end:
++
++1:
++#endif
+ movl $(__KERNEL_DS),%eax
+ movl %eax,%ds
+ movl %eax,%es
+@@ -92,7 +142,6 @@
+ cld
+ rep
+ movsl
+-
+ popl %esi # discard the address
+ popl %ebx # real mode pointer
+ popl %esi # low_buffer_start
+@@ -124,5 +173,10 @@
+ movsl
+ movl %ebx,%esi # Restore setup pointer
+ xorl %ebx,%ebx
++#ifdef CONFIG_BOOTIMG
++ movl $0x100000,%eax
++ jmpl *%eax
++#else
+ ljmp $(__KERNEL_CS), $0x100000
++#endif
+ move_routine_end:
+Index: linux/arch/i386//kernel/head.S
+===================================================================
+RCS file: /chaos/cvs/kernel-rh/linux/arch/i386/kernel/head.S,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.1.2.5
+diff -u -r1.2.2.1 -r1.2.2.1.2.5
+--- linux/arch/i386//kernel/head.S 12 Mar 2003 19:49:06 -0000 1.2.2.1
++++ linux/arch/i386//kernel/head.S 5 Apr 2003 05:51:27 -0000 1.2.2.1.2.5
+@@ -42,6 +42,21 @@
+ * On entry, %esi points to the real-mode code as a 32-bit pointer.
+ */
+ startup_32:
++#ifdef CONFIG_BOOTIMG
++/*
++ * 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_limit = SYMBOL_NAME(cpu_gdt_table_end) - SYMBOL_NAME(cpu_gdt_table) - 1
++
++_gdt_descr:
++ .word gdt_limit
++ .long SYMBOL_NAME(cpu_gdt_table)-__PAGE_OFFSET
++
++1:
++#endif
+ /*
+ * Set segments to known values
+ */
+@@ -452,6 +467,7 @@
+ .quad 0x00409a0000000000 /* 0xa8 APM CS code */
+ .quad 0x00009a0000000000 /* 0xb0 APM CS 16 code (16 bit) */
+ .quad 0x0040920000000000 /* 0xb8 APM DS data */
++ENTRY(cpu_gdt_table_end)
+
+ #if CONFIG_SMP
+ .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */