2.CH-3文档学习笔记

CH-3 页表

0、页表简介

  • 每个进程都有一个页表
  • 用于隔离不同进程的地址空间
  • 为每个进程提供私有的地址空间
  • 决定了进程能访问哪些地址
  • 复用物理内存,把同一物理页映射到几个页表中

1. 分页硬件

image-20220921014023506
  • 内存的实际地址是物理地址
  • 用户指令访问的是虚拟地址
  • 需要通过页表,将虚拟地址翻译为物理地址,才能访问
  • 在运行时,内核会讲页表加载到内存中,方便快速访问
  • 将一级页表的物理地址写入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 内核地址空间

image-20220921022817320
  • 每个进程都有一个独立的页表,描述进程的地址空间
  • 内核也有一个独立的页表,由内核自行配置地址空间的布局,使其能够通过虚拟地址访问物理内存和各种硬件资源。图3.3显示了内核页表和物理地址的关系
  • QEMU模拟的计算机,物理地址从0x80000000开始,持续到0x88000000,xv6称之为PHYSTOP
  • QEMU还包括I/O设备,如磁盘。QEMU将设备映射到内存供软件使用,这些设备分布在[0:0x80000000]的物理地址中。内核读/写这些物理地址,就可以直接操作设备硬件。
  • 内核通过 "直接映射 "管理RAM以及内存映射的设备;即,将资源映射到与物理地址相等的虚拟地址上。例如,内核所在的虚拟和物理地址都是0x80000000。直接映射简化了读写物理内存的内核代码。例如,当fork为子进程分配用户内存时,分配器会返回新分配的内存的物理地址;之后fork直接使用该物理地址作为虚拟地址将父进程的内存复制到子进程。
  • 内核映射trampoline和内核页面,权限为PTE_RPTE_X。内核可从这些页面读取并执行指令。内核映射其他页面的权限为PTE_RPTE_W,以便可以读取和写入这些页面。内核设置防护页,不映射任何页面,权限为PTE_V为无效。

2.2 用户进程地址空间

image-20220922201251797
  • 每个进程都有一个单独的页表,当切换进程时,页表也会切换。

  • 进程地址空间从0开始,可以增长到MAXVA (kernel/riscv.h:360),最大允许256g的内存。

  • 进程的地址空间由以下部分组成:

    • 包含程序文本的text页(映射的权限为PTE_RPTE_XPTE_U)
    • 包含程序预初始化数据的Data页、Stack页和Heap页。权限为PTE_RPTE_WPTE_U
  • 对不同的页设置不同的权限是加固用户进程的常用技术。

    • text没有PTE_W权限,是为了防止进程修改自己的程序。

      • 不给映射的数据PTE_X权限,用户程序就不会意外地跳转到一个地址,并开始执行。
  • 为防止栈溢出,我们在stack下方,放置一个清除了PTE_U权限的页,当溢出时,会报错。

  • 当进程请求更多内存时,Xv6首先使用kalloc分配物理内存页。之后将页表项添加到进程页表,指向新的物理内存页。为新的页分配PTE_WPTE_RPTE_UPTE_V权限。

  • 内核在所有用户地址空间顶部都映射了一页trampoline(没有设置PTE_U标志),这页只能由内核使用。

三、 相关代码介绍

  • 页表的相关代码位于kernel/vm.c:1
  • kvm开头的函数操作内核页表;uvm开头的函数操作用户页表;其他函数两者共用。
  • copyoutcopyin复制数据到用户虚拟地址或从用户虚拟地址复制数据,作为系统调用参数供使用
  • 代码介绍在代码流程分析文件中

3.1 地址空间初始化

  • kernel\main.c\main()开始初始化

    kinit();         // 初始化物理地址
    kvminit();       // 创建内核页表
    kvminithart();   // 启动页表映射功能
    

kinit() - 初始化物理地址

初始化,从内核代码结束的位置,一直到PHYSTOP,一共128MB的空间,按4KB分块,将其放置到kmem.freelist中,供以后分配使用

kvminit() - 创建内核页表

四、附录

4.1 SATP寄存器简介

SV39 satp寄存器格式:

image-20240201141547721
  • MODE:

    指示SATP的工作模式,当MODE=8时,代表工作在SV39模式,下表是可选值

    image-20240201142537593
  • ASID(address space identifier,地址空间标识符):xv6没用这个值

  • PPN(physical page number,物理页号):保存根页表的物理页号,是物理页号而不是物理地址,所以其中的值是物理地址除以4KB

posted @ 2024-04-21 00:09  INnoVation-V2  阅读(43)  评论(0)    收藏  举报