diff -uNr linux-2.6.9-vanilla/CREDITS linux-2.6.9/CREDITS
--- linux-2.6.9-vanilla/CREDITS	Sun Feb 12 21:53:56 2006
+++ linux-2.6.9/CREDITS	Tue Feb 14 18:05:27 2006
@@ -2716,6 +2716,14 @@
 S: Malvern, Pennsylvania 19355
 S: USA
 
+N: Rick van Rein
+E: vanrein@cs.utwente.nl
+W: http://www.cs.utwente.nl/~vanrein
+D: Memory, the BadRAM subsystem dealing with statically challanged RAM modules.
+S: Binnenes 67
+S: 9407 CX Assen
+S: The Netherlands
+
 N: Stefan Reinauer
 E: stepan@linux.de
 W: http://www.freiburg.linux.de/~stepan/
@@ -2944,6 +2952,13 @@
 N: Michael Schmitz
 E:
 D: Macintosh IDE Driver
+
+N: Nico Schmoigl
+E: eagle2@sourceforge.net
+W: http://badmem.sourceforge.net
+D: Migration of BadRAM patch to 2.4.x & 2.6.x series, BadMEM, 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: Peter De Schrijver
 E: stud11@cc4.kuleuven.ac.be
diff -uNr linux-2.6.9-vanilla/Documentation/badmem.txt linux-2.6.9/Documentation/badmem.txt
--- linux-2.6.9-vanilla/Documentation/badmem.txt	Thu Jan  1 01:00:00 1970
+++ linux-2.6.9/Documentation/badmem.txt	Tue Feb 14 18:05:27 2006
@@ -0,0 +1,266 @@
+INFORMATION ON USING BAD RAM MODULES
+====================================
+
+Initial note:
+	Please read through this entire document at least once. It gives you
+	a rough outline of what BadMEM is and how you must apply it!
+
+Introduction
+	RAM is getting smaller and smaller, and as a result, also more and more
+	vulnerable. This makes the manufacturing of hardware more expensive,
+	since an excessive amount of RAM chips must be discarded on account of
+	a single cell that is wrong. Similarly, static discharge may damage a
+	RAM module forever, which is usually remedied by replacing it
+	entirely.
+
+	This is not necessary, as the BadMEM code shows: By informing the Linux
+	kernel which addresses in a RAM are damaged, the kernel simply avoids
+	ever allocating such addresses but makes all the rest available.
+
+Reasons for this feature
+	There are many reasons why this kernel feature is useful:
+	 - Chip manufacture is resource intensive; waste less and sleep better
+	 - It's another chance to promote Linux as "the flexible OS"
+	 - Some laptops have their RAM soldered in... and then it fails!
+	 - It's plain cool ;-)
+
+Requirements
+        This patch needs the badmem-utils-package (version 1.3 or above) to be 
+	compiled correctly. You can download this package 
+	from http://badmem.sourceforge.net.
+
+Running example
+	To run this project, I was given two DIMMs, 32 MB each. One, that we
+	shall use as a running example in this text, contained 512 faulty bits,
+	spread over 1/4 of the address range in a regular pattern. Some tricks
+	with a RAM tester and a few binary calculations were sufficient to
+	write these faults down in 2 longword numbers.
+
+	The kernel recognised the correct number of pages with faults and did
+	not give them out for allocation. The allocation routines could
+	therefore progress as normally, without any adaption.
+	So, I gained 30 MB of DIMM which would otherwise have been thrown
+	away. After booting the kernel, the kernel behaved exactly as it
+	always had.
+
+Initial checks
+	If you experience RAM trouble, first read /usr/src/linux/memory.txt
+	and try out the mem=4M trick to see if at least some initial parts
+	of your RAM work well. The BadMEM routines halt the kernel in panic
+	if the reserved area of memory (containing kernel stuff) contains
+	a faulty address.
+
+Running a RAM checker
+	The memory checker is not built into the kernel, to avoid delays at
+	runtime. If you experience problems that may be caused by RAM, run
+	a good RAM checker, such as
+		http://reality.sgi.com/cbrady_denver/memtest86
+	The output of a RAM checker provides addresses that went wrong. In
+	the 32 MB chip with 512 faulty bits mentioned above, the errors were
+	found in the 8MB-16MB range (the DIMM was in slot #0) at addresses
+		xxx42f4
+		xxx62f4
+		xxxc2f4
+		xxxe2f4
+	and the error was a "sticky 1 bit", a memory bit that stayed "1" no
+	matter what was written to it. The regularity of this pattern
+	suggests the death of a buffer at the output stages of a row on one of
+	the chips. I expect such regularity to be commonplace. Finding this
+	regularity currently is human effort, but it should not be hard to
+	alter a RAM checker to capture it in some sort of pattern, possibly
+	the BadMEM patterns described below.
+
+	By the way, if you manage to get hold of memtest86 version 2.3 or
+	beyond, you can configure the printing mode to produce BadMEM patterns,
+	which find out exactly what you must enter on the LILO: commandline,
+	except that you shouldn't mention the added spacing. That means that
+	you can skip the following step, which saves you a *lot* of work.
+
+Capturing errors in a pattern
+	Instead of manually providing all 512 errors to the kernel, it's nicer
+	to generate a pattern. Since the regularity is based on address decoding
+	software, which generally takes certain bits into account and ignores
+	others, we shall provide a faulty address F, together with a bit mask M
+	that specifies which bits must be equal to F. In C code, an address A
+	is faulty if and only if
+		(F & M) == (A & M)
+	or alternately (closer to a hardware implementation):
+		~((F ^ A) & M)
+	In the example 32 MB chip, we had the faulty addresses in 8MB-16MB:
+		xxx42f4		....0100....
+		xxx62f4		....0110....
+		xxxc2f4		....1100....
+		xxxe2f4		....1110....
+	The second column represents the alternating hex digit in binary form.
+	Apperantly, the first and one-but last binary digit can be anything,
+	so the binary mask for that part is 0101. The mask for the part after
+	this is 0xfff, and the part before should select anything in the range
+	8MB-16MB, or 0x00800000-0x01000000; this is done with a bitmask
+	0xff80xxxx. Combining these partial masks, we get:
+		F=0x008042f4	M=0xff805fff
+	That covers everything for this DIMM; for more complicated failing
+	DIMMs, or for a combination of multiple failing DIMMs, it can be
+	necessary to set up a number of such F/M pairs.
+
+Rebooting Linux
+	Now that these patterns are known (and double-checked, the calculations
+	are highly error-prone... it would be neat to test them in the RAM
+	checker...) we simply restart Linux with these F/M pairs as a parameter.
+	If you normally boot as follows:
+		LILO: linux
+	you should now boot with
+		LILO: linux badmem=0x008042f4,0xff805fff
+	or perhaps by mentioning more F/M pairs in an order F0,M0,F1,M1,...
+	Please note here that you must *NOT* have chosen 
+	    
+	    Extended Module support
+        
+	to pass this type of badmem command line to the kernel. If you like to
+	use this advanced way of configuration setting, please read the
+	
+	    Module Configuration
+	
+	section below.
+	When you provide an odd number of arguments to BadMEM, the default mask
+	0xffffffff (only one address matched) is applied to the pattern.
+	
+	Beware of the commandline length. At least up to LILO version 0.21,
+	the commandline is cut off after the 78th character; later versions
+	may go as far as the kernel goes, namely 255 characters. In no way is
+	it possible to enter more than 10 numbers to the BadMEM boot option.
+
+	When the kernel now boots, it should not give any trouble with RAM.
+	Mind you, this is under the assumption that the kernel and its data
+	storage do not overlap an erroneous part. If this happens, and the
+	kernel does not choke on it right away, it will stop with a panic.
+	You will need to provide a RAM where the initial, say 2MB, is faultless.
+
+	Now look up your memory status with
+		dmesg | grep ^Memory:
+	which prints a line much like
+		Memory: 158524k/163840k available
+			(940k kernel code,
+			 412k reserved,
+			 1856k data,
+			 60k init,
+			 2048k badram)
+	The latter entry, the badram, is 2048k to represent the loss of 2MB
+	of general purpose RAM due to the errors. Or, positively rephrased,
+	instead of throwing out 32MB as useless, you only throw out 2MB.
+
+	If the system is stable (try compiling a few kernels, and do a few
+	finds in / or so) you may add the boot parameter to /etc/lilo.conf
+	as a line to _all_ the kernels that handle this trouble with a line
+		append="badmem=0x008042f4,0xff805fff"
+	after which you run "lilo".
+	Warning: Don't experiment with these settings on your only boot image.
+	If the BadMEM overlays kernel code, data, init, or other reserved
+	memory, the kernel will halt in panic. Try settings on a test boot
+	image first, and if you get a panic you should change the order of
+	your DIMMs [which may involve buying a new one just to be able to
+	change the order].
+
+BadRAM classification
+	This technique may start a lively market for "dead" RAM. It is important
+	to realise that some RAMs are more dead than others. So, instead of
+	just providing a RAM size, it is also important to know the BadRAM
+	class, which is defined as follows:
+	
+		A BadRAM class N means that at most 2^N bytes have a problem,
+		and that all problems with the RAMs are persistent: They
+		are predictable and always show up.
+
+	The DIMM that serves as an example here was of class 9, since 512=2^9
+	errors were found. Higher classes are worse, "correct" RAM is of class
+	-1 (or even less, at your choice).
+	Class N also means that the bitmask for your chip (if there's just one,
+	that is) counts N bits "0" and it means that (if no faults fall in the
+	same page) an amount of 2^N*PAGESIZE memory is lost, in the example on
+	an i386 architecture that would be 2^9*4k=2MB, which accounts for the
+	initial claim of 30MB RAM gained with this DIMM.
+
+	An alternative definition called "The BadRAM-4096 Specification" is
+	available from
+	
+	     http://webrum.uni-mannheim.de/math/schmoigl/linux/
+
+Further information on the BadMEM development process 
+	For further information on the programming progress, please visit
+
+	     http://badmem.sourceforge.net
+	     
+Module Configuration - the new way
+        If you have complex holes in your memory and must configure many
+        things via the LILO append line, it is very likely that it is not long
+	enough. Although you have approx. 255 characters, it is not much for
+	BadMEM. Therefore there is a new configuration way. To enable this, you
+	must have selected 
+	
+	     Extended Module support
+	     
+	     in General setup / BadMEM-patch
+	     
+        IMPORTANT NOTE: Never -- really never -- parse normal command lines
+	like
+	
+	    "badmem=0x0080fc04,0xffff4000"
+	    
+	to a kernel with Extended Module support! This will make the kernel
+	die during start up phase. For further configuration information please
+	read the file
+	
+	     badmem_conf.txt
+	     
+        in this directory. 
+       
+
+Known Bugs
+	LILO is known to cut off commandlines which are too long. For the
+	lilo-0.21 distribution, a commandline may not exceed 78 characters,
+	while actually, 255 would be possible [on i386, kernel 2.2.14].
+	LILO does _not_ report too-long commandlines, but the error will
+	show up as either a panic at boot time, stating
+		panic: BadMEM page in initial area
+	or the dmesg line starting with Memory: will mention an unpredicted
+	number of kilobytes. (Note that the latter number only includes
+	errors in accessed memory.)
+
+Future Possibilities
+	It would be possible to use even more of the faulty RAMs by employing
+	them for slabs. The smaller allocation granularity of slabs makes it
+	possible to throw out just, say, 32 bytes surrounding an error. This
+	would mean that the example DIMM only looses 16kB instead of 2MB.
+	It might even be possible to allocate the slabs in such a way that,
+	where possible, the remaining bytes in a slab structure are allocated
+	around the error, reducing the RAM loss to 0 in the optimal situation!
+
+	However, this yield is somewhat faked: It is possible to provide 512
+	pages of 32-byte slabs, but it is not certain that anyone would use
+	that many 32-byte slabs at any time.
+
+	A better solution might be to alter the page allocation for a slab to
+	have a preference for BadMEM pages, and given those a special treatment.
+	This way, the BadRAM would be spread over all the slabs, which seems
+	more likely to be a `true' pay-off. This would yield more overhead at
+	slab allocation time, but on the other hand, by the nature of slabs,
+	such allocations are made as rare as possible, so it might not matter
+	that much. I am uncertain where to go.
+
+Origin
+	The BadRAM project is an idea and implementation by
+		Rick van Rein
+		Binnenes 67
+		9407 CX Assen
+		The Netherlands
+		vanrein@cs.utwente.nl
+		http://home.zonnet.nl/vanrein/badram
+	
+	This patch uses his work as its basics. Patch migration to the 2.4.x
+        series, the proc fs support, MODSYSTEM, memmap support and much more
+        has been added by Nico Schmoigl, <nico@writemail.com> leading to the
+        new BadMEM patch. Its Homepage is viewable at
+
+                http://badmem.sourceforge.net
+ 
+                                Have fun with it!
+				Nico
diff -uNr linux-2.6.9-vanilla/Documentation/badmem_conf.txt linux-2.6.9/Documentation/badmem_conf.txt
--- linux-2.6.9-vanilla/Documentation/badmem_conf.txt	Thu Jan  1 01:00:00 1970
+++ linux-2.6.9/Documentation/badmem_conf.txt	Tue Feb 14 18:05:27 2006
@@ -0,0 +1,234 @@
+Extended Module Support -- configuration file language
+======================================================
+
+
+-=> Initial note
+
+Please make sure that you have read the file
+
+       Documentation/badmem.txt
+       
+   
+   
+-=> The /etc/badmem.conf file
+
+Almost every configuration of BadMEM is done in the file
+      
+       /etc/badmem.conf
+       
+if you have selected to install the Extended Module support during kernel
+configuration. This is a plain text file like the one you are currently
+reading. You can write it with your favourite text editor like vi, emacs,
+joe, or whatever.
+The length is not limited, although it is recommended that you take care
+that it is below 128kb which is very very much!
+
+
+
+-=> Commands
+
+The configuration file consists of one or more commands. Here is an example
+configuration file:
+
+
+*** CUT ***
+
+# /etc/badmem.conf
+#
+#
+# This file contains all information about your BadMEM modules.
+# It is needed at kernel compile time.
+# Only change this file, if you have read the documentation of BadMEM!
+
+module mod1
+ size 64m
+ base 128m
+ 0x80014f8,0xfe001ff8
+ 
+module mod2
+ size 64m
+ base 256m
+ 0x10000004,0xfc0430004
+ 0x10000000,0xfd8000000
+ 
+module good256
+ size 256m
+ base 0
+ 
+mdf /proc/badmem/mdf/mdfmod1
+ 
+*** CUT ***
+
+For explaination: This configuration file defines four (or even more) modules:
+
+1) called "mod1" which has 64MB. The calculation of bad areas was done
+during the presence of 128MB below of this module (that means, there was a
+128MB module in Memory Bank 0 and the faulty 64MB module was in Memory
+Bank 1). Use "0x80014f8,0xfe001ff8" and pass these options to the main
+BadMEM driver.
+
+2) called "mod2" which has 64MB, too. Now there was one 256MB module below
+(or two 128MB modules, or four 64MB modules or ...). Use the two lines above
+to pass them to the main BadMEM driver.
+
+3) called "good256". This just defines a good RAM module. BadMEM should not
+lock any line. We need this if you have good RAM in your PC. See the
+"GoodRAM" section below.
+
+4) no name is given; the file /proc/badmem/mdf/mdfmod1 is looked up and all
+the modules defined there will be included into the current setup.
+
+Comments are either initiated by setting a # or a ; (semicolon) at the first
+character in the line. 
+I will now try to explain every single command.
+
+-=> Command: module <modname>
+
+Declares to define a new module with the name <modname>. Do *not* use " or
+'. A module name must not contain white spaces ( ) but it may contain
+underscores (_). Try to make your module names as short as possible, as you
+will use them as short-cuts during kernel configuration in the LILO append
+line.
+
+-=> Command: mdf <path/filename>
+
+Looks at the file path/filename and tries to open it according to the MDF
+protocol. If successful, all the modules contained there is read and
+included in the current configuration. 
+Please note that you may not specify modules in a mdf file which are already
+declared by a command 'module' (see above). This would double-define it
+confusing the C-compiler.
+Hint: In the directory /proc/badmem/mdf/ you will find all your current
+compiled modules definitions as mdf files.
+
+-=> Command: size <size>
+
+Defines the size of the module which was defined before. You may use
+abbrivations like
+
+    m         for Megabytes (1048576 bytes)
+    k         for Kilobytes (1024 bytes)
+    g         for Gigabytes (well - something very huge...) ;-)
+    t         for Terabytes (that's g * 1024)
+
+Examples: 2m = 512p = 2048k = 4096b = 2097152
+
+Note: This is similar to the dd command line.
+
+You are not allowed to use the size command several times in one module. If
+you still define it more than once, the last size command is used.
+
+-=> Command: base <basemem>
+
+To ensure that the driver blocks the right memory areas and the right module,
+you must tell it with which how much memory you have measured the BadMEM
+regions. This has one very big advantage: You may test a module (let's call
+it the B module -- B like Bad) in Bank 1 while you have a good module (let's
+call this one the G module -- G like Good) in Bank 0. Let's say B is 64m
+sized an G is only 32m in size. Afterwards you remove the G module and put
+in a (perhaps bad) 128m module. Then all your lock line would be foo bar. If
+you set the <basemem>, then shifting the memory addresses are done
+automatically according to your current configuration. For further
+assistance to this issue, please read the HOWTO available at
+
+	   http://badmem.sourceforge.net
+	   
+which will be available in the very near future (2000/09/03).
+
+You may use the abbrevations m, b, k, etc. as you know it from the "size"
+command. You are allowed to use the base command several times in a 
+module. If you do not select it at all, 0 is assumed.
+
+-=> Command: <memaddr>,<memmask>
+
+This is the locking combination which you know from the Rick-van-Rein-methode
+described in the file Documentation/badmem.txt. 
+
+Common trap: Do not forget to use "0x" at the beginning of a hexadecimal
+number! Otherwise the number is interpreted as a decimal number.
+
+IMPORTANT NOTE: Different from the Rick-van-Rein-methode you *MUST* select a
+<memmask>. This parameter is therefore not optional.
+
+Note: You may define as many <memaddr>,<memmask> combinations as you like!
+There is no limit!
+
+
+-=> Complex (or crazy?) definitions:
+
+Have a short look on the following definition:
+
+*** CUT ***
+
+module test
+ size 128m
+ base 256m
+ 0x10000004,0xfc0430004
+ 0x10000000,0xfd8000000
+
+ base 128m
+ 0x080014f8,0xfe001ff8
+
+ size 64m
+
+*** CUT ***
+
+This will define a quite fuzzy module:
+
+ * Its size is 64m.
+ * Locking is done with the two lines above relative to a base of 256m
+ * Locking is done with the "0x080014f8,0xfe001ff8" relative to the base of
+   128m.
+   
+So, you can always add your knowledge to your latest configuration file.
+Overlapping locking areas are ignored by the kernel driver. Please note that
+no optimization is done during compile time, yet.
+
+
+
+-=> Activating the modules
+
+Up to now, there is no possibility to auto-detect which memory module is in
+which bank. Theory defines one, but this is not implemented yet. So you must
+tell the kernel, which module is next. This is done via the LILO kernel
+command line (append or during boot time query). Example:
+
+ append = "badmem=good256,mod1,mod2"
+ 
+This means, that the first module (typically in Bank 0) is the module which
+was defined with the name "good256". In Bank 1 there is the "mod1" module
+and so on. There is no limitation to length of this command except the total
+command line length of the LILO.
+
+During boot up phase, all data you specified in the badmem.conf is used to
+lock those areas which are marked as bad.
+
+
+
+-=> GoodRAM
+
+Please note that you must tell the driver all your RAM modules - those which
+are good, too! Otherwise it is asyncronous with your Banks. Then, the wrong
+areas will be marked as bad (well, this would not harm much) and the broken
+onces are left ok (this is the real-bad-thing(tm) !)
+
+
+
+-=> Final note
+
+If you walk over the syntax definitions in the /etc/badmem.conf file, it is
+very likely that kernel compilation will stop. So, if you suddenly do not
+know why the kernel stops during badmem compilation, check the correct
+syntax of your badmem.conf
+
+If you find any typos or you want to send me some idea or suggestion, please
+contact me via the email address below.
+
+
+
+By(t)e
+  Nico
+  
+  Germany, BW, (Uni-)Mannheim
+  <eagle2@users.sourceforge.net>, http://badmem.sourceforge.net
+  Last update: 2004/03/15
diff -uNr linux-2.6.9-vanilla/Documentation/kernel-parameters.txt linux-2.6.9/Documentation/kernel-parameters.txt
--- linux-2.6.9-vanilla/Documentation/kernel-parameters.txt	Sun Feb 12 21:53:56 2006
+++ linux-2.6.9/Documentation/kernel-parameters.txt	Tue Feb 14 18:05:27 2006
@@ -26,6 +26,7 @@
 	APIC	APIC support is enabled.
 	APM	Advanced Power Management support is enabled.
 	AX25	Appropriate AX.25 support is enabled.
+	BADMEM  Support for faulty RAM chips is enabled (successor of BadRAM).
 	CD	Appropriate CD support is enabled.
 	DEVFS	devfs support is enabled. 
 	DRM	Direct Rendering Management support is enabled. 
@@ -241,6 +242,11 @@
  
 	aztcd=		[HW,CD] Aztech CD268 CDROM driver
 			Format: <io>,0x79 (?)
+
+        badmem=         [BADMEM] Avoid allocating faulty RAM addresses.
+	                Format: depends on configuration
+			For additional information please see 
+			Documentation/badmem_conf.txt
 
 	baycom_epp=	[HW,AX25]
 			Format: <io>,<mode>
diff -uNr linux-2.6.9-vanilla/Documentation/memory.txt linux-2.6.9/Documentation/memory.txt
--- linux-2.6.9-vanilla/Documentation/memory.txt	Fri Jan  9 08:00:13 2004
+++ linux-2.6.9/Documentation/memory.txt	Tue Feb 14 18:05:27 2006
@@ -18,6 +18,14 @@
 	   as you add more memory.  Consider exchanging your 
            motherboard.
 
+        4) A static discharge or production fault causes a RAM module
+           to have (predictable) errors, usually meaning that certain
+           bits cannot be set or reset. Instead of throwing away your
+           RAM module, you may read /usr/src/linux/Documentation/badmem.txt
+           to learn how to detect, locate and circuimvent such errors
+           in your RAM module.
+ 
+
 All of these problems can be addressed with the "mem=XXXM" boot option
 (where XXX is the size of RAM to use in megabytes).  
 It can also tell Linux to use less memory than is actually installed.
@@ -45,6 +53,8 @@
 
 	* Try passing the "mem=4M" option to the kernel to limit
 	  Linux to using a very small amount of memory.
+          If this helps, read /usr/src/linux/Documentation/badmem.txt
+          to learn how to find and circuimvent memory errors.
 
 
 Other tricks:
diff -uNr linux-2.6.9-vanilla/arch/i386/Kconfig linux-2.6.9/arch/i386/Kconfig
--- linux-2.6.9-vanilla/arch/i386/Kconfig	Sun Feb 12 21:53:57 2006
+++ linux-2.6.9/arch/i386/Kconfig	Tue Feb 14 18:05:27 2006
@@ -870,6 +870,7 @@
 
 endmenu
 
+source "mm/Kconfig"
 
 menu "Power management options (ACPI, APM)"
 	depends on !X86_VOYAGER
diff -uNr linux-2.6.9-vanilla/arch/i386/defconfig linux-2.6.9/arch/i386/defconfig
--- linux-2.6.9-vanilla/arch/i386/defconfig	Sun Feb 12 21:46:49 2006
+++ linux-2.6.9/arch/i386/defconfig	Tue Feb 14 18:05:27 2006
@@ -120,6 +120,12 @@
 CONFIG_HAVE_DEC_LOCK=y
 # CONFIG_REGPARM is not set
 
+# 
+# Memory Management Features
+# 
+CONFIG_BADMEM=y
+CONFIG_PROC_MEMMAP=y
+
 #
 # Power management options (ACPI, APM)
 #
diff -uNr linux-2.6.9-vanilla/arch/i386/mm/init.c linux-2.6.9/arch/i386/mm/init.c
--- linux-2.6.9-vanilla/arch/i386/mm/init.c	Sun Feb 12 21:53:57 2006
+++ linux-2.6.9/arch/i386/mm/init.c	Tue Feb 14 18:05:27 2006
@@ -4,6 +4,7 @@
  *  Copyright (C) 1995  Linus Torvalds
  *
  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ *  Support of BadRAM/BadMEM by Rick van Rein and Nico Schmoigl, Feb.-Sept. 2000-2004
  */
 
 #include <linux/config.h>
@@ -42,6 +43,10 @@
 
 unsigned int __VMALLOC_RESERVE = 128 << 20;
 
+#ifdef CONFIG_BADMEM
+# include <linux/badmem.h>
+#endif // CONFIG_BADMEM
+
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 unsigned long highstart_pfn, highend_pfn;
 
@@ -563,6 +568,31 @@
 
 static struct kcore_list kcore_mem, kcore_vmalloc; 
 
+#ifdef CONFIG_BADMEM
+static int __init badmem_pages_init(void)
+{
+        int badpages, pfn;
+   
+        badpages = 0;
+        for (pfn = 0; pfn < max_low_pfn; pfn++) {
+	        /*
+		 * count pages with badmem flag only
+		 */
+	        if (!page_is_ram(pfn)) continue;
+	   
+	        if (PageBad(mem_map+pfn))
+	                badpages++;
+	   
+	        if (PageReserved(mem_map+pfn) && PageBad(mem_map+pfn))
+	                panic ("BADMEM: Iiee... Bad memory in a reserved area (page %i); please swap modules or try another module...", pfn);
+	}
+   
+        /* BADMEM_HIGHMEM_SUPPORT not available! */
+        return badpages;
+}
+#endif /* CONFIG_BADMEM */
+   
+
 void __init mem_init(void)
 {
 	extern int ppro_with_ram_bug(void);
@@ -570,6 +600,10 @@
 	int tmp;
 	int bad_ppro;
 
+#ifdef CONFIG_BADMEM
+        int badpages;
+#endif
+   
 #ifndef CONFIG_DISCONTIGMEM
 	if (!mem_map)
 		BUG();
@@ -598,6 +632,10 @@
 	/* this will put all low memory onto the freelists */
 	totalram_pages += __free_all_bootmem();
 
+#ifdef CONFIG_BADMEM
+        badmem_markpages();
+#endif // CONFIG_BADMEM
+   
 	reservedpages = 0;
 	for (tmp = 0; tmp < max_low_pfn; tmp++)
 		/*
@@ -608,6 +646,10 @@
 
 	set_highmem_pages_init(bad_ppro);
 
+#ifdef CONFIG_BADMEM 
+        badpages = badmem_pages_init();   
+#endif /* CONFIG_BADMEM */
+    
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
@@ -615,15 +657,34 @@
 	kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT); 
 	kclist_add(&kcore_vmalloc, (void *)VMALLOC_START, 
 		   VMALLOC_END-VMALLOC_START);
-
+#ifdef CONFIG_BADMEM
+#ifdef CONFIG_BADMEM_DEBUG
+        printk ("DEBUG BadMEM: init_begin=0x%lx, init_end=0x%lx, max_low_pfn=%li\n", (unsigned long) &__init_begin,  (unsigned long) &__init_end, max_low_pfn);
+        printk ("DEBUG BadMEM: code_begin=0x%lx, code_end=0x%lx\n", (unsigned long) &_text, (unsigned long) &_etext);
+        printk ("DEBUG BadMEM: data_begin=0x%lx, data_end=0x%lx\n", (unsigned long) &_etext, (unsigned long) &_edata); 
+        printk ("DEBUG BadMEM: virtual page offset=0x%x\n", __PAGE_OFFSET);
+#endif /* CONFIG_BADMEM_DEBUG */
+#endif // CONFIG_BADMEM
+   
+#ifdef CONFIG_BADMEM
+	printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem, %ldk badram)\n",
+#else
 	printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
+#endif // CONFIG_BADMEM
 		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+#ifdef CONFIG_BADMEM
 		num_physpages << (PAGE_SHIFT-10),
+#else
+	       	num_physpages << (PAGE_SHIFT-10) - (badpages << (PAGE_SHIFT-10)),
+#endif // CONFIG_BADMEM
 		codesize >> 10,
 		reservedpages << (PAGE_SHIFT-10),
 		datasize >> 10,
 		initsize >> 10,
 		(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
+#ifdef CONFIG_BADMEM
+	        ,(unsigned long) (badpages << (PAGE_SHIFT-10))
+#endif /* CONFIG_BADMEM */
 	       );
 
 #ifdef CONFIG_X86_PAE
diff -uNr linux-2.6.9-vanilla/include/linux/badmem.h linux-2.6.9/include/linux/badmem.h
--- linux-2.6.9-vanilla/include/linux/badmem.h	Thu Jan  1 01:00:00 1970
+++ linux-2.6.9/include/linux/badmem.h	Tue Feb 14 18:05:27 2006
@@ -0,0 +1,42 @@
+#ifndef __LINUX_BADMEM_H
+#define __LINUX_BADMEM_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+#define BADMEM_VERSION "V5.0"
+#define BADMEM_FEATURES "BIGMEMalpha PROC MODSYSTEMbeta"
+
+// The maximum number of values (address, mask pairs) covering bad RAM.
+// This value is hardcoded (!) in init/main.c, get_options()
+#define BADMEM_MAXPARAMS 10
+extern void badmem_markpages(void);
+
+#ifndef CONFIG_BADMEM_MODSYSTEM
+extern ulong badmem_params[BADMEM_MAXPARAMS+1];
+extern int badmem_paramcount;
+#else
+extern char badmem_instmodules[BADMEM_MAXPARAMS+1][32]; // the installed modules which we get by command line (LILO)
+#endif
+
+// cross import of page_is_ram() from arch/i386/mm/init.c
+// sorry, for this really dirty hack; has anyone a better idea?
+extern int page_is_ram (unsigned long pagenr);
+
+extern int badmemmemmap_read_proc (char *buf, char **start, off_t off, int count, int *eof, void *data);
+extern int badmemmemmap_write_proc (struct file *file, const char *buffer, unsigned long count, void *data); 
+
+
+#ifdef CONFIG_BADMEM_MODSYSTEM
+struct badmem_modules {
+   char *mod_name;
+   int mdflen;
+   char *mdfdata;
+};
+
+extern struct badmem_modules badmem_modtab[];
+extern int absolutemode;  // Defines whether there are absolute addresses (!= 0) or not (== 0)
+extern char mdf__absolute[];
+#endif
+
+#endif /* IFNDEF __LINUX_BADMEM_H */
diff -uNr linux-2.6.9-vanilla/include/linux/page-flags.h linux-2.6.9/include/linux/page-flags.h
--- linux-2.6.9-vanilla/include/linux/page-flags.h	Sun Feb 12 21:54:22 2006
+++ linux-2.6.9/include/linux/page-flags.h	Tue Feb 14 18:05:27 2006
@@ -75,6 +75,7 @@
 #define PG_mappedtodisk		17	/* Has blocks allocated on-disk */
 #define PG_reclaim		18	/* To be reclaimed asap */
 
+#define PG_badmem               20      /* flag bit for page that is marked as bad (do not use this page for any data) */
 
 /*
  * Global page accounting.  One instance per CPU.  Only unsigned longs are
@@ -297,6 +298,16 @@
 #else
 #define PageSwapCache(page)	0
 #endif
+
+
+#ifdef CONFIG_BADMEM
+// BadMEM stuff, see mm/page_alloc.c and arch/i386/mm/init.c
+// or Documentation/badmem.txt for more information on this issue
+# define PageBad(page)          test_bit(PG_badmem, &(page)->flags)
+# define PageSetBad(page)       set_bit(PG_badmem, &(page)->flags)
+# define PageClearBad(page)     clear_bit(PG_badmem, &(page)->flags)
+#endif
+
 
 struct page;	/* forward declaration */
 
diff -uNr linux-2.6.9-vanilla/mm/Kconfig linux-2.6.9/mm/Kconfig
--- linux-2.6.9-vanilla/mm/Kconfig	Thu Jan  1 01:00:00 1970
+++ linux-2.6.9/mm/Kconfig	Tue Feb 14 18:05:27 2006
@@ -0,0 +1,114 @@
+menu "Memory Management features"
+
+config BADMEM
+       bool "Work around bad spots in RAM (BadMEM-patch)"
+       ---help---
+          This small kernel extension makes it possible to use memory chips
+	  which are not entirely correct. It works by never allocating the
+	  places that are wrong. Those places are specified with the badmem
+	  boot option to LILO. Read /usr/src/linux/Documentation/badmem.txt
+	  and/or visit http://badmem.sourceforge.net for more information.
+	  
+	  This option co-operates well with a second boot option from LILO
+	  that starts memtest86, which is able to automatically produce the
+	  patterns for the commandline in case of memory trouble.
+	
+	  It is safe to say 'Y' here, and it is advised because there is no
+	  performance impact as long as you leave out any "badmem=" command
+	  line during boot up. This driver cannot be built as module, as it
+	  must be loaded as early as possible to ensure that bad memory is not
+	  used for sensitive data.
+	
+	  Please note that this is a alpha migration to the 2.4.x series. It
+	  is mainly untested, so be very careful with what you are doing!
+	  
+	  This is i386 code only. It may be possible to port this code to
+	  other cpus, too, but this has not been done. If you have access to
+	  a non-i386 system which may be used for testing, please visit
+	  http://home.zonnet.nl/vanrein/badram and leave a message. Thank you.
+
+config BADMEM_UTILPATH_WITH_QUOTES
+       string "   path to the BadMEM utilities package" 
+       default "/usr/src/badmem"
+       depends on BADMEM
+       ---help---
+	  Type in here your path to the latest badmem utilities which you may download
+	  from http://badmem.sourceforge.net
+	  
+	  Please note that this package is necessary for the compilation of the
+	  kernel!
+	
+       
+config BADMEM_DEBUG
+       bool "   Enable BadMEM debug messages during kernel boot"
+       depends on BADMEM
+       ---help---
+	  This will show much internal information for the BadMEM routines
+	  which should make it easier to debug it.
+	  
+	  If you are a normal user, you can say 'N' here, since it only fills
+	  up your log files, nothing else. If you are a kernel developer who
+	  wants to get to know a bit more about this driver by testing on your
+	  own, it is highly recommended that you say 'Y' here.
+
+config BADMEM_PROCFS
+       bool "   /proc fs support for BadMEM"
+       depends on BADMEM
+       depends on PROC_FS
+       ---help---
+	  This will add another entry in your /proc filesystem (this feature
+	  must be enabled for sure!) which will give you some more detailed
+	  information on the state of BadMEM during normal running process.
+	
+	  Currently there are no programs in userspace or in the kernel which
+	  need this option, but it might be useful for you. If you are an
+	  experienced user of the kernel, it might be worthy.
+	  
+	  It is safe to say 'N', but saying 'Y' will not hurt either.
+  
+config BADMEM_HIGHMEMSUPPORT
+       bool "   limited High Memory Support (DANGEROUS!)"
+       depends on BADMEM
+       depends on HIGHMEM
+       ---help---
+	  Attention! This is a big fat warning -- this part of BadMEM is very
+	  alpha. Only activate this switch if you really know what you are
+	  doing!!
+	  
+	  Hint for High Mem users: If you do not have any BadRAM above the
+	  first 1GB, you can always say no here. If you have such BadRAM,
+	  have a hard look at arch/i386/mm/init.c before proceeding!
+	  
+	  If you do not know about what I am talking, always say "N" here!
+	
+config BADMEM_MODSYSTEM
+       bool "   Extended Module support"
+       depends on BADMEM
+       ---help---
+	  There is an experimental version of another configuration method
+	  of BadMEM. Enable this option only, if you are very familiar with
+	  the BadMEM stuff. 
+	    
+	  If you are unsure what this means, always say "N" here. Especially
+	  if you want to use the Rick-van-Rein-compatible way of configuration
+	  you *MUST* say 'N' here, otherwise configuration will be totally
+	  messed up!
+	  
+	  If you enable this, please be sure that you have read the file
+	  Documentation/badmem_conf.txt
+
+config BADMEM_CONFIGFILENAME_WITH_QUOTES
+       string "     Configuration filename" 
+       default "/etc/badmem.conf"
+       depends on BADMEM_MODSYSTEM
+       ---help---
+	  If you want to alter the location of the BadMEM configuration file to
+	  something different than 
+	
+	  	    /etc/badmem.conf
+		    
+	  then you can parse the full filename (that is path and name with extension)
+	  to this field. If you leave it blank, then the standard location is used.
+       
+
+endmenu
diff -uNr linux-2.6.9-vanilla/mm/Makefile linux-2.6.9/mm/Makefile
--- linux-2.6.9-vanilla/mm/Makefile	Sun Feb 12 21:54:23 2006
+++ linux-2.6.9/mm/Makefile	Tue Feb 14 18:05:55 2006
@@ -18,3 +18,71 @@
 obj-$(CONFIG_SHMEM) += shmem.o
 obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
 
+
+
+clean-files := modparse badmem_modules.c kernel_badmemlib.o \
+	       badmemlib_version badmemkernellib_version
+
+ifeq ($(CONFIG_BADMEM),y)
+obj-$(CONFIG_BADMEM) += kernel_badmemlib.o
+obj-$(CONFIG_BADMEM_PROCFS) += badmem_proc.o
+obj-$(CONFIG_BADMEM_MODSYSTEM) += badmem_modules.o
+endif
+
+ifeq ($(CONFIG_BADMEM),y)
+ ifeq ($(CONFIG_BADMEM_MODSYSTEM),y)
+
+   CONFIG_BADMEM_CONFIGFILENAME = $(subst ",,$(CONFIG_BADMEM_CONFIGFILENAME_WITH_QUOTES))
+
+   ifeq ("$(CONFIG_BADMEM_CONFIGFILENAME)","")
+    CONFIG_BADMEM_CONFIGFILENAME = /etc/badmem.conf
+   endif
+
+mm/modparse: mm/modparse.c
+	$(CC) -o mm/modparse mm/modparse.c -lbadmem -lm
+ 
+mm/badmemlib_version: mm/badmemlib_version.c
+	$(CC) -DLIB_TEST -o mm/badmemlib_version mm/badmemlib_version.c -lbadmem -lm
+
+mm/runversiontest: mm/badmemlib_version
+	@mm/badmemlib_version; if [ $? == 1 ]; then echo "Sorry, the version\
+of your installed BadMEMlib is too old. Please update from\
+http://badmem.sourceforge.net"; exit 1; fi
+	rm -f mm/badmemlib_version  # This file is not used any more, so we can delete it
+ 
+mm/badmem_modules.o: mm/runversiontest mm/modparse $(CONFIG_BADMEM_CONFIGFILENAME)
+	mm/modparse $(CONFIG_BADMEM_CONFIGFILENAME) > mm/badmem_modules.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o mm/badmem_modules.o mm/badmem_modules.c
+
+ endif
+
+ ifeq ($(CONFIG_BADMEM_PROCFS),y)
+  ifneq ("$(CONFIG_BADMEM_UTILPATH_WITH_QUOTES)","")
+   CONFIG_BADMEM_UTILPATH:=$(strip $(subst ",,$(CONFIG_BADMEM_UTILPATH_WITH_QUOTES)))
+  else
+   CONFIG_BADMEM_UTILPATH:=/usr/src/badmem
+  endif
+  override CFLAGS+= -I$(CONFIG_BADMEM_UTILPATH)/badmemlib/include
+
+
+mm/badmemkernellib_version: mm/badmemlib_version.c
+	$(CC) -DKERNELLIB_TEST -o mm/badmemkernellib_version -I $(CONFIG_BADMEM_UTILPATH)/badmemlib/include mm/badmemlib_version.c -lbadmem -lm
+
+mm/runversiontest_kernel: mm/badmemkernellib_version
+	@mm/badmemkernellib_version; if [ $? == 1 ]; then echo "Sorry, the version \
+of your in the kernel configuration specified BadMEMlib is too old. Please update from \
+http://badmem.sourceforge.net"; exit 1; fi
+	rm -f mm/badmemkernellib_version   # This file is not used any more, so we can delete it
+ 
+mm/kernel_badmemlib.o: mm/runversiontest_kernel
+	@if [ ! -e $(CONFIG_BADMEM_UTILPATH) ]; then echo "$(CONFIG_BADMEM_UTILPATH) does not exists!"; exit 1; fi
+	@if [ ! -e $(CONFIG_BADMEM_UTILPATH)/badmemlib -o ! -e $(CONFIG_BADMEM_UTILPATH)/badmemlib/Makefile.in ]; then echo "Could not find util package in $(CONFIG_BADMEM_UTILPATH)!"; exit 1; fi
+	if [ -e $(CONFIG_BADMEM_UTILPATH)/configure -a ! -e $(CONFIG_BADMEM_UTILPATH)/Makefile ]; then cd $(CONFIG_BADMEM_UTILPATH); export CFLAGS=""; export LDFLAGS=""; ./configure ; fi
+	$(MAKE) -C $(CONFIG_BADMEM_UTILPATH)/badmemlib IN_KERNEL_MODE=1 clean links
+	$(MAKE) -C $(CONFIG_BADMEM_UTILPATH)/badmemlib IN_KERNEL_MODE=1 kernel_badmemlib.o
+	@if [ -L mm/kernel_badmemlib.o ]; then ln -sf $(CONFIG_BADMEM_UTILPATH)/badmemlib/kernel_badmemlib.o mm/kernel_badmemlib.o; fi
+	@if [ ! -e mm/kernel_badmemlib.o ]; then ln -s $(CONFIG_BADMEM_UTILPATH)/badmemlib/kernel_badmemlib.o mm/kernel_badmemlib.o; fi
+	@if [ ! -L mm/kernel_badmemlib.o ]; then echo "Could not create link for 'mm/kernel_badmemlib.o'"; exit 1; fi
+ endif
+
+endif
diff -uNr linux-2.6.9-vanilla/mm/badmem_proc.c linux-2.6.9/mm/badmem_proc.c
--- linux-2.6.9-vanilla/mm/badmem_proc.c	Thu Jan  1 01:00:00 1970
+++ linux-2.6.9/mm/badmem_proc.c	Tue Feb 14 18:05:27 2006
@@ -0,0 +1,241 @@
+/*
+ * 
+ * proc file system support for the BadMEM patch
+ * 
+ * Written by Nico Schmoigl, eagle2@users.sourceforge.com, August 2000
+ * Revised by Nico Schmoigl, March 2004
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <asm/byteorder.h>
+#include <linux/badmem.h>
+
+#ifdef CONFIG_BADMEM_MODSYSTEM
+#include <badmemlib.h>
+#endif /* CONFIG_BADMEM_MODSYSTEM */
+
+#define BADMEM_MODDIR "badmem/modules"
+
+static int badmem_proc_printmap (char *b) {
+   int totallen, thislen, badpages = 0;
+   int i, nopageprint = 0;
+
+   totallen = thislen = sprintf (b, "Marked as bad are:\n");
+   b += thislen;
+   
+   for (i=0;i<max_low_pfn;i++) {
+      char n[100];
+      struct page *p = pfn_to_page(i);
+      
+      if (!PageBad(p))
+	continue;
+      
+      // this is a bad page its offset is in i
+
+      if (++badpages >= 32) {
+	      nopageprint = 1; // otherwise this would kill proc fs! (Overflow issue)
+	      continue;
+      }
+
+      sprintf (n, "%s%s%s", PageReserved(p) ? "reserved " : "",
+	       PageLocked(p) ? "locked " : "",
+	       PageSlab(p) ? "slab" : "");
+	 
+      thislen = sprintf (b, "page #%i, mem 0x%08x-0x%08x, counter %u, %s\n", i, i << PAGE_SHIFT, ((i+1) << PAGE_SHIFT) - 1, page_count(p), n); 
+      totallen += thislen;
+      b += thislen;
+
+   }
+   
+   if (nopageprint) {
+      thislen = sprintf (b, "[...more...]\n");
+      totallen += thislen;
+      b+= thislen;
+   }
+   
+   thislen = sprintf (b, "\nSummary: %i pages (=%ik) are marked as bad\n", badpages, badpages << (PAGE_SHIFT - 10)); 
+   totallen += thislen;
+   b += thislen;
+   
+   return totallen;
+}
+
+
+static int badmem_read_proc (char *buf, char **start, off_t off, int count, int *eof, void *data)
+{
+   char *dat = buf;
+   
+   int len, totallen = 0;
+   register int i;
+   
+   len = sprintf (dat, "BADMEM driver version " BADMEM_VERSION "\nBADMEM features: " BADMEM_FEATURES "\n");
+   totallen += len;
+   dat += len;
+
+#ifndef CONFIG_BADMEM_MODSYSTEM
+   len = sprintf (dat, "BADMEM boot options: ");
+   totallen += len;
+   dat += len;
+   
+   /*
+    * Get all parameters from the array and put them 
+    */
+   for (i=1;i<=badmem_paramcount;i++) {
+      len = sprintf (dat, "0x%08lx ", badmem_params[i]);
+      totallen += len;
+      dat += len;
+   }
+   
+   len = sprintf (dat, "\n\n");
+   totallen += len;
+   dat += len;
+#endif /* CONFIG_BADMEM_MODSYSTEM */      
+
+#ifdef CONFIG_BADMEM_MODSYSTEM
+	// tell which modules are known to the kernel
+	len = sprintf (dat, "BADMEM known modules: ");
+	totallen += len; dat += len;
+	
+	i = 0;
+	while (badmem_modtab[i].mod_name != NULL) {
+		len = sprintf (dat, "%s,", badmem_modtab[i].mod_name);
+		totallen += len; dat += len;
+		i++;
+	}
+	// now dat has one comma at the end or at least a whitespace (on the case that the modtab was empty)...
+	*(dat-1) = '\n';
+#endif /* CONFIG_BADMEM_MODSYSTEM */
+	
+	
+   // Now print the map
+   totallen += badmem_proc_printmap (dat);
+   
+   // now we have to finish to proc read request... the buffer is already ok, but len, eof and start need
+   // another update...
+   *eof = 1;
+   *start = buf+off;
+   totallen -= off;
+   
+   if (totallen > count)
+     totallen = count;
+   
+   if (totallen < 0)
+     totallen = 0;
+   
+   return totallen;
+   
+}
+
+#ifdef CONFIG_BADMEM_MODSYSTEM
+/*
+ * The read routine for the mdf files in the proc/badmem/modules/mdf directory
+ */
+static int lock = 0;
+
+static int badmem_mdf_read_proc (char *buf, char **start, off_t off, int count, int *eof, void *data) {
+	struct badmem_modules *dat = (struct badmem_modules *) data;
+	register int i = 0, dummy;
+	char *tmpbuffer;
+	int internalcount;
+	
+	while (lock);
+	
+	lock = 1; // locking on;
+	
+	if (!data) 
+		return 0;
+
+
+#ifdef CONFIG_BADMEM_DEBUG
+	printk (KERN_DEBUG "BadMEM: %p belongs to '%s'\n", data, dat->mod_name);
+#endif	
+	
+        tmpbuffer = dat->mdfdata;
+        internalcount = dat->mdflen;
+        i = internalcount;  
+
+#define min_macro(a,b) ((a<b)?a:b)	
+   
+	*start = buf;
+
+	dummy = min_macro(i-off, min_macro(count, internalcount-off));
+	if (dummy < 0)
+		dummy = 0;
+
+	if (dummy < count)
+		*eof = 1;
+	else
+		*eof = 0;
+
+	if (i-off == dummy)
+		*eof = 1;
+	
+#ifdef CONFIG_BADMEM_DEBUG
+        printk (KERN_DEBUG "BadMEM: requested offset is %li\n", off);
+	printk (KERN_DEBUG "BadMEM: able to pass %li bytes, sending %u bytes, eof=%u\n", i-off, dummy, *eof);
+#endif	
+        if (dummy > 0)
+		memcpy (buf, tmpbuffer+off, dummy);
+	
+	lock = 0;
+	return dummy;
+#undef min
+}
+
+/*
+ * Registers all modules in /proc/badmem/modules
+ */
+static struct proc_dir_entry *moddir_proc_entry;
+
+static void __init register_modules_in_proc(void) {
+	register int i = 0;
+	struct proc_dir_entry *dentry;
+	
+	dentry = proc_mkdir("mdf", moddir_proc_entry);
+
+#ifdef CONFIG_BADMEM_DEBUG
+	printk ("BadMEM: register 'mdf' procfs-reporting: %p\n", dentry);
+#endif /* CONFIG_BADMEM_DEBUG */	
+	
+	if (!dentry)  // something went wrong...
+		return;
+
+	while (badmem_modtab[i].mod_name != NULL) {
+		create_proc_read_entry (badmem_modtab[i].mod_name, 0, dentry, badmem_mdf_read_proc, (void *) &badmem_modtab[i]);
+#ifdef CONFIG_BADMEM_DEBUG
+		printk ("BadMEM: created mdf entry %s in procfs\n", badmem_modtab[i].mod_name);
+#endif /* CONFIG_BADMEM_DEBUG */
+		i++;
+	}
+
+	printk ("BadMEM: summary - registered %i modules with mdf in procfs\n", i);
+	
+	return;
+}
+
+#endif /* CONFIG_BADMEM_MODSYSTEM */
+
+static int __init badmem_proc_init(void) {
+#ifdef CONFIG_BADMEM_MODSYSTEM
+   moddir_proc_entry = proc_mkdir ("badmem", 0);
+   
+   if (moddir_proc_entry) {
+	   register_modules_in_proc();
+	   create_proc_read_entry ("badmem/summary", 0, NULL, badmem_read_proc, NULL);
+   } else {
+	   create_proc_read_entry ("badmem", 0, NULL, badmem_read_proc, NULL);
+   }
+#else
+	create_proc_read_entry("badmem", 0, NULL, badmem_read_proc, NULL);
+#endif	/* CONFIG_BADMEM_MODSYSTEM */
+	   
+   return 0;
+}
+
+
+__initcall(badmem_proc_init);
diff -uNr linux-2.6.9-vanilla/mm/badmemlib_version.c linux-2.6.9/mm/badmemlib_version.c
--- linux-2.6.9-vanilla/mm/badmemlib_version.c	Thu Jan  1 01:00:00 1970
+++ linux-2.6.9/mm/badmemlib_version.c	Tue Feb 14 18:05:27 2006
@@ -0,0 +1,18 @@
+#include "badmemlib.h"
+
+#ifdef KERNELLIB_TEST 
+ // Version testing for the kernel utilities
+const int atleastversion = COMPUTE_VERSION(1,7,0); // the equal case leads to acception of the version!
+#endif // KERNELLIB_TEST
+
+#ifdef LIB_TEST
+ // Version testing for the standard badmem utils located in the path
+const int atleastversion = COMPUTE_VERSION(1,5,0); // the equal case leads to acception of the version!
+#endif // LIB_TEST
+
+
+int main (int argc, char **argv) {
+   badmem_library_allversions_stderr();
+   
+   return !( atleastversion <= VERSION );
+}
diff -uNr linux-2.6.9-vanilla/mm/modparse.c linux-2.6.9/mm/modparse.c
--- linux-2.6.9-vanilla/mm/modparse.c	Thu Jan  1 01:00:00 1970
+++ linux-2.6.9/mm/modparse.c	Tue Feb 14 18:05:28 2006
@@ -0,0 +1,490 @@
+/*
+ * Script utility for parsing the /etc/badmem.conf file into a kernel compilable .c file
+ *
+ * License: GPL as all of the kernel
+ * Author: Nico Schmoigl, nico@writemail.com
+ * 
+ * Changes: V1.0 release version
+ * 
+ * 
+ * NOTE: If you make any changes to this file, please note them at the CHANGES section above. Thanks.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <badmemlib.h>
+
+#define DELIMS "\n #,;"
+#define MODULE_TABLE_NAME "badmem_modtab"
+#define ABSOLUTE_MODULENAME "_absolute"
+
+FILE *fz;
+
+typedef struct {
+   char name[100];
+   int mdflen;
+   unsigned long base;
+} moddata;
+
+struct {
+   int openstruct;
+
+   char thisline[600];
+   moddata modnames[100];
+   unsigned int lastmodule;
+   int absolutemode, hadbeenamode;
+   mdf_cmdset *mdf;
+} ivar;
+
+unsigned long parse_ulong (char *s) {
+   register int i = 0, countdigits = 0;
+   unsigned long res = 0L;
+   char shifter = 0;
+   
+   for (;i<strlen(s);i++)
+     if (isdigit(s[i])) countdigits++;
+   
+   if (countdigits == strlen(s)) {
+      sscanf (s, "%lu", &res);
+      return res;
+   }
+   
+   countdigits = 0;
+   
+   for (i=2; i< strlen(s);i++) 
+     if (isxdigit(s[i])) countdigits++;
+   
+   if (countdigits == strlen(s)-2 && s[0] == '0' && s[1] == 'x') {
+      sscanf (s, "%lx", &res);
+      return res;
+   }
+   
+   i = strlen(s)-1;
+   
+   if (s[i] != 'm' && s[i] != 'g' && s[i] != 'b' && s[i] != 'p' && s[i] != 'k' && s[i] != 't')
+     return 0;
+
+   shifter = s[i];
+   s[i] = 0;
+   
+   sscanf (s, "%lu", &res);
+   
+   switch (shifter) {
+    case 'm': res <<= 20; break;
+    case 'g': res <<= 30; break;
+    case 'b': res <<= 9; break;
+    case 'p': res <<= 12; break;
+    case 'k': res <<= 10; break;
+   }
+   
+   return res;
+}
+
+void __inline__ internal_hexreturn (char *b, const char c) {
+   char dummy[5];
+   char *ptr = dummy;
+   
+   sprintf (dummy, "%02hx", (char) c);
+   if (strlen(dummy) == 4)
+     ptr += 2;
+   
+   strcpy (b, ptr);
+}
+
+void hexdumpram (char *buf, const int len) {
+   register int i = 0;
+   char dummy[3];
+   
+   if (len == 0)
+     return;
+   
+   printf ("  ");
+   while (len > i) {
+      char dummy[3];
+      
+      internal_hexreturn (dummy, buf[i]);
+      printf ("0x%s, ", dummy);
+      
+      i++;
+      if (i % 10 == 0)
+	printf ("\n  ");
+   }
+   internal_hexreturn (dummy, buf[len-1]);
+   printf ("0x%s", dummy);
+}
+
+
+void close_module (void) {
+     if (ivar.openstruct) {
+	// There is an 'old' mdf_cmdset to be written into the output file.
+	char buf[1000];
+	int mdflen;
+	mdf_cmd cmd;
+	
+	cmd.cmd = MDFCMD_END;
+	cmd.subcmd = 0;
+	cmd.len = 0;
+	cmd.data = NULL;
+	mdf_appendcmd (ivar.mdf, cmd);
+	
+	// print it in host order!
+	printf ("/* MDF CMD set in clear text is as follows:\n");
+	mdf_print_cmdset_out(ivar.mdf);
+
+	mdf_convert2networkorder (ivar.mdf);
+	
+	mdflen = mdf_gettotalsize(ivar.mdf);
+	if (mdflen > sizeof(buf)) {
+	   fprintf (stderr, "Error: MDF File too large (%u)... breaking!", mdflen);
+	   exit(1);
+	}
+ 	mdflen = mdf_writetomem(buf, sizeof(buf), ivar.mdf);
+	
+	printf ("total length in memory: %u\n", mdflen);
+ 	printf ("*/\n\n");
+	ivar.modnames[ivar.lastmodule-1].mdflen = mdflen;
+
+	free_mdfset (ivar.mdf);
+	ivar.mdf = NULL;
+	
+	printf ("char mdf_%s[] = {\n", ivar.modnames[ivar.lastmodule-1].name); 
+	
+	hexdumpram (buf, mdflen);
+	
+	printf ("};\n\n");
+
+     }
+
+     ivar.openstruct = 0;
+}
+
+void close_absolute (void) {
+   close_module();
+   
+   ivar.absolutemode = 0;
+   ivar.hadbeenamode = 1;
+}
+
+
+void define_module (const char *modname) {
+   mdf_cmd cmd;
+   char *mname, *dummy;
+   
+   if (ivar.openstruct) 
+     close_module();
+     
+   if (ivar.absolutemode) 
+     close_absolute();
+   
+   ivar.openstruct = 1;
+   ivar.modnames[ivar.lastmodule].base = 0;
+   strcpy (ivar.modnames[ivar.lastmodule++].name, modname);
+   
+   mname = (char *) malloc (strlen(modname)+1);
+   strcpy (mname, modname); 
+   
+   ivar.mdf = new_mdfset(32);       // 32 is the standard area size; allocation will be automatically increased by the library if necessary.
+   
+   cmd.cmd = MDFCMD_VERSION;
+   cmd.subcmd = 1;
+   cmd.data = NULL;
+   cmd.len = 0;
+   mdf_appendcmd (ivar.mdf, cmd);
+   
+   dummy = (char *) malloc(100);
+   cmd.cmd = MDFCMD_MODULENAME;
+   cmd.subcmd = 0;
+   cmd.data = mname;
+   cmd.len = strlen(mname)+1;
+   mdf_appendcmd (ivar.mdf, cmd);
+   
+   free (mname);
+   free (dummy);
+}
+
+void define_absolute (void) {
+   if (ivar.openstruct) {
+      fprintf (stderr, "ERROR: Absolute definitions must be defined before *ANY* other module!\n");
+      exit(1);
+   }
+   
+   if (ivar.hadbeenamode) {
+      fprintf (stderr, "ERROR: Definition of absolute values only allowed once!\n");
+      exit(1);
+   }
+   
+   if (ivar.absolutemode)
+     return;
+   
+   define_module (ABSOLUTE_MODULENAME);
+   
+   ivar.absolutemode = 1;
+}
+
+void define_base (const char *base) {
+   char *s = (char *) malloc (strlen(base)+10);
+   
+   strcpy (s, base);
+   
+   ivar.modnames[ivar.lastmodule-1].base = parse_ulong (s);
+   
+   free (s);
+}
+
+void define_size (const char *sizestr) { 
+   char *s = (char *) malloc (strlen(sizestr)+10);
+   unsigned long size;
+   mdf_cmd cmd;
+   
+   strcpy (s, sizestr);
+   
+   size = parse_ulong(s);
+
+   free (s);
+   
+   cmd.cmd = MDFCMD_MODULESIZE;
+   cmd.subcmd = 0;
+   cmd.len = sizeof(size);
+   cmd.data = &(size);
+   mdf_appendcmd (ivar.mdf, cmd);
+}
+
+
+void define_badmem (const badmem_patternset *bps) {
+   if ((!ivar.openstruct) && (!ivar.absolutemode))
+     // ups; we may not write here!
+     return;
+
+   if (bps == NULL)
+     return;
+   
+   mdf_append_patternset (ivar.mdf, bps);
+   
+}
+
+void make_moduletable (void) {
+   register int i = 0;
+   
+/*   if (!ivar.hadbeenamode) {
+      define_absolute();
+      close_absolute();
+   }*/
+
+   printf ("struct badmem_modules " MODULE_TABLE_NAME "[] = {\n");
+   
+   for (;i < ivar.lastmodule; i++) 
+      printf ("   { \"%s\", %u, mdf_%s },\n", ivar.modnames[i].name, ivar.modnames[i].mdflen, ivar.modnames[i].name);
+   
+   printf ("   { NULL, 0, NULL }\n};\n\n");
+   
+   printf ("int absolutemode = %i;\n\n",  ivar.hadbeenamode ? 1 : 0);
+}
+
+void insert_mdffile (const char *fname) {
+	FILE *fz = fopen (fname, "rb");
+	mdf_cmdset *set;
+	char modname[100];
+	int begin = 0, end = 0;
+	int i;
+
+	fprintf (stderr, "Inserting mdf file: %s...", fname);
+	
+	if (!fz) {
+		fprintf (stderr, "Could not open %s, exiting\n", fname);
+		exit(2);
+	}
+	
+	set = mdf_readfromfile (fz);
+        mdf_convert2hostorder (set);
+	fclose (fz);
+	
+	printf ("/* Dump of the mdf file %s:\n", fname);
+	mdf_print_cmdset_out(set);
+	printf ("*/\n\n");
+	
+	while (mdf_getnextindexpair (set, &begin, &end)) {
+	        badmem_patternset *bps;     
+	        char size[20];
+	   
+		if (mdf_extract_modulename (modname, set, begin, end) == NULL) {
+			free_mdfset(set);
+			fprintf (stderr, "An internal module name error occured!\nPlease report this bug!\n");
+			exit(1); // a sort of internal error!
+		}
+	   
+	        if (strcmp (modname, ABSOLUTE_MODULENAME) == 0) {
+		   fprintf (stderr, "Invalid module name found: %s\tSkipping this module!\n", modname);
+		   continue;
+		}
+
+		// In modname we now have the module's name
+	        define_module (modname);
+	        sprintf (size, "%u",mdf_extract_modulesize(set, begin, end)); 
+	        define_size (size);
+	        bps = mdf_extract_patternset (set, begin, end);
+
+	        define_badmem (bps);
+	   
+	        close_module();
+	}
+	free_mdfset (set);
+	fprintf (stderr, "done.\n");
+}
+
+int is_addr(const char *t) {
+   register int i = 0, countdigits = 0;
+   
+   // let's check for a hex first.
+   if (t[0] == '0' && t[1] == 'x' && strlen(t) > 2)
+     return 1;
+   
+   // we need the number of digits in the string
+   for (;i<strlen(t);i++)
+     if (isdigit(t[i]))
+       countdigits++;
+   
+   // if all chars are digits then this is a decimal (or an ocatal... ;-) )
+   if (countdigits == strlen(t))
+     return 1;
+   
+   // now this could be a abbreviated decimal (ie. "128m")
+   if (countdigits-1 == strlen(t)) {
+      i = strlen(t)-1;
+      if (t[i] == 'm') return 1;  // megabytes = 1048576 bytes
+      if (t[i] == 'b') return 1;  // blocks = 512 bytes
+      if (t[i] == 'k') return 1;  // kilobytes = 1024 bytes
+      if (t[i] == 'p') return 1;  // pages = 4096 bytes
+      if (t[i] == 'g') return 1;  // gigabytes = ehm... something huge =;-)
+      if (t[i] == 't') return 1;  // terabytes = that is gigabytes * 1024
+   }
+   
+   // wow, then this is no number...
+   return 0;
+}
+
+int main (int argc, char *argv[]) {
+   
+   ivar.openstruct = 0;
+   ivar.lastmodule = 0;
+   ivar.absolutemode = 0;
+   ivar.hadbeenamode = 0;
+   
+   if (argc != 2)
+     return 1;
+   
+   fz = fopen (argv[1], "rt");
+
+   if (!fz) {
+      fprintf (stderr, "ERROR: Could not open %s - did you configure BadMEM at all?!\n", argv[1]);
+      return 255;
+   }
+   
+   printf ("#include <linux/badmem.h>\n\n");
+   
+   while (!feof(fz)) {
+      char *token;
+      register int i = 0;
+      char *pos = NULL;
+      char securecopy[sizeof(ivar.thisline)];
+      
+      fgets (ivar.thisline, sizeof(ivar.thisline), fz);
+      strcpy (securecopy, ivar.thisline);
+      
+      // let's check it this could be a comment...therefor we skip some bs or tabs
+      while (ivar.thisline[i] == ' ' || ivar.thisline[i] == '\t') 
+	i++;
+      
+      // now we can check if this line is a comment or not
+      if (ivar.thisline[i] == '#' || ivar.thisline[i] == ';')
+	continue;
+
+      // the # or the ; may also be at the end of a line
+      pos = (char *) rindex (ivar.thisline, '#');
+      if (pos != NULL)
+	*pos = '\0';
+      
+      // the ; too!
+      pos = (char *) rindex (ivar.thisline, ';');
+      if (pos != NULL)
+	*pos = '\0';
+
+      // get the first token from this string
+      token = (char *) strtok (&ivar.thisline[i], DELIMS);
+
+#define NEXTTOKEN \
+      token = (char *) strtok(NULL, DELIMS);\
+      continue
+      
+      while (token != NULL) {
+	 char *param2;
+	 badmem_patternset *bps;
+	 
+	 if (strcasecmp (token, "mdf") == 0) {
+	    char *param1 = (char *) strtok (NULL, DELIMS);
+	    
+	    insert_mdffile (param1);
+	    NEXTTOKEN;
+	 }
+	      
+	 if (strcasecmp (token, "module") == 0) {
+	    char *param1 = (char *) strtok (NULL, DELIMS);
+	    
+	    
+	    define_module (param1);
+	    NEXTTOKEN;
+	 }
+	 if (strcasecmp (token, "base") == 0){
+	    char *param1 = (char *) strtok (NULL, DELIMS);
+	    define_base (param1);
+	    NEXTTOKEN;
+	 }
+
+	 if (strcasecmp (token, "size") == 0) {
+	    char *param1 = (char *) strtok (NULL, DELIMS);
+	    define_size (param1);
+	    NEXTTOKEN;
+	 }
+	 
+	 if (strcasecmp (token, "absolute") == 0) {
+	    define_absolute();
+	    NEXTTOKEN;
+	 }
+	 
+	 if (!is_addr(token)) {
+	    fprintf (stderr, "Unknown or unexpected token '%s'\n", token);
+	    return 2;
+	 }
+	 
+	 // in securecopy we have the whole line we are currently analyzing!
+	 bps = badmem_get_patternset_from_string (&securecopy[i]);
+	 token = NULL;
+
+	 if (bps == NULL)
+	   continue;
+	 
+	 for (i = 0; i<bps->used_patterns;i++) {
+	    // the base (the same idea as the 'offset') must be added here!
+	    // this is double-offsetting!
+	    bps->pattern[i]->offset += ivar.modnames[ivar.lastmodule-1].base;
+	 }
+
+	 define_badmem (bps);
+	 
+	 free_badmem_patternset(bps);
+      }
+
+#undef NEXTTOKEN
+   }
+ 
+   if (ivar.openstruct)
+	   close_module();
+	 
+   make_moduletable();
+   
+   
+   fclose (fz);
+   return 0;
+}
diff -uNr linux-2.6.9-vanilla/mm/page_alloc.c linux-2.6.9/mm/page_alloc.c
--- linux-2.6.9-vanilla/mm/page_alloc.c	Sun Feb 12 21:54:23 2006
+++ linux-2.6.9/mm/page_alloc.c	Tue Feb 14 18:05:28 2006
@@ -12,6 +12,7 @@
  *  Zone balancing, Kanoj Sarcar, SGI, Jan 2000
  *  Per cpu hot/cold page lists, bulk allocation, Martin J. Bligh, Sept 2002
  *          (lots of bits borrowed from Ingo Molnar & Andrew Morton)
+ *  BADMEM support, Nico Schmoigl, August/September 2000, April 2001, August 2001, March 2004
  */
 
 #include <linux/config.h>
@@ -34,6 +35,12 @@
 
 #include <asm/tlbflush.h>
 
+#ifdef CONFIG_BADMEM
+# include <linux/badmem.h>
+# include <badmemlib.h>
+# include <linux/string.h>
+#endif // CONFIG_BADMEM
+
 DECLARE_BITMAP(node_online_map, MAX_NUMNODES);
 struct pglist_data *pgdat_list;
 unsigned long totalram_pages;
@@ -785,6 +792,11 @@
 
 fastcall void __free_pages(struct page *page, unsigned int order)
 {
+#ifdef CONFIG_BADMEM
+        if (PageBad(page))
+                return;
+#endif // CONFIG_BADMEM
+
 	if (!PageReserved(page) && put_page_testzero(page)) {
 		if (order == 0)
 			free_hot_page(page);
@@ -2069,3 +2081,254 @@
 
 	return table;
 }
+
+
+
+#ifdef CONFIG_BADMEM
+
+#ifndef CONFIG_BADMEM_MODSYSTEM
+ulong badmem_params[BADMEM_MAXPARAMS+1];
+int badmem_paramcount;
+
+/*
+ * Setup routine for getting the kernel parameter in BADMEM
+ */
+static int __init badmem_setup (char *str) {
+       register int i;
+       int ints[11];
+
+       (void) get_options(str, ARRAY_SIZE(ints), ints);
+       if (ints[0] > BADMEM_MAXPARAMS)
+            panic ("Too bad: badmem=... length exceeds BADMEM_MAXPARAMS. Please try combining patterns");
+
+       badmem_paramcount = ints[0];
+
+       for (i=0;i<=ints[0];i++)
+            badmem_params[i]=ints[i];
+
+       return 1;
+}
+
+/*
+ * this is the heart of BADMEM. All pages will be marked here.
+ */
+void badmem_markpages(void) {
+    ulong *argv=badmem_params;
+    int   argc=*argv++;
+    ulong addr, mask;
+
+#ifdef CONFIG_BADMEM_DEBUG
+    printk ("DEBUG BADMEM: max_mapnr=%li, argc=%i\n", max_mapnr, argc);
+#endif
+
+    while (argc-- > 0) {
+        badmem_pattern p;
+
+       addr = *argv++;
+       mask = (argc-- > 0) ? *argv++: ~0L;
+
+       mask |= ~PAGE_MASK;    // Optimalisation
+        addr &= mask;           //  Normalisation
+
+        p.addrp = addr;
+        p.mask = mask;
+        p.ubound = ~0x0L;
+        p.offset = 0L;
+       do {
+          if ( ( p.addrp >> PAGE_SHIFT ) >= max_mapnr) {
+             // senseless to mark something here
+             printk ("BADMEM: address out mem area: 0x%lx\n", addr);
+             break;
+
+           }
+
+           // now we can mark it
+           PageSetBad(pfn_to_page(p.addrp >> PAGE_SHIFT));
+        } while (badmem_nextaddress (&p));
+    }
+}
+#else
+char badmem_instmodules[BADMEM_MAXPARAMS+1][32];
+
+/*
+ * Parse the command line with this routine
+ * parses the lines and copies it to the badmem_instmodules array
+ */
+static int __init badmem_setup (char *str) {
+   char localcopy[256], *lptr = localcopy;
+   char *ptr;
+   register int i = 0;
+
+   strncpy (localcopy, str, sizeof(localcopy)-1);
+
+   memset (badmem_instmodules, 0, sizeof(badmem_instmodules));
+
+   i = 0;
+   while (i != 32 && (ptr = strsep (&lptr, ", "))) {
+      strncpy (badmem_instmodules[i], ptr, 32);
+      i++;
+   }
+   return 1;
+}
+
+/*
+ * process a module by the mdf data which are packed dense at the memory location "mdfdata"
+ * with the base starting address thisstart (logical offset of the memory module due to not being in the Bank 0)
+ */
+unsigned long badmem_processmdfram (char *mdfdata, const int mdflen, const unsigned long thisstart) {
+   register int i = 0; // counter for all the areas we have to mark as bad
+   unsigned long size;
+   int beginidx = 0, endidx = 0;
+   mdf_cmdset *mdf;
+   badmem_patternset *bps;
+
+   mdf = mdf_readfrommem_static (mdfdata, mdflen);
+   if (mdf == NULL) {
+      printk ("Could not mangle the raw data. This is a bug\n");
+      return 0;
+   }
+
+   mdf_convert2hostorder(mdf);
+
+   if (!mdf_getnextindexpair (mdf, &beginidx, &endidx)) {
+      printk ("There is no module defined in this mdf set!\n");
+      free_mdfset(mdf);
+      return 0;
+   }
+
+   bps = mdf_extract_patternset_static (mdf, beginidx, endidx);
+   if (bps == NULL) {
+      printk ("Nothing to lock here\n");
+      free_mdfset(mdf);
+      return 0;
+   }
+
+   size = mdf_extract_modulesize (mdf, beginidx, endidx);
+
+#ifdef CONFIG_BADMEM_DEBUG
+   printk ("Running the patternset (size=%lu):\n", size);
+   badmem_print_patternset_out (bps);
+   printk ("---\n");
+#endif
+
+   printk ("Locking memory");
+
+   for (;i<bps->used_patterns;i++) {
+      badmem_pattern p;
+      int count = 0;
+
+      badmem_copy_pattern (&p, bps->pattern[i]);
+
+      do {
+        unsigned long realaddr = p.addrp+thisstart - p.offset;
+	 
+        if (count % 2048 == 0)
+          printk (".");
+
+        if (p.addrp-p.offset > size) {
+#ifdef CONFIG_BADMEM_DEBUG
+           printk ("got out of module (address %08lx with size %08lx); breaking\n", p.addrp, size);
+#endif
+           // we are out of this module. All furhter addresses will be higher, so we can break here.
+           break;
+        }
+
+
+        if ( (realaddr >> PAGE_SHIFT) >= max_mapnr) {
+           printk ("BADMEM: address out of mem area: 0x%08lx\n", realaddr);
+           printk ("BADMEM: most likely you specified too many (or too big) modules.\n");
+           break;
+        }
+
+        // now we can mark the page
+	PageSetBad(pfn_to_page(realaddr >> PAGE_SHIFT));
+        count++;
+      } while (badmem_nextaddress(&p));
+   }
+
+   printk ("\n");
+
+   free_badmem_patternset (bps);
+   free_mdfset (mdf);
+
+   return size;
+}
+
+/*
+ * Process the given module - that means: mark the ram pages as bad!
+ */
+unsigned long badmem_processmodule (const int mnum, const ulong thisstart) {
+   struct badmem_modules *module = &badmem_modtab[mnum];
+
+#ifdef CONFIG_BADMEM_DEBUG
+   printk ("called module index %i with starting address %lu which points to %p with a length of %u\n", mnum, thisstart, module->mdfdata, module->mdflen);
+#endif // CONFIG_BADMEM_DEBUG
+
+   return badmem_processmdfram (module->mdfdata, module->mdflen, thisstart);
+}
+
+/*
+ * Input: name of the module
+ * Output: element number of corresponding badmem_modtab field
+ * on errror: returns -1
+ */
+int badmem_modtab_index (const char *name) {
+   register int i = 0;
+   struct badmem_modules *mod = &badmem_modtab[i];
+
+   while (mod->mod_name != NULL) {
+      if (strcmp (mod->mod_name, name) == 0)
+       return i;
+
+      mod = &badmem_modtab[++i];
+   }
+
+   return -1;
+}
+
+
+void mark_absoluteaddresses(void) {
+
+   int idx = badmem_modtab_index ("_absolute");
+
+   if (idx == -1)
+     return;
+
+   badmem_processmodule (idx, 0L);
+
+}
+
+void badmem_markpages(void) {
+   register int i = 0;
+   ulong modstart = 0;
+
+   while (badmem_instmodules[i][0] != 0 && i <= BADMEM_MAXPARAMS) {
+      int modnum = badmem_modtab_index (badmem_instmodules[i]);  // To store the offset in our array
+
+#ifdef CONFIG_BADMEM_DEBUG
+      printk ("BadMEM: module %s has index %i\n", badmem_instmodules[i], modnum);
+#endif
+
+      if (modnum == -1) {
+	 printk ("BADMEM: Doah!! Module %s not configured - check spelling and configuration. Ignoring this module!\n", \
+              badmem_instmodules[i]);
+	 i++;
+	 continue;
+      }
+
+      modstart += badmem_processmodule (modnum, modstart);
+
+      i++;
+   }
+
+   if (absolutemode)
+     mark_absoluteaddresses();
+
+}
+
+#endif /* CONFIG_BADMEM_MODSYSTEM */
+
+__setup("badmem=", badmem_setup);
+
+#endif
+
