假设现在有个有个驱动,有一段内存叫做sh_mem。当用户打开这个文件并mmap。mmap要做什么,当然是建立用户态的地址与此驱动建立对应关系。我知道的有两种:
1. 我们给用户提供一个方法,如果你要用这个内存时才会映射。这就是请页机制。
2. 我们一次映射好。
这篇文章,我们先讲第一种,实验:arm平台linux-3.2.36
如果你只想看看nopage使用方法,就直接倒下面代码去。中间就不要看了,也没什么。
普通进程的地址空间定义:允许进程使用的全部线性地址组成。
内核可以通过增加或删除某些线性地址区间来动态地修改进程的地址空间。
普通进程获得新线性区的可能:
1. 创建新进程执行一个程序。这就是新地址空间+新进程。
2. 正在运行的进程装入不同的程序(如用exec函数),这个相当上面就是新地址空间+旧进程。
3. 对一个文件执行“内存映射”。内核给这个进程分配新线性区来映射这个文件。这对于我们搞驱动来说,主要就是mmap()。这个“内存映射”是我们的重点。
4. 进程可能持续向它的用户态堆栈增加数据,直到映射这个堆栈的线性区用完为止。这时内核也许会决定扩展这个线性区的大小。
5. 在我学习Linux高级编程中,进程间通信中说到一种共享内存区的东西,这个也需要分配新内存。
6. malloc分配。进程可能扩展自己的动态区(堆),内核可能确定扩展给这个堆所分配的线性区。
上面有些内核提供了系统调用方法。
普通进程地址空间信息包含在一个叫做内存描述符的结构的类型为struct mm_struct.网上有很多它的资料。它包涵一个struct vm_area_struct列表,一个struct vm_area_struct代表一个VMA,可以把structvm_area_struct叫做线性区描述符。structvm_area_struct包涵一个
const struct vm_operations_struct *vm_ops;这个是此线性区的操作方法。有个no_page方法:
在2.6.23之前structvm_operations_struct中只有
struct page * (*nopage)(struct vm_area_struct * area,unsigned long address, int *type)
从2.6.24后在structvm_operations_struct中的出现
int (*fault)(struct vm_area_struct *vma, structvm_fault *vmf)
并在一段时间里,内核同时支持这两个函数,但后面的内核版本取消了
struct page * (*nopage)(struct vm_area_struct * area,unsigned long address, int *type)
我的linux-3.2.36就取消了。 缺页也很我要弄明白的东西。
现在是fualt,struct vm_fault如下:
struct vm_fault {
unsigned intflags; /* FAULT_FLAG_xxxflags */
pgoff_t pgoff; /* Logical page offset b