[EXPERIMENT] 2.3.99-<all> tweaks to memory detection

From: david parsons (orc@pell.portland.or.us)
Date: Tue Apr 04 2000 - 16:03:27 EST


People who are feeling adventurous and want to help play around with
memory detection are welcome to try out this patch. This is redoing
memory exclusion areas from being hardcoded checks to a data-driven
arrangement. It's inspired by the code that was posted here for doing
partial memory area exclusion for bad memory (though it doesn't actually
use any of that code), and it make the memory region allocation code a
bunch more readable, plus it has the additional benefit of making the
e801 memory detection code properly handle the single memory hole it's
able to detect.

This is a prototype effort that may vanish (it is patched on top of the
2.3.99 fancy memory detection patch) as Nathan and I bat around various
methods for handling full and partial memory exclusion areas, but it
would be nice to have many eyes looking at it to see if it explodes on
machines other than Nathan's machines and my little compute farm.

                 ____
   david parsons \bi/ I love the smell of burning electronics in the morning.
                  \/

--- linux/include/asm-i386/e820.h.orig2 Mon Mar 27 09:47:16 2000
+++ linux/include/asm-i386/e820.h Mon Mar 27 10:21:18 2000
@@ -15,6 +15,7 @@
 
 #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 */
 
@@ -91,7 +92,18 @@
     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[E820MAX]; /* that we want to allocate */
+ 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;
--- linux/arch/i386/boot/setup.S.orig2 Thu Mar 30 01:36:47 2000
+++ linux/arch/i386/boot/setup.S Thu Mar 30 03:26:23 2000
@@ -261,8 +261,9 @@
 /* MEMORY DETECTION CODE */
 
         xorl %eax, %eax
- movl %eax, (0x1e0) # zero alt_mem_k
- movb %al, (E820NR) # e820_nr
+ 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
@@ -322,17 +323,9 @@
 #ifdef CONFIG_MEM_E801
 /*
  * 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.)
- *
- * This scheme does not write to a memory map, but returns an
- * accumulator containing all memory from 1-16mb + all memory from
- * 16->up mb. If a memory hole exists, all memory above that hole
- * is ignored.
+ * 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:
@@ -342,13 +335,8 @@
 
         andl $0xffff, %ecx # clear sign extend
         movl %ecx, (0x1e0) # store 1kb between 1-16mb
- cmpl $0x3C00, %ecx # if 1-16mb region isn't 15mb
- jne fine801 # there's a memory hole and
- # memory above the hole can't
- # be used.
         andl $0xffff, %edx # clear sign extend
- shll $6, %edx # and go from 64k to 1k chunks
- addl %edx, (0x1e0) # add high memory size.
+ movl %edx, (0x1e4) # store 64kb chunks above 16mb
 fine801:
 
 #endif/*CONFIG_MEM_E801*/
--- linux/arch/i386/kernel/setup.c.orig2 Mon Mar 27 09:46:54 2000
+++ linux/arch/i386/kernel/setup.c Thu Mar 30 10:11:18 2000
@@ -128,7 +128,8 @@
 #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))
@@ -483,6 +484,7 @@
 
 
 #define GIGABYTE(x) ((x) * 1024LL * 1024LL * 1024LL)
+#define MEGABYTE(x) ((x) * 1024LL * 1024LL)
 #if FLAG_E820_DEBUG
 # define E820DBG(x) printk x
 #else
@@ -521,97 +523,113 @@
 #endif
 
 
-/*
- * region_check() validates the physical_memory map, plus lops out memory
- * that lives in suspicious places.
- */
+static struct excluded_memory memory_hole;
+#define Hole memory_hole.hole
+
 int __init
-region_check(void)
+prune_region(int x)
 {
- unsigned int x, i;
+ int i, ct;
 
- 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) -- map dropped\n",
- x, Region[x].start,
- Region[x].end,
- x+1, Region[x+1].start,
- Region[x+1].end);
- return 1;
- }
-#if FLAG_E820_GULLIBLE
- if (physical_memory.p_flag & CHK_PMEM_GULLIBLE)
- continue;
-#endif
+ for (ct = 0; ct < memory_hole.nr_hole; ct++) {
 
-#if FLAG_E820_4GB_ONLY
- if (Region[x].start >= GIGABYTE(4)) {
- E820DBG(("SMAP: region %010Lx - %010Lx dropped\n",
- Region[x].start, Region[x].end));
- for (i=x; i < physical_memory.nr_region; i++)
- Region[i] = Region[i+1];
- x--;
- physical_memory.nr_region--;
- continue;
- }
-
- if (Region[x].end > GIGABYTE(4)) {
- E820DBG(("SMAP: region %010Lx - %010Lx truncated to %010Lx - %010Lx\n",
- Region[x].start, Region[x].end, Region[x].start,
- GIGABYTE(4)));
- Region[x].end = GIGABYTE(4);
- }
-#endif
-
- if (Region[x].start >= HIGH_MEMORY || Region[x].end <= LOWMEMSIZE())
+ if (Region[x].start >= Hole[ct].start || Region[x].end <= Hole[ct].end || Hole[ct].mask != 0)
                         continue;
 
- if (Region[x].start >= LOWMEMSIZE()) {
- if (Region[x].end < HIGH_MEMORY) {
- E820DBG(("%010Lx - %010Lx dropped\n",
+ 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];
- x--;
                                 physical_memory.nr_region--;
+ return --x;
                         }
                         else {
- E820DBG(("SMAP: %010Lx - %010Lx trimmed to %010lx - %010Lx\n",
+ E820DBG(("SMAP: %010Lx - %010Lx trimmed to %010Lx - %010Lx\n",
                                             Region[x].start, Region[x].end,
- (unsigned long)HIGH_MEMORY, Region[x].end));
- Region[x].start = HIGH_MEMORY;
+ Hole[ct].start, Region[x].end));
+ Region[x].start = Hole[ct].start;
                         }
                 }
- else if (Region[x].end < HIGH_MEMORY) {
- E820DBG(("%010Lx - %010Lx trimmed to %010Lx - %010lx\n",
+ 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, (unsigned long)LOWMEMSIZE()));
- Region[x].end = LOWMEMSIZE();
+ Region[x].start, Hole[ct].start));
+ Region[x].end = Hole[ct].start;
                 }
                 else {
- E820DBG(("%010Lx - %010Lx split to %010Lx - 640k, 1m - %010Lx\n",
+ E820DBG(("SMAP: %010Lx - %010Lx split to %010Lx - %010Lx, %010Lx - %010Lx\n",
                                 Region[x].start, Region[x].end,
- 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 = HIGH_MEMORY;
+ Region[x+1].start = Hole[ct].end;
                         Region[x+1].end = Region[x].end;
- Region[x].end = LOWMEMSIZE();
- x++;
+ 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 setup_memory_region(void)
+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;
- unsigned long mem_size;
+
+#if !FLAG_E820_GULLIBLE
+ add_memory_hole(LOWMEMSIZE(), HIGH_MEMORY, 0);
+#endif
+#if FLAG_E820_4GB_ONLY
+ add_memory_hole(GIGABYTE(4), (__u64)-1, 0);
+#endif
 
 #ifdef CONFIG_MEM_E820
         /*
@@ -622,21 +640,18 @@
          * 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.
+ * 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_GULLIBLE ? CHK_PMEM_GULLIBLE : 0)
- | (FLAG_E820_RECLAIM ? CHK_PMEM_RECLAIM : 0) ;
+ 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++) {
-#if FLAG_E820_DEBUG
- printk("SMAP: %010Lx - %010Lx ",
+ E820DBG(("SMAP: %010Lx - %010Lx ",
                                 Bios[i].addr,
- Bios[i].addr + Bios[i].size);
-#endif
+ Bios[i].addr + Bios[i].size));
                         if ( Bios[i].len < E820LEN)
                                 ret = RF_SHORT;
                         else
@@ -681,24 +696,22 @@
 #endif
 
     oldstyle:
- /* otherwise fake a memory map; one section from 0k->640k,
- * the next section from 1mb->appropriate_mem_k
- */
-
         physical_memory.nr_region = 0;
         physical_memory.p_flags = 0;
 
 #ifdef CONFIG_MEM_E801
- mem_size = (ALT_MEM_K < EXT_MEM_K) ? EXT_MEM_K : ALT_MEM_K;
-#else
- mem_size = EXT_MEM_K;
+ 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);
 
- add_memory_region(0, LOWMEMSIZE(), E820_RAM);
- add_memory_region(HIGH_MEMORY,
- HIGH_MEMORY + (mem_size << 10), E820_RAM);
+ region_check();
 } /* setup_memory_region */
 
+
 static inline void parse_mem_cmdline (char ** cmdline_p)
 {
         char c = ' ', *to = command_line, *from = COMMAND_LINE;
@@ -731,21 +744,14 @@
                                 unsigned long start_at, mem_size;
  
                                 if (usermem == 0) {
- /* first time in: zap the whitelist
- * and reinitialize it with the
- * standard low-memory region.
- */
                                         physical_memory.nr_region = 0;
                                         usermem = 1;
- add_memory_region(0, LOWMEMSIZE(), E820_RAM);
                                 }
                                 mem_size = memparse(from+4, &from);
                                 if (*from == '@')
                                         start_at = memparse(from+1, &from);
- else {
- start_at = HIGH_MEMORY;
- mem_size -= HIGH_MEMORY;
- }
+ else
+ start_at = 0;
                                 add_memory_region(start_at, mem_size, E820_RAM);
                         }
                 }
@@ -758,6 +764,9 @@
         }
         *to = '\0';
         *cmdline_p = command_line;
+
+ if (usermem)
+ region_check();
 }
 
 void __init setup_arch(char **cmdline_p)
--- linux/Documentation/i386/zero-page.txt.orig2 Thu Mar 30 01:31:43 2000
+++ linux/Documentation/i386/zero-page.txt Thu Mar 30 01:32:06 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 # 64k chunks 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)

-
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:13 EST