In article <linux.kernel.E12ukLj-0006V3-00@the-village.bc.nu>,
Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>Various folks wanted the format fixed, so stuff fixed is at the bottom and
>stuff that bites at boot time or is potentially hazardous is at the top.
>
>Hopefully having the boot time failure list seperate will help people figure
>why a kernel might not boot at all and help them work around it to test the
>rest
>
>Alan
>
>
>
>Capable Of Corrupting Your FS
>-----------------------------
>E820 memory setup causes crashes/corruption on some laptops
This patch may solve the problem. An ancester of it (pre my collaboration
with Nathan Zook) solved it for at least one person.
--- ./include/asm-i386/e820.h.orig Thu Nov 18 19:25:28 1999
+++ ./include/asm-i386/e820.h Sat May 27 02:11:12 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 Sat May 27 01:59:30 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
+ */
-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.
+#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].
+ */
+#define SMAP 0x534d4150
+meme820:
+ xorl %ebx, %ebx # e820 continuation counter
+ movw $E820MAP, %di # point di at the map
jmpe820:
- movl $0x0000e820, %eax # e820, upper word zeroed
- movl $20, %ecx # size of the e820rec
- pushw %ds # data record.
+ pushw %ds # set es := ds every time around.
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.)
+ movl $0x0000e820, %eax # e820, upper word zeroed
+ movl $SMAP, %edx # assign magic numbers
+ movl $E820LEN, %ecx # we'd like one memory record, please.
+
+ int $0x15 # make the call
+ jc fin820 # fall out if it fails
+
+ cmpl $SMAP, %eax # did e820 properly move the magic?
+ jne punte820
+
+ cmpw $E820LEN, %cx # did we get back a whole memory record?
+ jne punte820
+
+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 %di at the next record
+ jmp jmpe820 # and go around again
+
+punte820: # if something goes wrong, don't
+ xor %ah, %ah # let userland look at this (corrupt?)
+ movb %ah, (E820NR) # e820 map.
+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 Sat May 27 01:58:03 2000
+++ ./arch/i386/mm/init.c Sat May 27 01:59:31 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 Sat May 27 01:58:49 2000
+++ ./arch/i386/kernel/Makefile Sat May 27 01:59:31 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 Sat May 27 01:59:31 2000
+++ ./arch/i386/kernel/regions.c Sat May 27 01:59:31 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 Sat May 27 01:58:49 2000
+++ ./arch/i386/kernel/setup.c Sat May 27 02:02:39 2000
@@ -113,7 +113,7 @@
unsigned char table[0];
};
-struct e820map e820 = { 0 };
+struct physical_memory physical_memory;
unsigned char aux_device_present;
@@ -132,10 +132,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))
@@ -373,9 +370,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);
@@ -387,97 +384,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 void __init 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;
@@ -502,10 +416,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
@@ -518,17 +428,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);
}
}
@@ -539,12 +450,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)
@@ -590,10 +502,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
*/
@@ -609,21 +517,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:
@@ -666,23 +569,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;
@@ -763,30 +662,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 Sat May 27 01:58:49 2000
+++ ./arch/i386/config.in Sat May 27 02:04:09 2000
@@ -105,6 +105,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
+
if [ "$CONFIG_X86_FX" != "y" ]; then
bool 'Math emulation' CONFIG_MATH_EMULATION
fi
--- ./arch/i386/defconfig.orig Sat May 27 01:58:49 2000
+++ ./arch/i386/defconfig Sat May 27 01:59:31 2000
@@ -37,6 +37,10 @@
# CONFIG_X86_MSR is not set
# CONFIG_X86_CPUID 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 Sat May 27 01:59:31 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 Sat May 27 01:59:31 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 Sat May 27 01:58:49 2000
+++ ./Documentation/Configure.help Sat May 27 01:59:31 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 Sat May 27 01:58:49 2000
+++ ./Makefile Sat May 27 01:59:31 2000
@@ -336,10 +336,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 : Wed May 31 2000 - 21:00:17 EST