From 72461ab2c7b32925990612918800942e665f140f Mon Sep 17 00:00:00 2001 From: wangdi Date: Wed, 7 May 2003 09:57:54 +0000 Subject: [PATCH] add mcore-2.4.20-8.patch --- lustre/kernel_patches/patches/mcore-2.4.20-8.patch | 2738 ++++++++++++++++++++ 1 file changed, 2738 insertions(+) create mode 100644 lustre/kernel_patches/patches/mcore-2.4.20-8.patch diff --git a/lustre/kernel_patches/patches/mcore-2.4.20-8.patch b/lustre/kernel_patches/patches/mcore-2.4.20-8.patch new file mode 100644 index 0000000..c8b80eb --- /dev/null +++ b/lustre/kernel_patches/patches/mcore-2.4.20-8.patch @@ -0,0 +1,2738 @@ +? 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 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 ++#include ++#include ++#include ++#include ++#include ++ ++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 + #endif ++#ifdef CONFIG_BOOTIMG ++#include ++#endif + + #include + +@@ -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 + #include + #include ++#ifdef CONFIG_MCL_COREDUMP ++#include ++#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 + #include + ++#ifdef CONFIG_MCL_COREDUMP ++#include ++#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 + #include + ++#ifdef CONFIG_MCL_COREDUMP ++#include ++#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 ++#include ++ ++#ifdef CONFIG_SMP ++#include ++#include ++#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 ++ ++#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 + #endif + ++#ifdef CONFIG_BOOTIMG ++#include ++#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 , 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_BOOTIMG ++#include ++#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 + #include + ++#ifdef CONFIG_MCL_COREDUMP ++#include ++#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 + #endif + ++#ifdef CONFIG_MCL_COREDUMP ++#include ++#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<lock); + ++#ifdef CONFIG_MCL_COREDUMP ++ pagemap = page; ++ do { ++ pagemap->flags |= (1<flags &= ~((1<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<flags &= ~(1<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 + #include + #include + +@@ -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 */ -- 1.8.3.1