//------------------------------------------------------------------- // dram.c // // This module uses the 'kmap()' function to provide access to // all the installed physical memory (includes "high memory"). // Access here is 'read-only' because we deem it too hazardous // to proper system functioning let users arbitrary modify the // various parts of physical memory (which includes "critical" // kernel data structures). We implement an 'llseek()' method // so users can find out how much physical ram is installed. // // NOTE: Developed and tested with Linux kernel version 2.4.18 // // programmer: ALLAN CRUSE // written on: 26 FEB 2003 // revised on: 23 APR 2003 //------------------------------------------------------------------- #define __KERNEL__ #define MODULE #include // for init_module() #include // for copy_to_user() #include // for num_physpages #include // for kmap(), kunmap() #include #define SUCCESS 0 static char modname[] = "dram"; static int my_major = 253; // note static major assignment static unsigned long ramtop; static ssize_t my_read( struct file *file, char *buf, size_t count, loff_t *pos ) { struct page *pp; void *from; int page_number, page_indent, more; // we cannot read beyond the end-of-ram if ( *pos >= ramtop ) return 0; // determine which physical page to temporarily map // and how far into that page to begin reading from page_number = *pos / PAGE_SIZE; page_indent = *pos % PAGE_SIZE; // map the designated physical page into kernel space pp = &mem_map[ page_number ]; from = kmap( pp ) + page_indent; // cannot reliably read beyond the end of this mapped page if ( page_indent + count > PAGE_SIZE ) count = PAGE_SIZE - page_indent; // now transfer count bytes from mapped page to user-supplied buffer more = copy_to_user( buf, from, count ); // ok now to discard the temporary page mapping kunmap( pp ); // an error occurred if less than count bytes got copied if ( more ) return -EFAULT; // otherwise advance file-pointer and report number of bytes read *pos += count; return count; } static loff_t my_llseek( struct file *file, loff_t offset, int whence ) { loff_t newpos = -1; switch( whence ) { case 0: newpos = offset; break; // SEEK_SET case 1: newpos = file->f_pos + offset; break; // SEEK_CUR case 2: newpos = ramtop + offset; break; // SEEK_END } if (( newpos < 0 )||( newpos > ramtop )) return -EINVAL; file->f_pos = newpos; return newpos; } static struct file_operations my_fops = { owner: THIS_MODULE, llseek: my_llseek, read: my_read, }; int init_module( void ) { printk( "<1>\nInstalling \'%s\' module ", modname ); printk( "(major=%d)\n", my_major ); ramtop = num_physpages * PAGE_SIZE; printk( "<1> ramtop=%08X (%d MB)\n", ramtop, ramtop >> 20 ); return register_chrdev( my_major, modname, &my_fops ); } void cleanup_module( void ) { unregister_chrdev( my_major, modname ); printk( "<1>Removing \'%s\' module\n", modname ); } MODULE_LICENSE("GPL");