update xv6的页表.md

This commit is contained in:
shzhxh 2020-01-21 17:04:03 +08:00
parent 498a4b5ca3
commit 0add865b54
2 changed files with 33 additions and 0 deletions

View File

@ -16,8 +16,39 @@ PTE有10位的flag可以在kernel/riscv.h看到xv6对于它们的定义。`PT
#### 内核地址空间
内核有自己的页表。当进程进入内核xv6切换到内核页表当从内核返回用户空间又切换到用户进程的页表。内核的内存是私有的。
文件kernel/memlayout.h描述了内核内存的布局。
QEMU模拟了一个包含I/O设备的计算机。设备的控制寄存器被映射在物理内存0~0x80000000之间。内核通过读写那些内存与设备交互。
内核的大部分虚拟地址都使用的是恒等映射。对于即需要读写虚拟页又需要通过PTE管理物理页的内核来说这样的直接映射降低了复杂性。只有两处虚拟地址不是直接映射的
- trampoline页。它被映射在虚拟空间的顶端它也被用户页表映射在用户空间的同样位置。它被内核虚拟地址空间映射了两次一次是直接映射一次是虚拟空间的顶端。
- 内核栈所在的页。每个进程都有自己的内核栈它被映射在高位这样在它下面xv6可以保留一个未映射的守护页(guard page)。守护页的PTE是无效的这就确保了即使内核让内核栈溢出也仅仅是触发一个错误让内核panic。如果没有守护页栈溢出将导致执行不正确的指令。与其这样让内核panic是个更好的选择。
把内核栈和守护页直接映射不可取,因为守护页所对应的物理地址将难以被使用。
对于内核的trampoline页和代码页使用的权限是`PTE_R`和`PTE_X`,因为内核要从那些页里读取和执行指令。对于其它页则使用`PTE_R`和`PTE_W`,因为内核要从那些页里读写内存。对于保护页,则要将其设置为无效的。
#### 创建地址空间
管理地址空间和页表的代码主要在kernel/vm.c。核心数据结构是`pagetable_t`它是RISC-V根页表页的指针它要么是内核的页表要么是某个进程的页表。核心函数是`walk`它用来查找一个虚拟地址的PTE或者用来查找`mappages``mappages`用来为新的映射安装PTE。以`kvm`开头的函数用来管理内核页表,以`uvm`开头的函数则用来管理用户页表,其它函数即可以管理内核页表也可以管理用户页表。`copyout`用来把数据复制到用户虚拟地址(由系统调用的参数提供)`copyin`则是进行相反方向的复制它们都定义在vm.c里因为它们需要严格地转换这些地址以找到对应的物理地址。
在启动的早期,`main`函数调用了`kvminit`函数来创建内核的页表。此时还没有开启分页,使用的是物理地址。`kvminit`首先分配了一个物理页用以保存根页表页。然后调用`kvmmap`来保存内核所需的转换。这些转换包括了内核的指令和数据,至到`PHYSTOP`的物理内存,和实际设备的内存范围。
`kvmmap`调用`mappages`来把映射关系保存到页表里。对于每个要映射的虚拟地址,`mappages`通过`walk`来找到对应PTE的地址。然后初始化PTE来保存相关的物理页号所需的权限(RXV或RWV两种组合)。
`walk`在查找虚拟地址的PTE的时候模仿了分页硬件(paging hardware)。它是三级页表逐层查找。如果查到的PTE无效说明所需的页不存在如果参数`alloc`设置为1`walk`会分配新的页表页并把它的物理地址放在PTE里。最终返回的是第三级的PTE的地址。
如上代码依赖于物理地址和虚拟地址的直接映射。
`main`调用`kvminithart`来使内核页表生效。它把根页表页的物理地址保存在satp寄存器里。然后CPU就要开始地址转换了。由于内核使用了一致性映射当前虚拟地址的下一条指令将会映射在正确的物理地址上。
每个进程都会分配到一个内核栈。宏`KSTACK`用以生成每个内核栈的虚拟地址,它还为栈保护页(stack-guard pages)预留了空间。`kvmmap`把PTE加到内核页表里`kvminithart`重载satp寄存器这样硬件才能识别新的PTE。
每个RISC-V核都把页表缓存在TLB里。指令`sfence.vma`用以刷新当前核的TLB以使新的页表生效。
#### 物理内存分配
#### 物理内存分配器

View File

@ -77,6 +77,8 @@ n # 住所窗口编号向后切换
```
" # 将面板分为上下两块
% # 将面板分为左右两块
空格 # 对所有的面板重新布局
z # 最大化当前面板
x # 关闭当前面板
o # 切换面板