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
二、/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
只有在.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