[PATCH] 2.3.99pre9-2 fancy memory detection tweaks, not that anyone cares.

From: david parsons (orc@pell.portland.or.us)
Date: Wed May 17 2000 - 01:05:05 EST


The patch has been slightly modified because it seems to be colliding
with work other people are doing to the memory detection code. In
particular, the business of printing out the memory map if a user has
specified one needed to be lightly tweaked. I've also ripped out the
business of carrying the returned record size back into the kernel side,
but simply invalidate the e820 map in setup.S if what e820 returns is
not what I asked for. There are also some small tweaks from when someone
pointed out that gas does allow people to add to index registers.

              ____
david parsons \bi/ Now if the sg code would only work with cdrecord again...
               \/

--- ./include/asm-i386/e820.h.orig Thu Nov 18 19:25:28 1999
+++ ./include/asm-i386/e820.h Tue May 16 13:21:37 2000
@@ -5,16 +5,19 @@
  * 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.
+ * 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 E820NR 0x1e8 /* # entries in E820MAP */
+#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
@@ -23,18 +26,90 @@
 
 #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_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 1
+
+
 #ifndef __ASSEMBLY__
 
-struct e820map {
- int nr_map;
- struct {
- long long addr; /* start of memory segment */
- long long size; /* size of memory segment */
- long type; /* type of memory segment */
- } map[E820MAX];
-};
+struct e820 {
+ __u64 addr; /* addr,size,type are returned by e820 bios call */
+ __u64 size;
+ __u32 type;
+} __attribute__ ((__packed__));
+
+struct physical_region {
+ __u64 start;
+ __u64 end;
+} ;
+
+struct physical_memory {
+ 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 e820map e820;
-#endif/*!__ASSEMBLY__*/
+extern struct physical_memory physical_memory;
+
+/* Typing shortcuts.
+ */
+#define Region physical_memory.region
+#define Bios physical_memory.bios
 
+/*
+ * setup functions
+ */
+enum region_flags { RF_RECLAIM =0x01,
+ RF_NOT_RAM =0x02,
+ RF_OVERFLOW=0x04,
+ RF_ZERO =0x08,
+ RF_MERGED =0x10,
+ RF_ADDED =0x20,
+ RF_TOOLONG =0x80 } ;
+
+void clear_memory_regions(void);
+enum region_flags add_memory_region(__u64, __u64, __u32);
+int validate_regions(void);
+int add_memory_hole(__u64, __u64);
+void print_region_map(void);
+
+
+#endif/*!__ASSEMBLY__*/
 #endif/*__E820_HEADER*/
--- ./arch/i386/boot/setup.S.orig Sun Feb 20 20:37:09 2000
+++ ./arch/i386/boot/setup.S Tue May 16 13:21:17 2000
@@ -32,6 +32,9 @@
  *
  * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
  * <stiker@northlink.com>
+ *
+ * Extended memory detection made more paranoid by orc@pell.chi.il.us (david
+ * parsons) and Nathan Zook (nathan.zook@amd.com), December 1999-February 2000.
  */
 
 #define __ASSEMBLY__
@@ -255,91 +258,99 @@
 loader_panic_mess: .string "Wrong loader, giving up..."
 
 loader_ok:
-# Get memory size (extended mem, kB)
+/* MEMORY DETECTION CODE */
 
         xorl %eax, %eax
- movl %eax, (0x1e0)
-#ifndef STANDARD_MEMORY_BIOS_CALL
- movb %al, (E820NR)
-# 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].
-#
+ movl %eax, (0x1e0) # zero e801_mem_low
+ movl %eax, (0x1e4) # " e801_mem_high
+ movb %al, (E820NR) # " e820_nr
+
+/*
+ * 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].
+ */
 meme820:
- movl $0x534d4150, %edx # ascii `SMAP'
- xorl %ebx, %ebx # continuation counter
- movw $E820MAP, %di # point into the whitelist
- # so we can have the bios
- # directly write into it.
+ xorl %ebx, %ebx # continuation counter
 
-jmpe820:
- movl $0x0000e820, %eax # e820, upper word zeroed
- movl $20, %ecx # size of the e820rec
- pushw %ds # data record.
+ pushw %ds # es:di points at the whitelist
         popw %es
- int $0x15 # make the call
- jc bail820 # fall to e801 if it fails
-
- cmpl $0x534d4150, %eax # check the return is `SMAP'
- jne bail820 # fall to e801 if it fails
-
-# cmpl $1, 16(%di) # is this usable memory?
-# jne again820
-
- # If this is usable memory, we save it by simply advancing %di by
- # sizeof(e820rec).
- #
-good820:
- movb (E820NR), %al # up to 32 entries
- cmpb $E820MAX, %al
- jnl bail820
-
- incb (E820NR)
- movw %di, %ax
- addw $20, %ax
- movw %ax, %di
-again820:
- cmpl $0, %ebx # check to see if
- jne jmpe820 # %ebx is 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.)
+ movw $E820MAP, %di
+jmpe820:
+ movl $0x534d4150, %edx # ascii `SMAP'
+ movl $0x0000e820, %eax # e820, upper word zeroed
+ movl $E820LEN, %ecx # we'd like one memory record, please.
+
+ int $0x15 # make the call
+ jc fin820 # fall out if it fails
+
+ cmpl $0x534d4150, %eax # did the bios move for you?
+ jne punte820
+
+ cmpw $E820LEN, %cx # did we get back a whole memory record?
+ je stash820
+
+punte820:
+ xor %ah, %ah # no? chuck the whole thing.
+ movb %ah, (E820NR)
+ jmp fin820
+
+stash820:
+ incb (E820NR) # up the # of records
+ movb (E820NR), %al # If the table fills up
+ cmpb $E820MAX, %al # we must flee
+ jnl fin820
+
+ cmp $0, %ebx # any more records in the pipe?
+ jz fin820 # apparently not
+
+ addw $E820LEN, %di # point %es:%di at the next record
+ 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:
         movw $0xe801, %ax
         int $0x15
- jc mem88
+ jc fine801
 
- andl $0xffff, %edx # clear sign extend
- shll $6, %edx # and go from 64k to 1k chunks
- movl %edx, (0x1e0) # store extended memory size
         andl $0xffff, %ecx # clear sign extend
- addl %ecx, (0x1e0) # and add lower memory into
- # total size.
+ movl %ecx, (0x1e0) # store 1kb between 1-16mb
+ andl $0xffff, %edx # clear sign extend
+ movl %edx, (0x1e4) # store 64kb chunks above 16mb
+fine801:
 
-# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
-# 64mb, depending on the bios) in ax.
-mem88:
+#endif/*CONFIG_MEM_E801*/
 
-#endif
+/*
+ * Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
+ * 64mb, depending on the bios) in ax.
+ */
         movb $0x88, %ah
         int $0x15
         movw %ax, (2)
+
+/* END OF MEMORY DETECTION CODE */
 
 # Set the keyboard repeat rate to the max
         movw $0x0305, %ax
--- ./arch/i386/mm/init.c.orig Tue May 16 12:48:04 2000
+++ ./arch/i386/mm/init.c Tue May 16 12:49:18 2000
@@ -538,21 +538,11 @@
 {
         int i;
 
- for (i = 0; i < e820.nr_map; i++) {
- unsigned long addr, end;
-
- if (e820.map[i].type != E820_RAM) /* not usable memory */
- continue;
- /*
- * !!!FIXME!!! Some BIOSen report areas as RAM that
- * are not. Notably the 640->1Mb area. We need a sanity
- * check here.
- */
- addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
- end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
- if ((pagenr >= addr) && (pagenr < end))
+ for (i = 0; i < physical_memory.nr_region; i++)
+ if (pagenr >= PFN_UP(physical_memory.region[i].start)
+ && pagenr < PFN_DOWN(physical_memory.region[i].end) )
                         return 1;
- }
+
         return 0;
 }
 
--- ./arch/i386/kernel/Makefile.orig Tue Apr 11 16:10:32 2000
+++ ./arch/i386/kernel/Makefile Tue May 16 12:49:18 2000
@@ -15,7 +15,7 @@
 O_TARGET := kernel.o
 O_OBJS := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
             ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
- pci-dma.o
+ pci-dma.o regions.o
 OX_OBJS := i386_ksyms.o
 MX_OBJS :=
 
--- ./arch/i386/kernel/regions.c.orig Tue May 16 12:49:18 2000
+++ ./arch/i386/kernel/regions.c Tue May 16 13:26:38 2000
@@ -0,0 +1,363 @@
+/*
+ * memory region setup and pruning code
+ *
+ * Copyright (c) 2000 by David Parsons, Nathan Zook.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/e820.h>
+
+#define PARAM ((unsigned char *)empty_zero_page)
+
+#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
+#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 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)
+
+
+
+static struct excluded_memory memory_hole;
+
+#define Hole memory_hole.hole
+
+/*
+ * clear_memory_regions() wipes out the memory regions map so that it
+ * can be populated from scratch
+ */
+void __init clear_memory_regions()
+{
+ physical_memory.nr_region = 0;
+}
+
+
+/*
+ * add_memory_region() adds a memory region, merging and reclaiming memory
+ * as needed. it returns a bitmask of what happened.
+ */
+enum region_flags __init add_memory_region(__u64 start, __u64 end, __u32 type)
+{
+ int i, x;
+ enum region_flags flag = 0;
+
+#ifdef CONFIG_E820_RECLAIM
+ if ( type == E820_ACPI )
+ flag |= RF_RECLAIM;
+ else
+#endif
+ if (type != E820_RAM)
+ return RF_NOT_RAM;
+
+ 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 */
+
+
+void __init print_region_map()
+{
+ int x;
+ for (x = 0; x < physical_memory.nr_region; x++)
+ printk("MEM: %010L-%010L\n", Region[x].start, Region[x].end);
+} /* print_region_map */
+
+
+#if FLAG_E820_DEBUG && defined(CONFIG_MEM_E820)
+/*
+ * report_memory_region() decodes the return value from add_memory_region
+ */
+static void __init report_memory_region(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_OVERFLOW)
+ printk(" ERROR: table overflow");
+ else if (code & RF_TOOLONG)
+ printk(" ERROR: start+size > 64 bits");
+}
+#endif
+
+
+/*
+ * prune_memory_region() checks a memory region to see if it needs to be
+ * cut to fit around memory holes. It returns the index on the next
+ * memory region to process usually x+1, but it will be x if the memory
+ * region in question is swallowed by a memory hole.
+ */
+static int __init prune_memory_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)
+ 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+1;
+}
+
+
+/*
+ * validate_regions() validates the physical_memory map, plus lops out memory
+ * that lives in suspicious places.
+ */
+int __init validate_regions(void)
+{
+ unsigned int x;
+
+ for (x=0; x < physical_memory.nr_region; ) {
+ 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_memory_region(x)) < 0)
+ return 1;
+ }
+ return 0;
+} /* validate_regions */
+
+
+/*
+ * add_memory_hole() does what you'd think it does.
+ */
+int __init add_memory_hole(__u64 start, __u64 end)
+{
+ int idx;
+
+ if ( (idx=memory_hole.nr_hole) < NR_HOLES) {
+ Hole[idx].start = start;
+ Hole[idx].end = end;
+ memory_hole.nr_hole ++ ;
+ return 0;
+ }
+ printk("memory hole overflow adding %010Lx-%010Lx\n", start, end);
+ return 1;
+} /* add_memory_hole */
+
+
+/*
+ * setup_memory_region() build the initial physical_memory.region[] map
+ * from the information returned by the system bios (either an e820 memory
+ * map, a 801 low/high memory map, or the old fashioned 88 call)
+ */
+void __init setup_memory_region(void)
+{
+ int i;
+ enum region_flags ret;
+
+ add_memory_hole(LOWMEMSIZE(), HIGH_MEMORY);
+#if FLAG_E820_4GB_ONLY
+ add_memory_hole(GIGABYTE(4), (__u64)-1);
+#endif
+
+#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.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].addr + Bios[i].size,
+ Bios[i].type);
+#if FLAG_E820_DEBUG
+ printk("SMAP: %010Lx - %010Lx ",
+ Bios[i].addr,
+ 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;
+ }
+ report_memory_region(ret);
+ printk("\n");
+#endif
+ if (ret & (RF_TOOLONG|RF_OVERFLOW))
+ goto oldstyle;
+ }
+ /* after putting in the e820 map, massage it into shape
+ * for use by the kernel. If validate_regions returns
+ * anything except 0, something is very ill in the state
+ * of the bios map and we'll discard it with extreme
+ * prejudice.
+ */
+ if (validate_regions() == 0)
+ return /* the map is fine, so we'll use it */;
+ }
+#endif
+
+ oldstyle:
+ clear_memory_regions();
+
+#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);
+
+ validate_regions();
+} /* setup_memory_region */
--- ./arch/i386/kernel/setup.c.orig Tue May 16 12:48:04 2000
+++ ./arch/i386/kernel/setup.c Tue May 16 12:53:54 2000
@@ -112,7 +112,7 @@
         unsigned char table[0];
 };
 
-struct e820map e820 = { 0 };
+struct physical_memory physical_memory;
 
 unsigned char aux_device_present;
 
@@ -131,10 +131,7 @@
  */
 #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 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))
@@ -372,9 +369,9 @@
         }
 }
 
-unsigned long __init memparse(char *ptr, char **retptr)
+unsigned long long __init memparse(char *ptr, char **retptr)
 {
- unsigned long ret;
+ unsigned long long ret;
 
         ret = simple_strtoul(ptr, retptr, 0);
 
@@ -386,97 +383,14 @@
                 ret <<= 20;
                 (*retptr)++;
         }
+ else if (**retptr == 'G' || **retptr == 'g') {
+ ret << 30;
+ (*retptr)++;
+ }
         return ret;
 } /* memparse */
 
 
-void __init add_memory_region(unsigned long start,
- unsigned long size, int type)
-{
- int x = e820.nr_map;
-
- if (x == E820MAX) {
- printk("Ooops! Too many entries in the memory map!\n");
- return;
- }
-
- e820.map[x].addr = start;
- e820.map[x].size = size;
- e820.map[x].type = type;
- e820.nr_map++;
-} /* add_memory_region */
-
-#define E820_DEBUG 1
-
-static __init void print_e820_map (void)
-{
- int i;
-
- for (i = 0; i < e820.nr_map; i++) {
- printk(" e820: %016Lx @ %016Lx ",
- e820.map[i].size, e820.map[i].addr);
- switch (e820.map[i].type) {
- case E820_RAM: printk("(usable)\n");
- break;
- case E820_RESERVED:
- printk("(reserved)\n");
- break;
- case E820_ACPI:
- printk("(ACPI data)\n");
- break;
- case E820_NVS:
- printk("(ACPI NVS)\n");
- break;
- default: printk("type %lu\n", e820.map[i].type);
- break;
- }
- }
-}
-
-/*
- * Do NOT EVER look at the BIOS memory size location.
- * It does not work on many machines.
- */
-#define LOWMEMSIZE() (0x9f000)
-
-void __init setup_memory_region(void)
-{
- /*
- * 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. (The IBM
- * thinkpad 560x, for example, does not cooperate with the memory
- * detection code.)
- */
- if (E820_MAP_NR > 1) {
- /* got a memory map; copy it into a safe place.
- */
- 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]);
- }
- else {
- /* otherwise fake a memory map; one section from 0k->640k,
- * the next section from 1mb->appropriate_mem_k
- */
- unsigned long mem_size;
-
- 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, mem_size << 10, E820_RAM);
- }
- printk("BIOS-provided physical RAM map:\n");
- print_e820_map();
-} /* setup_memory_region */
-
-
 static inline void parse_mem_cmdline (char ** cmdline_p)
 {
         char c = ' ', *to = command_line, *from = COMMAND_LINE;
@@ -501,10 +415,6 @@
                         if (!memcmp(from+4, "nopentium", 9)) {
                                 from += 9+4;
                                 boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
- } else if (!memcmp(from+4, "exactmap", 8)) {
- from += 8+4;
- e820.nr_map = 0;
- usermem = 1;
                         } else {
                                 /* If the user specifies memory size, we
                                  * blow away any automatically generated
@@ -517,17 +427,18 @@
                                          * and reinitialize it with the
                                          * standard low-memory region.
                                          */
- e820.nr_map = 0;
                                         usermem = 1;
- add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+ clear_memory_regions();
                                 }
                                 mem_size = memparse(from+4, &from);
                                 if (*from == '@')
                                         start_at = memparse(from+1, &from);
- else {
- start_at = HIGH_MEMORY;
- mem_size -= HIGH_MEMORY;
+ else if (*from == '-') {
+ start_at = mem_size;
+ mem_size += memparse(from+1, &from);
                                 }
+ else
+ start_at = 0;
                                 add_memory_region(start_at, mem_size, E820_RAM);
                         }
                 }
@@ -538,12 +449,13 @@
                         break;
                 *(to++) = c;
         }
- *to = '\0';
- *cmdline_p = command_line;
         if (usermem) {
+ validate_regions();
                 printk("user-defined physical RAM map:\n");
- print_e820_map();
+ print_region_map();
         }
+ *to = '\0';
+ *cmdline_p = command_line;
 }
 
 void __init setup_arch(char **cmdline_p)
@@ -589,10 +501,6 @@
 
         parse_mem_cmdline(cmdline_p);
 
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
-
 /*
  * 128MB for vmalloc and initrd
  */
@@ -608,21 +516,16 @@
         start_pfn = PFN_UP(__pa(&_end));
 
         /*
- * Find the highest page frame number we have available
- */
- max_pfn = 0;
- for (i = 0; i < e820.nr_map; i++) {
- unsigned long start, end;
- /* RAM? */
- if (e820.map[i].type != E820_RAM)
- continue;
- start = PFN_UP(e820.map[i].addr);
- end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
- if (start >= end)
- continue;
- if (end > max_pfn)
- max_pfn = end;
- }
+ * Find the highest page frame number we have available
+ */
+ max_pfn = 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) && (end > max_pfn) )
+ max_pfn = end;
+ }
 
         /*
          * Determine low and high memory ranges:
@@ -665,23 +568,19 @@
         /*
          * Register fully available low RAM pages with the bootmem allocator.
          */
- for (i = 0; i < e820.nr_map; i++) {
+ for (i = 0; i < physical_memory.nr_region; i++) {
                 unsigned long curr_pfn, last_pfn, size;
- /*
- * Reserve usable low memory
- */
- if (e820.map[i].type != E820_RAM)
- continue;
+
                 /*
                  * We are rounding up the start address of usable memory:
                  */
- curr_pfn = PFN_UP(e820.map[i].addr);
+ curr_pfn = PFN_UP(Region[i].start);
                 if (curr_pfn >= max_low_pfn)
                         continue;
                 /*
                  * ... and at the end of the usable range downwards:
                  */
- last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
+ last_pfn = PFN_DOWN(Region[i].end);
 
                 if (last_pfn > max_low_pfn)
                         last_pfn = max_low_pfn;
@@ -762,30 +661,37 @@
          * and also for regions reported as reserved by the e820.
          */
         probe_roms();
- for (i = 0; i < e820.nr_map; i++) {
+ for (i = 0; i < physical_memory.nr_region; i++) {
+ struct resource *res;
+ res = alloc_bootmem_low(sizeof(struct resource));
+ res->start = Region[i].start;
+ res->end = Region[i].end-1;
+ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ res->name = "System RAM";
+ request_resource(&iomem_resource, res);
+ /*
+ * We dont't know which RAM region contains the
+ * kernel data, so we try it repeatedly and let
+ * the resource manager test it.
+ */
+ request_resource(res, &code_resource);
+ request_resource(res, &data_resource);
+ }
+ for (i = 0; i < physical_memory.nr_bios; i++) {
                 struct resource *res;
- if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
+ if (Bios[i].type == E820_RAM)
                         continue;
+
                 res = alloc_bootmem_low(sizeof(struct resource));
- switch (e820.map[i].type) {
- case E820_RAM: res->name = "System RAM"; break;
+ switch (Bios[i].type) {
                 case E820_ACPI: res->name = "ACPI Tables"; break;
                 case E820_NVS: res->name = "ACPI Non-volatile Storage"; break;
                 default: res->name = "reserved";
                 }
- res->start = e820.map[i].addr;
- res->end = res->start + e820.map[i].size - 1;
+ res->start = Bios[i].addr;
+ res->end = Bios[i].addr + Bios[i].size - 1;
                 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
                 request_resource(&iomem_resource, res);
- if (e820.map[i].type == E820_RAM) {
- /*
- * We dont't know which RAM region contains kernel data,
- * so we try it repeatedly and let the resource manager
- * test it.
- */
- request_resource(res, &code_resource);
- request_resource(res, &data_resource);
- }
         }
         request_resource(&iomem_resource, &vram_resource);
 
--- ./arch/i386/config.in.orig Tue May 16 12:42:12 2000
+++ ./arch/i386/config.in Tue May 16 12:49:18 2000
@@ -89,6 +89,16 @@
    define_bool CONFIG_X86_PAE y
 fi
 
+mainmenu_option next_comment
+comment 'Memory detection'
+bool 'Use extended bios calls to detect memory' CONFIG_MEM_E820
+if [ "$CONFIG_MEM_E820" = "y" ]; then
+ bool ' Merge adjacent memory regions' CONFIG_E820_MERGE
+ bool ' Reclaim ACPI table memory (DANGEROUS)' CONFIG_E820_RECLAIM
+ bool ' Also try bios call E801' CONFIG_MEM_E801
+fi
+endmenu
+
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 bool 'Symmetric multi-processing support' CONFIG_SMP
--- ./arch/i386/defconfig.orig Tue May 16 12:48:04 2000
+++ ./arch/i386/defconfig Tue May 16 12:49:18 2000
@@ -33,6 +33,10 @@
 CONFIG_X86_USE_PPRO_CHECKSUM=y
 # CONFIG_MICROCODE is not set
 CONFIG_NOHIGHMEM=y
+CONFIG_MEM_E820=y
+CONFIG_MEM_E801=y
+CONFIG_E820_MERGE=y
+#CONFIG_MEM_RECLAIM is not set
 # CONFIG_HIGHMEM4G is not set
 # CONFIG_HIGHMEM64G is not set
 # CONFIG_MATH_EMULATION is not set
--- ./scripts/Menuconfig.orig Sun Apr 2 17:28:22 2000
+++ ./scripts/Menuconfig Tue May 16 12:49:18 2000
@@ -545,7 +545,7 @@
 
                         # Semantics of + and ? in GNU expr changed, so
                         # we avoid them:
- if expr "$answer" : '0$\|-[1-9][0-9]*$\|[1-9][0-9]*$' >/dev/null
+ if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null
                         then
                                 eval $2="$answer"
                         else
--- ./Documentation/i386/zero-page.txt.orig Mon Aug 30 10:47:02 1999
+++ ./Documentation/i386/zero-page.txt Tue May 16 12:49:18 2000
@@ -29,7 +29,8 @@
                         ( struct sys_desc_table_struct )
  0xb0 - 0x1df Free. Add more parameters here if you really need them.
 
-0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb
+0x1e0 unsigned long E801_MEM_LOW, e801 # kbytes between 1mb and 16mb
+0x1e4 unsigned long E801_MEM_HIGH, e801 # kbytes above 16mb
 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)
--- ./Documentation/Configure.help.orig Tue May 16 12:48:04 2000
+++ ./Documentation/Configure.help Tue May 16 12:49:18 2000
@@ -185,6 +185,40 @@
   on the Alpha. The only time you would ever not say Y is to say M in
   order to debug the code. Say Y unless you know what you are doing.
 
+Use extended bios calls to detect memory
+CONFIG_MEM_E820
+ The traditional Linux memory detection code for ia32 machines is
+ restricted to detecting 64mb (or 16mb!) of core. The E820 call,
+ which is used by many operating systems, is a modern replacement
+ for it, which gives back a detailed memory map of usable memory,
+ rom, and ACPI tables. Older machines ignore this detection method,
+ so you should be able to say Y here unless your machine has
+ problems correctly detecting memory.
+
+Merge adjacent memory regions
+CONFIG_E820_MERGE
+ The E820 bios call may return a fragmented map where many segments
+ of the map are too small to fit a Linux memory table entry onto.
+ This option merges adjacent memory sections together before
+ initializing the Linux memory tables.
+
+Reclaim ACPI table memory (DANGEROUS)
+CONFIG_E820_RECLAIM
+ If you are not using ACPI (CONFIG_ACPI) on this machine, you can
+ use this option to use ACPI tables as regular memory. This is a
+ dangerous option -- some people have reported that attempting to
+ reclaim ACPI tables result in Linux crashing -- so only answer Y
+ if you know what you are doing.
+
+Use bios call e801 to detect memory
+CONFIG_MEM_E801
+ The E801 bios call was an earlier method for detecting memory on
+ ia32 machines. It has fallen out of favor, and some modern
+ bioses have broken it so that it returns garbage. The kernel
+ will attempt to use this call if the e820 bios call does not
+ exist on the machine. It's probably safe to answer Y here,
+ though 99% of the machines out there won't use this call.
+
 High Memory support
 CONFIG_NOHIGHMEM
   Linux can use up to 64 Gigabytes of physical memory on x86 systems.
--- ./Makefile.orig Tue May 16 12:48:04 2000
+++ ./Makefile Tue May 16 12:49:18 2000
@@ -340,10 +340,10 @@
         if [ -f PCMCIA_CHAR_MODULES ]; then inst_mod PCMCIA_CHAR_MODULES pcmcia; fi; \
         if [ -f PCMCIA_SCSI_MODULES ]; then inst_mod PCMCIA_SCSI_MODULES pcmcia; fi; \
         \
- ls -1 -U *.o | sort > $$MODLIB/.allmods; \
+ ls -1 *.o | sort > $$MODLIB/.allmods; \
         if [ -f $$MODLIB/net/3c59x.o ]; then \
                 mkdir -p $$MODLIB/pcmcia; \
- ln -nfs ../net/3c59x.o $$MODLIB/pcmcia/3c575_cb.o; \
+ ln -fs ../net/3c59x.o $$MODLIB/pcmcia/3c575_cb.o; \
                 MODULES="$$MODULES 3c575_cb.o"; fi; \
         echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \
         if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \

-
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 : Tue May 23 2000 - 21:00:12 EST