图片无法显示,请右键点击新窗口打开图片

BiscuitOS 内存管理之分页大专题订阅入口

在 Linux 内核中,一个虚拟地址可以根据不同页表级数划分成不同的区域,每个区域用于不同级页表的索引,但是由于不同的架构支持的页表级数不一致,有的支持 3 级页表,有的支持 4 级或 5 级页表,Linux 统一对页表进行统一管理,其中 PGD(Page Global Directory) 称为页全局目录,可以理解为顶层页表.

不同级数的页表使用虚拟地址不同的区域,以此作为索引在不同级页表索引下一级页表的 Entry. Linux 为了兼容不同级数的页表,将虚拟地址划分成 PGD_INDEX、P4D_INDEX、PUD_INDEX、PMD_INDEX、PTE_INDEX 和 PAGE_OFFSET 区域,有的区域可能长度为 0. 但无论如何 Linux 提供了统一的视角,虽然硬件上不支持所有级数的页表,但软件上支持 5 级页表,另外软件上也统一了每一级的页表分别是:

  • PGD(Page Global Directory) Table: 五级页表中的第 5 级页表
  • P4D(Page 4th Directory) Table: 五级页表中的第 4 级页表
  • PUD(Page Upper Directory) Table: 五级页表中的第 3 级页表
  • PMD(Page Middle Directory) Table: 五级页表中的第 2 级页表
  • PTE(Page Table): 五级页表中的第 1 级页表

PGD Table 由 4KiB 物理页构成,在 64 位系统,Linux 将 4KiB 页表页划分成 64Bit 的区域,每个区域称为 PGD Entry, 总共 512 个 PGD Entry,每个 PGD entry 的布局如上,不同架构可能存在差异,但其主要用于获得下一级页表的物理基地址和访问权限. 在 32 位系统中,Linux 将 4KiB 页表划分成 32Bit 区域,总共 1024 个 PGD Entry.

在多任务系统中,每个进程都有各自的地址空间,每个地址空间都是相互独立的,因此进程只能看到自己的地址空间,另外地址空间被划分成两部分: 用户空间内核空间. 对于所有的进程来说,他们的用户空间是相互独立的,但内核空间却是同一个, 那么如何实现这样的逻辑的呢? Linux 为每个进程分配一个 PGD 页表,其中用户空间对于的 PGD Entry 是进程私有的,而内核空间对应的 PGD Entry 都是来自 init_mm 的 PGD 页表,在切换进程时 CR3 加载不同进程的 PGD 页表, 以此实现了不同的地址空间切换,最后进程能看到什么,全由 PGD 页表决定,因此 PGD 就是进程地址空间的众生相. 那么接下来通过一个实践案例了解 Linux 对 PGD 的使用,其在 BiscuitOS 上的部署逻辑如下:

图片无法显示,请右键点击新窗口打开图片

BiscuitOS 内存管理之分页大专题订阅入口

图片无法显示,请右键点击新窗口打开图片