--- linux-2.2.14/lib/vsprintf.c.orig	Fri Apr  7 01:35:42 2000
+++ linux-2.2.14/lib/vsprintf.c	Fri Apr  7 01:37:15 2000
@@ -290,7 +290,9 @@
 				--fmt;
 			continue;
 		}
-		if (qualifier == 'l')
+		if (qualifier == 'L')
+			num = va_arg(args, unsigned long long);
+		else if (qualifier == 'l')
 			num = va_arg(args, unsigned long);
 		else if (qualifier == 'h') {
 			num = (unsigned short) va_arg(args, int);
--- linux-2.2.14/include/asm-i386/e820.h.orig	Fri Apr  7 00:58:05 2000
+++ linux-2.2.14/include/asm-i386/e820.h	Fri Apr  7 01:17:25 2000
@@ -0,0 +1,112 @@
+/*
+ * structures and definitions for the int 15, ax=e820 memory map
+ * scheme.
+ *
+ * In a nutshell, arch/i386/boot/setup.S populates a scratch table
+ * in the empty_zero_block that contains a list of usable address/size
+ * duples.   In arch/i386/kernel/setup.c, this information is
+ * transferred into the bios[], then converted into a list of valid
+ * memory regions in region[], and that new information is used in
+ * arch/i386/mm/init.c to mark pages available or not.
+ *
+ */
+#ifndef __E820_HEADER
+#define __E820_HEADER
+
+#define E820MAP		0x2d0	/* our map */
+#define E820MAX		32	/* number of entries in E820MAP */
+#define E820PHYSMAX	64	/* number of entries in physical_memory.region */
+#define E820NR		0x1e8	/* # entries in E820MAP */
+#define E820LEN		20	/* size of an e820 entry */
+
+#define E820_RAM	1
+#define E820_RESERVED	2
+#define E820_ACPI	3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS	4
+
+#define HIGH_MEMORY	(1024*1024)
+
+/* HACK: These macros map between page numbers and physical addresses.
+ * They used to be in arch/i386/kernel/setup.c, but have been moved here
+ * so that they can also be used in arch/i386/mm/init.c.
+ */
+#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+
+/*
+ * FLAG_E820_DEBUG enables bunches of debug messages.
+ */
+#define FLAG_E820_DEBUG	1
+
+/*
+ * FLAG_E820_GULLIBLE tells check_memory_region() to believe the bios
+ * when it says that memory in the 0x9fc00-0x100000 region is okay.  In
+ * most cases, this will NOT be the case and attempting to use this will
+ * result in your machine being converted to gravel as Linux scribbles
+ * in that memory region, but if you're trying to install Linux on an
+ * ultra-low memory machine and you can make this region usable, this
+ * might be useful.  If you enable this flag, you also need to set the
+ * corresponding flag in physical_memory.pflag before the memory will
+ * actually be used.
+ */
+#define FLAG_E820_GULLIBLE	0
+
+
+/* FLAG_E820_RECLAIM tells add_memory_region/check_memory_region to
+ * attempt to use E820 reclaim memory sections.  To have reclaim work,
+ * you need to configure it on, _plus_ CONFIG_ACPI needs to be turned off.
+ */
+#if defined(CONFIG_E820_RECLAIM) && !defined(CONFIG_ACPI)
+#  define FLAG_E820_RECLAIM	1
+#else
+#  define FLAG_E820_RECLAIM	0
+#endif
+
+/* FLAG_E820_4GB_ONLY tells the memory region adder to truncate memory
+ * segments to the first 4 gb of memory.
+ */
+#define	FLAG_E820_4GB_ONLY	0
+
+
+#ifndef __ASSEMBLY__
+
+struct e820 {
+    __u64 addr;	/* addr,size,type are returned by e820 bios call */
+    __u64 size;
+    __u32 type;
+    __u16 len;	/* %ecx(out) from the e820 bios call */
+} __attribute__ ((__packed__));
+
+struct physical_region {
+    __u64 start;
+    __u64 end;
+} ;
+
+struct physical_memory {
+    int p_flags;	/* assert sizeof(int) >= 3 bits */
+
+#define CHK_PMEM_GULLIBLE	0x02		/* user-settable in smap= */
+#define CHK_PMEM_RECLAIM	0x04		/* command line */
+
+    int nr_bios;				/* bios[] holds memory region */
+    int nr_region;				/* region[] holds valid mem */
+    struct e820 bios[E820MAX];			/* returned by the bios */
+    struct physical_region region[E820PHYSMAX];	/* that we want to allocate */
+} ;
+
+#define NR_HOLES	10
+
+struct excluded_memory {
+    int nr_hole;
+    struct __hole {
+	__u64 start;
+	__u64 end;
+	__u32 mask;
+    } hole[NR_HOLES];
+} ;
+
+extern struct physical_memory physical_memory;
+#endif/*!__ASSEMBLY__*/
+
+#endif/*__E820_HEADER*/
--- linux-2.2.14/arch/i386/boot/setup.S.orig	Fri Apr  7 00:20:11 2000
+++ linux-2.2.14/arch/i386/boot/setup.S	Fri Apr  7 01:09:17 2000
@@ -37,6 +37,7 @@
 #include <linux/version.h>
 #include <linux/compile.h>
 #include <asm/boot.h>
+#include <asm/e820.h>
 
 ! Signature words to ensure LILO loaded us right
 #define SIG1	0xAA55
@@ -59,7 +60,7 @@
 
 entry start
 start:
-	jmp	start_of_setup
+	jmp	trampoline
 ! ------------------------ start of header --------------------------------
 !
 ! SETUP-header, must start at CS:2 (old 0x9020:2)
@@ -119,6 +120,8 @@
 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.
+trampoline:     call    start_of_setup
+                .space  1024
 ! ------------------------ end of header ----------------------------------
 
 start_of_setup:
@@ -243,43 +246,97 @@
 	db	0
 
 loader_ok:
-! Get memory size (extended mem, kB)
+! MEMORY DETECTION CODE
 
-#ifndef STANDARD_MEMORY_BIOS_CALL
-	push	ebx
+	xor	eax, eax
+	mov	[0x1e0], eax		! zero e801_mem_low
+	mov	[0x1e4], eax		!  "   e801_mem_high
+	mov	[E820NR], al		!  "   e820_nr
 
-        xor     ebx,ebx		! preload new memory slot with 0k
-        mov	[0x1e0], ebx
+!
+! 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
+!
 
-        mov     ax,#0xe801
-	int     0x15
-	jc      oldstylemem
-
-! Memory size is in 1 k 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.)
-
-	and     ebx, #0xffff    ! clear sign extend
-	shl     ebx, 6          ! and go from 64k to 1k chunks
-	mov     [0x1e0],ebx     ! store extended memory size
-
-	and     eax, #0xffff    ! clear sign extend
- 	add     [0x1e0],eax     ! and add lower memory into total size.
-  
-	! and fall into the old memory detection code to populate the
-	! compatibility slot.
+#ifdef CONFIG_MEM_E820
 
-oldstylemem:
-	pop	ebx
-#else
-	mov     dword ptr [0x1e0], #0
-#endif
+!
+! 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].
+!
+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.
+
+	int	0x15			! make the call
+	jc	fin820			! fall out if it fails
+
+	cmp	eax, #0x534d4150	! did the bios move for you?
+	je	stash820
+
+	xor	ah, ah			! no?  chuck the whole thing.
+	mov	[E820NR], ah
+	jmp	fin820
+
+stash820:
+	inc	[E820NR]		! up the # of records
+	mov	al, [E820NR]		! If the table fills up
+	cmp	al, #E820MAX		! we must flee
+	jnl	fin820
+
+	mov	E820LEN(di),cx		! stash recsize
+	cmp	ebx,#0			! any more records in the pipe?
+	jz	fin820			! apparently not
+
+	mov	ax, di			! point %es:%di at the next
+	add	ax, #E820LEN+2		! record
+	mov	di, ax
+	jmp	jmpe820
+fin820:
+
+#endif/*CONFIG_MEM_E820*/
+
+#ifdef CONFIG_MEM_E801
+!
+! method E801H:
+! e801 returns 2 memory chunks: 1 from 1mb to 16mb, and 1 from 16mb up.
+! return the both of them, low in 1e0h, for compatability with older
+! versions of memory detection code, and high in 1e4h.
+!
+
+meme801:
+	mov	ax, #0xE801
+	int	0x15
+	jc	fine801
+
+	and	ecx, #0xffff			! clear sign extend
+	mov	[0x1e0], ecx			! store 1kb between 1-16mb
+	and	edx, #0xffff			! clear sign extend
+	mov	[0x1e4], edx			! store 64kb chunks above 16mb
+fine801:
+
+#endif/*CONFIG_MEM_E801*/
+
+!
+! Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
+! 64mb, depending on the bios) in ax.
+!
 	mov	ah,#0x88
 	int	0x15
-	mov	[2],ax
+	mov	[2], ax
+/* END OF MEMORY DETECTION CODE */
 
 ! Set the keyboard repeat rate to the max
 
--- linux-2.2.14/arch/i386/mm/init.c.orig	Fri Apr  7 00:53:36 2000
+++ linux-2.2.14/arch/i386/mm/init.c	Fri Apr  7 02:56:03 2000
@@ -27,6 +27,7 @@
 #include <asm/pgtable.h>
 #include <asm/dma.h>
 #include <asm/fixmap.h>
+#include <asm/e820.h>
 
 extern void show_net_buffers(void);
 extern unsigned long init_smp_mappings(unsigned long);
@@ -394,14 +395,14 @@
 	int datapages = 0;
 	int initpages = 0;
 	unsigned long tmp;
+	unsigned long start_low_page;
+	unsigned long start_mem_page;
+	int i;
 
 	end_mem &= PAGE_MASK;
 	high_memory = (void *) end_mem;
 	max_mapnr = num_physpages = MAP_NR(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)+PAGE_OFFSET;
 
@@ -417,15 +418,33 @@
 #endif
 	start_mem = PAGE_ALIGN(start_mem);
 
+	start_mem_page = PFN_UP(__pa(start_mem));
+	start_low_page = PFN_UP(__pa(start_low_mem));
+
 	while (start_low_mem < i386_endbase) {
 		clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags);
 		start_low_mem += PAGE_SIZE;
 	}
 
-	while (start_mem < end_mem) {
-		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_page)
+		start = start_low_page;
+	    else if ( start >= PFN_UP(HIGH_MEMORY) && start < start_mem_page)
+		start = start_mem_page;
+
+	    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 = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
 		if (tmp >= MAX_DMA_ADDRESS)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
--- linux-2.2.14/arch/i386/kernel/setup.c.orig	Fri Apr  7 00:28:46 2000
+++ linux-2.2.14/arch/i386/kernel/setup.c	Fri Apr  7 02:33:53 2000
@@ -59,6 +59,7 @@
 #include <asm/cobalt.h>
 #include <asm/msr.h>
 #include <asm/dma.h>
+#include <asm/e820.h>
 
 /*
  * Machine setup..
@@ -92,6 +93,9 @@
 	unsigned char table[0];
 };
 
+
+struct physical_memory physical_memory;
+
 unsigned char aux_device_present;
 
 #ifdef CONFIG_BLK_DEV_RAM
@@ -110,7 +114,15 @@
 #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 E801_MEM_LOW (*(unsigned long *) (PARAM+0x1e0))
+#define E801_MEM_HIGH (*(unsigned long *) (PARAM+0x1e4))
+#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))
 #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
 #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
@@ -257,6 +269,342 @@
 	}
 #endif
 
+unsigned long __init 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,
+		    RF_SHORT   =0x40,
+		    RF_TOOLONG =0x80 } ;
+
+enum region_flags __init 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;
+
+	if (start > end)
+		return RF_TOOLONG;
+
+#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)
+#define MEGABYTE(x)	((x) * 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_NOT_RAM)
+		printk(" rom");
+	if (code & RF_ZERO)
+		printk(" zero-length");
+
+	if (code & RF_SHORT)
+		printk(" ERROR: short record");
+	else if (code & RF_OVERFLOW)
+		printk(" ERROR: table overflow");
+	else if (code & RF_TOOLONG)
+		printk(" ERROR: start+size > 64 bits");
+}
+#endif
+
+
+static struct excluded_memory memory_hole;
+#define Hole	memory_hole.hole
+
+int __init
+prune_region(int x)
+{
+	int i, ct;
+
+	for (ct = 0; ct < memory_hole.nr_hole; ct++) {
+
+		if (Region[x].start >= Hole[ct].start || Region[x].end <= Hole[ct].end || Hole[ct].mask != 0)
+			continue;
+
+		if (Region[x].start >= Hole[ct].start) {
+			if (Region[x].end < Hole[ct].end) {
+				E820DBG(("SMAP: %010Lx - %010Lx dropped\n",
+					    Region[x].start, Region[x].end));
+				for (i=x; i < physical_memory.nr_region; i++)
+					Region[i] = Region[i+1];
+				physical_memory.nr_region--;
+				return --x;
+			}
+			else {
+				E820DBG(("SMAP: %010Lx - %010Lx trimmed to %010Lx - %010Lx\n",
+					    Region[x].start, Region[x].end,
+					    Hole[ct].start, Region[x].end));
+				Region[x].start = Hole[ct].start;
+			}
+		}
+		else if (Region[x].end < Hole[ct].end || physical_memory.nr_region >= E820PHYSMAX) {
+			if (physical_memory.nr_region >= E820PHYSMAX)
+				E820DBG(("SMAP: Memory region overflow\n"));
+			E820DBG(("SMAP: %010Lx - %010Lx trimmed to %010Lx - %010Lx\n",
+				    Region[x].start, Region[x].end,
+				    Region[x].start, Hole[ct].start));
+			Region[x].end = Hole[ct].start;
+		}
+		else {
+			E820DBG(("SMAP: %010Lx - %010Lx split to %010Lx - %010Lx, %010Lx - %010Lx\n",
+				Region[x].start, Region[x].end,
+				Region[x].start, Hole[ct].start,
+				Hole[ct].end, Region[x].end));
+			for (i=physical_memory.nr_region; i > x; --i)
+				Region[i+1] = Region[i];
+
+			Region[x+1].start = Hole[ct].end;
+			Region[x+1].end = Region[x].end;
+			Region[x].end = Hole[ct].start;
+			physical_memory.nr_region++;
+		}
+	}
+	return x;
+}
+
+
+/*
+ * region_check() validates the physical_memory map, plus lops out memory
+ * that lives in suspicious places.
+ */
+int __init
+region_check(void)
+{
+	unsigned int x;
+
+	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)\n",
+				    x, Region[x].start,
+				       Region[x].end,
+				    x+1, Region[x+1].start,
+					 Region[x+1].end);
+			return 1;
+		}
+		if ( (x = prune_region(x)) < 0)
+		    return 1;
+	}
+	return 0;
+} /* region_check */
+
+
+void __init
+add_memory_hole(__u64 start, __u64 end, __u32 mask)
+{
+    int idx;
+
+    if ( (idx=memory_hole.nr_hole) < NR_HOLES) {
+	Hole[idx].start = start;
+	Hole[idx].end   = end;
+	Hole[idx].mask  = mask;
+	memory_hole.nr_hole ++ ;
+    }
+}
+
+
+void __init
+setup_memory_region(void)
+{
+	int i;
+	enum region_flags ret;
+
+	add_memory_hole(LOWMEMSIZE(), HIGH_MEMORY, 0);
+#define VMALLOC_RESERVE	(64 << 20)	/* 64MB for vmalloc */
+#define MAXMEM	((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
+	add_memory_hole(MAXMEM, (__u64)-1, 0);
+
+#ifdef CONFIG_MEM_E820
+	/*
+	 * 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_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++) {
+			E820DBG(("SMAP: %010Lx - %010Lx ",
+				Bios[i].addr,
+				Bios[i].addr + Bios[i].size));
+			if ( Bios[i].len < E820LEN)
+				ret = RF_SHORT;
+			else
+				ret = add_memory_region(Bios[i].addr,
+						Bios[i].addr + Bios[i].size,
+						Bios[i].type);
+#if FLAG_E820_DEBUG
+			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 ( Bios[i].len != E820LEN )
+				printk(" [record is %d bytes long]", Bios[i].len);
+
+			report(ret);
+			printk("\n");
+#endif
+			if (ret & (RF_SHORT|RF_TOOLONG|RF_OVERFLOW))
+				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 */;
+	}
+#endif
+
+    oldstyle:
+	physical_memory.nr_region = 0;
+	physical_memory.p_flags = 0;
+
+#ifdef CONFIG_MEM_E801
+	if (E801_MEM_LOW > 0) {
+	    add_memory_region(0, (E801_MEM_LOW<<10)+HIGH_MEMORY, E820_RAM);
+	    add_memory_region(MEGABYTE(16), MEGABYTE(16)+(E801_MEM_HIGH<<16), E820_RAM);
+	}
+	else
+#endif
+	    add_memory_region(0, HIGH_MEMORY+(EXT_MEM_K << 10), E820_RAM);
+
+	region_check();
+} /* setup_memory_region */
+
+
 
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
@@ -268,6 +616,7 @@
 	unsigned long memory_start, memory_end;
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
+	int i;
 	int read_endbase_from_BIOS = 1;
 
 #ifdef CONFIG_VISWS
@@ -287,17 +636,9 @@
 		BIOS_revision = SYS_DESC_TABLE.table[2];
 	}
 	aux_device_present = AUX_DEVICE_INFO;
-	memory_end = (1<<20) + (EXT_MEM_K<<10);
-#ifndef STANDARD_MEMORY_BIOS_CALL
-	{
-		unsigned long memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
-		/* printk(KERN_DEBUG "Memory sizing: %08x %08x\n", memory_end, memory_alt_end); */
-		if (memory_alt_end > memory_end)
-			memory_end = memory_alt_end;
-	}
-#endif
 
-	memory_end &= PAGE_MASK;
+	setup_memory_region();
+
 #ifdef CONFIG_BLK_DEV_RAM
 	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
 	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
@@ -327,14 +668,11 @@
 				from += 9+4;
 				boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
 			} 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++;
-				}
+				long size = memparse(from+4, &from);
+
+				physical_memory.nr_region = 0;
+				add_memory_region(0, size, E820_RAM);
+				region_check();
 			}
 		}
 		else if (c == ' ' && !memcmp(from, "endbase=", 8))
@@ -351,6 +689,13 @@
 			break;
 		*(to++) = c;
 	}
+
+	for (memory_end = i = 0; i < physical_memory.nr_region; i++)
+	    if (memory_end < Region[i].end)
+		memory_end = Region[i].end;
+
+	memory_end &= PAGE_MASK;
+
 	*to = '\0';
 	*cmdline_p = command_line;
 
@@ -378,16 +723,6 @@
 			i386_endbase = BIOS_ENDBASE;
 		}
 		i386_endbase += PAGE_OFFSET;
-	}
-
-#define VMALLOC_RESERVE	(64 << 20)	/* 64MB for vmalloc */
-#define MAXMEM	((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
-
-	if (memory_end > MAXMEM)
-	{
-		memory_end = MAXMEM;
-		printk(KERN_WARNING "Warning only %ldMB will be used.\n",
-			MAXMEM>>20);
 	}
 
 	memory_end += PAGE_OFFSET;
--- linux-2.2.14/arch/i386/defconfig.orig	Fri Apr  7 00:21:49 2000
+++ linux-2.2.14/arch/i386/defconfig	Fri Apr  7 01:16:57 2000
@@ -21,6 +21,10 @@
 CONFIG_X86_POPAD_OK=y
 CONFIG_X86_TSC=y
 CONFIG_X86_GOOD_APIC=y
+CONFIG_MEM_E820=y
+# CONFIG_E820_RECLAIM is not set
+# CONFIG_E820_MERGE is not set
+CONFIG_MEM_E801=y
 CONFIG_1GB=y
 # CONFIG_2GB is not set
 # CONFIG_MATH_EMULATION is not set
--- linux-2.2.14/arch/i386/config.in.orig	Fri Apr  7 00:21:54 2000
+++ linux-2.2.14/arch/i386/config.in	Fri Apr  7 01:16:34 2000
@@ -33,6 +33,20 @@
   define_bool CONFIG_X86_GOOD_APIC y
 fi
 
+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 'Reclaim ACPI tables' CONFIG_E820_RECLAIM
+    bool 'Merge adjacent memory regions' CONFIG_E820_MERGE
+    bool 'Also use bios call E801 to detect memory' CONFIG_MEM_E801
+else
+    define_bool CONFIG_MEM_E801 n
+    define_bool CONFIG_E820_RECLAIM n
+    define_bool CONFIG_E820_MERGE n
+fi
+endmenu
+
 choice 'Maximum Physical Memory' \
 	"1GB		CONFIG_1GB \
 	 2GB		CONFIG_2GB" 1GB
