x86分页是如何工作的?

x86分页是如何工作的?,x86,paging,virtual-memory,X86,Paging,Virtual Memory,这个问题是为了填补关于这个主题的免费信息的空白 我相信一个好的答案会适合一个大的SO答案,或者至少适合几个答案 主要目标是为完全初学者提供足够的信息,以便他们能够自己阅读手册,并能够理解与分页相关的基本操作系统概念 建议的准则: 答案应该对初学者友好: 具体但可能简化的示例非常重要 欢迎应用所示概念 引用有用的资源是好的 对于OSs如何使用分页功能的一些小离题是受欢迎的 欢迎提供PAE和PSE解释 欢迎您将小的内容转移到x86_64中 相关问题以及为什么我认为他们不是傻瓜: :标题与此

这个问题是为了填补关于这个主题的免费信息的空白

我相信一个好的答案会适合一个大的SO答案,或者至少适合几个答案

主要目标是为完全初学者提供足够的信息,以便他们能够自己阅读手册,并能够理解与分页相关的基本操作系统概念

建议的准则:

  • 答案应该对初学者友好:
    • 具体但可能简化的示例非常重要
    • 欢迎应用所示概念
  • 引用有用的资源是好的
  • 对于OSs如何使用分页功能的一些小离题是受欢迎的
  • 欢迎提供PAE和PSE解释
  • 欢迎您将小的内容转移到x86_64中
相关问题以及为什么我认为他们不是傻瓜:

  • :标题与此问题几乎相同,但正文提出了与cr3和TLB相关的具体问题。那个问题是这个问题的一个子集

  • :body仅请求源

我将更正报告的任何错误。如果您想进行较大的修改或添加缺少的方面,请在您自己的答案中进行修改,以获得当之无愧的代表。较小的编辑可以直接合并到中

示例代码 最简单的例子:

与编程中的其他内容一样,真正理解这一点的唯一方法是使用最少的示例

这是一个“难”的主题,因为最简单的例子是大型的,因为您需要制作自己的小型操作系统

英特尔手册 虽然没有例子是不可能理解的,但要尽快熟悉手册

英特尔在第4章“分页”中介绍了分页

特别有趣的是图4-4“具有32位分页的CR3和分页结构项的格式”,其中给出了关键数据结构

MMU 分页由CPU的(MMU)部分完成。像许多其他的芯片一样(例如),这在早期是由单独的芯片实现的,后来集成到CPU中。但这个词仍然被使用

一般事实 逻辑地址是“常规”用户土地代码中使用的内存地址(例如
mov eax,[rsi]
rsi
的内容)

首先分段将它们转换为线性地址,然后分页将线性地址转换为物理地址

(logical) ------------------> (linear) ------------> (physical)
             segmentation                 paging
大多数情况下,我们可以将物理地址视为索引实际RAM硬件内存单元,但这并非100%正确,因为:

分页仅在受保护模式下可用。在保护模式下使用分页是可选的。如果设置了
cr0
寄存器的
PG
位,则分页处于打开状态

分页与分段 分页和分段之间的一个主要区别是:

  • 分页将RAM分成大小相等的块,称为页
  • 分段将内存分割为任意大小的块
这是分页的主要优点,因为大小相等的块使事情更易于管理

分页变得越来越流行,以至于在x86-64的64位模式下(新软件的主要操作模式)放弃了对分段的支持,在这种模式下,分页只存在于兼容模式下,而兼容模式模拟IA32

应用 分页用于在现代操作系统上实现进程虚拟地址空间。通过虚拟地址,操作系统可以在单个RAM上安装两个或多个并发进程,其方式如下:

  • 两个程序都不需要了解另一个
  • 两个程序的内存都可以根据需要增减
  • 程序之间的切换非常快
  • 一个程序永远不能访问另一个进程的内存
分页在历史上是在分段之后出现的,在现代操作系统(如Linux)中,分页在很大程度上被虚拟内存的实现所取代,因为它更容易管理页面中固定大小的内存块,而不是可变长度的段

硬件实现 与受保护模式下的分段一样(修改分段寄存器会触发来自GDT或LDT的加载),分页硬件使用内存中的数据结构来完成其工作(页表、页目录等)

这些数据结构的格式由硬件固定,但由操作系统在RAM上正确设置和管理这些数据结构,并告诉硬件在哪里可以找到它们(通过
cr3

其他一些体系结构将分页几乎完全交给了软件,因此TLB未命中将运行操作系统提供的函数来遍历页表并将新映射插入TLB。这使得页表格式由操作系统选择,但使其变得更容易

示例:简化的单级分页方案 这是一个分页如何在简化版本的x86体系结构上运行的示例 实现虚拟内存空间

页表 操作系统可以为他们提供以下页面表:

操作系统提供给进程1的页表:

RAM location        physical address   present
-----------------   -----------------  --------
PT1 + 0       * L   0x00001            1
PT1 + 1       * L   0x00000            1
PT1 + 2       * L   0x00003            1
PT1 + 3       * L                      0
...                                    ...
PT1 + 0xFFFFF * L   0x00005            1
RAM location       physical address   present
-----------------  -----------------  --------
PT2 + 0       * L  0x0000A            1
PT2 + 1       * L  0x0000B            1
PT2 + 2       * L                     0
PT2 + 3       * L  0x00003            1
...                ...                ...
PT2 + 0xFFFFF * L  0x00004            1
RAM location     physical address   present
---------------  -----------------  --------
PD1 + 0     * L  0x10000            1
PD1 + 1     * L                     0
PD1 + 2     * L  0x80000            1
PD1 + 3     * L                     0
...                                 ...
PD1 + 0x3FF * L                     0
操作系统提供给进程2的页表:

RAM location        physical address   present
-----------------   -----------------  --------
PT1 + 0       * L   0x00001            1
PT1 + 1       * L   0x00000            1
PT1 + 2       * L   0x00003            1
PT1 + 3       * L                      0
...                                    ...
PT1 + 0xFFFFF * L   0x00005            1
RAM location       physical address   present
-----------------  -----------------  --------
PT2 + 0       * L  0x0000A            1
PT2 + 1       * L  0x0000B            1
PT2 + 2       * L                     0
PT2 + 3       * L  0x00003            1
...                ...                ...
PT2 + 0xFFFFF * L  0x00004            1
RAM location     physical address   present
---------------  -----------------  --------
PD1 + 0     * L  0x10000            1
PD1 + 1     * L                     0
PD1 + 2     * L  0x80000            1
PD1 + 3     * L                     0
...                                 ...
PD1 + 0x3FF * L                     0
其中:

  • PT1
    PT2
    :表1和表2在RAM上的初始位置

    示例值:
    0x00000000
    0x12345678

    是操作系统决定了这些价值观

  • L
    :页表条目的长度

  • present
    :表示页面存在于内存中

页表位于RAM上。例如,它们可以定位为:

--------------> 0xFFFFFFFF


--------------> PT1 + 0xFFFFF * L
Page Table 1
--------------> PT1


--------------> PT2 + 0xFFFFF * L
Page Table 2
--------------> PT2

--------------> 0x0
两个页表在RAM上的初始位置是任意的,由操作系统控制。由操作系统来确保它们不会重叠

每个进程不能直接接触任何页表,尽管它可以向操作系统发出请求,导致页表被修改,例如请求更大的堆栈或堆段

页面是4KB(12位)的块
linear     physical
---------  ---------
00000 002  00001 002
00000 003  00001 003
00000 FFF  00001 FFF
00001 000  00000 000
00001 001  00000 001
00001 FFF  00000 FFF
00003 000  00003 000
FFFFF 000  00004 000
int is[1];
is[2] = 1;
| directory (10 bits) | table (10 bits) | offset (12 bits) |
RAM location     physical address   present
---------------  -----------------  --------
PD1 + 0     * L  0x10000            1
PD1 + 1     * L                     0
PD1 + 2     * L  0x80000            1
PD1 + 3     * L                     0
...                                 ...
PD1 + 0x3FF * L                     0
RAM location      physical address   present
---------------   -----------------  --------
PT1 + 0     * L   0x00001            1
PT1 + 1     * L                      0
PT1 + 2     * L   0x0000D            1
...                                  ...
PT1 + 0x3FF * L   0x00005            1
RAM location      physical address   present
---------------   -----------------  --------
PT2 + 0     * L   0x0000A            1
PT2 + 1     * L   0x0000C            1
PT2 + 2     * L                      0
...                                  ...
PT2 + 0x3FF * L   0x00003            1
----------------> 0xFFFFFFFF


----------------> PT2 + 0x3FF * L
Page Table 1
----------------> PT2

----------------> PD1 + 0x3FF * L
Page Directory 1
----------------> PD1


----------------> PT1 + 0x3FF * L
Page Table 2
----------------> PT1

----------------> 0x0
0    0    8    0    1    0    0    4
0000 0000 1000 0000 0001 0000 0000 0100
0000000010 0000000001 000000000100
0x2        0x1        0x4
linear    10 10 12 split   physical
--------  ---------------  ----------
00000001  000 000 001      00001001
00001001  000 001 001      page fault
003FF001  000 3FF 001      00005001
00400000  001 000 000      page fault
00800001  002 000 001      0000A001
00801008  002 001 008      0000C008
00802008  002 002 008      page fault
00B00001  003 000 000      page fault
  valid   linear   physical
  ------  -------  ---------
> 0       00000    00000
  0       00000    00000
  0       00000    00000
  0       00000    00000
  valid   linear   physical
  ------  -------  ---------
  1       00003    00005
> 0       00000    00000
  0       00000    00000
  0       00000    00000
  valid   linear   physical
  ------  -------  ---------
  1       00003    00005
  1       00007    00009
> 0       00000    00000
  0       00000    00000
  valid   linear   physical
  ------  -------  ---------
> 1       00003    00005
  1       00007    00009
  1       00009    00001
  1       0000B    00003
  valid   linear   physical
  ------  -------  ---------
  1       0000D    0000A
> 1       00007    00009
  1       00009    00001
  1       0000B    00003
linear   physical
-------  ---------
00000    00001
00001    00010
00010    00011
FFFFF    00000
linear   physical
-------  ---------
00000    00001
00001    00010
00010    00011
... (from 00011 to FFFFE)
FFFFF    00000
#define _PAGE_BIT_PRESENT   0   /* is present */
#define _PAGE_BIT_RW        1   /* writeable */
#define _PAGE_BIT_USER      2   /* userspace addressable */
#define _PAGE_BIT_PWT       3   /* page write through */
#define X86_CR0_PG_BIT      31 /* Paging */