x86 32 位系统下的分页

2018/03/25

Categories: OS Tags: os

分页是操作系统内存管理的重要方式。

在操作系统启动过程中,首先需要从实模式(real mode)进入到保护模式(protect mode)。这时使用的内存管理方式只有段翻译(segment translation)。之后需要开启分页(Page translation)。

段翻译

在仅启用段翻译下,逻辑地址(logical addresses)经过段选择子,翻译到线性地址(linear address),此时线性地址与物理地址(physical address)是一致的。

  1. 也正是由于线性地址与物理地址是一致的,限制了并行进程(任务)数。在同段下,一个进程的链接地址(link address)与逻辑地址的偏移地址 (offset)是相同的,多个进程同时运行,可能就会互相覆盖,因为你并不知道编译器是如何设置代码的链接地址。
  2. 采用分段管理时,需要为进程分配出一段大块的连续内存。只有当进程退出时,这些内存才会释放。某些未分配内存由于太小,长时间无法被分配出去,就成了内存碎片,导致内存利用率低。

分页

分页就是为了解决上面的问题的一种方式。在 x86 32 位 CPU 上,我们一般采用二级分页来管理内存。

在分页下,同样需要段翻译。

各种地址

逻辑地址selector:offset 组成,比如 cs:eip 。偏移地址(offset)一般等于编译器产生的链接地址

线性地址由 dir:page:offset 组成,dir 和 page 都占 10 位,offset 占 12 位。

逻辑地址的段选择子(selector)通过段翻译机制得到段起始地址,加上逻辑地址的偏移得到线性地址。

这里段翻译与描述符表有关,可以看上篇源码中有关 GDT 的内容。一般选择子经过翻译后,得到的段起始地址都是 0x0,所以,

$$ 线性地址 == 链接地址 $$

物理地址由线性地址经过页翻译得到。

地址之间的转换如下图:

mage-20180325150547

结构

页目录(page directory),与页表(page table)的条目结构是相同的,如下图。

mage-20180325151649

在页目录里,page frame address 是页表首地址;在页表中,则是物理地址上页帧的首地址。

与书本是不是很相似?

多任务

因为线性地址是等于链接地址的,如果页目录仍相同,那么不同任务经历页翻译后,其物理地址很可能相同,导致互相覆盖。

所以需要使用不同的页目录与页表,即不同的书,才能保证看到的内容不同。这就是 cr3 寄存器的功能,保存当前任务下的页目录,告诉 CPU 现在看的是什么书。

页保护

仔细看 Figure5-10 这张图,每个页条目都相应的权限位。

  1. P 位表示该条目是否存在,如果通过索引拿到的这个条目 P 位为 0,就表示这个条目是空白的,什么内容都没有。
  2. R/W 位表示该条目对应的页表或者内存是否可写。1 表示可写。
  3. U/S 位表示该条目对应的内容,普通用户是否有权限。

R/W 与 U/S 结合:

  1. U/S 位为 0 时,表示超级用户才能访问对应内存。
  2. U/S 位为 1 时,如果 R/W 为 0,则普通用户只能读;R/W 为 1时,普通用户可读可写。