Index: oldkernel/linux/Documentation/i386/zero-page.txt
diff -u linux/Documentation/i386/zero-page.txt:1.1.1.1 linux/Documentation/i386/zero-page.txt:1.2
--- linux/Documentation/i386/zero-page.txt:1.1.1.1	Wed May 31 12:33:54 2000
+++ linux/Documentation/i386/zero-page.txt	Thu Jun  1 17:04:05 2000
@@ -30,6 +30,7 @@
  0xb0 - 0x1df		Free. Add more parameters here if you really need them.
 
 0x1e0	unsigned long	ALT_MEM_K, alternative mem check, in Kb
+0x1e8	char		number of entries in E820MAP (below)
 0x1f1	char		size of setup.S, number of sectors
 0x1f2	unsigned short	MOUNT_ROOT_RDONLY (if !=0)
 0x1f4	unsigned short	size of compressed kernel-part in the
@@ -64,7 +65,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
-0x226 - 0x7ff		setup.S code.
+0x2d0 - 0x550		E820MAP
 
 0x800	string, 2K max	COMMAND_LINE, the kernel commandline as
 			copied using CL_OFFSET.
Index: oldkernel/linux/arch/i386/boot/setup.S
diff -u linux/arch/i386/boot/setup.S:1.2 linux/arch/i386/boot/setup.S:1.3
--- linux/arch/i386/boot/setup.S:1.2	Thu Jun  1 15:34:08 2000
+++ linux/arch/i386/boot/setup.S	Thu Jun  1 17:04:05 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:
@@ -245,37 +248,87 @@
 loader_ok:
 ! Get memory size (extended mem, kB)
 
+	xor	eax, eax		! preload new memory slots with 0k
+	mov	dword ptr [0x1e0], eax
 #ifndef STANDARD_MEMORY_BIOS_CALL
-	push	ebx
+	mov	byte ptr [E820NR], al
+! 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
+
+! 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 32 memory areas, which we return at [E820MAP].
+! 
+meme820:
+	mov	edx, #0x534d4150		! ascii `SMAP'
+	xor	ebx, ebx			! continuation counter
+
+	mov	di, #E820MAP			! point into the whitelist
+						! so we can have the bios
+						! directly write into it.
+
+jmpe820:
+	mov	eax, #0x0000e820		! e820, upper word zeroed
+	mov	ecx, #20			! size of the e820rec
+
+	push	ds				! data record.
+	pop	es
+	int	0x15				! make the call
+	jc	bail820				! fall to e801 if it fails
 
-        xor     ebx,ebx		! preload new memory slot with 0k
-        mov	[0x1e0], ebx
+	cmp	eax, #0x534d4150		! check the return is `SMAP'
+	jne	bail820				! fall to e801 if it fails
 
-        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,
+!	cmp	dword ptr [16+di], #1		! is this usable memory?
+!	jne	again820
+	
+	! If this is usable memory, we save it by simply advancing di by
+	! sizeof(e820rec).
+	!
+good820:
+	mov	al, byte ptr [E820NR]	! up to 32 good entries, that is
+	cmp	al, #E820MAX
+	jnl	bail820
+	inc	byte ptr [E820NR]
+	mov	ax, di
+	add	ax, #20
+	mov	di, ax
+
+again820:
+	cmp	ebx, #0			! check to see if ebx is
+	jne	jmpe820			! set to EOF
+
+bail820:
+
+
+! 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:
 
-	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.
+        mov     ax,#0xe801
+	int     0x15
+	jc	mem88
 
-oldstylemem:
-	pop	ebx
-#else
-	mov     dword ptr [0x1e0], #0
+	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.
+
+! Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
+! 64mb, depending on the bios) in ax.
+mem88:
+
 #endif
 	mov	ah,#0x88
 	int	0x15
Index: oldkernel/linux/arch/i386/kernel/setup.c
diff -u linux/arch/i386/kernel/setup.c:1.4 linux/arch/i386/kernel/setup.c:1.5
--- linux/arch/i386/kernel/setup.c:1.4	Thu Jun  1 16:47:27 2000
+++ linux/arch/i386/kernel/setup.c	Thu Jun  1 17:04:06 2000
@@ -62,6 +62,7 @@
 #include <asm/cobalt.h>
 #include <asm/msr.h>
 #include <asm/dma.h>
+#include <asm/e820.h>
 
 /*
  * Machine setup..
@@ -95,6 +96,8 @@
 	unsigned char table[0];
 };
 
+struct e820map e820 = { 0 };
+
 unsigned char aux_device_present;
 
 #ifdef CONFIG_BLK_DEV_RAM
@@ -125,6 +128,8 @@
 #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    ((unsigned long *) (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))
@@ -305,9 +310,37 @@
 #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); */
+		unsigned long mem_high;
+		int i;
+
 		if (memory_alt_end > memory_end)
 			memory_end = memory_alt_end;
+		else
+			memory_alt_end = memory_end;
+
+		e820.nr_map = E820_MAP_NR;
+		if (e820.nr_map > E820MAX)
+			e820.nr_map = E820MAX;
+		memcpy(e820.map, E820_MAP, e820.nr_map * sizeof e820.map[0]);
+
+		/* If a memory region is below "memory_alt_end", it
+		   will be marked as available. Above "memory_alt_end",
+		   we have to use E820_TYPE_OK. */
+		mem_high = 0;
+		for (i=0; i < e820.nr_map; i++) {
+			if (E820_REG_OK(e820.map[i])
+			    && (e820.map[i].addrlow < memory_alt_end
+				|| (E820_TYPE_OK(e820.map[i])
+				    && mem_high == e820.map[i].addrlow))) {
+				mem_high = e820.map[i].addrlow
+					   + e820.map[i].sizelow;
+				e820.map[i].type |= E820_AVAILABLE;
+				if (mem_high > memory_end)
+		    			memory_end = mem_high;
+			}
+			else
+				break;
+		}
 	}
 #endif
 
Index: oldkernel/linux/arch/i386/mm/init.c
diff -u linux/arch/i386/mm/init.c:1.3 linux/arch/i386/mm/init.c:1.4
--- linux/arch/i386/mm/init.c:1.3	Thu Jun  1 16:47:27 2000
+++ linux/arch/i386/mm/init.c	Thu Jun  1 17:04:06 2000
@@ -30,6 +30,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);
@@ -379,6 +380,50 @@
 	int initpages = 0;
 	int bigpages = 0;
 	unsigned long tmp;
+	unsigned long start_seg = 0;
+	unsigned long size_seg = ~0;
+	int nr_map = 0;
+	int i, type;
+	const char *available;
+	const char *mem_type [] = {
+		"usable",
+		"reserved",
+		"ACPI data",
+		"NVS data"
+
+	};
+
+	for (i=0; i < e820.nr_map; i++) {
+		available = (e820.map[i].type & E820_AVAILABLE)
+			    ? "available" : "unavailable";
+		type = e820.map[i].type & ~E820_AVAILABLE;
+		switch (type) {
+		case E820_RAM:
+		case E820_RESERVED:
+		case E820_ACPI:
+		case E820_NVS:
+			type--;
+			printk("e820 region %d: (%lu, %lu) @ 0x%08lx%08lx (%s) [%s]\n",
+				i, e820.map[i].sizehigh, e820.map[i].sizelow,
+				e820.map[i].addrhigh, e820.map[i].addrlow,
+				mem_type [type], available);
+			break;
+		default:
+			printk("e820 region %d: (%lu, %lu) @ 0x%08lx%08lx (type %d) [%s]\n",
+				i, e820.map[i].sizehigh, e820.map[i].sizelow,
+				e820.map[i].addrhigh, e820.map[i].addrlow,
+				type, available);
+			break;
+		}
+	}
+
+	if (nr_map < e820.nr_map
+	    && (e820.map[i].type & E820_AVAILABLE)) {
+		start_seg = e820.map[nr_map].addrlow + PAGE_OFFSET;
+		size_seg  = e820.map[nr_map].sizelow;
+		nr_map++;
+	}
+
 
 	end_mem &= PAGE_MASK;
 #ifdef CONFIG_BIGMEM
@@ -418,7 +463,22 @@
 	}
 
 	while (start_mem < end_mem) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
+		if (start_mem > start_seg) {
+		    if (start_mem < start_seg + size_seg)
+			    clear_bit(PG_reserved,
+					    &mem_map[MAP_NR(start_mem)].flags);
+		    else if (nr_map < e820.nr_map 
+			     && (e820.map[i].type & E820_AVAILABLE)) {
+			    start_seg = e820.map[nr_map].addrlow + PAGE_OFFSET;
+			    size_seg =  e820.map[nr_map].sizelow;
+			    nr_map++;
+			    continue;		/* be paranoid in case the */
+						/* e820 code hasn't collapsed */
+						/* adjacent usable memory */
+		    }
+		    else
+			    break;		/* no more valid memory */
+		}
 		start_mem += PAGE_SIZE;
 	}
 	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
Index: oldkernel/linux/include/asm-i386/e820.h
diff -u /dev/null linux/include/asm-i386/e820.h:1.1
--- /dev/null	Mon Jul 31 21:14:46 2000
+++ linux/include/asm-i386/e820.h	Thu Jun  1 17:04:06 2000
@@ -0,0 +1,54 @@
+/*
+ * 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 e820map, and in arch/i386/mm/init.c, that
+ * new information is used to mark pages reserved or not.
+ *
+ */
+#ifndef __E820_HEADER
+#define __E820_HEADER
+
+#define E820MAP	0x2d0		/* our map */
+#define E820MAX	32		/* number of entries in E820MAP */
+#define E820NR	0x1e8		/* # entries in E820MAP */
+
+#define E820_RAM	1	/* Memory available to OS. */
+#define E820_RESERVED	2	/* Memory reserved for BIOS. */
+#define E820_ACPI	3	/* Memory for ACPI. */
+#define E820_NVS	4	/* Memory for NVS. */
+
+/* Memory available to OS. */
+#define E820_AVAILABLE	0x80000000
+
+/* Memory region is ok. */
+#define E820_REG_OK(m)	((m).addrhigh == 0x0 && (m).sizehigh == 0x0)
+
+/* Memory region type is ok. */
+#define E820_TYPE_OK(m)	((m).type == E820_RAM)
+
+#ifndef __ASSEMBLY__
+
+struct e820map {
+    int nr_map;
+    struct {
+	/* low 4 bytes of start of memory segment */
+	unsigned long addrlow;
+	/* high 4 bytes of start of memory segment */
+	unsigned long addrhigh;
+	/* low 4 bytes of  size of memory segment */
+	unsigned long sizelow;
+	/* high 4 bytes of  size of memory segment */
+	unsigned long sizehigh;
+	/* type of memory segment */
+	unsigned long type;
+    } map[E820MAX];
+};
+
+extern struct e820map e820;
+#endif/*!__ASSEMBLY__*/
+
+#endif/*__E820_HEADER*/
