1.概述
在学习《Intel 汇编语言程序设计(第四版)》保护模式内存管理部分的时候,感觉该部分涉及的内容比较多,而且杂,很难一次全部理解清楚,因此针对理解部分做个总结,并列出暂时不理解的部分。
2.CPU的工作模式
IA-32家族的CPU支持三种工作模式和一种准工作模式:
保护模式
这是从intel 286 引入的工作模式,是286之后CPU工作的主要模式,可以使用cpu的全部特性。
实模式
和intel 8086 完全兼容的工作模式,和8086相比增强了一些特性,比如可以切换到保护模式或者系统管理模式
系统管理模式
80386引入,主要用于操作系统进行电源管理以及OEM厂商定制。
虚拟8086模式
执行在保护模式下的一种虚拟8086工作模式,允许多个任务同时运行。
3.CPU支持的内存模型
IA-32主要支持三种内存模型
l 平面内存模型
每个程序都独享连续的4GB线性地址空间。多有的代码数据都包含在该空间内。
实际上程序在运行的时候依然存在两个段:代码段和数据段。
l 段内存模型
将线性地址分割成独立的小内存空间,用来保存对应代码,数据或者堆栈。
这些小的内存空间叫做段。每个程序由不同的段集合组成。所有的段映射到线性地址空间中。程序通过逻辑地址访问相应的数据,CPU将逻辑地址转换成对应的物理地址。
逻辑地址由段选择子和一个32位的偏移量组成。
此时的段保存的是段选择子。
l 实模式内存模型
采用段+偏移量的模式进行寻址,同DOS下汇编。此时的段保存的是段的地址。
4. CPU段机制
在了解逻辑地址如何转成线性地址前必须弄清如下几个概念:
l 段描述符
段描述符是一个包含段的位置,大小,访问控制和状态信息的数据结构。
CPU通过这些信息区访问对应的段。
由上图可以看出一个段描述符占8个字节。
基地址占32位,段大小占20位。
G标志位表示段大小的单位,如果是0,那么以字节为单位,段最大为1MB。
如果设置为1,那么以4KB为单位,段最大为4GB。
GDT,LDT
GDT: Global descriptor table,全局描述符表
LDT: local descriptor table,本地描述符表
内存中的数据结构,用来保存段描述符的表。
每个系统必须有一个GDT表,用于系统所有程序。LDT是可选的,可定义定义一个或者多个
GDT中第一个段描述符系统不是用,系统保留??
如果系统存在LDT,那么GDT必须包含指向LDT的段描述符。
GDTR,LDTR,
IA-32中包含一系列的内存管理寄存器,他们是GDTR,LDTR,IDTR,TR)
GDTR:GDT寄存器
该寄存器保存GDT结构的基地址以及GDT结构的大小。
该寄存器位长48位,其中0-15未表示GDT大小,16-47位表示基地址
GDTR示意图
LDTR: LDT 寄存器
LDTR寄存器保存16位的段选择子。32位的段基地址,段的大小以及其他属性信息。其示意图如下:
LDTR保存的应该是16位的当前LDT的索引,它指向GDT表中对应的段描述符。
LDTR 本身应该是16位的,CPU在操作系统任务切换的时候,会将当前任务的LDT段选择子读取到LDTR中,为了提高性能同时也会将LDT中对应的数据直接读入到对应的高速缓冲中。( 是否是这么理解?还是所有信息都会存储到LDTR中?)
因此LDTR应该指向当前任务的LDT。LDT和GDT不同,LDT本身存储在系统段内,本身是一个LDT类型的段,所以这个地方用segment limit,其实指的应该是LDT本身的大小。
LDT,GDT表中最大数据:因为table limit和segment limited都是16位的,所有最多存贮64K的数据,而每个段描述符占8 BYTE,所以每个GDT或者LDT最多能存贮8192个段描述符
IDTR: 中断描述符表寄存器
用来存储指向IDT的地址和数据结果的大小。和GDTR的结构相同。
段选择子
段选择子时一个16bit大小的段索引,不是直接指向段,而是指向GDT或者LDT中的段描述符。
其示意图如下:
其中索引指的是LDT或者GDT中段描述符的表示,长度13位最大表示8092.
RPL:表示具体的访问权限级别 0-3,因此需要2bit位。具体作用还不清楚。
段寄存器
IA-32中提供了6个段相关的寄存器,分别是 CS,DS,SS,ES,FS,GS.
在实模式下,分别用来存储对应段的偏移量。在保护模式下这些寄存器保存的是对应段的选择子,这是保护模式和实模式的一个重大差异。
其中 CS 保存代码段选择子
DS 保存数据段选择子
SS 保存堆栈段选择子
ES,FS,GS 保存其他附加的数据段的选择子。
CPU在读取段选择子到相应寄存器的时候,会同时将段选择子指向的段描述符也一并读取到对应段寄存器的缓冲中保存起来,这样CPU可以直接访问对应的段信息,不需要再次从LDT或者GDT中读取。(这个不可见部分究竟是什么?寄存器?高速缓存)
逻辑地址和线性地址的转换步骤
在弄清楚上面几个关键概念后,我们可以得出如下逻辑示意图:
逻辑地址转换成线性地址示意图
具体步骤如下:
1)读取新的段选择子到对应的段寄存器,同时将该段选择子对应的段描述符中基地址,段大小,访问控制等信息一起读取到段寄存器的高速缓冲中。
2)检查段描述符中的信息,确保该段式可访问的,并且偏移量在该段的范围内
3)根据段的基地址和相应的32位偏移量可以得出对应的线性地址。
5 CPU页机制
IA-32 cpu支持分页机制,分页功能是可选功能。
5.1 三种分页模型
IA-32 目前支持三种分页模型
如果CR0寄存器的PG位=0,那么不启用分页功能。
如果要启用分页模式,CR0.PE 必须等于1
32位页模式
CR0.PG=1 , CR4.PAE=0
PAE页模式
CR0.PG=1,CR4.PAE=1,IA-32_EFER.LME=0
IA-32E页模式
CR0.PG=1,CR4.PAE=1,IA-32_EFER.LME=0
64位CPU使用
由该表可以归纳出
32bit 模式:用了2级数据结构PD----PT
PAE 模式:用了3级数据结构 PDPT-PD-PT
IA-32e 模式:用了 4级 数据结构: PML4T ----PDPT----PD----PT
第一级页结构都是由CR3保存其地址。
5.2.1 32 bit页模式
5.2.2 PAE页模式
暂时用不到,用到的时候再研究
5.2.3 IA-32e 页模式
暂时用不到,用到的时候再研究
6.逻辑地址转换到物理地址
在页功能没打开的时候,逻辑地址通过段逻辑转换到线性地址,直接映射到物理地址。
在页功能打开的时候,线性地址经过页逻辑转换到物理地址。