[PATCH] fancy memory detection for 2.2.14 (was Re: >64MB RAM problems, why?)

From: david parsons (orc@pell.portland.or.us)
Date: Fri Apr 07 2000 - 05:13:02 EST


In article <linux.kernel.38EB6DD8.7E43C0F6@home.com>,
 <tcrompton@home.com> wrote:

>I've also heard that 2.4 solves this problems. How hard would it be to
>"back-port" the solution to 2.2?

    About 5 hours to grab 2.2.14, patch it, make it compile, detect e820
    memory, and not do unpleasant things like only allocate about 800k
    on the little panasonic network appliance I've been using for quick
    tests.

    I don't run 2.2, so I don't have the infrastructure needed to
    actually do real work with this code. Therefore: This code is not
    tested, and make make your computer implode, explode, fold, spindle,
    mutilate, inspect, inject, and be at it's very best first thing in
    the morning.

                  ____
    david parsons \bi/ But it works for me.
                   \/

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

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Apr 07 2000 - 21:00:18 EST