用户态的程序都是在内存保护模式下使用内存,无法直接访问物理内存。同时用户程序使用的地址,也并不是物理地址,而是逻辑地址。至于这些逻辑地址对应的物理内存在哪里,用户进程本身并不知道。
通过用户程序若想访问物理内存,我们需要通过内核才能实现。本文介绍基于内核模块的方式,实现在Linux中用户态程序访问所有物理内存。
1、内核模块编写
通过文件读写的方式,实现物理地址访问。将物理地址,作为参数pos传递。
ssize_t my_read( struct file *file, char *buf, size_t count, loff_t *pos )
在内核代码中,是无法直接访问物理地址的,代码能访问的都是逻辑地址。此时我们需要先将物理地址转换成逻辑地址,才能在代码中对地址读写。
物理地址转换成逻辑地址方法:
1)根据物理地址,计算出对应的页面号和页内偏移
page_number = *pos / PAGE_SIZE;
page_indent = *pos % PAGE_SIZE;
2)将页面号找到对应的页面指针
注意在2.6.32及以上内核中,没有导出mem_map符号,只能通过
pfn_to_page()来找到对应的页面指针。
#if 0
pp = pfn_to_page( page_number);
#else
pp = &mem_map[ page_number ];
#endif
3)通过kmap映射成逻辑地址
from = kmap( pp ) + page_indent;
映射成逻辑地址后,我们直接通过from指针来访问物理地址pos了。
2、模块加载和使用方式
1)编译模块
[root@localhost Access_Physical_Memory]# ls
dram.c fileview.cpp Makefile
[root@localhost Access_Physical_Memory]# make
2)加载模块
[root@localhost Access_Physical_Memory]# insmod dram.ko
3)创建字符设备
模块代码中,将字符设备号设为85。这个设备号也可以自己改,与系统不冲突就行。
[root@localhost Access_Physical_Memory]# mknod /dev/dram c 85 0
[root@localhost Access_Physical_Memory]#
3、物理内存数据查看
我们使用简单的程序fileview来看物理内存中的实际数据,物理地址可以手工输入的。
点击下载:内核模块和fileview源码
源码主要参考来源:http://cs.usfca.edu/~cruse/cs635/