--- linux-2.0.28-orig/arch/i386/boot/setup.S	Sat Mar 30 10:58:57 1996
+++ linux-2.0.28+logo/arch/i386/boot/setup.S	Thu Feb 17 12:48:01 2000
@@ -26,11 +26,20 @@
 !
 ! Video handling moved to video.S by Martin Mares, March 1996
 ! <mj@k332.feld.cvut.cz>
+!
+! Extended memory detection scheme retwiddled by orc@pell.chi.il.us (jessica l.
+! parsons) to avoid loadlin confusion, July 1997
+!
+! Extended memory detection scheme from 2.3.x (Jessica L. Parsons, Nathan Zook)
+! backported to catch annoying machines that have mangled memory maps,
+! Feb 2000.
+!
 
 ! NOTE! These had better be the same as in bootsect.s!
 #define __ASSEMBLY__
 #include <linux/config.h>
 #include <asm/segment.h>
+#include <asm/e820.h>
 #include <linux/version.h>
 #include <linux/compile.h>
 
@@ -55,7 +64,7 @@
 
 entry start
 start:
-	jmp	start_of_setup
+	jmp	trampoline
 ! ------------------------ start of header --------------------------------
 !
 ! SETUP-header, must start at CS:2 (old 0x9020:2)
@@ -103,6 +112,8 @@
 ramdisk_size:	.long	0	! its size in bytes
 bootsect_kludge:
 		.word   bootsect_helper,SETUPSEG
+trampoline:	br	start_of_setup
+		.space	1024	! room for the e820 bios list
 heap_end_ptr:	.word	modelist+1024	! space from here (exclusive) down to
 				! end of setup code can be used by setup
 				! for local heap purposes.
@@ -232,6 +243,163 @@
 loader_ok:
 ! Get memory size (extended mem, kB)
 
+	xor	eax,eax			! prezero
+	mov	[0x1e0], eax		! alt_mem_k
+	mov	[E820NR], al		! e820_map_nr
+	mov	[E820MAP], ax		! and the e820 error flag
+
+! Try three different memory detection schemes.  First, try
+! e820h, which lets us assemble a memory map, then try e801h,
+! which returns a 32-bit memory size, and finally 88h, which
+! returns 0-64m
+
+#ifdef CONFIG_MEM_E820
+
+! method E820H:
+! the memory map from hell.  e820h returns memory classified into
+! a whole bunch of different types, and allows memory holes and
+! everything.  We scan through this memory map and build a list
+! of the first E820MAX memory areas, which we return at [E820MAP].
+!
+! sanity checking:  There are two levels of sanity checking here,
+! depending on how much you trust the bios.  The permissive level
+! merely drops out of the memory detection loop when carry is set
+! (signifying either no such function or finished) or %ebx == 0
+! (end of memory map). The e820 map is abandoned if %ecx < 20 or
+! %ecx > 255 bytes (we want 20 bytes, but e820 has been taken into
+! the ACPI spec, which is apparently veery vague about whether it
+! will adhere to transferring 20 bytes like the spec says) or
+! %eax != 'SMAP' (the call is supposed to copy %edx over to %eax.)
+!
+! The paranoid level of sanity checking also saves ds over the call,
+! in case this is some malicious bios the eats registers that it's
+! not supposed to, and it abandons the e820 map if es:di change over
+! the course of the call (the memory buffer is passed in via es:di,
+! and should not be randomly shuffled around)
+!
+! In both cases, we stash %ecx at the end of the record (rec+20) so
+! the kernelside can use it in further sanity checks.
+
+meme820:
+	xor	ebx, ebx		! continuation counter
+
+	push	ds			! es:di points at the whitelist
+	pop	es
+	mov	di, #E820MAP
+jmpe820:
+	mov	edx, #0x534d4150	! ascii `SMAP'
+	mov	eax, #0x0000e820	! e820, upper word zeroed
+	mov	ecx, #E820LEN		! 20 bytes is what we want.
+
+#ifdef FLAG_E820_PARANOID
+	push	ds
+	push	di			! stash %di into %dx
+	int	0x15			! make the call
+	pop	dx
+	pop	ds
+#else
+	int	0x15			! make the call
+#endif
+	jc	fin820			! fall to e801 if it fails
+
+! do some sanity checking:
+!
+! check to see if the SMAP moved over to %eax, like
+! G-d himself intended.
+
+	cmp	eax, #0x534d4150	! did the bios move for you?
+	je	chksiz820
+
+	mov	ax, #E820_ERR_SMAP
+abort820:
+	mov	[E820MAP], ax
+	xor	ax, ax
+	mov	[E820NR], al
+	jmp	fin820
+
+chksiz820:
+
+! check that %ecx >= 20 && %ecx < 20 + a fudge factor
+
+	mov	ax, #E820_ERR_SIZE
+	cmp	ecx, #E820LEN
+	jl	abort820
+	cmp	ecx, #255
+	jnl	abort820
+
+
+#if FLAG_E820_PARANOID
+
+! Then check that es:di is still the same.
+
+	mov	ax, #E820_ERR_ES
+	cmp	dx, di			! %di should be constant.
+	jne	abort820
+
+! As should %es
+
+	mov	ax, #E820_ERR_DI
+	mov	cx, es			! how about %es?
+	mov	dx, ds			! it should be == %ds
+	cmp	cx, dx
+	jne	abort820		! or it's the apocolypse
+#endif
+
+! If this is usable memory, we save it by simply advancing %di by
+! sizeof(e820rec).
+
+	mov	al, [E820NR]		! If the table gets too large
+	cmp	al, #E820MAX		! we must flee
+	jnl	fin820
+
+	mov	ax, #E820_ERR_WRAP
+	mov	E820LEN(di), cx		! stash recsize
+	mov	edx, dword ptr (di)	! convert start/size to start/end
+	mov	ecx, dword ptr 4(di)
+	add	dword ptr 8(di), edx
+	adc	dword ptr 12(di), ecx
+#if FLAG_E820_WRAP
+	jc	abort820
+#endif
+	inc	byte ptr [E820NR]	! up the # of records
+
+	mov	ax, di			! point %es:%di at the next
+	add	ax, #E820LEN+2		! record
+	mov	di, ax
+again820:
+	cmp	ebx, #0			! check to see if
+	je	fin820			! %ebx is set to EOF
+	br	jmpe820			! (too far for jne.  Sigh)
+fin820:
+#endif
+
+#ifdef CONFIG_MEM_E801
+
+! method E801H:
+! memory size is in 1k chunksizes, to avoid confusing loadlin.
+! we store the 0xe801 memory size in a completely different place,
+! because it will most likely be longer than 16 bits.
+! (use 1e0 because that's what Larry Augustine uses in his
+! alternative new memory detection scheme, and it's sensible
+! to write everything into the same place.)
+
+meme801:
+        mov     ax,#0xe801
+	int     0x15
+	jc	mem88
+
+	and     edx, #0xffff    ! clear sign extend
+	shl     edx, 6          ! and go from 64k to 1k chunks
+	mov     [0x1e0],edx     ! store extended memory size
+
+	and     ecx, #0xffff    ! clear sign extend
+	add     [0x1e0],ecx     ! and add lower memory into total size.
+#endif
+
+! Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
+! 64mb, depending on the bios) in ax.
+
+mem88:
 	mov	ah,#0x88
 	int	0x15
 	mov	[2],ax
--- linux-2.0.28-orig/arch/i386/kernel/setup.c	Fri Sep 20 07:00:34 1996
+++ linux-2.0.28+logo/arch/i386/kernel/setup.c	Thu Feb 17 12:58:42 2000
@@ -33,6 +33,8 @@
 #include <asm/system.h>
 #include <asm/smp.h>
 
+#include <asm/e820.h>
+
 /*
  * Tell us the machine setup..
  */
@@ -77,11 +79,25 @@
 
 extern char empty_zero_page[PAGE_SIZE];
 
+struct physical_memory physical_memory;
+
 /*
  * This is set up by the setup-routine at boot-time
  */
 #define PARAM	empty_zero_page
+
 #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    (  (unsigned long *) (PARAM+E820MAP))
+#define E820_ERR    (* (unsigned short*) (PARAM+E820MAP))
+
+#define Region	physical_memory.region
+#define Bios	physical_memory.bios
+
+#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
+
 #ifdef CONFIG_APM
 #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
 #endif
@@ -95,6 +111,7 @@
 #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
 
@@ -105,12 +122,352 @@
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
 
+
+unsigned long memparse(char *ptr, char **retptr)
+{
+	unsigned long ret;
+
+	ret = simple_strtoul(ptr, retptr, 0);
+
+	if (**retptr == 'K' || **retptr == 'k') {
+		ret <<= 10;
+		(*retptr)++;
+	}
+	else if (**retptr == 'M' || **retptr == 'm') {
+		ret <<= 20;
+		(*retptr)++;
+	}
+	else if (**retptr == 'G' || **retptr == 'g') {
+		ret <<= 30;
+		(*retptr)++;
+	}
+	return ret;
+} /* memparse */
+
+
+enum region_flags { RF_RECLAIM =0x01,
+                    RF_NOT_RAM =0x02,
+		    RF_OVERFLOW=0x04,
+		    RF_ZERO    =0x08,
+		    RF_MERGED  =0x10,
+		    RF_ADDED   =0x20 } ;
+
+enum region_flags add_memory_region(__u64 start, __u64 end, __u32 type)
+{
+    int i, x;
+    enum region_flags flag = 0;
+
+#if FLAG_E820_RECLAIM
+    if ( (physical_memory.p_flags & CHK_PMEM_RECLAIM) && (type == E820_ACPI) )
+	flag |= RF_RECLAIM;
+    else if (type != E820_RAM)
+	return RF_NOT_RAM;
+#else
+    if (type != E820_RAM)
+	return RF_NOT_RAM;
+#endif
+
+    if (start == end)
+	return flag|RF_ZERO;
+
+#ifdef CONFIG_E820_MERGE
+    /* see if we can merge this region with an existing one */
+
+    for (x=0; x < physical_memory.nr_region; x++)
+	if (end == Region[x].start) {
+	    /* glue memory region onto the start of this one */
+	    Region[x].start = start;
+	    break;
+	}
+	else if (Region[x].end == start) {
+	    /* glue memory region onto the end of this one */
+	    Region[x].end = end;
+	    break;
+	}
+    if (x < physical_memory.nr_region) {
+	/* If we've merged a region, check to see if the new region
+	 * want to merge with anyone else.
+	 */
+	if (x > 0 && Region[x].start == Region[x-1].end) {
+	    Region[x-1].end = Region[x].end;
+	    for (i=x; i < physical_memory.nr_region; i++)
+		Region[x] = Region[x+1];
+	    physical_memory.nr_region--;
+	    x--;
+	}
+	if (x < physical_memory.nr_region-1 && Region[x].end == Region[x+1].start) {
+	    Region[x].end = Region[x+1].end;
+	    for (i=x+1; i < physical_memory.nr_region-1; i++)
+		Region[x] = Region[x+1];
+	    physical_memory.nr_region--;
+	}
+	else
+	    return flag|RF_MERGED;
+    }
+#endif
+
+    if (physical_memory.nr_region == E820MAX)
+	return flag|RF_OVERFLOW;
+
+    /* insert the new region in order */
+    for (x=0; x < physical_memory.nr_region; x++)
+	if (end < Region[x].start) {
+	    /* add it in here */
+	    for (i=physical_memory.nr_region; i>x; --i)
+		Region[i] = Region[i-1];
+	    Region[x].start = start;
+	    Region[x].end   = end;
+	    physical_memory.nr_region++;
+	    return flag|RF_ADDED;
+	}
+    Region[physical_memory.nr_region].start = start;
+    Region[physical_memory.nr_region].end   = end;
+    physical_memory.nr_region++;
+    return flag|RF_ADDED;
+} /* add_memory_region */
+
+
+#define GIGABYTE(x)	((x) * 1024LL * 1024LL * 1024LL)
+#if FLAG_E820_DEBUG
+#  define E820DBG(x)	printk x
+#else
+#  define E820DBG(x)	
+#endif
+
+/*
+ * Do NOT EVER look at the BIOS memory size location.
+ * It does not work on many machines.
+ */
+#define LOWMEMSIZE()	(639 * 1024)
+
+
+#if FLAG_E820_DEBUG
+void
+report(enum region_flags code)
+{
+    if (code & RF_RECLAIM)
+	printk(" reclaimed");
+    if (code & RF_ADDED)
+	printk(" added");
+    if (code & RF_MERGED)
+	printk(" merged");
+    if (code & RF_OVERFLOW)
+	printk(" overflow");
+    if (code & RF_NOT_RAM)
+	printk(" rom");
+    if (code & RF_ZERO)
+	printk(" zero-length");
+}
+#endif
+
+
+/*
+ * region_check() validates the physical_memory map, plus lops out memory
+ * that lives in suspicious places.
+ */
+int
+region_check(void)
+{
+    unsigned int x, i;
+
+    for (x=0; x < physical_memory.nr_region; x++) {
+	if (x < physical_memory.nr_region-1
+		&& Region[x].end >= Region[x+1].start) {
+	    printk("SMAP: region %d (%010Lx - %010Lx) overlaps region %d (%010Lx - %010Lx) -- map dropped\n",
+		    x, Region[x].start,
+		       Region[x].end,
+		    x+1, Region[x+1].start,
+			 Region[x+1].end);
+	    return 1;
+	}
+#if FLAG_E820_GULLIBLE
+	if (physical_memory.p_flag & CHK_PMEM_GULLIBLE)
+	    continue;
+#endif
+#if FLAG_E820_4GB_ONLY
+	if (Region[x].start >= GIGABYTE(4)) {
+	    E820DBG(("SMAP: region %010Lx - %010Lx dropped\n",
+			Region[x].start, Region[x].end));
+	    for (i=x; i < physical_memory.nr_region; i++)
+		Region[i] = Region[i+1];
+	    x--;
+	    physical_memory.nr_region--;
+	    continue;
+	}
+
+	if (Region[x].end > GIGABYTE(4)) {
+	    E820DBG(("SMAP: region %010Lx - %010Lx truncated to %010Lx - %010Lx\n",
+		    Region[x].start, Region[x].end, Region[x].start,
+		    GIGABYTE(4)));
+	    Region[x].end = GIGABYTE(4);
+	}
+#endif
+
+	if (Region[x].start >= HIGH_MEMORY || Region[x].end <= LOWMEMSIZE())
+	    continue;
+
+	if (Region[x].start >= LOWMEMSIZE()) {
+	    if (Region[x].end < HIGH_MEMORY) {
+		E820DBG(("%010Lx - %010Lx dropped\n",
+			Region[x].start, Region[x].end));
+		for (i=x; i < physical_memory.nr_region; i++)
+		    Region[i] = Region[i+1];
+		x--;
+		physical_memory.nr_region--;
+	    }
+	    else {
+		E820DBG(("SMAP: %010Lx - %010Lx trimmed to %010lx - %010Lx\n",
+			Region[x].start, Region[x].end,
+			(unsigned long)HIGH_MEMORY, Region[x].end));
+		Region[x].start = HIGH_MEMORY;
+	    }
+	}
+	else if (Region[x].end < HIGH_MEMORY) {
+	    E820DBG(("%010Lx - %010Lx trimmed to %010Lx - %010lx\n",
+		    Region[x].start, Region[x].end,
+		    Region[x].start, (unsigned long)LOWMEMSIZE()));
+	    Region[x].end = LOWMEMSIZE();
+	}
+	else {
+	    E820DBG(("%010Lx - %010Lx split to %010Lx - 640k, 1m - %010Lx\n",
+		    Region[x].start, Region[x].end,
+		    Region[x].start, Region[x].end));
+	    for (i=physical_memory.nr_region; i > x; --i)
+		Region[i+1] = Region[i];
+
+	    Region[x+1].start = HIGH_MEMORY;
+	    Region[x+1].end = Region[x].end;
+	    Region[x].end = LOWMEMSIZE();
+	    x++;
+	    physical_memory.nr_region++;
+	}
+    }
+    return 0;
+} /* region_check */
+
+
+void setup_memory_region(void)
+{
+    int i;
+    enum region_flags ret;
+    unsigned long mem_size;
+
+    physical_memory.nr_region = 0;
+    physical_memory.p_flags = 0;
+
+#if FLAG_E820_DEBUG
+    if (E820_MAP_NR == 0 && E820_ERR != E820_ERR_NONE) {
+		/* spit out possible e820 error codes */
+	char *reason = 0;
+
+	switch (E820_ERR) {
+	case E820_ERR_SMAP:	reason = "SMAP didn't move";		break;
+	case E820_ERR_SIZE:	reason = "returned size is bogus";	break;
+	case E820_ERR_ES:	reason = "es changed";			break;
+	case E820_ERR_DI:	reason = "di changed";			break;
+	case E820_ERR_WRAP:	reason = "start+size > 64 bits";	break;
+	}
+
+	if (reason)
+	    printk("SMAP: map dropped, because %s\n", reason);
+	else
+	    printk("SMAP: map dropped, reason %d\n", E820_ERR);
+    }
+#endif
+
+    /*
+     * If we're lucky and live on a modern system, the setup code
+     * will have given us a memory map that we can use to properly
+     * set up memory.  If we aren't, we'll fake a memory map.
+     *
+     * We check to see that the memory map contains at least 2 elements
+     * before we'll use it, because the detection code in setup.S may
+     * not be perfect and most every PC known to man has two memory
+     * regions: one from 0 to 640k, and one from 1mb up.
+     */
+    if ( (E820_MAP_NR > 1) && (E820_MAP_NR < E820MAX) ) {
+	/* got a memory map; copy it into a safe place.
+	 */
+	physical_memory.p_flags = (FLAG_E820_LENGTH ? CHK_PMEM_LENGTH : 0)
+				| (FLAG_E820_GULLIBLE ? CHK_PMEM_GULLIBLE : 0)
+				| (FLAG_E820_RECLAIM ? CHK_PMEM_RECLAIM : 0) ;
+	physical_memory.nr_bios = E820_MAP_NR;
+	memcpy(&(Bios), E820_MAP,
+		E820_MAP_NR * sizeof Bios[0]);
+	for (i=0; i < E820_MAP_NR; i++) {
+	    ret = add_memory_region(Bios[i].addr,
+				    Bios[i].size,
+				    Bios[i].type);
+#if FLAG_E820_DEBUG
+	    printk("SMAP: %010Lx - %010Lx ",
+		    Bios[i].addr,
+		    Bios[i].size);
+
+	    switch (Bios[i].type) {
+	    case E820_RAM:	printk("(usable)");
+				break;
+	    case E820_RESERVED:
+				printk("(reserved)");
+				break;
+	    case E820_ACPI:
+				printk("(ACPI data)");
+				break;
+	    case E820_NVS:
+				printk("(ACPI NVS)");
+				break;
+	    default:
+				printk("(type %lu)",
+				    (unsigned long)Bios[i].type);
+				break;
+	    }
+#if FLAG_E820_LENGTH
+	    if ( (physical_memory.p_flags & CHK_PMEM_LENGTH) &&
+		 (Bios[i].len != E820LEN) )
+		printk(" [record is %d bytes long]",
+			    Bios[i].len);
+
+#endif
+	    report(ret);
+	    printk("\n");
+#endif
+	    if (ret & RF_OVERFLOW) {
+		printk("SMAP: table overflow -- reverting to old-style memory detection\n");
+		goto oldstyle;
+	    }
+	}
+	/* after putting in the e820 map, massage it into shape
+	 * for use by the kernel.  If region_check returns anything
+	 * except 0, something is very ill in the state of the
+	 * bios map.
+	 */
+	if (region_check() == 0)
+	    return /* the map is fine, so we'll use it */;
+    }
+
+oldstyle:
+    /* otherwise fake a memory map; one section from 0k->640k,
+     * the next section from 1mb->appropriate_mem_k
+     */
+
+    physical_memory.nr_region = 0;
+    physical_memory.p_flags = 0;
+
+    mem_size = (ALT_MEM_K < EXT_MEM_K) ? EXT_MEM_K : ALT_MEM_K;
+
+    add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+    add_memory_region(HIGH_MEMORY,
+		      HIGH_MEMORY + (mem_size << 10), E820_RAM);
+} /* setup_memory_region */
+
+
 void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
 	unsigned long memory_start, memory_end;
+	unsigned long memory_e801_end = 0;
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
+	int i;
 	static unsigned char smptrap=0;
 
 	if(smptrap==1)
@@ -126,8 +483,22 @@
 	apm_bios_info = APM_BIOS_INFO;
 #endif
 	aux_device_present = AUX_DEVICE_INFO;
-	memory_end = (1<<20) + (EXT_MEM_K<<10);
+
+	setup_memory_region();
+
+	/*
+  	 * Find the highest chunk of memory we have available
+  	 */
+	memory_end = 0;
+ 	for (i = 0; i < physical_memory.nr_region; i++) {
+  		unsigned long start, end;
+		start = PFN_UP(Region[i].start);
+ 		end = PFN_DOWN(Region[i].end);
+  		if ( (start < end) && (Region[i].end > memory_end) )
+			memory_end = Region[i].end;
+  	}
 	memory_end &= PAGE_MASK;
+
 #ifdef CONFIG_BLK_DEV_RAM
 	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
 	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
@@ -161,14 +532,12 @@
 				from += 9+4;
 				x86_capability &= ~8;
 			} else {
-				memory_end = simple_strtoul(from+4, &from, 0);
-				if ( *from == 'K' || *from == 'k' ) {
-					memory_end = memory_end << 10;
-					from++;
-				} else if ( *from == 'M' || *from == 'm' ) {
-					memory_end = memory_end << 20;
-					from++;
-				}
+				physical_memory.nr_region = 0;
+				memory_end = memparse(from+4, &from);
+				add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+				add_memory_region(HIGH_MEMORY,
+					          memory_end-HIGH_MEMORY,
+					          E820_RAM);
 			}
 		}
 		c = *(from++);
@@ -180,6 +549,7 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
+
 	*memory_start_p = memory_start;
 	*memory_end_p = memory_end;
 
--- linux-2.0.28-orig/arch/i386/mm/init.c	Thu Nov 14 05:20:09 1996
+++ linux-2.0.28+logo/arch/i386/mm/init.c	Wed Feb 16 20:21:10 2000
@@ -25,6 +25,7 @@
 #include <asm/segment.h>
 #include <asm/pgtable.h>
 #include <asm/dma.h>
+#include <asm/e820.h>
 
 #if 0
 /*
@@ -206,22 +207,18 @@
 
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
-	unsigned long start_low_mem = PAGE_SIZE;
+	unsigned long start_low_mem = PAGE_ALIGN(PAGE_SIZE);
 	int codepages = 0;
 	int reservedpages = 0;
 	int datapages = 0;
 	unsigned long tmp;
 	extern int _etext;
+	int i;
 
 	end_mem &= PAGE_MASK;
 	high_memory = end_mem;
 
-	/* clear the zero-page */
-	memset(empty_zero_page, 0, PAGE_SIZE);
-
 	/* mark usable pages in the mem_map[] */
-	start_low_mem = PAGE_ALIGN(start_low_mem);
-
 #ifdef __SMP__
 	/*
 	 * But first pinch a few for the stack/trampoline stuff
@@ -229,27 +226,34 @@
 	start_low_mem += PAGE_SIZE;				/* 32bit startup code */
 	start_low_mem = smp_alloc_memory(start_low_mem); 	/* AP processor stacks */
 #endif
-	start_mem = PAGE_ALIGN(start_mem);
 
-	/*
-	 * IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000.
-	 * They seem to have done something stupid with the floppy
-	 * controller as well..
-	 */
-	while (start_low_mem < 0x9f000) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags);
-		start_low_mem += PAGE_SIZE;
-	}
+	start_mem = PFN_UP(start_mem);
+	start_low_mem = PFN_UP(start_low_mem);
 
-	while (start_mem < high_memory) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
-		start_mem += PAGE_SIZE;
+	for (i = 0; i < physical_memory.nr_region; i++) {
+	    unsigned long start, end;
+
+	    start = PFN_UP(physical_memory.region[i].start);
+	    end   = PFN_DOWN(physical_memory.region[i].end);
+
+	    if (start < start_low_mem)
+		start = start_low_mem;
+	    else if ( start >= PFN_UP(HIGH_MEMORY) && start < start_mem)
+		start = start_mem;
+
+	    for (; start < end; ++start)
+		clear_bit(PG_reserved, &mem_map[start].flags);
 	}
+
+	/* clear the zero-page */
+	memset(empty_zero_page, 0, PAGE_SIZE);
+
+
 	for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) {
 		if (tmp >= MAX_DMA_ADDRESS)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
 		if (PageReserved(mem_map+MAP_NR(tmp))) {
-			if (tmp >= 0xA0000 && tmp < 0x100000)
+			if ((tmp >= 0xA0000 && tmp < 0x100000))
 				reservedpages++;
 			else if (tmp < (unsigned long) &_etext)
 				codepages++;
@@ -259,8 +263,7 @@
 		}
 		mem_map[MAP_NR(tmp)].count = 1;
 #ifdef CONFIG_BLK_DEV_INITRD
-		if (!initrd_start || (tmp < initrd_start || tmp >=
-		    initrd_end))
+		if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
 #endif
 			free_page(tmp);
 	}
--- linux-2.0.28-orig/arch/i386/defconfig	Tue Oct 29 17:42:40 1996
+++ linux-2.0.28+logo/arch/i386/defconfig	Tue Feb 15 15:57:56 2000
@@ -25,10 +30,15 @@
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-# CONFIG_M386 is not set
+CONFIG_M386=y
 # CONFIG_M486 is not set
-CONFIG_M586=y
+# CONFIG_M586 is not set
 # CONFIG_M686 is not set
+CONFIG_MEM_E820=y
+CONFIG_E820_PARANOID=y
+CONFIG_E820_MERGE=y
+# CONFIG_E820_RECLAIM is not set
+CONFIG_MEM_E801=y
 
 #
 # Floppy, IDE, and other block devices
--- linux-2.0.28-orig/arch/i386/config.in	Sun May 12 21:17:23 1996
+++ linux-2.0.28+logo/arch/i386/config.in	Wed Feb 16 21:05:30 2000
@@ -43,6 +48,18 @@
 	 486		CONFIG_M486	\
 	 Pentium	CONFIG_M586	\
 	 PPro		CONFIG_M686" Pentium
+
+mainmenu_option next_comment
+comment 'Memory detection'
+bool 'Use bios call e820 to detect memory' CONFIG_MEM_E820
+if [ "$CONFIG_MEM_E820" = "y" ]; then
+    bool '  Be extra cautious when using e820' CONFIG_E820_PARANOID
+    bool '  Merge adjacent memory regions' CONFIG_E820_MERGE
+    bool '  Reclaim ACPI table memory (DANGEROUS)' CONFIG_E820_RECLAIM
+fi
+bool 'Use bios call E801 to detect memory' CONFIG_MEM_E801
+endmenu
+
 endmenu
 
 source drivers/block/Config.in
--- linux-2.0.28-orig/lib/vsprintf.c	Tue Aug  1 00:02:48 1995
+++ linux-2.0.28+logo/lib/vsprintf.c	Wed Feb 16 18:06:52 2000
@@ -241,7 +241,10 @@
 
 
 		case 'n':
-			if (qualifier == 'l') {
+			if (qualifier == 'L') {
+				long long * ip = va_arg(args, long long *);
+				*ip = (str - buf);
+			} else if (qualifier == 'l') {
 				long * ip = va_arg(args, long *);
 				*ip = (str - buf);
 			} else {
@@ -276,7 +279,10 @@
 				--fmt;
 			continue;
 		}
-		if (qualifier == 'l')
+		if (qualifier == 'L') {
+			long long tmp = va_arg(args, unsigned long long);
+			num = (long) tmp;
+		} else if (qualifier == 'l')
 			num = va_arg(args, unsigned long);
 		else if (qualifier == 'h')
 			if (flags & SIGN)
