This C program illustrate the way to access the physical page using mem_map ptr.

http://www.cs.usfca.edu/~cruse/cs635f07/dram.c

//-------------------------------------------------------------------
//	dram.c
//
//	This module implements a Linux character-mode device-driver
//	for the processor's installed physical memory.  It utilizes
//	the kernel's 'kmap()' function, as a uniform way to provide  
//	access to all the memory-zones (including the "high memory"
//	on systems with more than 896MB of installed physical ram). 
//	The access here is 'read-only' because we deem it too risky 
//	to the stable functioning of our system to allow every user
//	the unrestricted ability to arbitrarily modify memory-areas
//	which might contain some "critical" kernel data-structures.
//	We implement an 'llseek()' method so that users can readily 
//	find out how much physical processor-memory is installed. 
//
//	NOTE: Developed and tested with Linux kernel version 2.6.10
//
//	programmer: ALLAN CRUSE
//	written on: 30 JAN 2005
//	revised on: 28 JAN 2008 -- for Linux kernel version 2.6.22.5
//	revised on: 06 FEB 2008 -- for machines having 4GB of memory
//-------------------------------------------------------------------

#include <linux/module.h>	// for module_init() 
#include <linux/highmem.h>	// for kmap(), kunmap()
#include <asm/uaccess.h>	// for copy_to_user() 

char modname[] = "dram";	// for displaying driver's name
int my_major = 85;		// note static major assignment 
loff_t 	dram_size;		// total bytes of system memory

loff_t my_llseek( struct file *file, loff_t offset, int whence );
ssize_t my_read( struct file *file, char *buf, size_t count, loff_t *pos );

struct file_operations 
my_fops =	{
		owner:		THIS_MODULE,
		llseek:		my_llseek,
		read:		my_read,
		};

static int __init dram_init( void )
{
	printk( "<1>\nInstalling \'%s\' module ", modname );
	printk( "(major=%d)\n", my_major );
	
	dram_size = (loff_t)num_physpages << PAGE_SHIFT;
	printk( "<1>  ramtop=%08llX (%llu MB)\n", dram_size, dram_size >> 20 );
	return 	register_chrdev( my_major, modname, &my_fops );
}

static void __exit dram_exit( void )
{
	unregister_chrdev( my_major, modname );
	printk( "<1>Removing \'%s\' module\n", modname );
}

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-file
	if ( *pos >= dram_size ) 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;
}

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 = dram_size + offset; break; 	// SEEK_END
		}

	if (( newpos < 0 )||( newpos > dram_size )) return -EINVAL;
	file->f_pos = newpos;
	return	newpos;
}

MODULE_LICENSE("GPL");
module_init( dram_init );
module_exit( dram_exit );


Reply via email to