http://blog.sina.com.cn/s/blog_6f5b220601012xbc.html
- 内核(驱动)里_get_fre_pages()申请物理页面,返回物理首地址X,
- 用户空间mmap文件/dem/mem的偏移X处到自己进程空间,对其操作
- /dev/mem是系统物理内存镜像文件,文件偏移X即内存的偏移X
- 2.内核(驱动)向设备文件比如/dev/video1写一定格式的数据
- 用户空间mmap文件/dev/video1到进程空间,去读写
一、mmap简介
对于mmap网络上有很多介绍的资料,我主要用来将物理地址映射到user space的虚拟地址,这样tool才能
读取到正确的data。
关于mmap的详细介绍可以直接用命令:man mmap看到。下面给出一个网络链接:
http://hi.baidu.com/yoursguang/blog/item/81f77f387720022296ddd814.html
二、/dev/mem简介
其实以前访问PCI device的MMIO space也是通过打开设备/dev/mem,然后通过mmap映射到user space就
可以直接访问。
这里的/dev/mem是整个物理地址空间的映射,之所以是物理地址空间而不是物理内存后面会说明。
访问物理地址的方式如下:
int fd = open("/dev/mem", O_RDWR); //打开设备
//通过mmap映射物理地址到user space的虚拟地址
virt_addr = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, physical_addr);
if (virt_addr == MAP_FAILED) {
//打印出错信息
}
如果mmap出错,那么virt_addr返回(void *) -1,否则就返回映射到的地址。
由于/dev/mem映射的是物理地址空间,所以start设置为NULL,这样offset就可以直接设置成物理地址。
题外话:前面说过访问PCI device的MMIO space也可以通过这种方式访问,但是MMIO register不是在内存条上,
而是在PCI device上面,但是由于这些register和内存一样是统一编址,所以最后的物理地址空间是内存条加上
各个device的映射到内存地址空间的部分,所以在32-bit操作系统下,也有可能申请到大于4G的地址。
三、问题
在driver中通过alloc_pages申请得到的page,将page的物理地址export到user space,但是user space拿到这个
物理地址后并不能mmap成功。通过perror(“mmap”),发现总是返回错误"Operation not permitted!",后来发现是
由于kernel对user space访问/dev/mem是有限制的,通过编译选项:CONFIG_STRICT_DEVMEM来限制user space
对物理内存的访问,这个选项的说明在arch/x86/Kconfig.debug中有说明:
config STRICT_DEVMEM
bool "Filter access to /dev/mem"
---help---
If this option is disabled, you allow userspace (root) access to all
of memory, including kernel and userspace memory. Accidental
access to this is obviously disastrous, but specific access can
be used by people debugging the kernel. Note that with PAT support
enabled, even in this case there are restrictions on /dev/mem
use due to the cache aliasing requirements.
If this option is switched on, the /dev/mem file only allows
userspace access to PCI space and the BIOS code and data regions.
This is sufficient for dosemu and X and all common users of
/dev/mem.
If in doubt, say Y.
只有在.config文件中设置CONFIG_STRICT_DEVMEM=n才能获得对整个memory的访问权限,在默认情况下,
CONFIG_STRICT_DEVMEM=y,这也就是之前mmap总是报错:“Operation not permitted”的原因。
设置这个选项后,编译kernel,然后运行tool,mmap还是返回错误:“Invalid argument”。后来查到还需要设置
编译选项CONFIG_X86_PAT=n,这个选项也是默认开启的,但是要关闭这个选项还需要开启CONFIG_EXPERT,
否则CONFIG_X86_PAT总是关不掉。
设置好这三个编译选项后,重新编译kernel,然后运行tool,发现kernel已经解除了对mmap的访问限制,可以
正确读取对应物理地址的内容了。
最后还可以通过修改内核源代码来实现,具体的源文件时在/drivers/char/目录下的mem.c文件
static inline int range_is_allowed(unsigned long pfn, unsigned long size);