diff -uNr linux-2.6.8-vanilla/CREDITS linux-2.6.8/CREDITS --- linux-2.6.8-vanilla/CREDITS Sun Feb 12 21:46:48 2006 +++ linux-2.6.8/CREDITS Tue Feb 14 18:02:26 2006 @@ -2661,6 +2661,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/ @@ -2887,6 +2895,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.8-vanilla/Documentation/badmem.txt linux-2.6.8/Documentation/badmem.txt --- linux-2.6.8-vanilla/Documentation/badmem.txt Thu Jan 1 01:00:00 1970 +++ linux-2.6.8/Documentation/badmem.txt Tue Feb 14 18:02:26 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, 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.8-vanilla/Documentation/badmem_conf.txt linux-2.6.8/Documentation/badmem_conf.txt --- linux-2.6.8-vanilla/Documentation/badmem_conf.txt Thu Jan 1 01:00:00 1970 +++ linux-2.6.8/Documentation/badmem_conf.txt Tue Feb 14 18:02:26 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 + +Declares to define a new module with the name . 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 + +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 + +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 + +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 , 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: , + +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 +. This parameter is therefore not optional. + +Note: You may define as many , 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 + , http://badmem.sourceforge.net + Last update: 2004/03/15 diff -uNr linux-2.6.8-vanilla/Documentation/kernel-parameters.txt linux-2.6.8/Documentation/kernel-parameters.txt --- linux-2.6.8-vanilla/Documentation/kernel-parameters.txt Sun Feb 12 21:46:48 2006 +++ linux-2.6.8/Documentation/kernel-parameters.txt Tue Feb 14 18:02:26 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. @@ -225,6 +226,11 @@ aztcd= [HW,CD] Aztech CD268 CDROM driver Format: ,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: , diff -uNr linux-2.6.8-vanilla/Documentation/memory.txt linux-2.6.8/Documentation/memory.txt --- linux-2.6.8-vanilla/Documentation/memory.txt Fri Jan 9 08:00:13 2004 +++ linux-2.6.8/Documentation/memory.txt Tue Feb 14 18:02:26 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.8-vanilla/arch/i386/Kconfig linux-2.6.8/arch/i386/Kconfig --- linux-2.6.8-vanilla/arch/i386/Kconfig Sun Feb 12 21:46:49 2006 +++ linux-2.6.8/arch/i386/Kconfig Tue Feb 14 18:02:26 2006 @@ -867,6 +867,7 @@ endmenu +source "mm/Kconfig" menu "Power management options (ACPI, APM)" depends on !X86_VOYAGER diff -uNr linux-2.6.8-vanilla/arch/i386/defconfig linux-2.6.8/arch/i386/defconfig --- linux-2.6.8-vanilla/arch/i386/defconfig Sun Feb 12 21:46:49 2006 +++ linux-2.6.8/arch/i386/defconfig Tue Feb 14 18:02:26 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.8-vanilla/arch/i386/mm/init.c linux-2.6.8/arch/i386/mm/init.c --- linux-2.6.8-vanilla/arch/i386/mm/init.c Sun Feb 12 21:46:49 2006 +++ linux-2.6.8/arch/i386/mm/init.c Tue Feb 14 18:02:26 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 @@ -40,6 +41,10 @@ #include #include +#ifdef CONFIG_BADMEM +# include +#endif // CONFIG_BADMEM + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long highstart_pfn, highend_pfn; @@ -561,6 +566,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); @@ -568,6 +598,10 @@ int tmp; int bad_ppro; +#ifdef CONFIG_BADMEM + int badpages; +#endif + #ifndef CONFIG_DISCONTIGMEM if (!mem_map) BUG(); @@ -596,6 +630,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++) /* @@ -606,6 +644,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; @@ -613,15 +655,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.8-vanilla/include/linux/badmem.h linux-2.6.8/include/linux/badmem.h --- linux-2.6.8-vanilla/include/linux/badmem.h Thu Jan 1 01:00:00 1970 +++ linux-2.6.8/include/linux/badmem.h Tue Feb 14 18:02:26 2006 @@ -0,0 +1,42 @@ +#ifndef __LINUX_BADMEM_H +#define __LINUX_BADMEM_H + +#include +#include + +#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.8-vanilla/include/linux/page-flags.h linux-2.6.8/include/linux/page-flags.h --- linux-2.6.8-vanilla/include/linux/page-flags.h Sun Feb 12 21:47:16 2006 +++ linux-2.6.8/include/linux/page-flags.h Tue Feb 14 18:02:26 2006 @@ -78,6 +78,7 @@ #define PG_anon 20 /* Anonymous: anon_vma in mapping */ +#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 @@ -303,6 +304,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.8-vanilla/mm/Kconfig linux-2.6.8/mm/Kconfig --- linux-2.6.8-vanilla/mm/Kconfig Thu Jan 1 01:00:00 1970 +++ linux-2.6.8/mm/Kconfig Tue Feb 14 18:02:26 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.8-vanilla/mm/Makefile linux-2.6.8/mm/Makefile --- linux-2.6.8-vanilla/mm/Makefile Sun Feb 12 21:41:23 2006 +++ linux-2.6.8/mm/Makefile Tue Feb 14 18:02:26 2006 @@ -15,3 +15,71 @@ obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.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.8-vanilla/mm/badmem_proc.c linux-2.6.8/mm/badmem_proc.c --- linux-2.6.8-vanilla/mm/badmem_proc.c Thu Jan 1 01:00:00 1970 +++ linux-2.6.8/mm/badmem_proc.c Tue Feb 14 18:02:26 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 +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_BADMEM_MODSYSTEM +#include +#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= 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 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.8-vanilla/mm/badmemlib_version.c linux-2.6.8/mm/badmemlib_version.c --- linux-2.6.8-vanilla/mm/badmemlib_version.c Thu Jan 1 01:00:00 1970 +++ linux-2.6.8/mm/badmemlib_version.c Tue Feb 14 18:02:26 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.8-vanilla/mm/modparse.c linux-2.6.8/mm/modparse.c --- linux-2.6.8-vanilla/mm/modparse.c Thu Jan 1 01:00:00 1970 +++ linux-2.6.8/mm/modparse.c Tue Feb 14 18:02:26 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 +#include +#include +#include +#include + +#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 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\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; iused_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.8-vanilla/mm/page_alloc.c linux-2.6.8/mm/page_alloc.c --- linux-2.6.8-vanilla/mm/page_alloc.c Sun Feb 12 21:47:17 2006 +++ linux-2.6.8/mm/page_alloc.c Tue Feb 14 18:02:26 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 @@ -34,6 +35,12 @@ #include +#ifdef CONFIG_BADMEM +# include +# include +# include +#endif // CONFIG_BADMEM + DECLARE_BITMAP(node_online_map, MAX_NUMNODES); struct pglist_data *pgdat_list; unsigned long totalram_pages; @@ -789,6 +796,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); @@ -2041,3 +2053,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 (;iused_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 +