Index: vanilla.2/CREDITS --- vanilla.2/CREDITS Tue, 20 Jan 2004 11:47:40 +0100 admin (linux/0_CREDITS 1.2 644) +++ memmap.3/CREDITS Tue, 20 Jan 2004 15:02:40 +0100 admin (linux/0_CREDITS 1.3 644) @@ -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 Index: vanilla.2/init/Kconfig --- vanilla.2/init/Kconfig Tue, 20 Jan 2004 11:47:40 +0100 admin (linux/y/d/40_Kconfig 1.2 644) +++ memmap.3/init/Kconfig Tue, 20 Jan 2004 16:58:24 +0100 admin (linux/y/d/40_Kconfig 1.3 644) @@ -162,6 +162,29 @@ This option enables access to kernel configuration file and build information through /proc/config.gz. +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/ menuconfig EMBEDDED bool "Remove kernel features (for embedded systems)" Index: vanilla.2/arch/i386/defconfig --- vanilla.2/arch/i386/defconfig Tue, 20 Jan 2004 11:31:23 +0100 admin (linux/s/e/4_defconfig 1.1 644) +++ memmap.3/arch/i386/defconfig Tue, 20 Jan 2004 15:02:40 +0100 admin (linux/s/e/4_defconfig 1.2 644) @@ -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 Index: vanilla.2/mm/page_alloc.c --- vanilla.2/mm/page_alloc.c Tue, 20 Jan 2004 11:47:40 +0100 admin (linux/j/f/26_page_alloc 1.2 644) +++ memmap.3/mm/page_alloc.c Tue, 20 Jan 2004 15:02:40 +0100 admin (linux/j/f/26_page_alloc 1.3 644) @@ -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 Index: vanilla.2/mm/Makefile --- vanilla.2/mm/Makefile Tue, 20 Jan 2004 11:31:23 +0100 admin (linux/j/f/39_Makefile 1.1 644) +++ memmap.3/mm/Makefile Tue, 20 Jan 2004 15:02:40 +0100 admin (linux/j/f/39_Makefile 1.2 644) @@ -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 Index: vanilla.2/Documentation/vm/memmap --- vanilla.2/Documentation/vm/memmap Tue, 20 Jan 2004 21:57:47 +0100 admin () +++ memmap.3/Documentation/vm/memmap Tue, 20 Jan 2004 15:02:40 +0100 admin (linux/E/f/1_memmap 1.1 644) @@ -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. Index: vanilla.2/mm/proc_memmap.c --- vanilla.2/mm/proc_memmap.c Tue, 20 Jan 2004 21:57:47 +0100 admin () +++ memmap.3/mm/proc_memmap.c Tue, 20 Jan 2004 16:32:18 +0100 admin (linux/E/f/2_proc_memma 1.2 644) @@ -0,0 +1,290 @@ +/* + * 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 + * + * - ported to 2.6 + * - made compatible with DISCONTIG_MEM (still supports only one node) + * + * + * KNOWN BUGS: + * + * - multi-node not supported yet: only reports node0 + * - probably needs some locking to ensure consistency of the snapshot + * - most likely do not support memory holes (see present_pages) + * + * problems with disabled write support: + * - changing nchars to 0 causes div-by-zero + * - buffer overflow when rows*col too large + * + */ + +#include + +MODULE_DESCRIPTION("Memory map in /proc/memmap"); +MODULE_AUTHOR("Nico Schmoigl, Yann Dirson"); +MODULE_LICENSE("GPL"); + +#include +#include +#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 { + struct zone *zone; + int maxlines, maxchars; +} memmap_data_t; + +static memmap_data_t *private; + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)) +# define ZONE_SIZEFIELD size +#else +# define ZONE_SIZEFIELD present_pages +#endif + +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->zone->ZONE_SIZEFIELD / (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->zone->zone_mem_map, + data->zone->zone_mem_map + data->zone->ZONE_SIZEFIELD - 1); + totallen += len; + dat += len; + + for (j = 0; (j < data->maxlines) && (offset < data->zone->ZONE_SIZEFIELD); j++) { + int thislineoffset = offset; + for (k = 0; (k < data->maxchars) && (offset < data->zone->ZONE_SIZEFIELD); k++, offset += dotconst) { + char dot = '.'; + + for (i = offset; (i < dotconst+offset) && (i < data->zone->ZONE_SIZEFIELD); i++) { + + if (dot == 'B') continue; +#ifdef CONFIG_BADMEM + if (PageBad(data->zone->zone_mem_map+i)) { + dot = 'B'; + continue; + } +#endif /* CONFIG_BADMEM */ + + if (dot == 'R') continue; + if (PageReserved(data->zone->zone_mem_map+i)) { + dot = 'R'; + continue; + } + + if (dot == '*') continue; + + if (atomic_read(&data->zone->zone_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 + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)) +# define ZONE_SIZEFIELD size +#else +# define ZONE_SIZEFIELD present_pages +#endif + +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].maxlines = 30; + private[zone].maxchars = 116; + + pde->data = &private[zone]; + + printk (KERN_INFO "proc_memmap: loaded node0 zone %d\n", zone); + } + + + 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);