Intel80386知识总结: 内存管理与访问保护

====================================================================
本文用于汇总整理Intel80386的内存管理与访问保护机制,
参考文献:

本文是系列文章《Intel80386知识总结》的一部分。
===================================================================

1. Overview
i386通过两次地址转换把逻辑地址(程序员可见的地址)转换为物理地址(实际的物理内存地址):分段转换和分页转换。其中,分页机制是可选是否开启的,即开启分页时转换过程为:
逻辑地址 =分段转换=> 线性地址 =分页转换=> 物理地址

不开启分页时转换过程为:
逻辑地址 =分段转换=> 线性地址,直接作为物理地址


2. 分段机制
分段转换过程:
Intel80386知识总结: 内存管理与访问保护_第1张图片
下面分别解释图中的各个要素。

2.1 Descriptors(段描述符)
一个段描述符提供由一个逻辑地址映射到线性地址的必要信息,对程序员不可见,由编译器、静态/动态链接器或操作系统负责创建。

2.1.1 段描述符的格式
Intel80386知识总结: 内存管理与访问保护_第2张图片
其中BASE、AVL和P字段的含义比较明了,如以下列表所示:
  • BASE:段的基址,用于和逻辑地址中的Offset字段相加,获得线性地址。在描述符中被分为3个部分,共32位。
  • AVL:是否为系统软件所用
  • Segment-Present bit:当取值为0时该段描述符无效,当该段描述符被载入段寄存器时,处理器将会产生异常

其余字段的含义如下。
2.1.1.1 TYPE字段
TYPE字段占据段描述符的第8位到第12位。当第12位=1时,该段描述符对应的段是一个系统段,当第12位=0时,该段描述符对应的段是一个用户段。当作为一个系统段时,剩余的四位构成一个十六进制数,用以区分段的类型,取值对应如下表:
段描述符第8位到第11位的取值 系统段(描述符第12位为1的段)的类型
0 -reserved
1 Available 286 TSS
2 LDT
3 Busy 286 TSS
4 Call Gate
5 Task Gate
6 286 Interrupt Gate
7 286 Trap Gate
8 -reserved
9 Available 386 TSS
A -reserved
B Busy 386 TSS
C 386 Call Gate
D -reserved
E 386 Interrupt Gate
F 386 Trap Gate

当作为一个用户段时,第8位被定义为Accessed bit,每次访问该段描述时都把此位置为1。第11位用以区分该段是一个数据段还是代码段。当该段是一个数据段时,第9位决定该段是否可写,第10位用以标识该段是否处于EXPAND_DOWN模式(EXPAND-DOWN模式的具体含义请参照LIMIT字段的说明)。当该段是一个代码段时,第9位决定该段是否可读,第10位用以区分该段是否处于CONFORMING模式,CONFORMING模式的含义请见:基于段的优先级保护机制。
处理器会在两个时机,对段选择符中相应信息的有效性进行验证。
段选择符被载入段寄存器时验证:
  • CS/SS寄存器只能载入代码段
  • 数据段寄存器不能载入数据段

访问段寄存器时验证:
  • 指令不应当写代码段
  • 指令不应当写第9位为0的数据段
  • 指令不应当读第9位为0的代码段


2.1.1.2 LIMIT字段、BIG字段(第22位)与GRANULARITY字段(第23位)
LIMIT字段表示段长,在描述符中被分为2个部分,共20位。段长的单位由GRANULARITY(1位)决定。当GRANULARITY=0时,LIMIT的单位为Byte,此时段长最大为1MBytes;当GRANULARITY=1时,LIMIT字段的单位为4KBytes,此时段长最大为4GBytes。段长的解释还受到EXPAND-DOWN模式的影响,当处于EXPAND-DOWN模式时,段的有效范围为:
  • 当Big字段为0时:LIMIT+1 ~ 64K
  • 当Big字段为1时: LIMIT+1 ~ 4G

当不处于EXPAND-DOWN模式时,处理器在做以下操作时会发生异常:
  • 访问位于>LIMIT处的BYTE类型
  • 访问位于≥LIMIT处的WORD类型
  • 访问位于≥(LIMIT-2)处的DOUBLEWORD类型


2.1.1.3 DPL(Descriptor Privilege Level)字段
两位长度,用于基于段的优先级保护机制,详见本文相关章节。


2.1.2 段描述符表
任意一个段描述符都被保存在两种段描述符表中的某一种中:GDT或LDT,分别由寄存器GDTR和LDTR指向基址。段选择符表是可变长度的,最多容纳8192(2^13)个段描述符,同时SELECTOR中指定表内描述符的INDEX字段长度也为13位。另外规定,GDT的第0个是不被使用的。



2.2 Selector(段选择符)
根据软件系统的不同实现,段选择符可能作为一个程序员可见的字段保存在指针变量中,但更多的情况是,段选择符是由静态/动态链接器赋值的。段选择符负责选中一个段描述符表,并给出段描述符表中的一个索引,用以最终选中一个段描述符。下面是段选择符的格式:

其中,各字段的含义:
  • RPL:Requested Privilege Level
  • TI:Table Indicator,取值为0时选中GDT,取值为1时选中LDT。
  • INDEX:选中段选择符表最多8192(2^13)个段选择符中的一个。

由于GDT中的第0个段描述符是不用的,选中GDT第0个段描述符的段选择符被定义为null段选择符,通过null段选择符选择段描述符时,处理器将会产生异常。

2.3 基于段的优先级保护机制(描述符中的DPL字段和选择符中的RPL字段的作用说明)
2.3.1 优先级
i386支持基于段的优先级保护机制,它用到描述符中的DPL字段和选择符中的RPL字段,这两个字段都是两位长度,因此可以定义4个优先级:0~3,其中0是最高优先级,3是最低优先级。系统运行的某一时刻,涉及到的优先级有三个:
  • DPL:位于描述符中
  • RPL:位于选择符中
  • CPL:Current Privilege Level,通常被定义为当前代码段的DPL

2.3.2 用优先级机制保护段的访问
处理器在段选择符载入段寄存器的时候进行优先级验证以下两个条件必须同时满足:
  • 被载入段寄存器的段选择符的RPL字段必须小于等于被其选中的段描述符的DPL字段
  • CPL必须小于等于被载入段寄存器的段选择符所选中的段描述符的DPL

2.3.3 用优先级机制保护远端控制流转移
控制流的转移分为近端和远端两种,近端控制流转移指的是在当前段范围内的转移,远端控制流转移指的是跨代码段的控制流转移。近端的控制流转移不涉及优先级的保护,只接受段长限制的保护。远端控制流转移比近端控制流转移多一重优先级的保护。远端控制流转移可以通过两种方式:
  • 转移指令的操作数选中另一个代码段的描述符
  • 转移指令的操作数选中一个调用门的描述符,称作基于调用门的远端控制流转移

2.3.3.1 用优先级机制保护不使用调用门的远端控制流转移
处理器在转移时进行优先级验证,下列条件满足其一即可:
  • 目标代码段DPL等于CPL
  • 目标代码段处于CONFORMING模式,且其DPL小于等于CPL

2.3.3.2 用优先级机制保护使用调用门的远端控制流转移
调用门是一种特殊的段描述符,其格式如下所示。
Intel80386知识总结: 内存管理与访问保护_第3张图片
由SELECTOR字段选中目标代码段,OFFSET字段选中段内起始执行点。当使用JMP指令通过调用门进行转移时,若目标代码段没有处于CONFORMING模式则必须同时满足下列两个条件:
  • 调用门DPL字段大于等于CPL和选中调用门的选择符的RPL字段
  • 目标代码段DPL等于CPL

当使用JMP指令通过调用门进行转移时,且目标代码段处于CONFORMING模式;或者使用CALL指令通过调用门进行转移时,则必须同时满足下列两个条件:
  • 调用门DPL字段大于等于CPL和选中调用门的选择符的RPL字段
  • 目标代码段DPL小于等于CPL

2.3.3.3 跨优先级控制流转移时堆栈的维护
i386要求不同的优先级使用不同的堆栈。当前使用的堆栈段由TR寄存器所指向的TSS(Task status structure)中读取,TSS为不同的优先级维护不同的堆栈段保存字段。当发生跨优先级控制流转移时,处理器会读取相应的堆栈段选择符,堆栈切换的过程如下:
  • 验证新的堆栈段DPL是否等于新的CPL,若不相等则产生异常。
  • 检查新的堆栈段是否够长,是否够长的标准是以下要拷贝的数据是否放得下
  • 压入调用者的堆栈栈顶,即SS:ESP
  • 拷贝需要的参数,要拷贝的参数长度由调用门的COUNT字段确定,最多拷贝31个double word,如果要用到的参数超过31个double word,则需要通过拷贝的SS:ESP去调用者堆栈上读取
  • 压入要返回的地址,即调用者的CS:EIP
  • 更新寄存器SS:ESP的值

上述过程图示如下:
Intel80386知识总结: 内存管理与访问保护_第4张图片
当控制流从被调用者返回调用者时,执行以下操作:
  • 验证新的堆栈段DPL是否等于新的CPL,若不相等则产生异常。
  • 从堆栈上读取CS、EIP、SS、ESP的值,并刷新相应寄存器
  • 根据RET指令的操作数,调整寄存器SS:ESP的值
  • 检查数据段寄存器:DS、ES、FS、和GS的取值,如果它们中有指向DPL大于新CPL的非CONFORMING段,则将它们的取值设为null段描述符



3 分页机制
3.1 分页转换
分页机制当CR0寄存器的PG位被置为1时被启用。i386采用两级页表,第一级页表被称为Page Dir,第二级称为Page Tab,线性地址的格式如下所示:
Intel80386知识总结: 内存管理与访问保护_第5张图片
下面是线性地址(DIR-PAGE-OFFSET三个字段)转换为物理地址的过程:
Intel80386知识总结: 内存管理与访问保护_第6张图片

3.2 页表
其中,当前Page Dir的地址保存在寄存器CR3中(所有CR3也被称为Page Dir Base Register, PDBR )。找到Page Dir之后就可以依照上图所示完成线性地址到物理地址的映射。每个页的长度是固定的4K(2^12)Bytes,每个页表(一个PageDir或一个PageTab)本身也是一个页。每个页表项长4Bytes,所以一级页表最多包含1K个页表项,两级页表最多包含1M个页表项,所有页长度总和刚好覆盖4GBytes(1K * 1K * 4K)地址空间。
每个页表项的格式如图所示:
Intel80386知识总结: 内存管理与访问保护_第7张图片
  • Page Frame Address: 给出一个页的基地址,由于页长度4K,所以低12位总是为0
  • P:PRESENT,当PRESENT=0时表示该页表项不可用
  • A:Accessed,当某个页发生读或写操作时,处理器在两级页表的相应页表项中置A位为1
  • D:Dirty,当某个页内发生写操作时,该页对应的PageTab中的相应页表项的D位被置为1,PageDir中的D位无定义
  • R/W: Read/Write, Page Level Protection
  • U/S: User/Supervisor, Page Level Protection


3.3 页级保护(页表项R/W字段与U/S字段的含义)
3.3.1 U/S字段的含义
当U/S字段等于1时,对应页被定义为用户级页,当U/S=0时,对应页被定义为系统级页。当CPL=0/1/2时,CPL被定义为系统级,当CPL=3时,CPL被定义为用户级。当CPL为系统级时,可以访问所有页,当CPL为用户级时只能访问用户级页。Certain accesses are checked as if they are privilege-level 0 references, even if CPL = 3:
  • LDT, GDT, TSS, IDT references.
  • Access to inner stack during ring-crossing CALL/INT.


3.3.2 R/W字段的含义
当R/W字段=0时,对应页被定义为只读页,当R/W字段=1时,对应页被定义为可读可写页。当CPL为系统级时,所有页都是可读可写的。当CPL为用户级时,只有用户级的可读可写页是可读可写的,用户级的只读页是只读的。系统级页是既不可读又不可写的(无法访问)。

3.3.3 两级页表的保护机制重载规则
对于任意某个页,都对应PageDir和PageTab中的两个页表项,这两个页表项中的保护机制字段取值可能不同,发生此种情况时,按照下列规则决定保护政策:
Intel80386知识总结: 内存管理与访问保护_第8张图片

3.4 Translation lookaside buffer
为提升分页转换性能,处理器会把最近使用过的页表项保存在TLB中,若在TLB命中所需的页表项,则不需要两次访存就可以取得所需的页表项信息。

你可能感兴趣的:(内存管理)