diff -ruN linux-2.6.1/CREDITS linux-2.6.1-memmap/CREDITS
--- linux-2.6.1/CREDITS	2004-01-09 07:59:47.000000000 +0100
+++ linux-2.6.1-memmap/CREDITS	2004-01-20 00:57:51.000000000 +0100
@@ -2841,6 +2841,13 @@
 S: S-226 64 LUND
 S: Sweden
 
+N: Nico Schmoigl
+E: eagle2@sourceforge.net
+W: http://badmem.sourceforge.net
+D: Migration of BadRAM patch to 2.4.0 series, BadMEM, memmap, BadMEM-MODSYSTEM
+S: Mannheim, BW, Germany
+P: 2047/38FC9E03  5D DB 09 E4 3F F3 CD 09 75 59 - 11 17 9C 03 46 E3 38 FC 9E 03
+
 N: Henning P. Schmiedehausen
 E: hps@tanstaafl.de
 D: added PCI support to the serial driver
diff -ruN linux-2.6.1/Documentation/vm/memmap linux-2.6.1-memmap/Documentation/vm/memmap
--- linux-2.6.1/Documentation/vm/memmap	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.1-memmap/Documentation/vm/memmap	2004-01-20 01:01:40.000000000 +0100
@@ -0,0 +1,45 @@
+	/proc/memmap documentation
+	==========================
+
+The /proc/memmap file allow root to see how the physical memory pages
+are used.  By default, by reading /proc/memmap you will get a map of
+the full physical memory.
+
+Legend:
+	'B' at least one Bad
+	'R' at least one Reserved
+	'*' at least one used
+	'x' at least one below min_low_pfn (unusable ?), and none bad, reserved, or used
+	'.' all unused
+
+The range of physical pages to be displayed can be changed by writing
+to /proc/memmap:
+
+	echo '0 3480' > /proc/memmap
+
+will display the map of the 3480 (=116*30) first pages, thus showing
+the precise information for each page.
+
+Range changes will be refused if (max > min) or (min > max_low_pfn).
+Max will be adjusted to max_low_pfn if too large.
+
+The display size is limited (116 columns, 30 lines by default), so one
+character will often represent more than one page.  If you want to see
+more or less, you can change them as 3rd and 4th numbers written to
+/proc/memmap:
+
+	echo '0 10000 80 25' > /proc/memmap
+
+
+Caveats:
+
+ - looks at memory starting at address 0, which may not work on some
+ architectures (eg. arm/xscale).  min_low_pfn should probably not be
+ the limit, however.
+
+ - stops at max_low_pfn, not at max_pfn
+
+
+/proc/memmap was written by Nico Schmoigl as part of the badmem
+project, and extended by Yann Dirson.  This documentation file was
+started by Yann Dirson.
diff -ruN linux-2.6.1/arch/i386/Kconfig linux-2.6.1-memmap/arch/i386/Kconfig
--- linux-2.6.1/arch/i386/Kconfig	2004-01-09 07:59:10.000000000 +0100
+++ linux-2.6.1-memmap/arch/i386/Kconfig	2004-01-20 01:14:15.000000000 +0100
@@ -1237,6 +1237,30 @@
 	  This options enables addition error checking for high memory systems.
 	  Disable for production systems.
 
+config PROC_MEMMAP
+	tristate "/proc/memmap support"
+	depends on PROC_FS
+	help
+	  To have some more specific information on page allocation, you can
+	  enable this feature. A new file in /proc called /proc/memmap is
+	  created (note: you need /proc fs support of course!). If you
+	  read from this file you get a graphical memory map. If you write
+	  to this file a line, you can select the view. Example
+	  
+	    echo "0 1000" > /proc/memmap
+	    
+	  will print the first 1001 pages in RAM. You can then read the   
+	  result with for example
+	  
+	    cat /proc/memmap
+	    
+	  There is no user space program which needs this yet. So it is
+	  safe to say 'N' here. If you are a kernel hacker and want to
+	  debug BadMEM, you should say 'Y' here. 
+	  
+	  For version updates and further information,
+	  please visit http://badmem.sourceforge.net/
+
 config DEBUG_INFO
 	bool "Compile the kernel with debug info"
 	depends on DEBUG_KERNEL
diff -ruN linux-2.6.1/arch/i386/defconfig linux-2.6.1-memmap/arch/i386/defconfig
--- linux-2.6.1/arch/i386/defconfig	2004-01-09 07:59:46.000000000 +0100
+++ linux-2.6.1-memmap/arch/i386/defconfig	2004-01-20 01:15:23.000000000 +0100
@@ -1099,6 +1099,7 @@
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_PROC_MEMMAP=y
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 CONFIG_FRAME_POINTER=y
 CONFIG_X86_EXTRA_IRQS=y
diff -ruN linux-2.6.1/mm/Makefile linux-2.6.1-memmap/mm/Makefile
--- linux-2.6.1/mm/Makefile	2004-01-09 07:59:45.000000000 +0100
+++ linux-2.6.1-memmap/mm/Makefile	2004-01-20 00:59:37.000000000 +0100
@@ -12,3 +12,5 @@
 			   slab.o swap.o truncate.o vmscan.o $(mmu-y)
 
 obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o
+
+obj-$(CONFIG_PROC_MEMMAP) += proc_memmap.o
diff -ruN linux-2.6.1/mm/page_alloc.c linux-2.6.1-memmap/mm/page_alloc.c
--- linux-2.6.1/mm/page_alloc.c	2004-01-09 07:59:07.000000000 +0100
+++ linux-2.6.1-memmap/mm/page_alloc.c	2004-01-20 01:01:03.000000000 +0100
@@ -45,6 +45,7 @@
 
 EXPORT_SYMBOL(totalram_pages);
 EXPORT_SYMBOL(nr_swap_pages);
+EXPORT_SYMBOL(pgdat_list);
 
 /*
  * Used by page_zone() to look up the address of the struct zone whose
diff -ruN linux-2.6.1/mm/proc_memmap.c linux-2.6.1-memmap/mm/proc_memmap.c
--- linux-2.6.1/mm/proc_memmap.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.1-memmap/mm/proc_memmap.c	2004-01-20 00:58:05.000000000 +0100
@@ -0,0 +1,273 @@
+/*
+ * memmap support for the proc filesystem
+ * (-> /proc/memmap/node%d/<zonename>)
+ *
+ * written by Nico Schmoigl, nico@writemail.com, 2000
+ *
+ * Updates:
+ * 
+ * Yann Dirson, ydirson@alcove.fr, 2004:
+ * - extracted from badmem patch, and made so that both can be applied
+ *   in any order
+ * - allowed to be used as a module to ease further development
+ * - fixed displayed offset for each line to be offset for this line,
+ *   not next one's
+ * - fixed calculation of dotconst to include all requested pages
+ * - moved legend from /proc/memmap into Documentation/vm/memmap
+ * - fixed error codes to be all negative, printk a message on all errors
+ * - protect write from buffer overflow
+ * - turned on auto-detection of numeration base of numbers written to
+ *   procfile, instead of forcing 10
+ * - allow changing numbers of rows and columns
+ *
+ * - use page_alloc::pgdat_list instead of bootmem stuff
+ * - changed layout to use /proc/memmap/node%d/<zonename>
+ * - provide separate info for all zones in a node
+ * 
+ * KNOWN BUGS:
+ *
+ * - buffer overflow when rows*col too large
+ * - multi-node not supported yet: only reports node0
+ * - probably needs some locking to ensure consistency of the snapshot
+ * - changing nchars to 0 causes div-by-zero
+ *
+ */
+
+#include <linux/module.h>
+
+MODULE_DESCRIPTION("Memory map in /proc/memmap");
+MODULE_AUTHOR("Nico Schmoigl, Yann Dirson");
+MODULE_LICENSE("GPL");
+
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/kernel.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+
+static struct proc_dir_entry* proc_memmap; /* the /proc/memmap/ dir */
+static struct proc_dir_entry* proc_nodes[1]; /* /proc/memmap/node%d/ */
+
+typedef struct {
+  zone_t* zone;
+  long frompage, topage;
+  int maxlines, maxchars;
+} memmap_data_t;
+
+static memmap_data_t *private;
+
+int memmap_read_proc (char *buf, char **start, off_t off, int count, int *eof, void *_data)
+{
+   char *dat = buf;
+   char *line;
+   memmap_data_t* data = _data;
+   int len = 0, totallen = 0;
+   int dotconst = (data->topage-data->frompage)/(data->maxlines*data->maxchars) + 1;
+   register int i = 0, k = 0, j = 0, offset = 0;
+
+   line = kmalloc (data->maxchars+1, GFP_KERNEL);
+   if (line == NULL) {
+     printk (KERN_ERR "proc_memmap: cannot allocate buffer\n");
+     return -ENOMEM;
+   }
+
+   if (dotconst == 0)
+     dotconst = 1;
+
+   len = sprintf (dat, "1 char <=> %u pages\nShowing pages #%li - #%li\n\n", dotconst,data->frompage,data->topage);
+   totallen += len;
+   dat += len;
+
+
+   offset = data->frompage;
+   
+   for (j = 0; (j < data->maxlines) && (offset <= data->topage); j++) {
+     int thislineoffset = offset;
+     for (k = 0; (k < data->maxchars) && (offset <= data->topage); k++, offset += dotconst) {
+	 char dot = '.';
+
+	 for (i = offset; (i < dotconst+offset) && (i <= data->topage); i++) {
+	      
+	    if (dot == 'B') continue;
+#ifdef CONFIG_BADMEM		 
+	    if (PageBad(mem_map+i)) {
+	       dot = 'B';
+	       continue;
+	    }
+#endif /* CONFIG_BADMEM */		 
+	 
+	    if (dot == 'R') continue;
+	    if (PageReserved(mem_map+i)) {   
+	       dot = 'R';
+	       continue;
+	    }
+	 
+	    if (dot == '*') continue;
+	 
+	    if (atomic_read(&mem_map[i].count)) {
+	       dot = '*';
+	       continue;
+	    }
+	 }
+	 line[k] = dot;
+	 
+      }
+      line[k] = '\0';
+      len = sprintf (dat, "#%5i: %s\n", thislineoffset, line);
+      totallen += len;
+      dat += len;
+      
+   }
+
+   *eof = 1;
+   *start = buf+off;
+   totallen -= off;
+
+   kfree (line);
+   return totallen;
+   
+}
+
+#define MAX_WR_LEN 100
+#define MAX_NUMS 4
+
+int memmap_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) {
+   char gtest[MAX_WR_LEN];
+   long nums[MAX_NUMS] = {0, 0, 0, 0};
+   int nnums;
+   char *ptr;
+
+   return -EINVAL;
+#if 0
+
+   if (count > MAX_WR_LEN) {
+     printk (KERN_ERR "proc_memmap: you cannot write more than %i characters\n", MAX_WR_LEN);
+     return -EINVAL;
+   }
+
+   copy_from_user(&gtest, buffer, count);
+
+   ptr = gtest;
+   for (ptr = gtest, nnums = 0; nnums < MAX_NUMS; nnums++) {
+     char* ptr2;
+     nums[nnums] = simple_strtol(ptr, &ptr2, 0);
+     if (ptr == ptr2) { /* no number could be read */
+       break;
+     }
+     /* printk (KERN_INFO "Read %li from memmap\n", nums[nnums]); */
+     ptr = ptr2;
+     while (ptr[0] == ' ')
+       ptr++;
+   }
+
+   if (nnums < 2) {
+     printk (KERN_ERR "proc_memmap: must write at least two arguments\n");
+     return -EINVAL;
+   }
+
+   
+   if (nums[0] > nums[1]) {
+     printk (KERN_ERR "proc_memmap: cannot set lower bound greater than higher bound\n");
+     return -EINVAL;
+   }
+
+   if (nums[0] > max_low_pfn) {
+     printk (KERN_ERR "proc_memmap: cannot set lower bound higher than max_low_pfn\n");
+     return -EINVAL;
+   }
+
+   if (nums[1] > max_low_pfn)
+     nums[1] = max_low_pfn;
+
+   frompage = nums[0];
+   topage = nums[1];
+   printk (KERN_INFO "proc_memmap: setting range to %li - %li\n", frompage, topage);
+
+   /* maybe change display size */
+   if (nums[2]) maxchars = nums[2];
+   if (nums[3]) maxlines = nums[3];
+
+   if (nums[2] || nums[3])
+     printk (KERN_INFO "proc_memmap: setting display size to %i x %i\n", maxchars, maxlines);
+
+   return count;
+#endif
+}
+
+/* FIXME: to be made variable to support multi-node */
+#define NODE 0
+
+static int __init proc_memmap_init(void) {
+  int zone;
+
+  proc_memmap = proc_mkdir ("memmap", NULL);
+  if (!proc_memmap) {
+     printk (KERN_ERR "proc_memmap: cannot create /proc/memmap/ directory\n");
+     goto error1;
+  }
+
+  proc_nodes[NODE] = proc_mkdir ("node0", proc_memmap);
+  if (!proc_nodes[NODE]) {
+     printk (KERN_ERR "proc_memmap: cannot create /proc/memmap/node0/ directory\n");
+     goto error2;
+  }
+
+  private = kmalloc (pgdat_list->nr_zones * sizeof(memmap_data_t), GFP_KERNEL);
+  if (!private) {
+    printk (KERN_ERR "proc_memmap: cannot allocate private data\n");
+    goto error3;
+  }
+
+  for (zone = 0; zone < pgdat_list->nr_zones; zone++) {
+    struct proc_dir_entry* pde =
+      create_proc_entry (pgdat_list->node_zones[zone].name,
+			 S_IWUSR | S_IRUSR, proc_nodes[NODE]);
+    if (!pde) {
+      printk (KERN_ERR "proc_memmap: cannot create proc entry for node0 zone %d\n",
+	      zone);
+      goto error4;
+    }
+
+    pde->read_proc = memmap_read_proc;
+    pde->write_proc = memmap_write_proc;
+
+    private[zone].zone = &pgdat_list->node_zones[zone];
+    private[zone].frompage = pgdat_list->node_zones[zone].zone_mem_map - mem_map;
+    private[zone].topage = private[zone].frompage + pgdat_list->node_zones[zone].size - 1;
+    private[zone].maxlines = 30;
+    private[zone].maxchars = 116;
+
+    pde->data = &private[zone];
+
+    printk (KERN_INFO "proc_memmap: loaded node0 zone %d with range %li - %li\n",
+	    zone, private[zone].frompage, private[zone].topage);
+  }
+  
+   
+  return 0;
+
+ error4:
+   for (; zone >= 0; zone--)
+     remove_proc_entry (pgdat_list->node_zones[zone].name, proc_nodes[NODE]);
+ error3:
+   remove_proc_entry ("node0", proc_memmap);
+ error2:
+   remove_proc_entry ("memmap", NULL);
+ error1:
+   return -EAGAIN;
+}
+
+static void __exit proc_memmap_exit(void) {
+  int zone;
+  for (zone=0; zone < pgdat_list->nr_zones; zone++)
+    remove_proc_entry (pgdat_list->node_zones[zone].name, proc_nodes[NODE]);
+  remove_proc_entry ("node0", proc_memmap);
+  remove_proc_entry ("memmap", NULL);
+  kfree (private);
+
+  printk (KERN_INFO "proc_memmap: unloading\n");
+}
+
+module_init (proc_memmap_init);
+module_exit (proc_memmap_exit);
