update xv6的页表.md
This commit is contained in:
parent
498a4b5ca3
commit
0add865b54
|
@ -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以使新的页表生效。
|
||||
|
||||
#### 物理内存分配
|
||||
|
||||
#### 物理内存分配器
|
||||
|
|
|
@ -77,6 +77,8 @@ n # 住所窗口编号向后切换
|
|||
```
|
||||
" # 将面板分为上下两块
|
||||
% # 将面板分为左右两块
|
||||
空格 # 对所有的面板重新布局
|
||||
z # 最大化当前面板
|
||||
x # 关闭当前面板
|
||||
!
|
||||
o # 切换面板
|
||||
|
|
Loading…
Reference in New Issue