概述
通过设置页表和对应的页表项,可建立虚拟内存地址和物理内存地址的对应关系。其中的
get_pte函数是设置页表项环节中的一个重要步骤。此函数找到一个虚地址对应的二级页表项 的内核虚地址,如果此二级页表项不存在,则分配一个包含此项的二级页表。本练习需要补全
kern/mm/pmm.c文件中的get_pte函数,实现其功能。请仔细查看和理解get_pte函数中的注释。
函数原型如下:
 |  | 
我们先来翻译一下这个函数的注释:
函数 get_pte 的相关注释:
- 作用:通过页目录项和逻辑地址,取得对应的页表;如果页表不存在则会分配这个页表;
 - 参数:
pgdir:页目录项;la:逻辑地址;create:是否创建新的页表; - 返回值:内核对应页表的虚拟地址。
 
在对应的头文件 pmm.h 与 mmu.h 中,定义了一些你可能会用到宏和函数:
PDX(la):通过一个进程的虚拟逻辑地址,求得一个页目录项的索引;PTX(la):通过一个进程的虚拟逻辑地址,求得一个页表项的索引;KADDR(pa):通过一个物理地址,返回一个对应的内核虚拟地址;set_page_ref(page, 1):将页的引用计数加一;page2pa(page):通过一个页表项,得到它实际的物理地址;struct Page * alloc_page():分配一个内存页;memset(void *s, char c, size_t n):将指针s之后的n个区域的内容设置为c;PTE_P:存在;PTE_W:写;PTE_U:读。
问题一
请描述页目录项 (Page Directory Entry) 和页表 (Page Table Entry) 中每个组成部分的含义和以及对 ucore 而言的潜在用处。
因为页目录项、页表、物理地址对应的起始地址都要求按照 4096 比特对齐。因此:
页目录项的高 20 位用于存储页表的实际物理地址;
页表项的高 20 位用于存储虚拟地址对应的真实物理地址;
页目录项和页表项的低 12 位都用于存储一些标志位,详细的内容列举在了
./kern/mm/mmu.h这个文件中。
问题二
如果 ucore 执行过程中访问内存,出现了页访问异常,请问硬件要做哪些事情?
进行换页操作:
- 首先 CPU 将产生页访问异常的线性地址放到 cr2 寄存器中
 - 然后就是和普通的中断一样保护现场,将寄存器的值压入栈中,然后压入 
error_code中断服务例程将外存的数据换到内存中来 - 最后退出中断,回到进入中断前的状态