diff -uNr linux-2.5.11/Documentation/i386/boot.txt linux-2.5.11.boot.elf/Documentation/i386/boot.txt
--- linux-2.5.11/Documentation/i386/boot.txt	Sun Mar 10 20:05:16 2002
+++ linux-2.5.11.boot.elf/Documentation/i386/boot.txt	Mon Apr 29 11:22:46 2002
@@ -4,6 +4,9 @@
 		    H. Peter Anvin <hpa@zytor.com>
 			Last update 2002-01-01
 
+		Eric Biederman <ebiederm@xmission.com>
+		       Last update 28 April 2002
+
 On the i386 platform, the Linux kernel uses a rather complicated boot
 convention.  This has evolved partially due to historical aspects, as
 well as the desire in the early days to have the kernel itself be a
@@ -35,6 +38,14 @@
 		initrd address available to the bootloader.
 
 
+Protocol 2.04:  (Kernel 2.5.11) 
+		- Decompression in place (smaller load footpribnt)
+		  The overhead is now 72KB below 1MB && 8 bytes above 1MB
+		- 32bit entry point support
+		- Exported the load time memory usage.
+		- zImage now has a larger memory footprint than bzImage.
+		  should we just kill zImage?
+
 **** MEMORY LAYOUT
 
 The traditional memory map for the kernel loader, used for Image or
@@ -100,34 +111,42 @@
 
 The header looks like:
 
-Offset	Proto	Name		Meaning
+Offset  Proto  Name                  Meaning
 /Size
 
-01F1/1	ALL	setup_sects	The size of the setup in sectors
-01F2/2	ALL	root_flags	If set, the root is mounted readonly
-01F4/2	ALL	syssize		DO NOT USE - for bootsect.S use only
-01F6/2	ALL	swap_dev	DO NOT USE - obsolete
-01F8/2	ALL	ram_size	DO NOT USE - for bootsect.S use only
-01FA/2	ALL	vid_mode	Video mode control
-01FC/2	ALL	root_dev	Default root device number
-01FE/2	ALL	boot_flag	0xAA55 magic number
-0200/2	2.00+	jump		Jump instruction
-0202/4	2.00+	header		Magic signature "HdrS"
-0206/2	2.00+	version		Boot protocol version supported
-0208/4	2.00+	realmode_swtch	Boot loader hook (see below)
-020C/2	2.00+	start_sys	The load-low segment (0x1000) (obsolete)
-020E/2	2.00+	kernel_version	Pointer to kernel version string
-0210/1	2.00+	type_of_loader	Boot loader identifier
-0211/1	2.00+	loadflags	Boot protocol option flags
-0212/2	2.00+	setup_move_size	Move to high memory size (used with hooks)
-0214/4	2.00+	code32_start	Boot loader hook (see below)
-0218/4	2.00+	ramdisk_image	initrd load address (set by boot loader)
-021C/4	2.00+	ramdisk_size	initrd size (set by boot loader)
-0220/4	2.00+	bootsect_kludge	DO NOT USE - for bootsect.S use only
-0224/2	2.01+	heap_end_ptr	Free memory after setup end
-0226/2	N/A	pad1		Unused
-0228/4	2.02+	cmd_line_ptr	32-bit pointer to the kernel command line
-022C/4	2.03+	initrd_addr_max	Highest legal initrd address
+01F1/1  ALL    setup_sects           The size of the setup in sectors
+01F2/2  ALL    root_flags            If set, the root is mounted readonly
+01F4/2  ALL    syssize               DO NOT USE - for bootsect.S use only
+01F6/2  ALL    swap_dev              DO NOT USE - obsolete
+01F8/2  ALL    ram_size              DO NOT USE - for bootsect.S use only
+01FA/2  ALL    vid_mode              Video mode control
+01FC/2  ALL    root_dev              Default root device number
+01FE/2  ALL    boot_flag             0xAA55 magic number
+0200/2  2.00+  jump                  Jump instruction
+0202/4  2.00+  header_magic          Magic signature "HdrS"
+0206/2  2.00+  protocol_version      Boot protocol version supported
+0208/4  2.00+  realmode_swtch        Boot loader hook (see below)
+020C/2  2.00+  start_sys_seg         Segment the zImage kernel was loaded at (0x1000) (obsolete)
+020E/2  2.00+  kernel_version        Pointer to kernel version string
+0210/1  2.00+  type_of_loader        Boot loader identifier
+0211/1  2.00+  loadflags             Boot protocol option flags
+0212/2  2.00+  setup_move_size       Move to high memory size (used with hooks)
+0214/4  2.00+  code32_start          Boot loader hook (see below)
+0218/4  2.00+  initrd_start          initrd load address (set by boot loader)
+021C/4  2.00+  initrd_size           initrd size (set by boot loader)
+0220/4  2.00+  bootsect_kludge       DO NOT USE - for bootsect.S use only
+0224/2  2.01+  heap_end_ptr          Free memory after setup end
+0226/2  N/A    pad1                  Unused
+0228/4  2.02+  cmd_line_ptr          32-bit pointer to the kernel command line
+022C/4  2.03+  ramdisk_max           Highest legal initrd address
+0230/2  2.04+  entry32_off           offset of 32bit entry point
+0230/2  2.04+  internal_cmdline_off  offset of compiled in command line
+0234/4  2.04+  real_base             Default load address of real mode code
+0238/4  2.04+  real_memsz            Memory used @ real_base
+023C/4  2.04+  real_filesz           Amount of data loaded @ real_base
+0240/4  2.04+  kern_base             Kernel decompressor load address
+0244/4  2.04+  kern_memsz            Memory used @ kern_base
+0248/4  2.04+  kern_filesz           Amount of data loaeded @ kern_base
 
 For backwards compatibility, if the setup_sects field contains 0, the
 real value is 4.
@@ -180,8 +199,14 @@
   loadflags, heap_end_ptr:
 	If the protocol version is 2.01 or higher, enter the
 	offset limit of the setup heap into heap_end_ptr and set the
-	0x80 bit (CAN_USE_HEAP) of loadflags.  heap_end_ptr appears to
-	be relative to the start of setup (offset 0x0200).
+	0x80 bit (CAN_USE_HEAP) of loadflags.  heap_end_ptr is
+	relative to the start of setup (offset 0x0200).
+
+	If the protocol version is 2.04 or higher set the 0x40 bit
+	(STAY_PUT).  This explictly tells the real mode code that you
+	don't expect it to relocate itself to 0x90000.  No earlier
+	protocols versions look at this bit so it is safe to set it
+	unconditionally.
 
   setup_move_size: 
 	When using protocol 2.00 or 2.01, if the real mode
@@ -190,17 +215,20 @@
 	additional data (such as the kernel command line) moved in
 	addition to the real-mode kernel itself.
 
-  ramdisk_image, ramdisk_size:
+  initrd_start, initrd_size:
 	If your boot loader has loaded an initial ramdisk (initrd),
-	set ramdisk_image to the 32-bit pointer to the ramdisk data
-	and the ramdisk_size to the size of the ramdisk data.
+	set initrd_start to the 32-bit pointer to the ramdisk data
+	and the initrd_size to the size of the ramdisk data.
 
 	The initrd should typically be located as high in memory as
 	possible, as it may otherwise get overwritten by the early
 	kernel initialization sequence.	 However, it must never be
-	located above the address specified in the initrd_addr_max
+	located above the address specified in the ramdisk_max
 	field.	The initrd should be at least 4K page aligned.
 
+	With boot protocol 2.04 and above the initrd can be loaded
+	as low as kern_base + kern_memsz.
+
   cmd_line_ptr:
 	If the protocol version is 2.02 or higher, this is a 32-bit
 	pointer to the kernel command line.  The kernel command line
@@ -248,6 +276,11 @@
 	covered by setup_move_size, so you may need to adjust this
 	field.
 
+If the protocol version is 2.04 or higher a compiled in command line
+may be present.  If this is the case the passed command line is
+appended onto the tail of the compiled command line.  Assuming
+there is room.
+
 
 **** SAMPLE BOOT CONFIGURATION
 
@@ -269,8 +302,8 @@
 	if ( protocol >= 0x0200 ) {
 		type_of_loader = <type code>;
 		if ( loading_initrd ) {
-			ramdisk_image = <initrd_address>;
-			ramdisk_size = <initrd_size>;
+			initrd_start = <initrd_address>;
+			initrd_size = <initrd_size>;
 		}
 		if ( protocol >= 0x0201 ) {
 			heap_end_ptr = 0x9000 - 0x200;
@@ -436,3 +469,176 @@
 
 	After completing your hook, you should jump to the address
 	that was in this field before your boot loader overwrote it.
+
+
+**** THE COMPRESSED KERNEL HEADER
+
+As of boot protocol version 2.04 a header has been added to the
+compressed data, to reduce information loss.  Most bootloaders
+should never need to look at these fields.
+
+Offset  Proto  Name             Meaning
+/Size
+
+0000/4  2.04+  jump             Jump Instruction
+0004/4  2.04+  input_addr       Load address of compressed data
+0008/4  2.04+  input_len        Length of compressed data
+000C/4  2.04+  output_overhang  Extra bytes needed for inplace decompression
+0010/4  2.04+  kernel_base      Kernel load address
+0014/4  2.04+  kernel_filesz    Memory usage @ kernel_base     
+0018/4  2.04+  kernel_memsz     Data size @ kernel_base
+001C/4  2.04+  unzip_filesz     Decompressor code/data size
+0020/4  2.04+  unzip_memsz      Decompressor code memory usage
+
+**** DETAILED DESCRIPTION OF FIELDS
+
+  entry32_off:
+	The unsigned offset of the 32bit entry point from the real
+	mode kernel. For boot protocols 2.03 or earlier, this field is
+	not present, and there is no 32bit entry point.
+
+	The 32bit entry point is a mechanism for entering the kernel
+	without doing 16bit PC BIOS calls.  Very useful for systems
+	with alternative firmware implementations.
+
+	A bootloader using the 32bit entry point should verify that
+	there are real_memsz bytes available at real_base (real_base
+	remains relocatable in bzImages).  And that there kern_memsz
+	bytes available at kern_base.  For zImages you should also
+	verify that there are kernel_memsz bytes available at
+	kernel_base.
+
+	Verifing there is enough memory for the kernel to load is
+	necessary for using the 32bit entry point, and suggested for
+	the 16bit entry point.  In the case of the 32bit entry point
+	the kernel has no ability to talk to whatever weird firmware you
+	have until it is fully loaded.
+
+	The 32bit entry point makes the following assumptions.  You
+	are calling it protected mode.  Paging is disabled.  All
+	segment registers are loaded with a 32bit segment with a base
+	of 0, and a limit of 0xFFFFFFFF (limitless).  Either %esp == 0
+	and you are using the default real_base or %esp points to a
+	stack large enough to hold at least 12 new bytes of data.
+
+
+  internal_cmdline_off:
+	The offset of the null terminated compiled in command line
+	from the real mode kernel.   For boot protocols 2.03 or
+	earlier this field is not present, and there is no built in
+	command line.  The memory from internal_cmdline_off to
+	real_filesz is reserved for the compiled in command_line.  An
+	external utility may modify this command line.
+
+	To change the maximum size of the compiled in command line several
+	variables need to be modified.  real_filesz to indicate the
+	new maximum size.  setup_sects to indicate if the number of
+	sectors needed for the realmode kernel changes.  
+
+	A heap is maintained between real_filesz and real_memsz/heap_end_ptr.
+	Increasing the size of the heap is not a problem, decreasing
+	it is.  So when changing the real_filesz, real_memsz and
+	heap_end_ptr should also be changed.
+
+  input_addr/input_len:
+	The kernel is loaded into memory in compressed form.
+	input_addr is the location where the compressed data is
+	loaded, and input_len is the count of how many bytes of
+	compressed data there are.
+	
+	These two variables allow an external program to inspect a
+	bzImage and find the compressed data.  This is mostly of use
+	to build.c as it computes output_overhang but other programs
+	may find it useful as well.
+
+  output_overhang:
+	Most decompression algorithms may transformed into near
+	in-place algorithms by simply overlapping the compressed data
+	and the decompressed data buffers.  For a particular
+	decompression algorithm then the question becomes how much
+	overlap is safe.  More practically how much must the
+	compressed data stick out from the end of the decompressed
+	data buffer for this technique to work.
+
+	output_overhang is that amount the compressed data buffer
+	must extend beyond the decompressed data buffer for
+	decompression in place to work for the linux kernel.
+
+	build.c is responsible for computing this number.  For
+	gzip typically this number is 8 (file length and checksum).
+	But in pathological cases it may be worse.
+
+  real_base, real_memsz, real_filesz, 
+  kern_base, kern_memsz, kern_filesz,
+  kernel_base, kernel_memsz, kernel_filesz,
+  unzip_memsz, unzip_filesz,
+
+	Up to this point building a zImage or a bzImage has been a
+	very lossy process.  The introduction of these variables
+        attempts to rectify that situation.  They document exactly
+	which pieces of memory, the kernel uses during the boot
+	process, and they indicate exactly how large the various data
+	segments of the kernel are.  It is now possible to create a
+	lossless transformation to and from a static ELF executable.
+
+	Program segments are described with 3 variables.  The base
+	address where the segment is loaded in memory.  The file size
+	which records the amount of data in the input file that is
+	loaded into memory.  The memory size which is greater than or
+	equal to the file size and records how much memory this
+	program segment consumes.
+
+	base   +-----------+
+	       | code/data |
+	filesz +-----------+
+	       |  bss      |
+	memsz  +-----------+
+
+	The real program segment (real_base, real_filesz, real_memsz)
+	describes the memory usage of the real mode code from 4KB to
+	640KB.  The real code segment and the command line must be  
+	located somewhere in this range.
+
+	The compressed kernel segment (kern_base, kern_filesz,
+	kern_memsz) describes the memory usage of the compressed
+	kernel.  For a zImage this is memory below 1MB for a bzImage
+	this is memory starting at 1MB.
+
+	For bzImages it is sufficient to look at the real program
+	segment, and the compressed kernel segment to get the entire
+	boottime memory usage of the kernel.  real_memsz is increased
+	to also document the decompressors real memory usage, and the
+	kern_memsz value is increased to document the decompressed
+	kernels memory usage.
+
+	You can look at heap_end_ptr to get the actual memory
+	footprint of the real mode segment.  Just the decompressors
+	memory footprint is kern_base + kernel_filesz +
+	output_overhang, if unzip_memsz bytes are available of real
+	memory, and kern_base + kernel_filesz + output_overhang +
+	unzip_memsz bytes otherwise.
+	
+	The decompressed kernel segment (kernel_base, kernel_filesz,
+	kernel_memsz) describes the memory usage of the decompresed
+	kernel (essentially vmlinux). 
+
+	The decompressor segment (load_address, unzip_filesz, unzip_memsz)
+	describes the memory usage of the kernel decompressor,
+	not counting the compressed data.
+
+	The real program segment describes memory in the range
+	4KB (0x1000) to 640KB (0xa0000) that the real mode kernel
+	uses.  real_base may be moved lower or higher in memory if
+	there is a memory conflict with another address.  When doing
+	so the following considerations should apply.
+
+		For a zImage the range [real_base, real_base +
+		real_memsz) should not overlap the range [ kern_base,
+		kern_base + kern_memsz].
+
+		Ensure that the range [real_base, real_base +
+		real_memsz) is within the range [ 0x1000, 0xa0000).
+		
+	With this information it becomes safe to statically relocate
+	the real mode kernel as well as to dynamically relocate the
+	real_mode kernel.
diff -uNr linux-2.5.11/Documentation/i386/zero-page.txt linux-2.5.11.boot.elf/Documentation/i386/zero-page.txt
--- linux-2.5.11/Documentation/i386/zero-page.txt	Mon Aug 30 11:47:02 1999
+++ linux-2.5.11.boot.elf/Documentation/i386/zero-page.txt	Mon Apr 29 11:21:06 2002
@@ -9,7 +9,11 @@
   arch/i386/boot/video.S
   arch/i386/kernel/head.S
   arch/i386/kernel/setup.c
- 
+
+See include/asm-i386/boot_param.h a structure is kept there with
+uptodate information.  The kernel no longer copies this information
+into the empty zero page, but instead uses it directly.
+
 
 Offset	Type		Description
 ------  ----		-----------
@@ -65,7 +69,7 @@
 0x21c	unsigned long	INITRD_SIZE, size in bytes of ramdisk image
 0x220	4 bytes		(setup.S)
 0x224	unsigned short	setup.S heap end pointer
-0x2d0 - 0x600		E820MAP
+0x2d0 - 0x550		E820MAP
 
 0x800	string, 2K max	COMMAND_LINE, the kernel commandline as
 			copied using CL_OFFSET.
diff -uNr linux-2.5.11/Makefile linux-2.5.11.boot.elf/Makefile
--- linux-2.5.11/Makefile	Mon Apr 29 00:17:10 2002
+++ linux-2.5.11.boot.elf/Makefile	Mon Apr 29 11:22:43 2002
@@ -93,15 +93,6 @@
 AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
 
 #
-# ROOT_DEV specifies the default root-device when making the image.
-# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
-# the default of FLOPPY is used by 'build'.
-# This is i386 specific.
-#
-
-export ROOT_DEV = CURRENT
-
-#
 # If you want to preset the SVGA mode, uncomment the next line and
 # set SVGA_MODE to whatever number you want.
 # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
diff -uNr linux-2.5.11/arch/i386/Config.help linux-2.5.11.boot.elf/arch/i386/Config.help
--- linux-2.5.11/arch/i386/Config.help	Mon Apr 29 00:17:11 2002
+++ linux-2.5.11.boot.elf/arch/i386/Config.help	Mon Apr 29 11:22:48 2002
@@ -803,6 +803,28 @@
   a work-around for a number of buggy BIOSes. Switch this option on if
   your computer crashes instead of powering off properly.
 
+LinuxBIOS support
+CONFIG_LINUXBIOS
+  LinuxBIOS is an alternative GPL'd firmware initially for x86
+  compatible machines.  LinuxBIOS attempts to be a simple and as fast
+  as possible, and is initially optimized for linux.  The interface to
+  the OS is a table at the beginning of memory.  Which should make the
+  inevitable firmware bugs easier to work around, as should the source
+  code :)  A goal of this table is to provide enough information so
+  that any OS but especially linux does not need to have motherboard
+  specific knowledge.
+
+  This first release only provides LinuxBIOS detection (by detecting
+  it's table) and memory size detection. 
+
+  For more information on LinuxBIOS see http://www.linuxbios.org
+
+CONFIG_CMDLINE
+  Generally it is best to pass command line parameters via the
+  bootloader but there are times it is convinient not to do this.
+  This allows you to hard code a default kernel command line, whatever
+  the bootloader passes will be appended to it.
+
 CONFIG_X86_MCE
   Machine Check Exception support allows the processor to notify the
   kernel if it detects a problem (e.g. overheating, component failure).
diff -uNr linux-2.5.11/arch/i386/Makefile linux-2.5.11.boot.elf/arch/i386/Makefile
--- linux-2.5.11/arch/i386/Makefile	Thu Apr 12 13:20:31 2001
+++ linux-2.5.11.boot.elf/arch/i386/Makefile	Mon Apr 29 11:23:04 2002
@@ -18,7 +18,7 @@
 
 LD=$(CROSS_COMPILE)ld -m elf_i386
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e stext
+LDFLAGS=
 LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS)
 
 CFLAGS += -pipe
@@ -118,6 +118,9 @@
 
 bzImage: vmlinux
 	@$(MAKEBOOT) bzImage
+
+bzElf: vmlinux
+	@$(MAKEBOOT) bzElf
 
 compressed: zImage
 
diff -uNr linux-2.5.11/arch/i386/boot/Makefile linux-2.5.11.boot.elf/arch/i386/boot/Makefile
--- linux-2.5.11/arch/i386/boot/Makefile	Sun Aug  5 14:13:19 2001
+++ linux-2.5.11.boot.elf/arch/i386/boot/Makefile	Mon Apr 29 11:23:04 2002
@@ -12,13 +12,14 @@
 		$(TOPDIR)/include/linux/autoconf.h \
 		$(TOPDIR)/include/asm/boot.h
 
-zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
-	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
-	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
-
-bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build
-	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
-	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+zImage: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux realmode compressed/vmlinux 
+	tools/build $(TOPDIR)/vmlinux realmode compressed/vmlinux zImage
+
+bzImage: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux brealmode compressed/bvmlinux 
+	tools/build -b $(TOPDIR)/vmlinux brealmode compressed/bvmlinux bzImage
+
+bzElf: $(CONFIGURE) tools/build $(TOPDIR)/vmlinux brealmode compressed/bvmlinux 
+	tools/build -e -b $(TOPDIR)/vmlinux brealmode compressed/bvmlinux bzElf
 
 compressed/vmlinux: $(TOPDIR)/vmlinux
 	@$(MAKE) -C compressed vmlinux
@@ -39,49 +40,43 @@
 install: $(CONFIGURE) $(BOOTIMAGE)
 	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
-tools/build: tools/build.c
+tools/build: tools/build.c $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h $(TOPDIR)/include/asm-i386/boot.h
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
 
-bootsect: bootsect.o
-	$(LD) -Ttext 0x0 -s --oformat binary -o $@ $<
-
 bootsect.o: bootsect.s
 	$(AS) -o $@ $<
 
 bootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bbootsect: bbootsect.o
-	$(LD) -Ttext 0x0 -s --oformat binary $< -o $@
-
 bbootsect.o: bbootsect.s
 	$(AS) -o $@ $<
 
 bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
 	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-setup: setup.o
-	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
 setup.o: setup.s
 	$(AS) -o $@ $<
 
 setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
 	$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
-bsetup: bsetup.o
-	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
 bsetup.o: bsetup.s
 	$(AS) -o $@ $<
 
 bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
 	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
+realmode: bootsect.o setup.o
+	$(LD) -T realmode.lds -o $@ $^
+
+brealmode: bbootsect.o bsetup.o
+	$(LD) -T realmode.lds -o $@ $^
+
 dep:
 
 clean:
 	rm -f tools/build
-	rm -f setup bootsect zImage compressed/vmlinux.out
-	rm -f bsetup bbootsect bzImage compressed/bvmlinux.out
+	rm -f realmode zImage
+	rm -f brealmode bzImage
 	@$(MAKE) -C compressed clean
diff -uNr linux-2.5.11/arch/i386/boot/bootsect.S linux-2.5.11.boot.elf/arch/i386/boot/bootsect.S
--- linux-2.5.11/arch/i386/boot/bootsect.S	Sun Mar 10 20:07:02 2002
+++ linux-2.5.11.boot.elf/arch/i386/boot/bootsect.S	Mon Apr 29 11:22:43 2002
@@ -54,7 +54,7 @@
 #endif
 
 .code16
-.text
+.section ".bootsect", "ax", @progbits
 
 .global _start
 _start:
Binary files linux-2.5.11/arch/i386/boot/bzElf and linux-2.5.11.boot.elf/arch/i386/boot/bzElf differ
diff -uNr linux-2.5.11/arch/i386/boot/compressed/Makefile linux-2.5.11.boot.elf/arch/i386/boot/compressed/Makefile
--- linux-2.5.11/arch/i386/boot/compressed/Makefile	Sun Mar 10 20:07:02 2002
+++ linux-2.5.11.boot.elf/arch/i386/boot/compressed/Makefile	Mon Apr 29 11:22:40 2002
@@ -9,8 +9,6 @@
 
 OBJECTS = $(HEAD) misc.o
 
-ZLDFLAGS = -e startup_32
-
 #
 # ZIMAGE_OFFSET is the load offset of the compression loader
 # BZIMAGE_OFFSET is the load offset of the high loaded compression loader
@@ -18,8 +16,8 @@
 ZIMAGE_OFFSET = 0x1000
 BZIMAGE_OFFSET = 0x100000
 
-ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS)
-BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS)
+ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) -T vmlinuz.lds
+BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) -T vmlinuz.lds 
 
 all: vmlinux
 
@@ -42,7 +40,7 @@
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
 	$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
 	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
-	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
+	echo "SECTIONS { .input : { *(.data) }}" > $$tmppiggy.lnk; \
 	$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
 
diff -uNr linux-2.5.11/arch/i386/boot/compressed/head.S linux-2.5.11.boot.elf/arch/i386/boot/compressed/head.S
--- linux-2.5.11/arch/i386/boot/compressed/head.S	Mon Apr 29 00:17:11 2002
+++ linux-2.5.11.boot.elf/arch/i386/boot/compressed/head.S	Mon Apr 29 11:22:40 2002
@@ -25,24 +25,56 @@
 
 #include <linux/linkage.h>
 #include <asm/segment.h>
+#include <asm/boot.h>
 
 	.globl startup_32
 	
 startup_32:
+	jmp 1f
+	.balign		4
+	.globl input_addr, input_len, output_overhang
+	.globl kernel_base, kernel_memsz, kernel_filesz
+	.globl unzip_memsz, unzip_filesz
+input_addr:		.long input_data
+input_len:		.long input_data_len
+output_overhang:	.long input_data_len # Will be set to 8 later...
+kernel_base:		.long HIGH_BASE
+kernel_memsz:		.long 0
+kernel_filesz:		.long 0
+unzip_memsz:		.long _end
+unzip_filesz:		.long _edata
+1:	
 	cld
 	cli
-	movl $(__KERNEL_DS),%eax
-	movl %eax,%ds
-	movl %eax,%es
-	movl %eax,%fs
-	movl %eax,%gs
 
-	lss stack_start,%esp
-	xorl %eax,%eax
-1:	incl %eax		# check that A20 really IS enabled
-	movl %eax,0x000000	# loop forever if it isn't
-	cmpl %eax,0x100000
-	je 1b
+	/*
+	 * Save the initial registers
+	 */
+	movl %eax, eax
+	movl %ebx, ebx
+	movl %ecx, ecx
+	movl %edx, edx
+	movl %esi, esi
+	movl %edi, edi
+	movl %esp, esp
+	movl %ebp, ebp
+
+	/* 
+	 * Move the input data off the bss segment
+	 */
+	std
+	movl $input_data_end -1, %esi
+	movl %esi, %edi
+	addl $input_data_shift, %edi
+	movl $input_data_len, %ecx
+	rep movsb
+	cld
+	addl $input_data_shift, input_addr
+
+	/*
+	 * Setup the stack
+	 */
+	movl stack_start, %esp
 
 /*
  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
@@ -66,16 +98,10 @@
  */
 	subl $16,%esp	# place for structure on the stack
 	movl %esp,%eax
-	pushl %esi	# real mode pointer as second arg
 	pushl %eax	# address of structure as first arg
 	call decompress_kernel
-	orl  %eax,%eax 
-	jnz  3f
-	popl %esi	# discard address
-	popl %esi	# real mode pointer
-	xorl %ebx,%ebx
-	ljmp $(__KERNEL_CS), $0x100000
-
+	orl  %eax,%eax
+	jz out
 /*
  * We come here, if we were loaded high.
  * We need to move the move-in-place routine down to 0x1000
@@ -83,8 +109,21 @@
  * which we got from the stack.
  */
 3:
-	movl $move_routine_start,%esi
-	movl $0x1000,%edi
+	/* Relocate the move routine */
+	movl $move_routine_start,%esi	#src
+	movl %eax,%edi			#dest
+	movl %eax, %ebp                 #saved dest
+	movl %edi, %eax 
+	subl %esi, %eax			# The relocation factor
+	addl %eax, reloc1
+	addl %eax, reloc2
+	addl %eax, reloc3
+	addl %eax, reloc4
+	addl %eax, reloc5
+	addl %eax, reloc6
+	addl %eax, reloc7
+	addl %eax, reloc8
+	addl %eax, reloc9
 	movl $move_routine_end,%ecx
 	subl %esi,%ecx
 	addl $3,%ecx
@@ -93,20 +132,23 @@
 	rep
 	movsl
 
+	/* Load it's arguments and jump to the move routine */
 	popl %esi	# discard the address
-	popl %ebx	# real mode pointer
 	popl %esi	# low_buffer_start
 	popl %ecx	# lcount
 	popl %edx	# high_buffer_start
 	popl %eax	# hcount
-	movl $0x100000,%edi
+	movl $HIGH_BASE,%edi
 	cli		# make sure we don't get interrupted
-	ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine
+	jmpl *%ebp
 
 /*
  * Routine (template) for moving the decompressed kernel in place,
- * if we were high loaded. This _must_ PIC-code !
+ * if we were high loaded. This _must_ be PIC-code !
+ * Or it must be anotated with lables so it can be manually relocated.
  */
+	.globl move_routine_start, move_routine_end
+	.balign 4
 move_routine_start:
 	movl %ecx,%ebp
 	shrl $2,%ecx
@@ -122,7 +164,35 @@
 	shrl $2,%ecx
 	rep
 	movsl
-	movl %ebx,%esi	# Restore setup pointer
-	xorl %ebx,%ebx
-	ljmp $(__KERNEL_CS), $0x100000
+out:
+	.byte 0xa1		# movl eax,  %eax
+reloc1:	.long eax
+	.byte 0x8b, 0x1d	# movl ebx,  %ebx
+reloc2:	.long ebx
+	.byte 0x8b, 0x0d	# movl ecx,  %ecx
+reloc3:	.long ecx
+	.byte 0x8b, 0x15	# movl edx, %edx
+reloc4:	.long edx
+	.byte 0x8b, 0x35	# movl esi, %esi
+reloc5:	.long esi
+	.byte 0x8b, 0x3d	# movl edi, %edi
+reloc6:	.long edi
+	.byte 0x8b, 0x25	# movl esp, %esp
+reloc7:	.long esp
+	.byte 0x8b, 0x2d	# movl ebp, %ebp
+reloc8:	.long ebp
+	.byte 0xff, 0x25	# jmpl *(kernel_start)
+reloc9:	.long kernel_start
+	.balign 4
+ENTRY(initial_regs)
+eax:	.long 0x12345678 /* eax */
+ebx:	.long 0x12345678 /* ebx */
+ecx:	.long 0x12345678 /* ecx */
+edx:	.long 0x12345678 /* edx */
+esi:	.long 0x12345678 /* esi */
+edi:	.long 0x12345678 /* edi */
+esp:	.long 0x12345678 /* esp */
+ebp:	.long 0x12345678 /* ebp */
+kernel_start:
+	.long HIGH_BASE
 move_routine_end:
diff -uNr linux-2.5.11/arch/i386/boot/compressed/misc.c linux-2.5.11.boot.elf/arch/i386/boot/compressed/misc.c
--- linux-2.5.11/arch/i386/boot/compressed/misc.c	Mon Nov 12 10:59:43 2001
+++ linux-2.5.11.boot.elf/arch/i386/boot/compressed/misc.c	Mon Apr 29 11:22:40 2002
@@ -9,10 +9,14 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 
+#include <linux/string.h> /* for: memset, memmove */
 #include <linux/linkage.h>
-#include <linux/vmalloc.h>
 #include <linux/tty.h>
 #include <asm/io.h>
+#include <linux/apm_bios.h>
+#include <asm/e820.h>
+#include <asm/boot_param.h>
+#include <asm/boot.h>
 
 /*
  * gzip declarations
@@ -21,16 +25,11 @@
 #define OF(args)  args
 #define STATIC static
 
-#undef memset
-#undef memcpy
-
 /*
  * Why do we do this? Don't ask me..
  *
  * Incomprehensible are the ways of bootloaders.
  */
-static void* memset(void *, int, size_t);
-static void* memcpy(void *, __const void *, size_t);
 #define memzero(s, n)     memset ((s), 0, (n))
 
 typedef unsigned char  uch;
@@ -47,15 +46,6 @@
 static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
 static unsigned outcnt = 0;  /* bytes in output buffer */
 
-/* gzip flag byte */
-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
-#define COMMENT      0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
-#define RESERVED     0xC0 /* bit 6,7:   reserved */
-
 #define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
 		
 /* Diagnostic functions */
@@ -84,16 +74,20 @@
 /*
  * This is set up by the setup-routine at boot-time
  */
-static unsigned char *real_mode; /* Pointer to real-mode data */
-
-#define EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
-#ifndef STANDARD_MEMORY_BIOS_CALL
-#define ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
-#endif
-#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
-
-extern char input_data[];
-extern int input_len;
+static struct boot_params *real_mode; /* Pointer to real-mode data */
+/* Amount of memory in kilobytes, if it isn't set assume enough */
+static unsigned long mem_k = 0xFFFFFFFF;
+
+/* Variables in our header */
+extern unsigned long input_addr;
+extern unsigned long input_len;
+extern unsigned long output_overhang;
+extern unsigned long kernel_memsz;
+extern unsigned long kernel_filesz;
+
+/* External symbols */
+extern unsigned char move_routine_end[], move_routine_start[];
+extern unsigned char _end[];
 
 static long bytes_out = 0;
 static uch *output_data;
@@ -108,17 +102,15 @@
  
 static void puts(const char *);
   
-extern int end;
-static long free_mem_ptr = (long)&end;
-static long free_mem_end_ptr;
-
-#define INPLACE_MOVE_ROUTINE  0x1000
-#define LOW_BUFFER_START      0x2000
-#define LOW_BUFFER_MAX       0x90000
-#define HEAP_SIZE             0x3000
+#define HEAP_SIZE         0x003000
+static unsigned char heap[HEAP_SIZE];
+static unsigned long move_routine;
+static long free_mem_ptr = (unsigned long)&heap[0];
+static long free_mem_end_ptr = (unsigned long)&heap[HEAP_SIZE];
+
 static unsigned int low_buffer_end, low_buffer_size;
 static int high_loaded =0;
-static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
+static uch *high_buffer_start;
 
 static char *vidmem = (char *)0xb8000;
 static int vidport;
@@ -166,18 +158,22 @@
 {
 	int i;
 
-	memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
+	memmove ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
 	for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
 		vidmem[i] = ' ';
 }
 
+static int vid_initialized = 0;
 static void puts(const char *s)
 {
 	int x,y,pos;
 	char c;
 
-	x = SCREEN_INFO.orig_x;
-	y = SCREEN_INFO.orig_y;
+	if (!vid_initialized)
+		return;
+
+	x = real_mode->screen.info.orig_x;
+	y = real_mode->screen.info.orig_y;
 
 	while ( ( c = *s++ ) != '\0' ) {
 		if ( c == '\n' ) {
@@ -198,8 +194,8 @@
 		}
 	}
 
-	SCREEN_INFO.orig_x = x;
-	SCREEN_INFO.orig_y = y;
+	real_mode->screen.info.orig_x = x;
+	real_mode->screen.info.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
 	outb_p(14, vidport);
@@ -208,23 +204,19 @@
 	outb_p(0xff & (pos >> 1), vidport+1);
 }
 
-static void* memset(void* s, int c, size_t n)
+static void vid_puts_init(void)
 {
-	int i;
-	char *ss = (char*)s;
-
-	for (i=0;i<n;i++) ss[i] = c;
-	return s;
-}
-
-static void* memcpy(void* __dest, __const void* __src,
-			    size_t __n)
-{
-	int i;
-	char *d = (char *)__dest, *s = (char *)__src;
-
-	for (i=0;i<__n;i++) d[i] = s[i];
-	return __dest;
+	vid_initialized = 1;
+	if (real_mode->screen.info.orig_video_mode == 7) {
+		vidmem = (char *) 0xb0000;
+		vidport = 0x3b4;
+	} else {
+		vidmem = (char *) 0xb8000;
+		vidport = 0x3d4;
+	}
+	
+	lines = real_mode->screen.info.orig_video_lines;
+	cols = real_mode->screen.info.orig_video_cols;
 }
 
 /* ===========================================================================
@@ -233,14 +225,8 @@
  */
 static int fill_inbuf(void)
 {
-	if (insize != 0) {
-		error("ran out of input data\n");
-	}
-
-	inbuf = input_data;
-	insize = input_len;
-	inptr = 1;
-	return inbuf[0];
+	error("ran out of input data\n");
+	return 0;
 }
 
 /* ===========================================================================
@@ -302,18 +288,22 @@
 
 struct {
 	long * a;
-	short b;
-	} stack_start = { & user_stack [STACK_SIZE] , __KERNEL_DS };
+	} stack_start = { & user_stack [STACK_SIZE] };
+
+static char command_line[COMMAND_LINE_SIZE];
+
+extern struct initial_regs32 initial_regs;
+extern __u32 kernel_start;
 
-static void setup_normal_output_buffer(void)
+static void setup_normal_buffers(void)
 {
-#ifdef STANDARD_MEMORY_BIOS_CALL
-	if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
-#else
-	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory.\n");
-#endif
-	output_data = (char *)0x100000; /* Points to 1M */
-	free_mem_end_ptr = (long)real_mode;
+	/* Input buffers */
+	inbuf  = (uch *)input_addr;
+	insize = input_len; 
+	inptr  = 0;
+
+	/* Output buffers */
+	output_data = (char *)HIGH_BASE; /* Points to 1M */
 }
 
 struct moveparams {
@@ -321,26 +311,43 @@
 	uch *high_buffer_start; int hcount;
 };
 
-static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
+static void setup_buffers_if_we_run_high(struct moveparams *mv)
 {
-	high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
-#ifdef STANDARD_MEMORY_BIOS_CALL
-	if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n");
-#else
-	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory.\n");
-#endif	
-	mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
-	low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
-	  ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
-	low_buffer_size = low_buffer_end - LOW_BUFFER_START;
+	unsigned long high_compressed_start;
+	/* Ouput buffers */
+	high_buffer_start = _end;
+	move_routine = LOW_BASE;
+	mv->low_buffer_start = output_data = 
+		(char *)move_routine + (move_routine_end - move_routine_start);
+	low_buffer_end = ((unsigned int)real_mode > LOW_MAX
+	  ? LOW_MAX : (unsigned int)real_mode) & ~0xfff;
+	low_buffer_size = low_buffer_end - (unsigned long)mv->low_buffer_start;
 	high_loaded = 1;
-	free_mem_end_ptr = (long)high_buffer_start;
-	if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
-		high_buffer_start = (uch *)(0x100000 + low_buffer_size);
+	if ( (HIGH_BASE + low_buffer_size) > ((ulg)high_buffer_start)) {
+		high_buffer_start = (uch *)(HIGH_BASE + low_buffer_size);
 		mv->hcount = 0; /* say: we need not to move high_buffer */
 	}
 	else mv->hcount = -1;
 	mv->high_buffer_start = high_buffer_start;
+	if ((ulg)output_data >= low_buffer_end) output_data=high_buffer_start;
+
+	/* Input buffers */
+	inptr  = 0;
+	insize = input_len;
+	high_compressed_start = (ulg)high_buffer_start;
+	high_compressed_start -=low_buffer_size;
+	high_compressed_start += kernel_filesz + output_overhang;
+	high_compressed_start -= insize;
+	if (high_compressed_start > input_addr) {
+		inbuf = (uch *)high_compressed_start;
+	} else {
+		inbuf = (uch *)input_addr;
+	}
+	/* Move the compressed data to a location where the
+	 * decompressed data can overwrite it but will not
+	 * before it is used.
+	 */
+	memmove(inbuf, (void *)input_addr, insize);
 }
 
 static void close_output_buffer_if_we_run_high(struct moveparams *mv)
@@ -355,29 +362,103 @@
 	}
 }
 
-
-asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
+static void relocate_realmode(void)
 {
-	real_mode = rmode;
-
-	if (SCREEN_INFO.orig_video_mode == 7) {
-		vidmem = (char *) 0xb0000;
-		vidport = 0x3b4;
-	} else {
-		vidmem = (char *) 0xb8000;
-		vidport = 0x3d4;
+	unsigned long high_addr;
+	unsigned long new_real_mode, new_cmdline;
+	int cmdline_len;
+	char *cmdline;
+
+	/* Compute the highest address we can actually use */
+	if (initial_regs.ebp == ENTRY16) {
+		high_addr = real_mode->base_mem_k << 10;
+		/* To be safe enforce the 640K barrier */
+		if (high_addr > LOW_MAX) {
+			high_addr = LOW_MAX;
+		}
+	}
+	else {
+		high_addr = real_mode->real_base + real_mode->real_memsz;
+	}
+	/* To allow a maximal sized decompression buffer
+	 * we need to move the command line, and the real mode
+	 * buffer out of the way.
+	 */
+	/* Find the command line and get it out of the way */
+	cmdline = 0;
+	if (real_mode->cmd_line_ptr) {
+		cmdline = (char *)(real_mode->cmd_line_ptr);
 	}
+	else if (real_mode->screen.overlap.cl_magic == CL_MAGIC_VALUE) {
+		cmdline = (char *)real_mode + real_mode->screen.overlap.cl_offset;
+	}
+	cmdline_len = 0;
+	if (cmdline) {
+		while(cmdline_len < COMMAND_LINE_SIZE) {
+			cmdline_len++;
+			if (cmdline[cmdline_len -1] == '\0')
+				break;
+		}
+		memmove(command_line, cmdline, cmdline_len);
+		command_line[cmdline_len -1] = '\0';
+	}
+	/* relocate the real mode code and the command line */
+	new_real_mode = (high_addr - real_mode->real_filesz - DEF_HEAP_SIZE);
+	new_real_mode -= cmdline_len;
+	new_real_mode &= ~15;
+	new_cmdline = new_real_mode + real_mode->real_filesz + DEF_HEAP_SIZE;
+	memmove((void *)new_real_mode, real_mode, real_mode->real_filesz);
+	memmove((void *)new_cmdline, cmdline, cmdline_len);
+
+	/* Note the new real_mode address */
+	real_mode = (struct boot_params *)new_real_mode;
+	*((__u32 *)&initial_regs.esi) = new_real_mode;
+	/* Note the change in heap size */
+	real_mode->heap_end_ptr = (new_real_mode + 
+		real_mode->real_filesz + DEF_HEAP_SIZE - 0x200) & 0xffff;
+	/* Note the new command line address */
+	if (real_mode->cmd_line_ptr) {
+		real_mode->cmd_line_ptr = new_cmdline;
+	}
+	if (real_mode->screen.overlap.cl_magic == CL_MAGIC_VALUE) {
+		real_mode->screen.overlap.cl_offset = 
+			new_cmdline - (unsigned long)real_mode;
+	}
+}
 
-	lines = SCREEN_INFO.orig_video_lines;
-	cols = SCREEN_INFO.orig_video_cols;
+asmlinkage unsigned long decompress_kernel(struct moveparams *mv)
+{
+	/* If we don't know better assume we can't use any
+	 * real mode memory, and we have enough protected mode memory.
+	 */
+	real_mode = 0;
+	if ((initial_regs.ebp == ENTRY16) || (initial_regs.ebp == ENTRY32)) {
+		real_mode = (struct boot_params *)initial_regs.esi;
+	}
+	if (initial_regs.ebp == ENTRY16) {
+		vid_puts_init();
 
-	if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
-	else setup_output_buffer_if_we_run_high(mv);
+		mem_k = real_mode->screen.overlap.ext_mem_k;
+#ifndef STANDARD_MEMORY_BIOS_CALL
+		if (real_mode->alt_mem_k > mem_k) {
+			mem_k = real_mode->alt_mem_k;
+		}
+#endif
+		mem_k += 1024;
+	}
+	if (real_mode) {
+		relocate_realmode();
+	}
+	if ((mem_k << 10) < HIGH_BASE + kernel_memsz) {
+		error("Too little memory\n");
+	}
+	if (free_mem_ptr < HIGH_BASE) setup_normal_buffers();
+	else setup_buffers_if_we_run_high(mv);
 
 	makecrc();
 	puts("Uncompressing Linux... ");
 	gunzip();
 	puts("Ok, booting the kernel.\n");
 	if (high_loaded) close_output_buffer_if_we_run_high(mv);
-	return high_loaded;
+	return move_routine;
 }
diff -uNr linux-2.5.11/arch/i386/boot/compressed/vmlinuz.lds linux-2.5.11.boot.elf/arch/i386/boot/compressed/vmlinuz.lds
--- linux-2.5.11/arch/i386/boot/compressed/vmlinuz.lds	Wed Dec 31 17:00:00 1969
+++ linux-2.5.11.boot.elf/arch/i386/boot/compressed/vmlinuz.lds	Mon Apr 29 11:22:40 2002
@@ -0,0 +1,29 @@
+/* ld script to make compressed i386 Linux kernel
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(startup_32)
+SECTIONS
+{
+	. = 0x1000;
+	_text = .;			/* Text and read-only data */
+	.text : { *(.text) } = 0x9090
+	_etext = .;			/* End of text section */
+	.rodata : { *(.rodata) *(.rodata.*) }
+	.data : { 
+		*(.data) 
+		
+	}
+	_edata = .;			/* End of data section */
+	.bss _edata : { *(.bss) }
+	_end = .;
+	.input _edata : { 
+		input_data = . ;
+		*(.input)
+		input_data_end = . ;
+	}
+	input_data_len = input_data_end - input_data;
+	input_data_shift = _end - _edata;
+
+	/DISCARD/ : { *(*) }
+}		
diff -uNr linux-2.5.11/arch/i386/boot/realmode.lds linux-2.5.11.boot.elf/arch/i386/boot/realmode.lds
--- linux-2.5.11/arch/i386/boot/realmode.lds	Wed Dec 31 17:00:00 1969
+++ linux-2.5.11.boot.elf/arch/i386/boot/realmode.lds	Mon Apr 29 11:22:46 2002
@@ -0,0 +1,18 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+ENTRY(entry32)
+OUTPUT_ARCH(i386)
+SECTIONS
+{
+	.bootsect 0 : AT(0x10000) {
+		*(.bootsect)
+	}
+	.setup 0 : AT(LOADADDR(.bootsect) + SIZEOF(.bootsect)) {
+		*(.setup)
+	}
+	.setup.heap SIZEOF(.setup) : AT(LOADADDR(.setup) + SIZEOF(.setup)) {
+		*(.setup.heap)
+	}
+	/DISCARD/ : {
+		*(*)
+	}
+}
diff -uNr linux-2.5.11/arch/i386/boot/setup.S linux-2.5.11.boot.elf/arch/i386/boot/setup.S
--- linux-2.5.11/arch/i386/boot/setup.S	Mon Apr 29 00:17:11 2002
+++ linux-2.5.11.boot.elf/arch/i386/boot/setup.S	Mon Apr 29 11:22:46 2002
@@ -45,6 +45,12 @@
  * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
  * by Robert Schwebel, December 2001 <robert@schwebel.de>
  *
+ * Update boot protocol to version 2.04
+ * - Add support for a compiled in command line.
+ * - Add support for a 32bit kernel entry point
+ * - Stop information loss when bzImage is created
+ * Eric Biederman 29 March 2002 <ebiederm@xmission.com>
+ *
  */
 
 #include <linux/config.h>
@@ -59,6 +65,20 @@
 #define SIG1	0xAA55
 #define SIG2	0x5A5A
 
+#ifndef __BIG_KERNEL__
+#define KERNEL_START LOW_BASE		/* zImage */
+#else
+#define KERNEL_START HIGH_BASE 		/* bzImage */
+#endif
+
+#define DELTA_BOOTSECT 512
+
+/* Segments used by setup.S */
+#define __SETUP_CS      0x10
+#define __SETUP_DS      0x18
+#define __SETUP_REAL_CS 0x20
+#define __SETUP_REAL_DS 0x28
+
 INITSEG  = DEF_INITSEG		# 0x9000, we move boot here, out of the way
 SYSSEG   = DEF_SYSSEG		# 0x1000, system loaded at 0x10000 (65536).
 SETUPSEG = DEF_SETUPSEG		# 0x9020, this is the current segment
@@ -67,27 +87,22 @@
 DELTA_INITSEG = SETUPSEG - INITSEG	# 0x0020
 
 .code16
-.globl begtext, begdata, begbss, endtext, enddata, endbss
+.globl _setup, _esetup
 
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
+.section ".setup", "ax", @progbits
+_setup:	
 
 start:
 	jmp	trampoline
 
 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
 
-		.ascii	"HdrS"		# header signature
-		.word	0x0203		# header version number (>= 0x0105)
+header_magic:	.ascii	"HdrS"		# header signature
+version:	.word	0x0204		# header version number (>= 0x0105)
 					# or else old loadlin-1.5 will fail)
 realmode_swtch:	.word	0, 0		# default_switch, SETUPSEG
 start_sys_seg:	.word	SYSSEG
-		.word	kernel_version	# pointing to kernel version string
+kernel_version:	.word	kversion_str	# pointing to kernel version string
 					# above section of header is compatible
 					# with loadlin-1.5 (header v1.5). Don't
 					# change it.
@@ -100,6 +115,8 @@
 # flags, unused bits must be zero (RFU) bit within loadflags
 loadflags:
 LOADED_HIGH	= 1			# If set, the kernel is loaded high
+STAY_PUT        = 0x40                  # If set, the loader doesn't expect
+                                        # us to relocate anything
 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
@@ -118,31 +135,26 @@
 					# loader knows how much data behind
 					# us also needs to be loaded.
 
-code32_start:				# here loaders can put a different
+code32_start:	.long	KERNEL_START	# here loaders can put a different
 					# start address for 32-bit code.
-#ifndef __BIG_KERNEL__
-		.long	0x1000		#   0x1000 = default for zImage
-#else
-		.long	0x100000	# 0x100000 = default for big kernel
-#endif
 
-ramdisk_image:	.long	0		# address of loaded ramdisk image
+initrd_start:	.long	0		# address of loaded ramdisk image
 					# Here the loader puts the 32-bit
 					# address where it loaded the image.
 					# This only will be read by the kernel.
 
-ramdisk_size:	.long	0		# its size in bytes
+initrd_size:	.long	0		# its size in bytes
 
 bootsect_kludge:
-		.word  bootsect_helper, SETUPSEG
+		.word	bootsect_helper, SETUPSEG
 
-heap_end_ptr:	.word	modelist+1024	# (Header version 0x0201 or later)
+heap_end_ptr:	.word	_esetup_heap	# (Header version 0x0201 or later)
 					# space from here (exclusive) down to
 					# end of setup code can be used by setup
 					# for local heap purposes.
 
 pad1:		.word	0
-cmd_line_ptr:	.long 0			# (Header version 0x0202 or later)
+cmd_line_ptr:	.long	0		# (Header version 0x0202 or later)
 					# If nonzero, a 32-bit pointer
 					# to the kernel command line.
 					# The command line should be
@@ -157,16 +169,48 @@
 					# can be located anywhere in
 					# low memory 0x10000 or higher.
 
-ramdisk_max:	.long __MAXMEM-1	# (Header version 0x0203 or later)
+ramdisk_max:	.long	__MAXMEM-1	# (Header version 0x0203 or later)
 					# The highest safe address for
 					# the contents of an initrd
 
+entry32_off:	.word	entry32 - _setup + DELTA_BOOTSECT
+					# offset of the 32bit entry point
+					# relative to the start of
+					# the real mode kernel
+
+internal_cmdline_off:			# offset of compiled in	command line
+		.word	internal_command_line - _setup + DELTA_BOOTSECT
+real_base:	.long	REAL_BASE	# Location of real mode kernel
+real_memsz:				# Memory usage of real mode kernel
+		.long	(_esetup_heap - _setup) + DELTA_BOOTSECT
+real_filesz:				# Datasize of the real mode kernel
+		.long (_esetup - _setup) + DELTA_BOOTSECT
+kern_base:	.long	KERNEL_START	# Kernel load address
+kern_memsz:	.long	0x00000000	# Kernel memory usage
+kern_filesz:	.long	0x00000000	# Kernel datasize
+# variables private to the kernel (not for bootloaders)
+entry32_used:	.long	0x00000000
+entry32_16_off:	.long	protected_to_real - _setup + DELTA_BOOTSECT
+eax:		.long	0x00000000
+ebx:		.long	0x00000000
+ecx:		.long	0x00000000
+edx:		.long	0x00000000
+esi:		.long	0x00000000
+edi:		.long	0x00000000
+esp:		.long	0x00000000
+ebp:		.long	0x00000000
 trampoline:	call	start_of_setup
-		.space	1024
+		# Don't let the E820 map overlap code
+		. = (E820MAP - DELTA_BOOTSECT) + (E820MAX * E820ENTRY_SIZE)
 # End of setup header #####################################################
 
 start_of_setup:
+#ifndef __BIG_KERNEL__
 # Bootlin depends on this being done early
+#NOTE:  Bootlin was written before the kernel had hooks for anything
+# 	used the BIOS calls setup.S made as hooks (ouch!)
+#       Bootlin only loaded zImages, so we can drop support for it
+#       when we are loading a bzImage.
 	movw	$0x01500, %ax
 	movb	$0x81, %dl
 	int	$0x13
@@ -177,6 +221,7 @@
 	movb	$0x80, %dl
 	int	$0x13
 #endif
+#endif /* __BIG_KERNEL__ */
 
 # Set %ds = %cs, we know that SETUPSEG = %cs at this point
 	movw	%cs, %ax		# aka SETUPSEG
@@ -226,6 +271,7 @@
 
 # We now have to find the rest of the setup code/data
 bad_sig:
+#ifndef __BIG_KERNEL__
 	movw	%cs, %ax			# SETUPSEG
 	subw	$DELTA_INITSEG, %ax		# INITSEG
 	movw	%ax, %ds
@@ -255,7 +301,7 @@
 	jne	no_sig
 
 	jmp	good_sig
-
+#endif /* __BIG_KERNEL__ */
 no_sig:
 	lea	no_sig_mess, %si
 	call	prtstr
@@ -268,10 +314,8 @@
 	movw	%cs, %ax			# aka SETUPSEG
 	subw	$DELTA_INITSEG, %ax 		# aka INITSEG
 	movw	%ax, %ds
+#ifdef __BIG_KERNEL__
 # Check if an old loader tries to load a big-kernel
-	testb	$LOADED_HIGH, %cs:loadflags	# Do we have a big kernel?
-	jz	loader_ok			# No, no danger for old loaders.
-
 	cmpb	$0, %cs:type_of_loader 		# Do we have a loader that
 						# can deal with us?
 	jnz	loader_ok			# Yes, continue.
@@ -284,8 +328,18 @@
 	jmp	no_sig_loop
 
 loader_panic_mess: .string "Wrong loader, giving up..."
+#endif /* __BIG_KERNEL__ */
 
 loader_ok:
+# Get base memory size
+# The size in kilobytes is returned in %ax
+# There shouldn't be any subfunctions but just
+# in case we clear eax and ecx
+	xorl	%eax, %eax
+	xorl	%ecx, %ecx
+	int	$0x12
+	movw	%ax, (0x1e4)
+	
 # Get memory size (extended mem, kB)
 
 	xorl	%eax, %eax
@@ -337,7 +391,7 @@
 
 	incb	(E820NR)
 	movw	%di, %ax
-	addw	$20, %ax
+	addw	$E820ENTRY_SIZE, %ax
 	movw	%ax, %di
 again820:
 	cmpl	$0, %ebx			# check to see if
@@ -561,15 +615,8 @@
 	movl	%cs:code32_start, %eax
 	movl	%eax, %cs:code32
 
-# Now we move the system to its rightful place ... but we check if we have a
-# big-kernel. In that case we *must* not move it ...
-	testb	$LOADED_HIGH, %cs:loadflags
-	jz	do_move0			# .. then we have a normal low
-						# loaded zImage
-						# .. or else we have a high
-						# loaded bzImage
-	jmp	end_move			# ... and we skip moving
-
+#ifndef __BIG_KERNEL__
+# Move the kernel image where it expects to be loaded.
 do_move0:
 	movw	$0x100, %ax			# start of destination segment
 	movw	%cs, %bp			# aka SETUPSEG
@@ -595,15 +642,18 @@
 	jb	do_move
 
 end_move:
+#endif /* !__BIG_KERNEL__ */
+	
 # then we load the segment descriptors
 	movw	%cs, %ax			# aka SETUPSEG
 	movw	%ax, %ds
-		
+
 # Check whether we need to be downward compatible with version <=201
+# We don't relocate if STAY_PUT is specified or we have a 202 cmd_line
+	testb  	$STAY_PUT, loadflags
+	jnz	end_move_self
 	cmpl	$0, cmd_line_ptr
 	jne	end_move_self		# loader uses version >=202 features
-	cmpb	$0x20, type_of_loader
-	je	end_move_self		# bootsect loader, we know of it
 
 # Boot loader doesnt support boot protocol version 2.02.
 # If we have our code not at 0x90000, we need to move it there now.
@@ -795,13 +845,22 @@
 	jmp	flush_instr
 
 flush_instr:
-	xorw	%bx, %bx			# Flag to indicate a boot
 	xorl	%esi, %esi			# Pointer to real-mode code
 	movw	%cs, %si
 	subw	$DELTA_INITSEG, %si
 	shll	$4, %esi			# Convert to 32-bit pointer
+	movl	$ENTRY16, %ebp			# Magic to indicate 16bit entry
+
+# Setup the data segments
+	movw	$(__SETUP_DS), %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	movw	%ax, %ss
+
 # NOTE: For high loaded big kernels we need a
-#	jmpi    0x100000,__KERNEL_CS
+#	jmpi    0x100000,__SETUP_CS
 #
 #	but we yet haven't reloaded the CS register, so the default size 
 #	of the target offset still is 16 bit.
@@ -812,10 +871,10 @@
 	.byte 0x66, 0xea			# prefix + jmpi-opcode
 code32:	.long	0x1000				# will be set to 0x100000
 						# for big kernels
-	.word	__KERNEL_CS
+	.word	__SETUP_CS
 
 # Here's a bunch of information about your current kernel..
-kernel_version:	.ascii	UTS_RELEASE
+kversion_str:	.ascii	UTS_RELEASE
 		.ascii	" ("
 		.ascii	LINUX_COMPILE_BY
 		.ascii	"@"
@@ -842,6 +901,7 @@
 	jnz	bootsect_second
 
 	movb	$0x20, %cs:type_of_loader
+	orb	$STAY_PUT, %cs:loadflags
 	movw	%es, %ax
 	shrw	$4, %ax
 	movb	%ah, %cs:bootsect_src_base+2
@@ -1004,29 +1064,175 @@
 	outb	%al,$0x80
 	ret
 
+	.code32
+	.globl entry32
+entry32:
+	testl	%esp, %esp
+	jnz	1f
+	/* If there isn't a valid stack pointer assume
+	 * we are loaded at our default address and put
+	 * a temporary stack a _esetup_heap.
+	 */
+	movl	%esp, (REAL_BASE + _esetup_heap - _setup - 4)
+	movl	$(REAL_BASE + _esetup_heap - _setup - 4), %esp
+	jmp	2f
+1:	pushl	%esp
+2:	pushl	%esi
+	call	3f
+3:	popl	%esi
+	subl	$(3b - _setup), %esi
+	movl	%eax, eax - _setup(%esi)
+	movl	%ebx, ebx - _setup(%esi)
+	movl	%ebx, ebx - _setup(%esi)
+	movl	%ecx, ecx - _setup(%esi)
+	movl	%edx, edx - _setup(%esi)
+	popl	%eax
+	movl	%eax, esi - _setup(%esi)
+	movl	%edi, edi - _setup(%esi)
+	movl	%ebp, ebp - _setup(%esi)
+	popl	%esp
+	movl	%esp, esp - _setup(%esi)
+
+	/* Magic to indicate 32bit entry */
+	movl	$ENTRY32, %ebp
+	movl	%ebp, entry32_used - _setup(%esi)
+
+	/* Pointer to real mode code */
+	subl	$(DELTA_INITSEG << 4), %esi
+
+	/* Start address for 32-bit code */
+	movl	$KERNEL_START, %ebx
+	jmpl	*%ebx
+
+protected_to_real:
+	cli
+	/* Get pointer to start */
+	call	1f
+1:	popl	%esi
+	subl	$(1b - _setup), %esi
+
+	/* Fixup my real mode segment */
+	movl	%esi, %eax
+	shrl	$4, %eax
+	movw	%ax, 2 + realptr - _setup(%esi)
+
+	/* Compute the gdt fixup */
+	movl	%esi, %eax
+	shll	$16, %eax			# Base low
+
+	movl	%esi, %ebx
+	shrl	$16, %ebx
+	andl	$0xff, %ebx
+
+	movl	%esi, %edx
+	andl	$0xff000000, %edx
+	orl	%edx, %ebx			# Base high
+
+	/* Fixup the gdt */
+	andl	$0x0000ffff, (gdt - _setup + __SETUP_REAL_CS)(%esi)
+	orl	%eax,        (gdt - _setup + __SETUP_REAL_CS)(%esi)
+	andl	$0x00ffff00, (gdt - _setup + __SETUP_REAL_CS + 4)(%esi)
+	orl	%ebx,        (gdt - _setup + __SETUP_REAL_CS + 4)(%esi)
+	andl	$0x0000ffff, (gdt - _setup + __SETUP_REAL_DS)(%esi)
+	orl	%eax,        (gdt - _setup + __SETUP_REAL_DS)(%esi)
+	andl	$0x00ffff00, (gdt - _setup + __SETUP_REAL_DS + 4)(%esi)
+	orl	%ebx,        (gdt - _setup + __SETUP_REAL_DS + 4)(%esi)
+
+	/* Fixup gdt_48 */
+	leal	gdt - _setup(%esi), %eax	# Compute gdt_base
+	movl	%eax, gdt_48 +2 - _setup(%esi)	# Store gdt_base
+
+	/* Setup the classic BIOS interrupt table at 0x0 */
+	lidt	idt_real - _setup(%esi)
+	
+	/* Load 16bit segments we can use */
+	lgdt	gdt_48 - _setup(%esi)
+
+	/* Don't disable the a20 line, (this shouldn't be required) */
+
+	/* Load 16bit data segments, to ensure the segment limits are set */
+	movl	$__SETUP_REAL_DS, %ebx
+	movl	%ebx, %ds
+	movl	%ebx, %es
+	movl	%ebx, %ss
+	movl	%ebx, %fs
+	movl	%ebx, %gs
+
+	/* switch to 16bit mode */
+	ljmp	$__SETUP_REAL_CS, $1f - _setup
+1:
+	.code16
+	/* Disable Paging and protected mode */
+	/* clear the PG & PE bits of CR0 */
+	movl	%cr0,%eax
+	andl	$~((1 << 31)|(1<<0)),%eax
+	movl	%eax,%cr0
+
+	/* make intersegment jmp to flush the processor pipeline
+	 * and reload %cs:%eip (to clear upper 16 bits of %eip).
+	 */
+	ljmp	*(realptr - _setup)
+2:
+	/* we are in real mode now
+	 * set up the real mode segment registers : %ds, %ss, %es, %gs, %fs
+	 */
+	movw	%cs, %ax
+	/* Put the data segments in INITSEG */
+	subw	$DELTA_INITSEG, %ax
+	movw	%ax, %ds
+	movw	%ax, %es
+	movw	%ax, %fs
+	movw	%ax, %gs
+	/* Put the stack ss:sp at the end of the heap */
+	movw	%cs, %ax
+	movw	%cs:heap_end_ptr, %bx
+	movw	%ax, %ss
+	movw	%bx, %sp
+	jmp	start
+	
+realptr:
+	.word	2b - _setup
+	.word	0x0000
+
 # Descriptor tables
 gdt:
 	.word	0, 0, 0, 0			# dummy
 	.word	0, 0, 0, 0			# unused
 
-	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
+	.word	0xFFFF				# 32bit 4GB - (0x100000*0x1000 = 4GB)
 	.word	0				# base address = 0
-	.word	0x9A00				# code read/exec
-	.word	0x00CF				# granularity = 4096, 386
+	.byte	0x00, 0x9B			# code read/exec/accessed
+	.byte	0xCF, 0x00			# granularity = 4096, 386
 						#  (+5th nibble of limit)
 
-	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
+	.word	0xFFFF				# 32bit 4GB - (0x100000*0x1000 = 4GB)
 	.word	0				# base address = 0
-	.word	0x9200				# data read/write
-	.word	0x00CF				# granularity = 4096, 386
+	.byte	0x00, 0x93			# data read/write/accessed
+	.byte	0xCF, 0x00			# granularity = 4096, 386
 						#  (+5th nibble of limit)
+
+	.word	0xFFFF				# 16bit 64KB - (0x10000*1 = 64KB)
+	.word	0				# base address = SETUPSEG
+	.byte	0x00, 0x9b			# code read/exec/accessed
+	.byte	0x00, 0x00			# granularity = bytes
+
+
+	.word	0xFFFF				# 16bit 64KB - (0x10000*1 = 64KB)
+	.word	0				# base address = SETUPSEG
+	.byte	0x00, 0x93			# data read/write/accessed
+	.byte	0x00, 0x00			# granularity = bytes
+gdt_end:
+	
 idt_48:
 	.word	0				# idt limit = 0
 	.word	0, 0				# idt base = 0L
-gdt_48:
-	.word	0x8000				# gdt limit=2048,
-						#  256 GDT entries
 
+idt_real:
+	.word	0x400 - 1			# idt limit ( 256 entries)
+	.word	0, 0				# idt base = 0L
+	
+gdt_48:
+	.word	gdt_end - gdt - 1		# gdt limit
 	.word	0, 0				# gdt base (filled in later)
 
 # Include video setup & detection code
@@ -1039,12 +1245,10 @@
 
 # After this point, there is some free space which is used by the video mode
 # handling code to store the temporary mode table (not used by the kernel).
-
-modelist:
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
+internal_command_line:
+	.asciz CONFIG_CMDLINE
+_esetup:
+.section ".setup.heap", "a", @nobits
+_setup_heap:
+. = DEF_HEAP_SIZE
+_esetup_heap:
diff -uNr linux-2.5.11/arch/i386/boot/tools/build.c linux-2.5.11.boot.elf/arch/i386/boot/tools/build.c
--- linux-2.5.11/arch/i386/boot/tools/build.c	Mon Jul  2 14:56:40 2001
+++ linux-2.5.11.boot.elf/arch/i386/boot/tools/build.c	Mon Apr 29 11:23:04 2002
@@ -1,19 +1,24 @@
+
 /*
  *  $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1997 Martin Mares
+ *  Copyright (C) 2002 Eric Biederman
+ *
  */
 
 /*
  * This file builds a disk-image from three different files:
  *
- * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
- * - setup: 8086 machine code, sets up system parm
+ * - vmlinux: kernel before compression
+ * - realmode: composed of:
+ *    - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ *    - setup: 8086 machine code, sets up system parm
  * - system: 80386 code for actual system
  *
  * It does some checking that all files are of the correct type, and
- * just writes the result to stdout, removing headers and padding to
+ * just writes the result, removing headers and padding to
  * the right amount. It also writes some system data to stderr.
  */
 
@@ -22,34 +27,280 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  * Cross compiling fixes by Gertjan van Wingerde, July 1996
  * Rewritten by Martin Mares, April 1997
+ * Rewriten by Eric Biederman to remove the need for objcopy and
+ *   to stop losing information. 29 Mary 2002
  */
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <byteswap.h>
+#include <endian.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/sysmacros.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <errno.h>
+#include <elf.h>
+/* To stay in sync with the kernel we must include these headers */
+#include <linux/version.h>
+#include <linux/compile.h>
 #include <asm/boot.h>
 
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long u32;
-
 #define DEFAULT_MAJOR_ROOT 0
 #define DEFAULT_MINOR_ROOT 0
 
 /* Minimal number of setup sectors (see also bootsect.S) */
 #define SETUP_SECTS 4
 
-byte buf[1024];
-int fd;
-int is_big_kernel;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(x) x
+#define cpu_to_le32(x) x
+#define cpu_to_le64(x) x
+#define le16_to_cpu(x) x
+#define le32_to_cpu(x) x
+#define le64_to_cpu(x) x
+#else
+#define cpu_to_le16(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define cpu_to_le64(x) bswap_64(x)
+#define le16_to_cpu(x) bswap_16(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define le64_to_cpu(x) bswap_64(x)
+#endif
+
+
+/* Input segments */
+#define IKERN  0
+#define IREAL  1
+#define IZKERN 2
+#define ISEGS  3
+
+/* Segments of the output file */
+#define OEHDR 0
+#define OREAL 1
+#define OKERN 2
+#define OBSS1 3
+#define OBSS2 4
+#define OSEGS 5
+
+struct file_seg
+{
+	size_t mem_addr;
+	size_t mem_size;
+	size_t data_size;
+	off_t  file_offset;
+	size_t entry;
+	unsigned char *data;
+};
+
+/* Kernel version */
+#define LINUX_KERNEL_VERSION \
+	UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") " UTS_VERSION
+
+typedef uint16_t Elf_Half;
+typedef uint32_t Elf_Word;
+typedef uint64_t Elf_Xword;
+
+typedef struct 
+{
+	Elf_Word n_namesz;		/* Length of the note's name.  */
+	Elf_Word n_descsz;		/* Length of the note's descriptor.  */
+	Elf_Word n_type;		/* Type of the note.  */
+} Elf_Nhdr;
 
-void die(const char * str, ...)
+typedef struct 
+{
+	Elf_Word n_paddr;
+	Elf_Word n_size;
+} Elf_Pdesc;
+
+/*  Elf image notes for booting... The name for all of these is ELFBoot */
+
+#define EIN_NOTE_NAME	"ELFBoot"
+#define EIN_PROGRAM_NAME	0x00000001
+/* The program in this ELF file */
+#define EIN_PROGRAM_VERSION	0x00000002
+/* The version of the program in this ELF file */
+#define EIN_PROGRAM_CHECKSUM	0x00000003
+/* ip style checksum of the memory image. */
+
+struct boot_params {
+	uint8_t  reserved1[0x1f1];		/* 0x000 */
+	uint8_t  setup_sects;			/* 0x1f1 */
+	uint16_t mount_root_rdonly;		/* 0x1f2 */
+	uint16_t syssize;			/* 0x1f4 */
+	uint16_t swapdev;			/* 0x1f6 */
+	uint16_t ramdisk_flags;			/* 0x1f8 */
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000	
+	uint16_t vid_mode;			/* 0x1fa */
+	uint16_t root_dev;			/* 0x1fc */
+	uint8_t  reserved9[1];			/* 0x1fe */
+	uint8_t  aux_device_info;		/* 0x1ff */
+	/* 2.00+ */
+	uint8_t  jump[2];			/* 0x200 */
+	uint8_t  header_magic[4];		/* 0x202 */
+	uint16_t version;			/* 0x206 */
+	uint8_t  reserved11[8];			/* 0x208 */
+	uint8_t  type_of_loader;		/* 0x210 */
+#define LOADER_LILO            0x00
+#define LOADER_LOADLIN         0x10
+#define LOADER_BOOTSECT_LOADER 0x20
+#define LOADER_SYSLINUX        0x30
+#define LOADER_ETHERBOOT       0x40
+#define LOADER_UNKNOWN         0xFF
+	uint8_t  loadflags;			/* 0x211 */
+#define LOADFLAG_LOADED_HIGH  1
+#define LOADFLAG_STAY_PUT     0x40
+#define LOADFLAG_CAN_USE_HEAP 0x80
+	uint8_t  reserved12[2];			/* 0x212 */
+	uint32_t code32_start;			/* 0x214 */
+	uint32_t initrd_start;			/* 0x218 */
+	uint32_t initrd_size;			/* 0x21c */
+	uint8_t  reserved13[4];			/* 0x220 */
+	/* 2.01+ */
+	uint16_t heap_end_ptr;			/* 0x224 */
+	uint8_t  reserved14[2];			/* 0x226 */
+	/* 2.02+ */
+	uint32_t cmd_line_ptr;			/* 0x228 */
+	/* 2.03+ */
+	uint32_t ramdisk_max;			/* 0x22c */
+	/* 2.04+ */
+	uint16_t entry32_off;			/* 0x230 */
+	uint16_t internal_cmdline_off;		/* 0x232 */
+	uint32_t real_base;			/* 0x240 */
+	uint32_t real_memsz;			/* 0x244 */
+	uint32_t real_filesz;			/* 0x248 */
+	uint32_t kern_base;			/* 0x24C */
+	uint32_t kern_memsz;			/* 0x250 */
+	uint32_t kern_filesz;			/* 0x254 */
+						/* 0x258 */
+};
+
+#define OF(args) args
+#define STATIC static
+				/* and a power of two */
+
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#define memzero(s, n) memset ((s), 0, (n))
+
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000         /* Window size must be at least 32k, */
+
+static uch *inbuf;           /* input buffer */
+static uch window[WSIZE];    /* Sliding window buffer */
+
+static unsigned insize = 0;  /* valid bytes in inbuf */
+static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0;  /* bytes in output buffer */
+
+static long bytes_out = 0;
+
+#define get_byte()  (inptr<insize?inbuf[inptr++]:(die("missing input data\n"),0))
+#define error(m) die(m)
+static void flush_window(void);
+#define gzip_mark(x) 
+#define gzip_release(x)
+
+static void die(const char * str, ...);
+
+#include "../../../../lib/inflate.c"
+
+struct zkernel_header {
+	/* 2.04+ */
+	uint8_t  jump[4];
+	uint32_t input_addr;
+	uint32_t input_len;
+	uint32_t output_overhang;
+	uint32_t kernel_base;
+	uint32_t kernel_memsz;
+	uint32_t kernel_filesz;
+	uint32_t unzip_memsz;
+	uint32_t unzip_filesz;
+};
+
+static struct overhang_info {
+	size_t overhang;
+	size_t output_bytes;
+} oh;
+static void flush_window(void)
+{
+	size_t input_bytes_left;
+	size_t output_bytes_left;
+	size_t overhang;
+	unsigned long lcrc = crc;
+	unsigned i;
+
+	/* Flush the window */
+	for(i = 0; i < outcnt; i++) {
+		unsigned char ch;
+		ch = window[i];
+		lcrc = crc_32_tab[((int)lcrc ^ ch) & 0xff] ^ (lcrc >> 8);
+	}
+	crc = lcrc;
+	bytes_out += outcnt;
+	outcnt = 0;
+	
+	input_bytes_left = insize - inptr;
+	output_bytes_left = oh.output_bytes - bytes_out;
+
+	overhang = 0;
+	if (input_bytes_left > output_bytes_left) {
+		overhang = input_bytes_left - output_bytes_left;
+	}
+	if (overhang > oh.overhang) {
+		oh.overhang = overhang;
+	}
+}
+static size_t compute_unzip_overhang(struct file_seg *iseg)
+{
+	struct zkernel_header *zhdr;
+	unsigned char *data;
+	size_t data_size;
+	size_t result_size;
+	size_t offset;
+	
+	/* Set up the input buffer */
+	data = iseg[IZKERN].data;
+	data_size = iseg[IZKERN].data_size;
+	zhdr = (struct zkernel_header *)data;
+	offset = le32_to_cpu(zhdr->input_addr) - iseg[IZKERN].mem_addr;
+	inbuf = data + offset;
+	insize = le32_to_cpu(zhdr->input_len);
+	if (insize != data_size - offset)
+		die("Compressed kernel sizes(%d,%d) do not match!\n",
+			insize, data_size - offset);
+	result_size = le32_to_cpu(*(uint32_t *)(inbuf + insize - 4));
+	if (result_size != iseg[IKERN].data_size)
+		die("Uncompressed kernel sizes(%d,%d) do not match!\n",
+			result_size, iseg[IKERN].data_size);
+	inptr = 0;
+
+	/* Setup the overhang computation */
+	oh.overhang = 0;
+	oh.output_bytes = result_size;
+	
+	makecrc();
+	gunzip();
+	
+	return oh.overhang;
+}
+
+static void die(const char * str, ...)
 {
 	va_list args;
 	va_start(args, str);
@@ -58,132 +309,622 @@
 	exit(1);
 }
 
-void file_open(const char *name)
+static int checked_open(const char *pathname, int flags, mode_t mode)
 {
-	if ((fd = open(name, O_RDONLY, 0)) < 0)
-		die("Unable to open `%s': %m", name);
+	int result;
+	result = open(pathname, flags, mode);
+	if (result < 0) {
+		die("Cannot open %s : %s", 
+			pathname,
+			strerror(errno));
+	}
+	return result;
 }
 
-void usage(void)
+static void checked_read(int fd, void *buf, size_t count, const char *pathname)
 {
-	die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
+	ssize_t result;
+	result = read(fd, buf, count);
+	if (result != count) {
+		die("Cannot read %d bytes from %s: %s",
+			count, 
+			pathname,
+			strerror(errno));
+	}
 }
 
-int main(int argc, char ** argv)
+static void checked_write(int fd, void *buf, size_t count, const char *pathname)
 {
-	unsigned int i, c, sz, setup_sectors;
-	u32 sys_size;
-	byte major_root, minor_root;
-	struct stat sb;
-
-	if (argc > 2 && !strcmp(argv[1], "-b"))
-	  {
-	    is_big_kernel = 1;
-	    argc--, argv++;
-	  }
-	if ((argc < 4) || (argc > 5))
-		usage();
-	if (argc > 4) {
-		if (!strcmp(argv[4], "CURRENT")) {
-			if (stat("/", &sb)) {
-				perror("/");
-				die("Couldn't stat /");
+	ssize_t result;
+	result = write(fd, buf, count);
+	if (result != count) {
+		die("Cannot write %d bytes from %s: %s",
+			count, 
+			pathname,
+			strerror(errno));
+	}
+}
+
+static off_t checked_lseek(int fd, off_t offset, int whence, const char *pathname)
+{
+	off_t result;
+	result = lseek(fd, offset, whence);
+	if (result == (off_t)-1) {
+		die("lseek failed on %s: %s",
+			pathname, strerror(errno));
+	}
+	return result;
+}
+
+static void *checked_malloc(size_t size)
+{
+	void *result;
+	result = malloc(size);
+	if (result == 0) {
+		die("malloc of %d bytes failed: %s",
+			size, strerror(errno));
+	}
+	return result;
+}
+
+static unsigned long compute_ip_checksum(void *addr, unsigned long length)
+{
+	uint16_t *ptr;
+	unsigned long sum;
+	unsigned long len;
+	unsigned long laddr;
+	/* compute an ip style checksum */
+	laddr = (unsigned long )addr;
+	sum = 0;
+	if (laddr & 1) {
+		uint16_t buffer;
+		unsigned char *ptr;
+		/* copy the first byte into a 2 byte buffer.
+		 * This way automatically handles the endian question
+		 * of which byte (low or high) the last byte goes in.
+		 */
+		buffer = 0;
+		ptr = addr;
+		memcpy(&buffer, ptr, 1);
+		sum += buffer;
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+		length -= 1;
+		addr = ptr +1;
+	}
+	len = length >> 1;
+	ptr = addr;
+	while (len--) {
+		sum += *(ptr++);
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+	}
+	addr = ptr;
+	if (length & 1) {
+		uint16_t buffer;
+		unsigned char *ptr;
+		/* copy the last byte into a 2 byte buffer.
+		 * This way automatically handles the endian question
+		 * of which byte (low or high) the last byte goes in.
+		 */
+		buffer = 0;
+		ptr = addr;
+		memcpy(&buffer, ptr, 1);
+		sum += buffer;
+		if (sum > 0xFFFF)
+			sum -= 0xFFFF;
+	}
+	return (~sum) & 0xFFFF;
+	
+}
+
+static unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)
+{
+	unsigned long checksum;
+	sum = ~sum & 0xFFFF;
+	new = ~new & 0xFFFF;
+	if (offset & 1) {
+		/* byte swap the sum if it came from an odd offset 
+		 * since the computation is endian independant this
+		 * works.
+		 */
+		new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
+	}
+	checksum = sum + new;
+	if (checksum > 0xFFFF) {
+		checksum -= 0xFFFF;
+	}
+	return (~checksum) & 0xFFFF;
+}
+
+static void check_ehdr(Elf32_Ehdr *ehdr, char *name)
+{
+	/* Do some basic to ensure it is an ELF image */
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
+		die("%s is not an ELF binary", name);
+	}
+	if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
+		die("%s is not a 32bit ELF object", name);
+	}
+	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+		die("%s does not have little endian data", name);
+	}
+	if ((ehdr->e_ident[EI_VERSION] != EV_CURRENT) ||
+		ehdr->e_version != EV_CURRENT) {
+		die("%s has invalid ELF version", name);
+	}
+	if (ehdr->e_type != ET_EXEC) {
+		die("%s is not an ELF executable", name);
+	}
+	if (ehdr->e_machine != EM_386) {
+		die("%s is not for x86", name);
+	}
+	if ((ehdr->e_phoff == 0) || (ehdr->e_phnum == 0)) {
+		die("%s has no program header", name);
+	}
+	if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) {
+		die("%s has invalid program header size", name);
+	}
+}
+
+static Elf32_Phdr *read_sorted_phdr(char *name, int fd, 
+	Elf32_Ehdr *ehdr, struct file_seg *seg)
+{
+	int i, j;
+	Elf32_Phdr *phdr, *plow, *phigh;
+	size_t phdr_size;
+	seg->mem_addr = 0;
+	seg->mem_size = 0;
+	seg->data_size = 0;
+	seg->file_offset = 0;
+	seg->entry = ehdr->e_entry;
+	seg->data = 0;
+
+	phdr_size = ehdr->e_phnum * sizeof(*phdr);
+	phdr = checked_malloc(phdr_size);
+	checked_lseek(fd, ehdr->e_phoff, SEEK_SET, name);
+	checked_read(fd, phdr, phdr_size, name);
+
+	plow = 0;
+	phigh = 0;
+	/* Do an insertion sort on the program headers */
+	for(i = 0; i < ehdr->e_phnum; i++) {
+		Elf32_Phdr *least;
+		least = phdr +i;
+		for(j = i+1; j < ehdr->e_phnum; j++) {
+			if (phdr[j].p_type != PT_LOAD) {
+				continue;
 			}
-			major_root = major(sb.st_dev);
-			minor_root = minor(sb.st_dev);
-		} else if (strcmp(argv[4], "FLOPPY")) {
-			if (stat(argv[4], &sb)) {
-				perror(argv[4]);
-				die("Couldn't stat root device.");
+			if ((least->p_type != PT_LOAD) || 
+				(phdr[j].p_paddr < least->p_paddr)) {
+				least = phdr + j;
 			}
-			major_root = major(sb.st_rdev);
-			minor_root = minor(sb.st_rdev);
-		} else {
-			major_root = 0;
-			minor_root = 0;
 		}
-	} else {
-		major_root = DEFAULT_MAJOR_ROOT;
-		minor_root = DEFAULT_MINOR_ROOT;
+		if (least != phdr +i) {
+			Elf32_Phdr tmp;
+			tmp = phdr[i];
+			phdr[i] = *least;
+			*least = tmp;
+		}
+	}
+	plow = phdr;
+	phigh = 0;
+	for(i = 0; i < ehdr->e_phnum; i++) {
+		if (phdr[i].p_type != PT_LOAD)
+			break;
+		phigh = phdr +i;
+	}
+	if (phigh) {
+		size_t start, middle, end;
+		start = plow->p_paddr;
+		middle = phigh->p_paddr + phigh->p_filesz;
+		end = phigh->p_paddr + phigh->p_memsz;
+		seg->mem_addr = start;
+		seg->mem_size = end - start;
+		seg->data_size = middle - start;
 	}
-	fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+	return phdr;
+	
+}
 
-	file_open(argv[1]);
-	i = read(fd, buf, sizeof(buf));
-	fprintf(stderr,"Boot sector %d bytes.\n",i);
-	if (i != 512)
-		die("Boot block must be exactly 512 bytes");
-	if (buf[510] != 0x55 || buf[511] != 0xaa)
-		die("Boot block hasn't got boot flag (0xAA55)");
-	buf[508] = minor_root;
-	buf[509] = major_root;
-	if (write(1, buf, 512) != 512)
-		die("Write call failed");
-	close (fd);
-
-	file_open(argv[2]);				    /* Copy the setup code */
-	for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
-		if (write(1, buf, c) != c)
-			die("Write call failed");
-	if (c != 0)
-		die("read-error on `setup'");
-	close (fd);
-
-	setup_sectors = (i + 511) / 512;	/* Pad unused space with zeros */
-	/* for compatibility with ancient versions of LILO. */
-	if (setup_sectors < SETUP_SECTS)
-		setup_sectors = SETUP_SECTS;
-	fprintf(stderr, "Setup is %d bytes.\n", i);
-	memset(buf, 0, sizeof(buf));
-	while (i < setup_sectors * 512) {
-		c = setup_sectors * 512 - i;
-		if (c > sizeof(buf))
-			c = sizeof(buf);
-		if (write(1, buf, c) != c)
-			die("Write call failed");
-		i += c;
-	}
-
-	file_open(argv[3]);
-	if (fstat (fd, &sb))
-		die("Unable to stat `%s': %m", argv[3]);
-	sz = sb.st_size;
-	fprintf (stderr, "System is %d kB\n", sz/1024);
-	sys_size = (sz + 15) / 16;
-	/* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */
-	if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE))
-		die("System is too big. Try using %smodules.",
-			is_big_kernel ? "" : "bzImage or ");
-	if (sys_size > 0xefff)
-		fprintf(stderr,"warning: kernel is too big for standalone boot "
-		    "from floppy\n");
-	while (sz > 0) {
-		int l, n;
-
-		l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
-		if ((n=read(fd, buf, l)) != l) {
-			if (n < 0)
-				die("Error reading %s: %m", argv[3]);
-			else
-				die("%s: Unexpected EOF", argv[3]);
-		}
-		if (write(1, buf, l) != l)
-			die("Write failed");
-		sz -= l;
+static void get_elf_sizes(char *name, size_t pstart, struct file_seg *sizes)
+{
+	int fd;
+	Elf32_Ehdr ehdr;
+	Elf32_Phdr *phdr;
+	fd = checked_open(name, O_RDONLY, 0);
+	checked_read(fd, &ehdr, sizeof(ehdr), name);
+	check_ehdr(&ehdr, name);
+
+	phdr = read_sorted_phdr(name, fd, &ehdr, sizes);
+	if (sizes->mem_addr != pstart) {
+		die("Low PHDR in %s not at 0x%08x", name, pstart);
 	}
+
+	free(phdr);
 	close(fd);
+	return;
+}
+
+static void read_elf(char *name, size_t pstart, struct file_seg *seg)
+{
+	int src_fd;
+	Elf32_Ehdr ehdr;
+	Elf32_Phdr *phdr;
+	size_t last_paddr;
+	size_t loc;
+	int i;
+
+	src_fd = checked_open(name, O_RDONLY, 0);
+	checked_read(src_fd, &ehdr, sizeof(ehdr), name);
+	check_ehdr(&ehdr, name);
+
+	phdr = read_sorted_phdr(name, src_fd, &ehdr, seg);
+	if (seg->mem_addr != pstart) {
+		die("Low PHDR in %s not at 0x%08x", name, pstart);
+	}
+	
+	last_paddr = phdr[0].p_paddr;
+	seg->data = checked_malloc(seg->data_size);
+	loc = 0;
+	for(i = 0; i < ehdr.e_phnum; i++) {
+		size_t size;
+		if (phdr[i].p_type != PT_LOAD) {
+			break;
+		}
+		if (last_paddr != phdr[i].p_paddr) {
+			size = phdr[i].p_paddr - last_paddr;
+			memset(seg->data + loc, 0, size);
+			loc += size;
+		}
+		last_paddr = phdr[i].p_paddr + phdr[i].p_filesz;
+
+		size = phdr[i].p_filesz;
+		checked_lseek(src_fd, phdr[i].p_offset, SEEK_SET, name);
+		checked_read(src_fd, seg->data + loc, size, name);
+		loc += size;
+	}
+	free(phdr);
+	close(src_fd);
+	return;
+}
+
+struct image_info {
+	int is_big_kernel;
+	int is_elf;
+	size_t entry32;
+	size_t setup_sectors;
+	size_t sys_size;
+	size_t root_dev;
+	size_t unzip_overhang;
+	struct boot_params *param;
+	struct zkernel_header *zhdr;
+};
+
+static void update_image(
+	struct file_seg *iseg, struct file_seg *oseg, struct image_info *info)
+{
+	struct boot_params *param = info->param;
+	struct zkernel_header *zhdr = info->zhdr;
+	info->setup_sectors &= 0xff;
+	info->sys_size &= 0xffff;
+	info->root_dev &= 0xffff;
+	param->setup_sects    = info->setup_sectors;
+	param->syssize        = cpu_to_le16(info->sys_size);
+	param->root_dev       = cpu_to_le16(info->root_dev);
+	param->real_base      = cpu_to_le32(oseg[OREAL].mem_addr);
+	param->real_memsz     = cpu_to_le32(oseg[OREAL].mem_size);
+	param->real_filesz    = cpu_to_le32(oseg[OREAL].data_size);
+	param->kern_base      = cpu_to_le32(oseg[OKERN].mem_addr);
+	param->kern_memsz     = cpu_to_le32(oseg[OKERN].mem_size);
+	param->kern_filesz    = cpu_to_le32(oseg[OKERN].data_size);
+	zhdr->output_overhang = cpu_to_le32(info->unzip_overhang);
+	zhdr->kernel_memsz    = cpu_to_le32(iseg[IKERN].mem_size);
+	zhdr->kernel_filesz   = cpu_to_le32(iseg[IKERN].data_size);
+	if (info->is_elf) {
+		/* For ELF images we don't expect the header to be relocated */
+		param->loadflags |= cpu_to_le32(LOADFLAG_STAY_PUT);
+		param->type_of_loader = LOADER_UNKNOWN;
+	}
+}
+
+struct elf_header {
+	Elf32_Ehdr ehdr;
+	Elf32_Phdr phdr[OSEGS - (OEHDR + 1)];
+	Elf_Nhdr   program_name_hdr;
+	uint8_t    program_name_name[8];
+	uint8_t    program_name_desc[8];
+	Elf_Nhdr   program_version_hdr;
+	uint8_t    program_version_name[8];
+	uint8_t    program_version_desc[(sizeof(LINUX_KERNEL_VERSION) + 3) & ~3];
+	Elf_Nhdr   program_checksum_hdr;
+	uint8_t    program_checksum_name[8];
+	uint16_t   program_checksum;
+	uint16_t   program_checksum_pad;
+} __attribute__((packed));
+
+static void build_elf_header(struct file_seg *seg, struct image_info *info)
+{
+	struct elf_header *hdr;
+	size_t checksum, bytes;
+	size_t offset, size;
+	int i;
+	hdr = checked_malloc(sizeof(*hdr));
+	memset(hdr, 0, sizeof(*hdr));
+	memcpy(hdr->ehdr.e_ident, ELFMAG, 4);
+	hdr->ehdr.e_ident[EI_CLASS]   = ELFCLASS32;
+	hdr->ehdr.e_ident[EI_DATA]    = ELFDATA2LSB;
+	hdr->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+	hdr->ehdr.e_type      = cpu_to_le16(ET_EXEC);
+	hdr->ehdr.e_machine   = cpu_to_le16(EM_386);
+	hdr->ehdr.e_version   = cpu_to_le32(EV_CURRENT);
+	hdr->ehdr.e_entry     = cpu_to_le32(info->entry32);
+	hdr->ehdr.e_phoff     = cpu_to_le32(offsetof(struct elf_header, phdr));
+	hdr->ehdr.e_shoff     = cpu_to_le32(0);
+	hdr->ehdr.e_flags     = cpu_to_le16(0);
+	hdr->ehdr.e_ehsize    = cpu_to_le16(sizeof(hdr->ehdr));
+	hdr->ehdr.e_phentsize = cpu_to_le16(sizeof(hdr->phdr[0]));
+	hdr->ehdr.e_phnum     = cpu_to_le16(sizeof(hdr->phdr)/sizeof(hdr->phdr[0]));
+	hdr->ehdr.e_shentsize = cpu_to_le16(0);
+	hdr->ehdr.e_shnum     = cpu_to_le16(0);
+	hdr->ehdr.e_shstrndx  = cpu_to_le16(0);
+
+	offset = offsetof(struct elf_header, program_name_hdr);
+	size = sizeof(*hdr) - offset;
+	hdr->phdr[0].p_type   = cpu_to_le32(PT_NOTE);
+	hdr->phdr[0].p_offset = cpu_to_le32(offset);
+	hdr->phdr[0].p_vaddr  = cpu_to_le32(0);
+	hdr->phdr[0].p_paddr  = cpu_to_le32(0);
+	hdr->phdr[0].p_filesz = cpu_to_le32(size);
+	hdr->phdr[0].p_memsz  = cpu_to_le32(size);
+	hdr->phdr[0].p_flags  = cpu_to_le32(0);
+	hdr->phdr[0].p_align  = cpu_to_le32(0);
+	
+	for(i = OEHDR +1; i < OSEGS; i++) {
+		hdr->phdr[i].p_type = cpu_to_le32(PT_NULL);
+		if (seg[i].mem_size == 0) 
+			continue;
+		hdr->phdr[i].p_type   = cpu_to_le32(PT_LOAD);
+		hdr->phdr[i].p_offset = cpu_to_le32(seg[i].file_offset);
+		hdr->phdr[i].p_vaddr  = cpu_to_le32(seg[i].mem_addr);
+		hdr->phdr[i].p_paddr  = cpu_to_le32(seg[i].mem_addr);
+		hdr->phdr[i].p_filesz = cpu_to_le32(seg[i].data_size);
+		hdr->phdr[i].p_memsz  = cpu_to_le32(seg[i].mem_size);
+		hdr->phdr[i].p_flags  = cpu_to_le32(0);
+		hdr->phdr[i].p_align  = cpu_to_le32(0);
+	}
+	
+	hdr->program_name_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1);
+	hdr->program_name_hdr.n_descsz = cpu_to_le32(strlen("Linux") +1);
+	hdr->program_name_hdr.n_type   = cpu_to_le32(EIN_PROGRAM_NAME);
+	strcpy(hdr->program_name_name, EIN_NOTE_NAME);
+	strcpy(hdr->program_name_desc, "Linux");
+	
+	hdr->program_version_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1);
+	hdr->program_version_hdr.n_descsz = cpu_to_le32(strlen(LINUX_KERNEL_VERSION)+1);
+	hdr->program_version_hdr.n_type   = cpu_to_le32(EIN_PROGRAM_VERSION);
+	strcpy(hdr->program_version_name, EIN_NOTE_NAME);
+	strcpy(hdr->program_version_desc, LINUX_KERNEL_VERSION);
+
+	hdr->program_checksum_hdr.n_namesz = cpu_to_le32(strlen(EIN_NOTE_NAME) +1);
+	hdr->program_checksum_hdr.n_descsz = cpu_to_le32(2);
+	hdr->program_checksum_hdr.n_type   = cpu_to_le32(EIN_PROGRAM_CHECKSUM);
+	strcpy(hdr->program_checksum_name, EIN_NOTE_NAME);
+	hdr->program_checksum = cpu_to_le16(0); /* This is written later */
+
+	/* Compute the image checksum, this covers everything except the
+	 * ELF notes.
+	 */
+	bytes = sizeof(hdr->ehdr) + sizeof(hdr->phdr);
+	checksum = compute_ip_checksum(hdr, bytes);
+	for(i = 1; i < 4; i++) {
+		checksum = add_ip_checksums(bytes, checksum, 
+			compute_ip_checksum(seg[i].data, seg[i].data_size));
+		bytes += seg[i].mem_size;
+	}
+	hdr->program_checksum = cpu_to_le16(checksum);
+	seg[OEHDR].data = (unsigned char *)hdr;
+}
 
-	if (lseek(1, 497, SEEK_SET) != 497)		    /* Write sizes to the bootsector */
-		die("Output: seek failed");
-	buf[0] = setup_sectors;
-	if (write(1, buf, 1) != 1)
-		die("Write of setup sector count failed");
-	if (lseek(1, 500, SEEK_SET) != 500)
-		die("Output: seek failed");
-	buf[0] = (sys_size & 0xff);
-	buf[1] = ((sys_size >> 8) & 0xff);
-	if (write(1, buf, 2) != 2)
-		die("Write of image length failed");
+static void usage(void)
+{
+	die("Usage: build [-e] [-b] vmlinux realmode compressed/vmlinux image");
+}
+
+int main(int argc, char ** argv)
+{
+	char *kernel;
+	char *realmode;
+	char *zkernel;
+	char *image;
+	int image_fd;
+	size_t major_root, minor_root;
+	size_t zkernel_base;
+	struct image_info info;
+	struct file_seg iseg[ISEGS];
+	struct file_seg oseg[OSEGS];
+	struct stat st;
+	int i;
+
+	memset(iseg, 0, sizeof(iseg));
+	memset(oseg, 0, sizeof(oseg));
+	memset(&info, 0, sizeof(info));
+	info.is_big_kernel = 0;
+	info.is_elf = 0;
+	if (argc > 2 && (strcmp(argv[1], "-e") == 0)) {
+		info.is_elf = 1;
+		argc--;
+		argv++;
+	}
+	if (argc > 2 && (strcmp(argv[1], "-b") == 0)) {
+		info.is_big_kernel = 1;
+		argc--;
+		argv++;
+	}
+	if (argc != 5) {
+		usage();
+	}
+	kernel = argv[1];
+	realmode = argv[2];
+	zkernel = argv[3];
+	image = argv[4];
+
+	/* Compute the current root device */
+	major_root = DEFAULT_MAJOR_ROOT;
+	minor_root = DEFAULT_MINOR_ROOT;
+	if (stat("/", &st) == 0) {
+		major_root = major(st.st_dev);
+		minor_root = minor(st.st_dev);
+	}
+	major_root &= 0xff;
+	minor_root &= 0xff;
+	info.root_dev = (major_root << 8) | minor_root;
+	printf("Root device is (%d, %d)\n", major_root, minor_root);
+
+	/* Read in the file information */
+	zkernel_base = info.is_big_kernel? HIGH_BASE : LOW_BASE;
+	get_elf_sizes(kernel, HIGH_BASE,    &iseg[IKERN]);
+	read_elf(realmode,    REAL_BASE,     &iseg[IREAL]);
+	read_elf(zkernel,     zkernel_base, &iseg[IZKERN]);
+	
+	oseg[OREAL] = iseg[IREAL];
+	oseg[OKERN] = iseg[IZKERN];
+
+	info.param = (struct boot_params *)oseg[OREAL].data;
+	info.zhdr = (struct zkernel_header *)oseg[OKERN].data;
+	info.unzip_overhang = compute_unzip_overhang(iseg);
+
+	/* Compute the memory usage when the compressed data
+	 * and the BSS stop overlapping.
+	 */
+	oseg[OKERN].mem_size = oseg[OKERN].data_size + 
+		(le32_to_cpu(info.zhdr->unzip_memsz) - 
+			le32_to_cpu(info.zhdr->unzip_filesz));
+	if (!info.is_big_kernel) {
+		/* zImage */
+		size_t kern_end;
+		/* zImages are wacky, they load at 64K but then
+		 * setup.S relocates them down to 4K.
+		 */
+		/* Check the decompression address and ensure we
+		 * have enough space, to decompress.
+		 */
+		oseg[OREAL].mem_addr = DEF_INITSEG << 4;
+		kern_end = oseg[OKERN].mem_addr + oseg[OKERN].mem_size;
+		kern_end = (kern_end + 15) & ~15; 
+		if (kern_end > oseg[OREAL].mem_addr) {
+			die("System is to big.  Try using bzImage or modules");
+		}
+
+		/* Describe the initial hole */
+		oseg[OBSS1].mem_addr = oseg[OKERN].mem_addr;
+		oseg[OBSS1].data_size = 0;
+		oseg[OBSS1].mem_size = 	(DEF_SYSSEG << 4) - oseg[OBSS1].mem_addr;
+
+		/* Check the load time address and verify we
+		 * have enough space to load.
+		 */
+		oseg[OKERN].mem_addr = DEF_SYSSEG << 4;
+		kern_end = oseg[OKERN].mem_addr + oseg[OKERN].data_size;
+		kern_end = (kern_end + 15) & ~15;
+		if (kern_end > oseg[OREAL].mem_addr) {
+			die("System is to big.  Try using bzImage or modules");
+		}
+		
+		/* Describe where the kernel actually runs */
+		oseg[OBSS2].mem_addr = HIGH_BASE;
+		oseg[OBSS2].mem_size = iseg[IKERN].mem_size;
+		oseg[OBSS2].data_size = 0;
+	} else {
+		/* bzImage */
+		size_t unzip_bufsz;
 
-	return 0;					    /* Everything is OK */
+		/* Compute the bzImage decompressor memory size */
+		unzip_bufsz = iseg[IKERN].data_size + info.unzip_overhang;
+		if (unzip_bufsz > oseg[OKERN].mem_size) {
+			oseg[OKERN].mem_size = unzip_bufsz;
+		}
+
+		/* Compute how much real memory we need */
+		oseg[OREAL].mem_size += 
+			((le32_to_cpu(info.zhdr->unzip_memsz) - 
+				oseg[OKERN].mem_addr) + 0xfff) & ~0xfff;
+		oseg[OREAL].mem_size += COMMAND_LINE_SIZE;
+		if (oseg[OREAL].mem_size > REAL_MAX - REAL_BASE) {
+			die("Kernel requires %d bytes low memory %d available!\n",
+				oseg[OREAL].mem_size,
+				REAL_MAX - REAL_BASE);
+		}
+		/* See if the loaded kernel uses more memory */
+		if (iseg[IKERN].mem_size > oseg[OKERN].mem_size) {
+			oseg[OKERN].mem_size = iseg[IKERN].mem_size;
+		}
+	}
+
+	/* Compute the file offsets */
+	info.setup_sectors = (oseg[OREAL].data_size - 512 + 511)/512;
+	if (info.setup_sectors < SETUP_SECTS)
+		info.setup_sectors = SETUP_SECTS;
+	if (info.is_elf) {
+		oseg[OEHDR].data_size = sizeof(struct elf_header);
+	}
+
+	/* Note: for ELF images I don't have to make OREAL
+	 * info.setup_sectors long, but it makes the conversion back
+	 * to a bzImage just a trivial header removal.
+	 */
+	oseg[OREAL].file_offset = oseg[OEHDR].file_offset + oseg[OEHDR].data_size;
+	oseg[OKERN].file_offset = oseg[OREAL].file_offset + (info.setup_sectors +1)*512;
+
+	/* Check and print the values to write back. */
+	info.entry32 = oseg[OREAL].mem_addr + 
+		le32_to_cpu(info.param->entry32_off);
+	printf("Boot sector is 512 bytes\n");
+	printf("Setup is %d bytes\n", oseg[OREAL].data_size - 512);
+
+	info.sys_size = (oseg[OKERN].data_size + 15)/16;
+	if ((iseg[IKERN].mem_addr + iseg[IKERN].mem_size) 
+		>= INITIAL_PAGE_TABLE_SIZE) {
+		die("System is to big.  Try using modules.");
+	}
+	if (info.sys_size > 0xefff) {
+		fprintf(stderr, "warning: kernel is too big for standalone boot " 
+			"from floppy\n");
+	}
+	printf("System is %d KB\n", (info.sys_size*16)/1024);
+	printf("entry32: 0x%x\n", info.entry32);
+	printf("[real] base: %08x filesz %5d B  memsz= %5d KB\n", 
+		oseg[OREAL].mem_addr,
+		oseg[OREAL].data_size,
+		oseg[OREAL].mem_size/1024);
+	printf("[kern] base: %08x filesz %5d KB memsz= %5d KB\n", 
+		oseg[OKERN].mem_addr, 
+		oseg[OKERN].data_size/1024,
+		oseg[OKERN].mem_size/1024); 
+	printf("[bss1] base: %08x filesz %5d KB memsz= %5d KB\n",
+		oseg[OBSS1].mem_addr,
+		oseg[OBSS1].data_size/1024,
+		oseg[OBSS1].mem_size/1024);
+	printf("[bss2] base: %08x filesz %5d KB memsz= %5d KB\n",
+		oseg[OBSS2].mem_addr,
+		oseg[OBSS2].data_size/1024,
+		oseg[OBSS2].mem_size/1024);
+
+	/* Write the values back */
+	update_image(iseg, oseg, &info);
+	if (info.is_elf) {
+		build_elf_header(oseg, &info);
+		printf("elf_header_size=%d\n", oseg[OEHDR].data_size);
+	}
+
+	/* Write destination file */
+	image_fd = checked_open(image, O_RDWR | O_CREAT | O_TRUNC, 0666);
+	for(i = 0; i < OSEGS; i++) {
+		if (oseg[i].data_size == 0)
+			continue;
+		checked_lseek(image_fd, oseg[i].file_offset, SEEK_SET, image);
+		checked_write(image_fd, oseg[i].data, oseg[i].data_size, image);
+	}
+	close(image_fd);
+	return 0;
 }
diff -uNr linux-2.5.11/arch/i386/boot/video.S linux-2.5.11.boot.elf/arch/i386/boot/video.S
--- linux-2.5.11/arch/i386/boot/video.S	Thu Jul  5 12:28:16 2001
+++ linux-2.5.11.boot.elf/arch/i386/boot/video.S	Mon Apr 29 11:22:00 2002
@@ -117,6 +117,12 @@
 	xorw	%ax, %ax
 	movw	%ax, %gs	# GS is zero
 	cld
+
+	# Setup the heap
+	movl	real_filesz, %eax
+	subl	$DELTA_BOOTSECT, %eax
+	movw	%ax, heap_start
+	
 	call	basic_detect	# Basic adapter type testing (EGA/VGA/MDA/CGA)
 #ifdef CONFIG_VIDEO_SELECT
 	movw	%fs:(0x01fa), %ax		# User selected video mode
@@ -201,7 +207,7 @@
 #ifdef CONFIG_VIDEO_SELECT
 # Fetching of VESA frame buffer parameters
 mopar_gr:
-	leaw	modelist+1024, %di
+	movw	heap_start, %di
 	movb	$0x23, %fs:(PARAM_HAVE_VGA)
 	movw	16(%di), %ax
 	movw	%ax, %fs:(PARAM_LFB_LINELENGTH)
@@ -223,7 +229,7 @@
 	movl	%eax, %fs:(PARAM_LFB_COLORS+4)
 
 # get video mem size
-	leaw	modelist+1024, %di
+	movw	heap_start, %di
 	movw	$0x4f00, %ax
 	int	$0x10
 	xorl	%eax, %eax
@@ -284,7 +290,7 @@
 	leaw	listhdr, %si			# Table header
 	call	prtstr
 	movb	$0x30, %dl			# DL holds mode number
-	leaw	modelist, %si
+	movw	modelist, %si
 lm1:	cmpw	$ASK_VGA, (%si)			# End?
 	jz	lm2
 
@@ -529,7 +535,7 @@
 	jmp	_m_s
 
 check_vesa:
-	leaw	modelist+1024, %di
+	movw	heap_start, %di
 	subb	$VIDEO_FIRST_VESA>>8, %bh
 	movw	%bx, %cx			# Get mode information structure
 	movw	$0x4f01, %ax
@@ -774,12 +780,13 @@
 	mulb	%ah
 	movw	%ax, %cx			# CX=number of characters
 	addw	%ax, %ax			# Calculate image size
-	addw	$modelist+1024+4, %ax
+	addw	heap_start, %ax
+	addw	$4, %ax
 	cmpw	heap_end_ptr, %ax
 	jnc	sts1				# Unfortunately, out of memory
 
 	movw	%fs:(PARAM_CURSOR_POS), %ax	# Store mode params
-	leaw	modelist+1024, %di
+	movw	heap_start, %di
 	stosw
 	movw	%bx, %ax
 	stosw
@@ -802,7 +809,7 @@
 	call	mode_params			# Get parameters of current mode
 	movb	%fs:(PARAM_VIDEO_LINES), %cl
 	movb	%fs:(PARAM_VIDEO_COLS), %ch
-	leaw	modelist+1024, %si		# Screen buffer
+	movw	heap_start, %si			# Screen buffer
 	lodsw					# Set cursor position
 	movw	%ax, %dx
 	cmpb	%cl, %dh
@@ -883,7 +890,8 @@
 	orw	%di, %di
 	jnz	mtab1x
 	
-	leaw	modelist, %di			# Store standard modes:
+	movw	heap_start, %di			# Store standard modes:
+	movw	%di, modelist
 	movl	$VIDEO_80x25 + 0x50190000, %eax	# The 80x25 mode (ALL)
 	stosl
 	movb	adapter, %al			# CGA/MDA/HGA -- no more modes
@@ -929,13 +937,13 @@
 mtabe:
 
 #ifdef CONFIG_VIDEO_COMPACT
-	leaw	modelist, %si
+	movw	modelist, %si
 	movw	%di, %dx
 	movw	%si, %di
 cmt1:	cmpw	%dx, %si			# Scan all modes
 	jz	cmt2
 
-	leaw	modelist, %bx			# Find in previous entries
+	movw	modelist, %bx			# Find in previous entries
 	movw	2(%si), %cx
 cmt3:	cmpw	%bx, %si
 	jz	cmt4
@@ -957,7 +965,8 @@
 
 	movw	$ASK_VGA, (%di)			# End marker
 	movw	%di, mt_end
-mtab1:	leaw	modelist, %si			# SI=mode list, DI=list end
+	movw	%di, heap_start
+mtab1:	movw	modelist, %si			# SI=mode list, DI=list end
 ret0:	ret
 
 # Modes usable on all standard VGAs
@@ -1932,3 +1941,5 @@
 adapter:	.byte	0	# Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
 video_segment:	.word	0xb800	# Video memory segment
 force_size:	.word	0	# Use this size instead of the one in BIOS vars
+modelist:	.word	0	# Start of modelist on the heap
+heap_start:	.word	0	# low heap address
diff -uNr linux-2.5.11/arch/i386/config.in linux-2.5.11.boot.elf/arch/i386/config.in
--- linux-2.5.11/arch/i386/config.in	Mon Apr 29 00:17:11 2002
+++ linux-2.5.11.boot.elf/arch/i386/config.in	Mon Apr 29 11:22:48 2002
@@ -206,6 +206,7 @@
    fi
 fi
 
+bool 'LinuxBIOS support' CONFIG_LINUXBIOS
 endmenu
 
 mainmenu_option next_comment
@@ -282,6 +283,7 @@
    bool '    Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
 fi
 
+string 'Initial kernel command line' CONFIG_CMDLINE ""
 endmenu
 
 source drivers/mtd/Config.in
diff -uNr linux-2.5.11/arch/i386/defconfig linux-2.5.11.boot.elf/arch/i386/defconfig
--- linux-2.5.11/arch/i386/defconfig	Mon Apr 29 00:17:11 2002
+++ linux-2.5.11.boot.elf/arch/i386/defconfig	Mon Apr 29 11:22:48 2002
@@ -119,6 +119,7 @@
 CONFIG_BINFMT_MISC=y
 CONFIG_PM=y
 # CONFIG_APM is not set
+# CONFIG_LINUXBIOS is not set
 
 #
 # Memory Technology Devices (MTD)
diff -uNr linux-2.5.11/arch/i386/kernel/Makefile linux-2.5.11.boot.elf/arch/i386/kernel/Makefile
--- linux-2.5.11/arch/i386/kernel/Makefile	Tue Apr 16 11:10:43 2002
+++ linux-2.5.11.boot.elf/arch/i386/kernel/Makefile	Mon Apr 29 11:22:48 2002
@@ -42,6 +42,7 @@
 obj-$(CONFIG_SMP)		+= smp.o smpboot.o trampoline.o
 obj-$(CONFIG_X86_LOCAL_APIC)	+= mpparse.o apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
+obj-$(CONFIG_LINUXBIOS)		+= linuxbios.o
 ifdef CONFIG_VISWS
 obj-y += setup-visws.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
diff -uNr linux-2.5.11/arch/i386/kernel/head.S linux-2.5.11.boot.elf/arch/i386/kernel/head.S
--- linux-2.5.11/arch/i386/kernel/head.S	Mon Apr 29 00:17:11 2002
+++ linux-2.5.11.boot.elf/arch/i386/kernel/head.S	Mon Apr 29 11:22:03 2002
@@ -16,12 +16,6 @@
 #include <asm/pgtable.h>
 #include <asm/desc.h>
 
-#define OLD_CL_MAGIC_ADDR	0x90020
-#define OLD_CL_MAGIC		0xA33F
-#define OLD_CL_BASE_ADDR	0x90000
-#define OLD_CL_OFFSET		0x90022
-#define NEW_CL_POINTER		0x228	/* Relative to real mode data */
-
 /*
  * References to members of the boot_cpu_data structure.
  */
@@ -39,46 +33,41 @@
 /*
  * swapper_pg_dir is the main page directory, address 0x00101000
  *
- * On entry, %esi points to the real-mode code as a 32-bit pointer.
+ * On entry
+ *   %ds, %es, %ss, %fs, %gs 32bit data segment base=0 mask=0xffffffff
+ *
  */
-startup_32:
+ENTRY(startup_32)
 /*
- * Set segments to known values
+ * Set eflags to a safe state
  */
 	cld
-	movl $(__KERNEL_DS),%eax
+	cli
+/*
+ * Save the initial registers
+ */
+	movl %eax, initial_regs-__PAGE_OFFSET+0
+	movl %ebx, initial_regs-__PAGE_OFFSET+4
+	movl %ecx, initial_regs-__PAGE_OFFSET+8
+	movl %edx, initial_regs-__PAGE_OFFSET+12
+	movl %esi, initial_regs-__PAGE_OFFSET+16
+	movl %edi, initial_regs-__PAGE_OFFSET+20
+	movl %esp, initial_regs-__PAGE_OFFSET+24
+	movl %ebp, initial_regs-__PAGE_OFFSET+28
+
+/*
+ * Set segments to known values
+ */
+	lgdt gdt_48-__PAGE_OFFSET
+	ljmp $__KERNEL_CS,$1f-__PAGE_OFFSET
+1:	movl $__KERNEL_DS,%eax
 	movl %eax,%ds
 	movl %eax,%es
 	movl %eax,%fs
 	movl %eax,%gs
-#ifdef CONFIG_SMP
-	orw %bx,%bx
-	jz 1f
+	movl %eax,%ss
 
 /*
- *	New page tables may be in 4Mbyte page mode and may
- *	be using the global pages. 
- *
- *	NOTE! If we are on a 486 we may have no cr4 at all!
- *	So we do not try to touch it unless we really have
- *	some bits in it to set.  This won't work if the BSP
- *	implements cr4 but this AP does not -- very unlikely
- *	but be warned!  The same applies to the pse feature
- *	if not equally supported. --macro
- *
- *	NOTE! We have to correct for the fact that we're
- *	not yet offset PAGE_OFFSET..
- */
-#define cr4_bits mmu_cr4_features-__PAGE_OFFSET
-	cmpl $0,cr4_bits
-	je 3f
-	movl %cr4,%eax		# Turn on paging options (PSE,PAE,..)
-	orl cr4_bits,%eax
-	movl %eax,%cr4
-	jmp 3f
-1:
-#endif
-/*
  * Initialize page tables
  */
 	movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */
@@ -106,14 +95,13 @@
 	/* Set up the stack pointer */
 	lss stack_start,%esp
 
-#ifdef CONFIG_SMP
-	orw  %bx,%bx
-	jz  1f				/* Initial CPU cleans BSS */
+/*
+ * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
+ * confuse the debugger if this code is traced.
+ * XXX - best to initialize before switching to protected mode.
+ */
 	pushl $0
 	popfl
-	jmp checkCPUtype
-1:
-#endif CONFIG_SMP
 
 /*
  * Clear BSS first so that there are no surprises...
@@ -131,42 +119,76 @@
  * in 16-bit mode for the "real" operations.
  */
 	call setup_idt
+	
+	call checkCPUtype
+	call start_kernel
+L6:
+	jmp L6			# main should never return here, but
+				# just in case, we know what happens.
+
+
+#ifdef CONFIG_SMP
+ENTRY(secondary_startup_32)
 /*
- * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
- * confuse the debugger if this code is traced.
- * XXX - best to initialize before switching to protected mode.
+ * Set eflags to a safe state
  */
-	pushl $0
-	popfl
+	cld
+	cli
+
+/*
+ * Set segments to known values
+ */
+	movl	$(__KERNEL_DS), %eax
+	movl	%eax,%ds
+	movl	%eax,%es
+	movl	%eax,%fs
+	movl	%eax,%gs
+	movl	%eax,%ss
+
 /*
- * Copy bootup parameters out of the way. First 2kB of
- * _empty_zero_page is for boot parameters, second 2kB
- * is for the command line.
+ *	New page tables may be in 4Mbyte page mode and may
+ *	be using the global pages. 
  *
- * Note: %esi still has the pointer to the real-mode data.
+ *	NOTE! If we are on a 486 we may have no cr4 at all!
+ *	So we do not try to touch it unless we really have
+ *	some bits in it to set.  This won't work if the BSP
+ *	implements cr4 but this AP does not -- very unlikely
+ *	but be warned!  The same applies to the pse feature
+ *	if not equally supported. --macro
+ *
+ *	NOTE! We have to correct for the fact that we're
+ *	not yet offset PAGE_OFFSET..
  */
-	movl $empty_zero_page,%edi
-	movl $512,%ecx
-	cld
-	rep
-	movsl
-	xorl %eax,%eax
-	movl $512,%ecx
-	rep
-	stosl
-	movl empty_zero_page+NEW_CL_POINTER,%esi
-	andl %esi,%esi
-	jnz 2f			# New command line protocol
-	cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
-	jne 1f
-	movzwl OLD_CL_OFFSET,%esi
-	addl $(OLD_CL_BASE_ADDR),%esi
-2:
-	movl $empty_zero_page+2048,%edi
-	movl $512,%ecx
-	rep
-	movsl
+#define cr4_bits mmu_cr4_features-__PAGE_OFFSET
+	cmpl $0,cr4_bits
+	je 3f
+	movl %cr4,%eax		# Turn on paging options (PSE,PAE,..)
+	orl cr4_bits,%eax
+	movl %eax,%cr4
+/*
+ * Enable paging
+ */
+3:
+	movl $swapper_pg_dir-__PAGE_OFFSET,%eax
+	movl %eax,%cr3		/* set the page table pointer.. */
+	movl %cr0,%eax
+	orl $0x80000000,%eax
+	movl %eax,%cr0		/* ..and set paging (PG) bit */
+	jmp 1f			/* flush the prefetch-queue */
 1:
+	movl $1f,%eax
+	jmp *%eax		/* make sure eip is relocated */
+1:
+	/* Set up the stack pointer */
+	lss stack_start,%esp
+	call checkCPUtype
+	call initialize_secondary
+L7:
+	jmp L7			# initialize_secondary should never return here, but
+				# just in case, we know what happens.
+#endif /* CONFIG_SMP */
+
+
 checkCPUtype:
 
 	movl $-1,X86_CPUID		#  -1 for no CPUID initially
@@ -240,40 +262,11 @@
 	orl $2,%eax		# set MP
 2:	movl %eax,%cr0
 	call check_x87
-	incb ready
-	lgdt gdt_descr
+	/* Now that we know the cpu, setup the idt & ldt */
 	lidt idt_descr
-	ljmp $(__KERNEL_CS),$1f
-1:	movl $(__KERNEL_DS),%eax	# reload all the segment registers
-	movl %eax,%ds		# after changing gdt.
-	movl %eax,%es
-	movl %eax,%fs
-	movl %eax,%gs
-#ifdef CONFIG_SMP
-	movl $(__KERNEL_DS), %eax
-	movl %eax,%ss		# Reload the stack pointer (segment only)
-#else
-	lss stack_start,%esp	# Load processor stack
-#endif
 	xorl %eax,%eax
 	lldt %ax
-	cld			# gcc2 wants the direction flag cleared at all times
-#ifdef CONFIG_SMP
-	movb ready, %cl	
-	cmpb $1,%cl
-	je 1f			# the first CPU calls start_kernel
-				# all other CPUs call initialize_secondary
-	call initialize_secondary
-	jmp L6
-1:
-#endif
-	call start_kernel
-L6:
-	jmp L6			# main should never return here, but
-				# just in case, we know what happens.
-
-ready:	.byte 0
-
+	ret
 /*
  * We depend on ET to be correct. This checks for 287/387.
  */
@@ -372,6 +365,10 @@
 gdt:
 	.long gdt_table
 
+	.word 0
+gdt_48:
+	.word GDT_ENTRIES*8-1
+	.long gdt_table-__PAGE_OFFSET
 /*
  * This is initialized to create an identity-mapping at 0-8M (for bootup
  * purposes) and another mapping of the 0-8M area at virtual address
diff -uNr linux-2.5.11/arch/i386/kernel/linuxbios.c linux-2.5.11.boot.elf/arch/i386/kernel/linuxbios.c
--- linux-2.5.11/arch/i386/kernel/linuxbios.c	Wed Dec 31 17:00:00 1969
+++ linux-2.5.11.boot.elf/arch/i386/kernel/linuxbios.c	Mon Apr 29 11:22:48 2002
@@ -0,0 +1,103 @@
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+#include <asm/linuxbios.h>
+#include <asm/e820.h>
+#include "linuxbios_tables.h"
+
+#define for_each_lbrec(head, rec) \
+	for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
+		(((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes))  && \
+		(rec->size >= 1) && \
+		((((char *)rec) + rec->size) <= (((char *)head) + sizeof(*head) + head->table_bytes)); \
+		rec = (struct lb_record *)(((char *)rec) + rec->size)) 
+		
+
+static int __init count_lb_records(struct lb_header *head)
+{
+	struct lb_record *rec;
+	int count;
+	count = 0;
+	for_each_lbrec(head, rec) {
+		count++;
+	}
+	return count;
+}
+
+static struct lb_header * __init __find_lb_table(unsigned long start, unsigned long end)
+{
+	unsigned long addr;
+	/* For now be stupid.... */
+	for(addr = start; addr < end; addr += 16) {
+		struct lb_header *head = phys_to_virt(addr);
+		struct lb_record *recs = phys_to_virt(addr + sizeof(*head));
+		if (memcmp(head->signature, "LBIO", 4) != 0)
+			continue;
+		if (head->header_bytes != sizeof(*head))
+			continue;
+		if (ip_compute_csum((unsigned char *)head, sizeof(*head)) != 0)
+			continue;
+		if (ip_compute_csum((unsigned char *)recs, head->table_bytes) 
+			!= head->table_checksum)
+			continue;
+		if (count_lb_records(head) != head->table_entries)
+			continue;
+		printk(KERN_DEBUG "Found LinuxBIOS table at: %p\n", head);
+		return head;
+	};
+	return 0;
+}
+
+static struct lb_header * __init find_lb_table(void)
+{
+	struct lb_header *head;
+	head = 0;
+	if (!head) {
+		/* First try at address 0 */
+		head = __find_lb_table(0x00000, 0x1000);
+	}
+	if (!head) {
+		/* Then try at address 0xf0000 */
+		head = __find_lb_table(0xf0000, 0x100000);
+	}
+	return head;
+}
+
+void __init read_linuxbios_params(void)
+{
+	struct lb_header *head;
+	struct lb_record *rec;
+	struct lb_memory *mem;
+	int i, entries;
+	head = find_lb_table();
+	if (!head) {
+		return;
+	}
+	mem = 0;
+	for_each_lbrec(head, rec) {
+		if (rec->tag == LB_TAG_MEMORY) {
+			mem = (struct lb_memory *)rec;
+			break;
+		}
+	}
+	if (!mem) {
+		return;
+	}
+	entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
+	if (entries == 0)
+		return;
+	e820.nr_map = 0;
+	for(i = 0; i < entries; i++) {
+		unsigned long long start;
+		unsigned long long size;
+		unsigned long type;
+		start = mem->map[i].start;
+		size = mem->map[i].size;
+		type = (mem->map[i].type == LB_MEM_RAM)?E820_RAM: E820_RESERVED;
+		add_memory_region(start, size, type);
+	}
+	print_memory_map("LinuxBIOS");
+	return;
+}
+
diff -uNr linux-2.5.11/arch/i386/kernel/linuxbios_tables.h linux-2.5.11.boot.elf/arch/i386/kernel/linuxbios_tables.h
--- linux-2.5.11/arch/i386/kernel/linuxbios_tables.h	Wed Dec 31 17:00:00 1969
+++ linux-2.5.11.boot.elf/arch/i386/kernel/linuxbios_tables.h	Mon Apr 29 11:51:21 2002
@@ -0,0 +1,82 @@
+#ifndef LINUXBIOS_TABLES_H
+#define LINUXBIOS_TABLES_H
+
+#include <linux/types.h>
+
+/* The linuxbios table information is for conveying information
+ * from the firmware to the loaded OS image.  Primarily this
+ * is expected to be information that cannot be discovered by
+ * other means, such as quering the hardware directly.
+ *
+ * All of the information should be Position Independent Data.  
+ * That is it should be safe to relocated any of the information
+ * without it's meaning/correctnes changing.   For table that
+ * can reasonably be used on multiple architectures the data
+ * size should be fixed.  This should ease the transition between
+ * 32 bit and 64 bit architectures etc.
+ *
+ * The completeness test for the information in this table is:
+ * - Can all of the hardware be detected?
+ * - Are the per motherboard constants available?
+ * - Is there enough to allow a kernel to run that was written before
+ *   a particular motherboard is constructed? (Assuming the kernel
+ *   has drivers for all of the hardware but it does not have
+ *   assumptions on how the hardware is connected together).
+ *
+ * With this test it should be straight forward to determine if a
+ * table entry is required or not.  This should remove much of the
+ * long term compatibility burden as table entries which are
+ * irrelevant or have been replaced by better alternatives may be
+ * dropped.  Of course it is polite and expidite to include extra
+ * table entries and be backwards compatible, but it is not required.
+ */
+
+
+struct lb_header
+{
+	uint8_t  signature[4]; /* LBIO */
+	uint32_t header_bytes;
+	uint32_t header_checksum;
+	uint32_t table_bytes;
+	uint32_t table_checksum;
+	uint32_t table_entries;
+};
+
+/* Every entry in the boot enviroment list will correspond to a boot
+ * info record.  Encoding both type and size.  The type is obviously
+ * so you can tell what it is.  The size allows you to skip that
+ * boot enviroment record if you don't know what it easy.  This allows
+ * forward compatibility with records not yet defined.
+ */
+struct lb_record {
+	uint32_t tag;		/* tag ID */
+	uint32_t size;		/* size of record (in bytes) */
+};
+
+#define LB_TAG_UNUSED	0x0000
+
+#define LB_TAG_MEMORY	0x0001
+
+struct lb_memory_range {
+	uint64_t start;
+	uint64_t size;
+	uint32_t type;
+#define LB_MEM_RAM      1
+#define LB_MEM_RESERVED 2
+	
+};
+
+struct lb_memory {
+	uint32_t tag;
+	uint32_t size;
+	struct lb_memory_range map[0];
+};
+
+#define LB_TAG_HWRPB	0x0002
+struct lb_hwrpb {
+	uint32_t tag;
+	uint32_t size;
+	uint64_t hwrpb;
+};
+
+#endif /* LINUXBIOS_TABLES_H */
diff -uNr linux-2.5.11/arch/i386/kernel/setup.c linux-2.5.11.boot.elf/arch/i386/kernel/setup.c
--- linux-2.5.11/arch/i386/kernel/setup.c	Mon Apr 29 00:17:11 2002
+++ linux-2.5.11.boot.elf/arch/i386/kernel/setup.c	Mon Apr 29 11:22:48 2002
@@ -103,6 +103,7 @@
 #include <linux/pci_ids.h>
 #include <linux/seq_file.h>
 #include <linux/console.h>
+#include <linux/smp_lock.h>
 #include <asm/processor.h>
 #include <asm/mtrr.h>
 #include <asm/uaccess.h>
@@ -116,6 +117,9 @@
 #include <asm/dma.h>
 #include <asm/mpspec.h>
 #include <asm/mmu_context.h>
+#include <asm/boot.h>
+#include <asm/boot_param.h>
+#include <asm/linuxbios.h>
 
 /*
  * Machine setup..
@@ -146,14 +150,9 @@
 /*
  * Setup options
  */
-struct drive_info_struct { char dummy[32]; } drive_info;
+struct drive_info_struct drive_info;
 struct screen_info screen_info;
 struct apm_info apm_info;
-struct sys_desc_table_struct {
-	unsigned short length;
-	unsigned char table[0];
-};
-
 struct e820map e820;
 
 unsigned char aux_device_present;
@@ -168,33 +167,8 @@
 static int disable_x86_serial_nr __initdata = 1;
 static int disable_x86_fxsr __initdata = 0;
 
-/*
- * This is set up by the setup-routine at boot-time
- */
-#define PARAM	((unsigned char *)empty_zero_page)
-#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
-#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
-#define E820_MAP_NR (*(char*) (PARAM+E820NR))
-#define E820_MAP    ((struct e820entry *) (PARAM+E820MAP))
-#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
-#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
-#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
-#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
-#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
-#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
-#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
-#define COMMAND_LINE ((char *) (PARAM+2048))
-#define COMMAND_LINE_SIZE 256
-
-#define RAMDISK_IMAGE_START_MASK  	0x07FF
-#define RAMDISK_PROMPT_FLAG		0x8000
-#define RAMDISK_LOAD_FLAG		0x4000	
-
+/* Don't let the initial_regs sit in the BSS */
+struct initial_regs32 initial_regs __initdata = { 0 };
 
 static char command_line[COMMAND_LINE_SIZE];
        char saved_command_line[COMMAND_LINE_SIZE];
@@ -292,7 +266,7 @@
 	}
 }
 
-static void __init add_memory_region(unsigned long long start,
+void __init add_memory_region(unsigned long long start,
                                   unsigned long long size, int type)
 {
 	int x = e820.nr_map;
@@ -310,7 +284,7 @@
 
 #define E820_DEBUG	1
 
-static void __init print_memory_map(char *who)
+void __init print_memory_map(char *who)
 {
 	int i;
 
@@ -557,7 +531,7 @@
  */
 #define LOWMEMSIZE()	(0x9f000)
 
-static void __init setup_memory_region(void)
+static void __init setup_memory_region(struct boot_params *params)
 {
 	char *who = "BIOS-e820";
 
@@ -567,16 +541,16 @@
 	 * Otherwise fake a memory map; one section from 0k->640k,
 	 * the next section from 1mb->appropriate_mem_k
 	 */
-	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
-	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+	sanitize_e820_map(params->e820_map, &params->e820_map_nr);
+	if (copy_e820_map(params->e820_map, params->e820_map_nr) < 0) {
 		unsigned long mem_size;
 
 		/* compare results from other methods and take the greater */
-		if (ALT_MEM_K < EXT_MEM_K) {
-			mem_size = EXT_MEM_K;
+		if (params->alt_mem_k < params->screen.overlap.ext_mem_k) {
+			mem_size = params->screen.overlap.ext_mem_k;
 			who = "BIOS-88";
 		} else {
-			mem_size = ALT_MEM_K;
+			mem_size = params->alt_mem_k;
 			who = "BIOS-e801";
 		}
 
@@ -591,13 +565,12 @@
 
 static void __init parse_mem_cmdline (char ** cmdline_p)
 {
-	char c = ' ', *to = command_line, *from = COMMAND_LINE;
+	char c = ' ', *to = command_line, *from = saved_command_line;
 	int len = 0;
 	int usermem = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
-	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
-	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+	memcpy(saved_command_line, command_line, sizeof(saved_command_line));
 
 	for (;;) {
 		/*
@@ -667,6 +640,164 @@
 	}
 }
 
+static void init_settings(void)
+{
+	ROOT_DEV = to_kdev_t(0x0000);
+	memset(&drive_info, 0, sizeof(drive_info));
+	memset(&screen_info, 0, sizeof(screen_info));
+	memset(&apm_info.bios, 0, sizeof(apm_info.bios));
+	aux_device_present = 0;
+#ifdef CONFIG_BLK_DEV_RAM
+	rd_image_start = 0;
+	rd_prompt = 0;
+	rd_doload = 0;
+#endif
+	e820.nr_map = 0;
+	saved_command_line[0] = '\0';
+#ifdef CONFIG_BLK_DEV_INITRD
+	initrd_start = 0;
+	initrd_end = 0;
+#endif
+	/* set default screen information */
+	screen_info.orig_x = 0;
+	screen_info.orig_y = 25;
+	screen_info.orig_video_page = 0;
+	screen_info.orig_video_mode = 0;
+	screen_info.orig_video_cols = 80;
+	screen_info.orig_video_lines = 25;
+	screen_info.orig_video_ega_bx = 0;
+	screen_info.orig_video_isVGA = 1;
+	screen_info.orig_video_points = 16;
+}
+
+static void read_entry32_params(struct boot_params *params)
+{
+	char *cmdline;
+	int cmdline_off;
+	/*
+	 * These values are set a compile time or set by the bootloader
+	 */
+ 	ROOT_DEV = to_kdev_t(params->root_dev);
+
+	if (!params->mount_root_rdonly)
+		root_mountflags &= ~MS_RDONLY;
+
+#ifdef CONFIG_BLK_DEV_RAM
+	rd_image_start = params->ramdisk_flags & RAMDISK_IMAGE_START_MASK;
+	rd_prompt = ((params->ramdisk_flags & RAMDISK_PROMPT_FLAG) != 0);
+	rd_doload = ((params->ramdisk_flags & RAMDISK_LOAD_FLAG) != 0);
+#endif
+
+	/* The compiled in command line */
+	cmdline = (char *)params;
+	cmdline += params->internal_cmdline_off;
+	strncpy(command_line, cmdline, COMMAND_LINE_SIZE);
+	command_line[COMMAND_LINE_SIZE -1] = '\0';
+	cmdline_off = strlen(command_line);
+
+	/* Add a spece between command lines */
+	if (cmdline_off && (cmdline_off < COMMAND_LINE_SIZE) &&
+		(command_line[cmdline_off -1] != ' ')) {
+		command_line[cmdline_off++] = ' ';
+	}
+
+	/* The bootloader passed command line */
+	cmdline = "";
+	if (params->cmd_line_ptr) {
+		/* New command line protocol */
+		cmdline = (char *)(params->cmd_line_ptr);
+	}
+	else if (params->screen.overlap.cl_magic == CL_MAGIC_VALUE) {
+		cmdline = (char *)params + params->screen.overlap.cl_offset;
+	}
+	memcpy(command_line + cmdline_off, cmdline, COMMAND_LINE_SIZE - cmdline_off);
+	command_line[COMMAND_LINE_SIZE -1] = '\0';
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (params->type_of_loader && params->initrd_start) {
+		initrd_start = params->initrd_start ?
+			params->initrd_start + PAGE_OFFSET : 0;
+		initrd_end = initrd_start + params->initrd_size;
+	}
+#endif	
+}
+
+static void read_entry16_params(struct boot_params *params)
+{
+	/*
+	 * These values are set up by the setup-routine at boot-time
+	 */
+ 	drive_info = params->drive_info;
+ 	screen_info = params->screen.info;
+	apm_info.bios = params->apm_bios_info;
+	if( params->sys_desc_table.length != 0 ) {
+		MCA_bus = params->sys_desc_table.table[3] &0x2;
+		machine_id = params->sys_desc_table.table[0];
+		machine_submodel_id = params->sys_desc_table.table[1];
+		BIOS_revision = params->sys_desc_table.table[2];
+	}
+	aux_device_present = params->aux_device_info;
+
+	setup_memory_region(params);
+}
+
+static void call_entry16(struct boot_params *params)
+{
+	extern void (startup_32)(void);
+	void (*entry32_16)(void);
+	entry32_16 = (void (*)(void))(initial_regs.esi + params->entry32_16_off);
+	/* Disable advanced boot time hooks */
+	params->code32_start = __pa(&startup_32);
+	params->realmode_swtch[0] = 0;
+	params->realmode_swtch[1] = 0;
+	/* Don't have the realmode code self relocate */
+	params->loadflags |= LOADFLAG_STAY_PUT;
+	unlock_kernel();
+	entry32_16();
+	    
+}
+static void parse_params(char **cmdline_p)
+{
+	struct boot_params *params;
+	int entry16, entry32;
+	
+	params = (struct boot_params *)initial_regs.esi;
+	entry16 = initial_regs.ebp == ENTRY16;
+	entry32 = (initial_regs.ebp == ENTRY32) && (params->entry32_used);
+
+	init_settings();
+
+	/* Get compiled in and bootloader parameters */
+	if (entry16 || entry32) {
+		read_entry32_params(params);
+	}
+
+	/* Get parameters from the 16bit BIOS */
+	if (entry16) {
+		read_entry16_params(params);
+	}
+
+	/* Attempt to get the LinuxBIOS parameters */
+	read_linuxbios_params();
+
+	/* Read user specified params */
+	parse_mem_cmdline(cmdline_p);
+
+	if ((e820.nr_map == 0) && entry32) {
+		/* If we came in via the 32bit entry point and don't
+		 * have a memory size we need help.
+		 * So go out and come back in the 16bit entry point.
+		 */
+		printk(KERN_INFO 
+		       "No memory size information so reentering 16bit mode\n");
+		call_entry16(params);
+	}
+
+	if (e820.nr_map == 0) {
+		panic("Unknown memory size\n");
+	}
+}
+
 void __init setup_arch(char **cmdline_p)
 {
 	unsigned long bootmap_size, low_mem_size;
@@ -677,27 +808,8 @@
 	visws_get_board_type_and_rev();
 #endif
 
- 	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
- 	drive_info = DRIVE_INFO;
- 	screen_info = SCREEN_INFO;
-	apm_info.bios = APM_BIOS_INFO;
-	if( SYS_DESC_TABLE.length != 0 ) {
-		MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
-		machine_id = SYS_DESC_TABLE.table[0];
-		machine_submodel_id = SYS_DESC_TABLE.table[1];
-		BIOS_revision = SYS_DESC_TABLE.table[2];
-	}
-	aux_device_present = AUX_DEVICE_INFO;
-
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-	setup_memory_region();
+	parse_params(cmdline_p);
 
-	if (!MOUNT_ROOT_RDONLY)
-		root_mountflags &= ~MS_RDONLY;
 	init_mm.start_code = (unsigned long) &_text;
 	init_mm.end_code = (unsigned long) &_etext;
 	init_mm.end_data = (unsigned long) &_edata;
@@ -708,8 +820,6 @@
 	data_resource.start = virt_to_phys(&_etext);
 	data_resource.end = virt_to_phys(&_edata)-1;
 
-	parse_mem_cmdline(cmdline_p);
-
 #define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 #define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
 #define PFN_PHYS(x)	((x) << PAGE_SHIFT)
@@ -881,18 +991,16 @@
 	find_smp_config();
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
-	if (LOADER_TYPE && INITRD_START) {
-		if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
-			reserve_bootmem(INITRD_START, INITRD_SIZE);
-			initrd_start =
-				INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
-			initrd_end = initrd_start+INITRD_SIZE;
+	if (initrd_start) {
+		if ((initrd_end - PAGE_OFFSET) <= (max_low_pfn << PAGE_SHIFT)) {
+			reserve_bootmem(initrd_start - PAGE_OFFSET,
+				initrd_end - initrd_start);
 		}
 		else {
 			printk(KERN_ERR "initrd extends beyond end of memory "
-			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-			    INITRD_START + INITRD_SIZE,
-			    max_low_pfn << PAGE_SHIFT);
+				"(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+				initrd_end - PAGE_OFFSET, 
+				max_low_pfn << PAGE_SHIFT);
 			initrd_start = 0;
 		}
 	}
diff -uNr linux-2.5.11/arch/i386/kernel/trampoline.S linux-2.5.11.boot.elf/arch/i386/kernel/trampoline.S
--- linux-2.5.11/arch/i386/kernel/trampoline.S	Mon Apr 29 00:17:11 2002
+++ linux-2.5.11.boot.elf/arch/i386/kernel/trampoline.S	Mon Apr 29 11:22:04 2002
@@ -12,10 +12,6 @@
  *	In fact we don't actually need a stack so we don't
  *	set one up.
  *
- *	We jump into the boot/compressed/head.S code. So you'd
- *	better be running a compressed kernel image or you
- *	won't get very far.
- *
  *	On entry to trampoline_data, the processor is in real mode
  *	with 16-bit addressing and 16-bit data.  CS has some value
  *	and IP is zero.  Thus, data addresses need to be absolute
@@ -23,12 +19,16 @@
  *
  *	If you work on this file, check the object module with objdump
  *	--full-contents --reloc to make sure there are no relocation
- *	entries except for the gdt one..
+ *	entries except for gdt & secondary_startup_32..
  */
 
 #include <linux/linkage.h>
+#include <linux/threads.h>
 #include <asm/segment.h>
 #include <asm/page.h>
+#include <asm/desc.h>
+
+#define GDT_ENTRIES	(__TSS(NR_CPUS))
 
 .data
 
@@ -42,7 +42,6 @@
 	mov	%cs, %ax	# Code and data in the same place
 	mov	%ax, %ds
 
-	mov	$1, %bx		# Flag an SMP trampoline
 	cli			# We should be safe anyway
 
 	movl	$0xA5A5A5A5, trampoline_data - r_base
@@ -56,15 +55,16 @@
 	lmsw	%ax		# into protected mode
 	jmp	flush_instr
 flush_instr:
-	ljmpl	$__KERNEL_CS, $0x00100000
-			# jump to startup_32 in arch/i386/kernel/head.S
+		# jump to secondary_startup_32 in arch/i386/kernel/head.S
+	ljmpl	$__KERNEL_CS, $(secondary_startup_32 - __PAGE_OFFSET)
+	
 
 idt_48:
 	.word	0			# idt limit = 0
 	.word	0, 0			# idt base = 0L
 
 gdt_48:
-	.word	0x0800			# gdt limit = 2048, 256 GDT entries
+	.word	GDT_ENTRIES*8-1		# gdt limit
 	.long	gdt_table-__PAGE_OFFSET	# gdt base = gdt (first SMP CPU)
 
 .globl trampoline_end
diff -uNr linux-2.5.11/arch/i386/vmlinux.lds linux-2.5.11.boot.elf/arch/i386/vmlinux.lds
--- linux-2.5.11/arch/i386/vmlinux.lds	Sun Mar 10 20:09:08 2002
+++ linux-2.5.11.boot.elf/arch/i386/vmlinux.lds	Mon Apr 29 11:21:23 2002
@@ -3,7 +3,13 @@
  */
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
-ENTRY(_start)
+physical_startup_32 = startup_32 - 0xC0000000;
+ENTRY(physical_startup_32)
+PHDRS
+{
+	text PT_LOAD AT(0x100000);
+
+}
 SECTIONS
 {
   . = 0xC0000000 + 0x100000;
@@ -12,7 +18,7 @@
 	*(.text)
 	*(.fixup)
 	*(.gnu.warning)
-	} = 0x9090
+	} :text = 0x9090
 
   _etext = .;			/* End of text section */
 
@@ -73,8 +79,16 @@
   __bss_start = .;		/* BSS */
   .bss : {
 	*(.bss)
+        _end = . ;
+	/* Reserve space for the bootmem bitmap,
+	 * With a start at 0xC0000000 this is just 32k in the worst case.
+	 *
+	 * Ideally this would be in an initdata segment but that causes
+	 * problems with memory being reserved twice.
+	 */
+	. = ALIGN(4096);
+	. = . + 32768;
 	}
-  _end = . ;
 
   /* Sections to be discarded */
   /DISCARD/ : {
diff -uNr linux-2.5.11/arch/x86_64/boot/Makefile linux-2.5.11.boot.elf/arch/x86_64/boot/Makefile
--- linux-2.5.11/arch/x86_64/boot/Makefile	Sun Mar 10 20:08:39 2002
+++ linux-2.5.11.boot.elf/arch/x86_64/boot/Makefile	Mon Apr 29 11:22:43 2002
@@ -14,11 +14,11 @@
 
 zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
 	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
-	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
+	tools/build bootsect setup compressed/vmlinux.out CURRENT > zImage
 
 bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build
 	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
-	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+	tools/build -b bbootsect bsetup compressed/bvmlinux.out CURRENT > bzImage
 
 bzImage-padded: bzImage
 	dd if=/dev/zero bs=1k count=70 >> bzImage
diff -uNr linux-2.5.11/include/asm-i386/boot.h linux-2.5.11.boot.elf/include/asm-i386/boot.h
--- linux-2.5.11/include/asm-i386/boot.h	Wed Apr 16 15:15:00 1997
+++ linux-2.5.11.boot.elf/include/asm-i386/boot.h	Mon Apr 29 11:22:04 2002
@@ -1,15 +1,39 @@
 #ifndef _LINUX_BOOT_H
 #define _LINUX_BOOT_H
 
+/* Address space division during load */
+	/* Memory below 640 we can use for loading */
+#define LOW_BASE   0x001000
+#define LOW_MAX    0x0a0000  /* Maximum low memory address to use */
+	/* Memory above 640 we can use for loading */
+#define HIGH_BASE  0x100000
+#define HIGH_MAX   __MAXMEM
+	/* Subset of the low segment that is generally safe to
+	 * use for loading.
+	 */
+#define REAL_BASE  0x010000
+#define REAL_MAX   0x090000
+
 /* Don't touch these, unless you really know what you're doing. */
 #define DEF_INITSEG	0x9000
 #define DEF_SYSSEG	0x1000
 #define DEF_SETUPSEG	0x9020
 #define DEF_SYSSIZE	0x7F00
+#define DEF_HEAP_SIZE	1024
 
 /* Internal svga startup constants */
 #define NORMAL_VGA	0xffff		/* 80x25 mode */
 #define EXTENDED_VGA	0xfffe		/* 80x50 mode */
 #define ASK_VGA		0xfffd		/* ask for it at bootup */
+
+/* Entry point ID constants */
+#define ENTRY16		0x73726468 /* 'hdrs' */
+#define ENTRY32		0x53524448 /* 'HDRS' */
+
+/* Maximum command line size */
+#define COMMAND_LINE_SIZE 256
+
+/* Initial page table size 8MB */
+#define INITIAL_PAGE_TABLE_SIZE 0x800000
 
 #endif
diff -uNr linux-2.5.11/include/asm-i386/boot_param.h linux-2.5.11.boot.elf/include/asm-i386/boot_param.h
--- linux-2.5.11/include/asm-i386/boot_param.h	Wed Dec 31 17:00:00 1969
+++ linux-2.5.11.boot.elf/include/asm-i386/boot_param.h	Mon Apr 29 11:22:46 2002
@@ -0,0 +1,103 @@
+#ifndef __I386_BOOT_PARAM_H
+#define __I386_BOOT_PARAM_H
+
+struct initial_regs32 {
+	const __u32 eax;
+	const __u32 ebx;
+	const __u32 ecx;
+	const __u32 edx;
+	const __u32 esi;
+	const __u32 edi;
+	const __u32 esp;
+	const __u32 ebp;
+}; 
+struct drive_info_struct { __u8 dummy[32]; };
+struct sys_desc_table {
+	__u16 length;
+	__u8 table[318];
+};
+struct screen_info_overlap {
+	__u8  reserved1[2];		/* 0x00 */
+	__u16 ext_mem_k;		/* 0x02 */
+	__u8  reserved2[0x20 - 0x04];	/* 0x04 */
+	__u16 cl_magic;			/* 0x20 */
+#define CL_MAGIC_VALUE 0xA33F
+	__u16 cl_offset;		/* 0x22 */
+	__u8  reserved3[0x40 - 0x24];	/* 0x24 */
+};
+
+struct boot_params {
+	union {					/* 0x00 */
+		struct screen_info info;
+		struct screen_info_overlap overlap;
+	} screen;
+
+	struct apm_bios_info apm_bios_info;	/* 0x40 */
+	__u8 reserved4[0x80 - 0x54];		/* 0x54 */
+	struct drive_info_struct drive_info;	/* 0x80 */
+	struct sys_desc_table sys_desc_table;	/* 0xa0 */
+	__u32 alt_mem_k;			/* 0x1e0 */
+	__u16 base_mem_k;			/* 0x1e4 */
+	__u8  reserved5[2];			/* 0x1e6 */
+	__u8  e820_map_nr;			/* 0x1e8 */
+	__u8  reserved6[8];			/* 0x1e9 */
+	__u8  setup_sects;			/* 0x1f1 */
+	__u16 mount_root_rdonly;		/* 0x1f2 */
+	__u16 syssize;				/* 0x1f4 */
+	__u16 swapdev;				/* 0x1f6 */
+	__u16 ramdisk_flags;			/* 0x1f8 */
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000	
+	__u16 vid_mode;				/* 0x1fa */
+	__u16 root_dev;				/* 0x1fc */
+	__u8  reserved9[1];			/* 0x1fe */
+	__u8  aux_device_info;			/* 0x1ff */
+	/* 2.00+ */
+	__u8  jump[2];				/* 0x200 */
+	__u8  header_magic[4];			/* 0x202 */
+	__u16 version;				/* 0x206 */
+	__u16 realmode_swtch[2];		/* 0x208 */
+	__u16 start_sys_seg;			/* 0x20c */
+	__u16 kernel_version;			/* 0x20e */
+	__u8  type_of_loader;			/* 0x210 */
+#define LOADER_LILO            0x00
+#define LOADER_LOADLIN         0x10
+#define LOADER_BOOTSECT_LOADER 0x20
+#define LOADER_SYSLINUX        0x30
+#define LOADER_ETHERBOOT       0x40
+#define LOADER_UNKNOWN         0xFF
+	__u8  loadflags;			/* 0x211 */
+#define LOADFLAG_LOADED_HIGH  1
+#define LOADFLAG_STAY_PUT     0x40
+#define LOADFLAG_CAN_USE_HEAP 0x80
+	__u16 setup_move_size;			/* 0x212 */
+	__u32 code32_start;			/* 0x214 */
+	__u32 initrd_start;			/* 0x218 */
+	__u32 initrd_size;			/* 0x21c */
+	__u8  reserved13[4];			/* 0x220 */
+	/* 2.01+ */
+	__u16 heap_end_ptr;			/* 0x224 */
+	__u8  pad1[2];				/* 0x226 */
+	/* 2.02+ */
+	__u32 cmd_line_ptr;			/* 0x228 */
+	/* 2.03+ */
+	__u32 ramdisk_max;			/* 0x22c */
+	/* 2.04+ */
+	__u16 entry32_off;			/* 0x230 */
+	__u16 internal_cmdline_off;		/* 0x232 */
+	__u32 real_base;			/* 0x234 */
+	__u32 real_memsz;			/* 0x238 */
+	__u32 real_filesz;			/* 0x23c */
+ 	__u32 kern_base;			/* 0x240 */
+ 	__u32 kern_memsz;			/* 0x244 */
+ 	__u32 kern_filesz;			/* 0x248 */
+	/* Below this point for internal kernel use only */
+	__u32 entry32_used;			/* 0x24c */
+	__u32 entry32_16_off;			/* 0x250 */
+	struct initial_regs32 regs;		/* 0x254 */
+	__u8  reserved15[0x2d0 - 0x274];	/* 0x274 */
+	struct e820entry e820_map[E820MAX];	/* 0x2d0 */
+						/* 0x550 */
+} __attribute__((packed));
+#endif /* __I386_BOOT_PARAM_H */
diff -uNr linux-2.5.11/include/asm-i386/e820.h linux-2.5.11.boot.elf/include/asm-i386/e820.h
--- linux-2.5.11/include/asm-i386/e820.h	Fri Aug 18 10:30:51 2000
+++ linux-2.5.11.boot.elf/include/asm-i386/e820.h	Mon Apr 29 11:22:48 2002
@@ -15,6 +15,7 @@
 #define E820MAP	0x2d0		/* our map */
 #define E820MAX	32		/* number of entries in E820MAP */
 #define E820NR	0x1e8		/* # entries in E820MAP */
+#define E820ENTRY_SIZE 20	/* size of an E820MAP entry */
 
 #define E820_RAM	1
 #define E820_RESERVED	2
@@ -35,6 +36,9 @@
 };
 
 extern struct e820map e820;
+extern void  add_memory_region(unsigned long long start,
+	unsigned long long size, int type);
+extern void print_memory_map(char *who);
 #endif/*!__ASSEMBLY__*/
 
 #endif/*__E820_HEADER*/
diff -uNr linux-2.5.11/include/asm-i386/linuxbios.h linux-2.5.11.boot.elf/include/asm-i386/linuxbios.h
--- linux-2.5.11/include/asm-i386/linuxbios.h	Wed Dec 31 17:00:00 1969
+++ linux-2.5.11.boot.elf/include/asm-i386/linuxbios.h	Mon Apr 29 11:51:05 2002
@@ -0,0 +1,10 @@
+#ifndef __ASMi386_LINUXBIOS_H
+#define __ASMi386_LINUXBIOS_H
+
+#ifdef CONFIG_LINUXBIOS
+void read_linuxbios_params(void);
+#else
+#define read_linuxbios_params()
+#endif /* CONFIG_LINUXBIOS */
+
+#endif
