练习0
填写已有实验
本实验依赖实验1和实验2.请把要做的实验1的代码填入本实验中代码有lab1、lab2的注释相应部分
首先利用meld工具比较两个文件的差异
发现缺失的是kdebug.c、trap.c、default_pmm.c、pmm.c
四个文件的相关代码,补全后进行下一练习
练习1
给未被映射的地址映射上物理页(需要编程)
完成do_pgfault(mm/vmm.c)
函数,给未被映射的地址映射上物理页。设置访问权限的时候需要参考页面所在VMA的权限,同时需要注意映射物理页时需要操作内存控制结构所制定的页表,而不是内核的页表。
原理分析
在程序的执行过程中由于某种原因(页框不存在/写只读页等)而是CPU无法最终访问到相应的物理内存单元,即无法完成从虚拟地址到物理地址的映射是,CPU会产生一次页错误异常,从而需要进行相应的页错误异常服务例程。当相关处理完成后,将返回产生异常的指令处重新执行,使得软件正常运行。
产生页面异常的只要原因如下:
- 目标页面不存在(页表项全为0,即该线性地址与物理地址尚未建立映射或者已经撤销);
- 相应的物理页面不在内存中(页表项非空,但Present标志位=0,比如在swap分区或磁盘文件上)
- 访问权限不符合(此时页表项P标志=1,比如企图写只读页面).
当出现上面情况之一,就会产生页面page fault(#PF)
异常。产生异常的线性地址存储在
CR2中,并且将是page fault
的产生类型保存在 error code
中
因此此函数是完成页错误异常处理的主要函数,他根据从CPU的控制寄存器CR2中获取的页错误异常的虚拟地址,以及根据error code的错误类型来查找次虚拟地址是否在某个VMA的地址范围内,并且是否满足正确的读写权限,如果在此范围内并且权限也正确,就认为这是一次合法访问,但没有建立虚实对应关系,所以需要分配一个空闲的内存页,并修改页表完成虚地址到物理地址的映射,刷新TLB,然后调用iret中断,返回并重新执行。如果该虚地址不在某VMA范围内,这认为是一个非法访问
这里把vma_struct结构的变量简称为VMA变量。
vma_struct
struct vma_struct {
// the set of vma using the same PDT
struct mm_struct *vm_mm;
uintptr_t vm_start; // start addr of vma
uintptr_t vm_end; // end addr of vma
uint32_t vm_flags; // flags of vma
//linear list link which sorted by start addr of vma
list_entry_t list_link;
};
vm_start
和vm_end
描述了一个连续地址的虚拟内存空间的起始位置和结束位置,描述的是一个合理的地址空间范围(即严格确保 vm_start < vm_end的关系);list_link
是一个双向链表,按照从小到大的顺序把一系列用vma_struct
表示的虚拟内存空间链接起来,并且还要求这些链起来的vma_struct
应该是不相交的,即vma之间的地址空间无交集;vm_flags
表示了这