2.CH-3文档学习笔记
CH-3 页表
0、页表简介
- 每个进程都有一个页表
- 用于隔离不同进程的地址空间
- 为每个进程提供私有的地址空间
- 决定了进程能访问哪些地址
- 复用物理内存,把同一物理页映射到几个页表中
1. 分页硬件
- 内存的实际地址是物理地址
- 用户指令访问的是虚拟地址
- 需要通过页表,将虚拟地址翻译为物理地址,才能访问
- 在运行时,内核会讲页表加载到内存中,方便快速访问
- 将一级页表的物理地址写入
satp寄存器,CPU会使用它翻译虚拟地址。每个CPU都有一个satp,所以不同的CPU可运行不同的进程。 - 编址单位是字节Byte
三级页表
简介
- XV6运行在Sv39 RISC-V上,虚拟地址长64位,
- 高25位不使用,只使用低39位
- 39位中,高27位由3个9位索引组成,分别对应3级页表
- 每一级页表有\(2^9\)个页表项,每一项大小为64bit,所以每个页表大小都为一页:4KB
- 翻译过程中,任一级页表找不到,都会抛出分页错误:
page-fault exception
优点
-
相比单层设计,节省空间
如果程序只使用了从地址0开始的几个页面,那么一级页表中的1到511项的二级页表就暂时不需要创建,更不必创建这些二级页表对应的三级页表。
页表项Flag介绍
相关文件:kernel/riscv.h
PTE_V:页表项是否存在,如果未设置,则对该页的使用会引起异常(即不允许访问)。PTE_R:是否允许指令读取该页。PTE_W:是否允许写入页。PTE_X:CPU是否可以将页的内容解释为指令并执行它们。PTE_U:是否允许用户模式下的指令访问该页,如果未设置PTE_U,则只能在监督者模式下使用。
2、地址空间
2.1 内核地址空间
- 每个进程都有一个独立的页表,描述进程的地址空间
- 内核也有一个独立的页表,由内核自行配置地址空间的布局,使其能够通过虚拟地址访问物理内存和各种硬件资源。
图3.3显示了内核页表和物理地址的关系 - QEMU模拟的计算机,物理地址从
0x80000000开始,持续到0x88000000,xv6称之为PHYSTOP。 - QEMU还包括I/O设备,如磁盘。QEMU将设备映射到内存供软件使用,这些设备分布在
[0:0x80000000]的物理地址中。内核读/写这些物理地址,就可以直接操作设备硬件。 - 内核通过 "直接映射 "管理RAM以及内存映射的设备;即,将资源映射到与物理地址相等的虚拟地址上。例如,内核所在的虚拟和物理地址都是
0x80000000。直接映射简化了读写物理内存的内核代码。例如,当fork为子进程分配用户内存时,分配器会返回新分配的内存的物理地址;之后fork直接使用该物理地址作为虚拟地址将父进程的内存复制到子进程。 - 内核映射
trampoline和内核页面,权限为PTE_R和PTE_X。内核可从这些页面读取并执行指令。内核映射其他页面的权限为PTE_R和PTE_W,以便可以读取和写入这些页面。内核设置防护页,不映射任何页面,权限为PTE_V为无效。
2.2 用户进程地址空间
-
每个进程都有一个单独的页表,当切换进程时,页表也会切换。
-
进程地址空间从0开始,可以增长到
MAXVA(kernel/riscv.h:360),最大允许256g的内存。 -
进程的地址空间由以下部分组成:
- 包含程序文本的text页(映射的权限为
PTE_R、PTE_X和PTE_U) - 包含程序预初始化数据的Data页、Stack页和Heap页。权限为
PTE_R、PTE_W和PTE_U
- 包含程序文本的text页(映射的权限为
-
对不同的页设置不同的权限是加固用户进程的常用技术。
-
text没有
PTE_W权限,是为了防止进程修改自己的程序。- 不给映射的数据
PTE_X权限,用户程序就不会意外地跳转到一个地址,并开始执行。
- 不给映射的数据
-
-
为防止栈溢出,我们在stack下方,放置一个清除了
PTE_U权限的页,当溢出时,会报错。 -
当进程请求更多内存时,Xv6首先使用kalloc分配物理内存页。之后将页表项添加到进程页表,指向新的物理内存页。为新的页分配
PTE_W、PTE_R、PTE_U和PTE_V权限。 -
内核在所有用户地址空间顶部都映射了一页
trampoline(没有设置PTE_U标志),这页只能由内核使用。
三、 相关代码介绍
- 页表的相关代码位于
kernel/vm.c:1。 kvm开头的函数操作内核页表;uvm开头的函数操作用户页表;其他函数两者共用。copyout和copyin复制数据到用户虚拟地址或从用户虚拟地址复制数据,作为系统调用参数供使用- 代码介绍在
代码流程分析文件中
3.1 地址空间初始化
-
从
kernel\main.c\main()开始初始化kinit(); // 初始化物理地址 kvminit(); // 创建内核页表 kvminithart(); // 启动页表映射功能
kinit() - 初始化物理地址
初始化,从内核代码结束的位置,一直到PHYSTOP,一共128MB的空间,按4KB分块,将其放置到kmem.freelist中,供以后分配使用
kvminit() - 创建内核页表
四、附录
4.1 SATP寄存器简介
SV39 satp寄存器格式:
-
MODE:
指示SATP的工作模式,当MODE=8时,代表工作在SV39模式,下表是可选值
-
ASID(address space identifier,地址空间标识符):xv6没用这个值
-
PPN(physical page number,物理页号):保存根页表的
物理页号,是物理页号而不是物理地址,所以其中的值是物理地址除以4KB

浙公网安备 33010602011771号