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