--- linux-2.2.13/include/asm-i386/e820.h.orig   Thu Nov 18 13:31:21 1999
+++ linux-2.2.13/include/asm-i386/e820.h        Fri Nov 19 07:33:56 1999
@@ -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*/
--- linux-2.2.13/Documentation/i386/zero-page.txt.orig  Thu Nov 18 13:18:51 1999
+++ linux-2.2.13/Documentation/i386/zero-page.txt       Thu Nov 18 13:18:54 1999
@@ -30,6 +30,7 @@ Offset        Type            Description
 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 @@ Offset        Type            Description
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.
--- linux-2.2.13/arch/i386/boot/setup.S.orig    Thu Nov 18 13:18:51 1999
+++ linux-2.2.13/arch/i386/boot/setup.S Thu Nov 18 13:18:55 1999
@@ -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 @@ begbss:

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 @@ bootsect_kludge:
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_panic_mess:
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
+
+       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:

-oldstylemem:
-       pop     ebx
-#else
-       mov     dword ptr [0x1e0], #0
#endif
       mov     ah,#0x88
       int     0x15
--- linux-2.2.13/arch/i386/kernel/setup.c.orig  Thu Nov 18 13:18:51 1999
+++ linux-2.2.13/arch/i386/kernel/setup.c       Fri Nov 19 07:26:20 1999
@@ -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,8 @@ struct sys_desc_table_struct {
       unsigned char table[0];
};

+struct e820map e820 = { 0 };
+
unsigned char aux_device_present;

#ifdef CONFIG_BLK_DEV_RAM
@@ -117,6 +120,8 @@ int disable_x86_serial_nr = 0;
#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))
@@ -297,9 +302,37 @@ __initfunc(void setup_arch(char **cmdlin
#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

--- linux-2.2.13/arch/i386/mm/init.c.orig       Thu Nov 18 13:18:51 1999
+++ linux-2.2.13/arch/i386/mm/init.c    Thu Nov 18 13:18:55 1999
@@ -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);
@@ -416,6 +417,50 @@ __initfunc(void mem_init(unsigned long s
       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
@@ -455,7 +500,22 @@ __initfunc(void mem_init(unsigned long s
       }

       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) {