80386 分页

高级设计

80386 是一个 32 位处理器,具有 32 位可寻址存储空间。Paging 子系统的设计者注意到 4K 页面设计以相当简洁的方式映射到这 32 位 –10 位,10 位和 12 位:

+-----------+------------+------------+
| Dir index | Page index | Byte index |
+-----------+------------+------------+
 3         2 2          1 1          0  Bit
 1         2 1          2 1          0  number

这意味着字节索引是 12 位宽,它将索引到 4K 页面。目录和页面索引是 10 位,每个都映射到 1,024 条目表 - 如果这些表条目每个 4 个字节,那么每个表将是 4K:也是一个页面!

这就是他们所做的:

  • 每个程序都有自己的目录,一个包含 1,024 个页面条目的页面,每个页面都定义了下一级页面表的位置 - 如果有的话。
  • 如果有的话,那个页面表将有 1,024 个页面条目,每个页面条目定义了最后一级页面所在的位置 - 如果有的话。
  • 如果有,那么该页面可以直接读出它的字节。

页面输入

顶级目录和下一级页表都包含 1,024 个页面条目。这些条目中最重要的部分是索引的地址:页表或实际页面。请注意,此地址不需要完整的 32 位 - 因为所有内容都是 Page,所以只有前 20 位是重要的。因此,页面输入中的其他 12 位可用于其他事项:是否存在下一级别; 关于页面是否被访问或写入的内务管理; 甚至是否应该允许写入!

+--------------+----+------+-----+---+---+
| Page Address | OS | Used | Sup | W | P |
+--------------+----+------+-----+---+---+
Page Address = Top 20 bits of Page Table or Page address
OS           = Available for OS use
Used         = Whether this page has been accessed or written to
Sup          = Whether this page is Supervisory - only accessible by the OS
W            = Whether this page is allowed to be Written
P            = Whether this page is even Present

请注意,如果 P 位为 0,则允许条目的其余部分具有操作系统想要放入的任何内容 - 例如,页面的内容位于硬盘上的位置!

页目录基址寄存器(PDBR

如果每个程序都有自己的目录,那么硬件如何知道从哪里开始映射?由于 CPU 一次只运行一个程序,因此它只有一个控制寄存器来保存当前程序目录的地址。这是页面目录基本寄存器(CR3)。当操作系统在不同程序之间交换时,它会使用程序的相关页面目录更新 PDBR

页面错误

每次 CPU 访问内存时,都必须将指示的虚拟地址映射到适当的物理地址。这是一个三步过程:

  1. 将地址的前 10 位索引到 PDBR 指示的页面中,以获取相应页面表的地址;
  2. 将地址的下 10 位索引到目录所指示的页面中,以获取相应页面的地址;
  3. 索引地址的最后 12 位以从该页面获取数据。

由于上面的步骤 1.和 2.上面都使用了页面条目,因此每个条目都可能表示存在问题:

  • 下一级可能标记为不存在;
  • 下一级可以标记为只读 - 操作是写入;
  • 下一级可能被标记为主管 - 它是访问内存的程序,而不是操作系统。

当硬件注意到这样的问题时,它不会完成访问,而是引发故障:中断#14,即页面错误。它还填写了一些特定的控制寄存器,其中包含故障发生原因的信息:引用的地址; 是否是主管访问; 以及是否是写入尝试。

操作系统应该捕获该故障,解码控制寄存器,并决定做什么。如果它是无效访问,它可以终止错误程序。如果它是虚拟内存访问,操作系统应该分配一个新的页面(可能需要腾出一个已经在使用的页面!),用所需的内容填充它(全部为零,或者从磁盘加载的前一个内容) ),将新页面映射到适当的页面表,将其标记为存在,然后恢复故障指令。这次访问将成功进行,程序将不知道发生了什么特别的事情(除非它看一下时钟!)