Linux 0.11 是一个 32 位操作系统,最初运行在 Intel 80386 微处理器上。下文主要集中介绍跟 80386 微处理器相关的一些知识点或微处理器共性。
80386 有多个工作模式,即实模式、保护模式和 V86 模式。《32 位微型计算机接口技术及应用》一书对微处理器工作模式有很简明扼要的解释:
微处理器的工作模式是指微处理器对“存储器”的操作模式。
早期的微处理器(如 8086)只有一种工作模式就是实地址模式(Real Address Mode),简称实模式
,程序和数据运行在实际存储空间,无存储保护;从 80286 到 Pentium 的微处理器又增加了一种工作模式,即受保护的虚拟地址模式(Protected Virtual Address Mode),简称保护模式
,对程序和数据的管理采用虚拟存储空间,并且增加了存储保护,还支持多任务;在保护模式下,为了兼容 8086 微处理器对存储器的实模式操作,又派生出一种虚拟 8086 工作模式,又称 V8086 模式,简称V86 模式
。所以,32 位微处理器有实模式、保护模式和 V86 模式 3 种工作模式供用户选择使用。其中,保护模式是 32 位微处理器的本机工作模式,而实模式和 V86 模式是为了兼容 16 位微处理器程序而留下来的工作模式。
另外,实模式和保护模式下的寄存器模型是不一样的(后者基本包括了前者,不同之处在后文指出
),下边分开阐述。
注:下文内容主要参考自 80386 官方手册 Intel 80386 programmer’s reference manual及《32 位微型计算机接口技术及应用》一书。
实模式下的 80386 寄存器模型
按照 80386 官方手册 Intel 80386 programmer’s reference manual,其所有的寄存器可分为通用寄存器(General registers)、段寄存器(Segment registers)和标志寄存器(Flags register)。这跟《32 位微型计算机接口技术及应用》一书第 3.2 节分类稍微有点不一样,不过内容是相同的。
通用寄存器
80386 的通用寄存器如下表所示:
包含了 EAX、EDX、ECX、EBX、EBP、ESI、EDI、ESP 共 8 个寄存器。从上表我们也可以看出,这些寄存器也能够用作 16 位或 8 位寄存器,或两者兼有。
下边将分成两个部分来阐述。
EAX、EDX、ECX、EBX
- EAX 是累加器寄存器,主要用于存放程序执行过程中的一些中间结果,以及 I/O 数据。
- EBX 是基址寄存器,常用来存放访问内存时的地址。
- ECX 是计数寄存器,在串、循环、循环移位和移位操作指令中用作计数器。
- EDX 是数据寄存器,在寄存器间接寻址中的 I/O 指令中存放 I/O 端口的地址。
EBP、ESI、EDI、ESP
EBP、ESP 是指针寄存器,ESI 和 EDI 是变址寄存器。
由于有些指令(算术、逻辑指令)的操作数在数据寄存器中,另一些指令(串指令)的操作数不在数据寄存器中,而在存储器内,因此,需要有一些能够确定操作数在存储器中的位置的寄存器。指针寄存器和变址寄存器就是用于存放“偏移量”地址,而不是存放数据的寄存器。
- 指针寄存器(EBP、ESP)用于选取
堆栈内
的具体存储单元,即指针寄存器的值指向堆栈段的栈顶或栈内的具体存储单元。如 EBP 和段寄存器 SS 的组合 SS:EBP 可指向堆栈内的存储单元;ESP 和 SS 的组合 SS:ESP 可指向堆栈的顶部(TOS,Top of the Stack)。 - 变址寄存器(ESI、EDI)用于选取
数据段
内的具体存储单元,即变址寄存器的值指向存储器数据段或附加段内的存储单元。在指令包含变址时,ESI 用于保存源操作数的偏移量地址,EDI 用于保存目标操作数用的偏移地址。
注意:这里的堆栈
实际上只指栈
,不包括堆。
段寄存器
段寄存器是为了存储器分段的需要而设置的,用于存放段基址。80386 中总共有 1 个代码段、1 个堆栈段和 4 个数据段寄存器,如下表所示:
一段内存,既可以用作代码的存储空间,也可以用作数据的存储空间,还可以用作堆栈空间,主要是由微处理器中的段寄存器来指定。例如,由 CS 和 EIP 指定为代码的存储空间,由 DS 和偏移量指定为数据的存储空间,由 SS 和 ESP 指定为堆栈存储空间。
指令指针寄存器
指令指针寄存器(Instruction pointer)在 80386 官方手册中被归到标志寄存器下(根据目录上下级来判断),但个人总觉得这不大妥当,所以单独拿出来说。
指令指针寄存器指示存储器中当前代码段内的“偏移量”,即代码与代码段基址的距离。
它和代码段寄存器 CS 的组合 CS:EIP 指向待访问的代码。指令指针寄存器如下图所示:
标志寄存器
标志寄存器(Flags register)是一个 32 位寄存器,称为 EFLAGS (16 位的称为 FLAGS),用于指示微处理器的状态并控制它的工作,如下图所示:
实模式下,微处理器只用到了低 9 位(除去保留位,即从 OF~CF)。
关于详细的标志意义,请参考 80386 官方手册或《32 位微型计算机接口技术及应用》一书第 3.2 节。
值得注意的是,在实模式下,还有一个控制寄存器 CR0
。该寄存器在保护模式中介绍。
保护模式下的 80386 寄存器模型
保护模式中跟实模式中相同的就不再介绍了,但有不同之处,在后文介绍。
全局描述符表寄存器
全局描述符表寄存器 GDTR 用来在存储器地址空间内定位一个全局描述符表 GDT。
如表 1 所示,GDTR 长 48 位,其
高 32 位基地址 Base,指示 GDT 在存储器的开始位置。
32 位基址允许把 GDT 定位在线性地址空间内的任何地方。低 16 位指示 GDT 的段限长 Limit。它规定了 GDT 按"字节"计算的大小(Limit 的值要比实际表小 1。例如,如果 Limit=00FFH,则表长为 256B)。
16 位段限长允许 GDT 表做长可达 65536B,因而最多可容纳 8192 个描述符(每个描述符长 8B,64 位),实际应用根据需要来确定 GDT 的长度。
表 1:GDTR 和 IDTR 寄存器
中断描述符表寄存器
中断描述符表寄存器 IDTR 用来在存储器地址空间内定位一个中断描述符表 IDT。
如表 1 所示,IDTR 长 48 位,其
高 32 位基地址 Base,指示 IDT 在存储器的开始位置。
32 位基址允许把 IDT 定位在线性地址空间内的任何地方。低 16 位指示 IDT 的段限长 Limit。它规定了 IDT 按字节计算的大小(Limit 的值要比实际表小 1。例如,如果 Limit=00FFH,则表长为 256B)。
16 位段限长允许 IDT 表做长可达 65536B,但系统只支持 256 个中断和异常
,所以,实际上 IDT 的最大长度是 2048B,以字节为单位的界限为 7FFH。
局部描述符表寄存器
如表 2 所示,局部描述符表寄存器 LDTR 长 16 位,是一个选择子
,它指向存放在 GDT 中的 LDT 的描述符。
LDTR (选择子)并不能直接定位 LDT,只有描述符才能定位 LDT
(注意:描述符跟描述符表是不一样的)。
实际上,LDT 需要两次定位
:
- LDTR (选择子)定位 GDT 中 LDT 的(真正的)描述符。该描述符会被装入 LDTR 的高速缓冲寄存器中(如表 2 所示);其高 32 位的 Base 值指示 LDT 在存储器的起始地址,20 位的 Limit 值指示 LDT 的大小,12 位的 Attribute 值说明 LDT 的属性。
- 利用该描述符,定位 LDT 在存储器中的位置。
表 2:LDTR 和 TR 寄存器
任务状态段寄存器
任务状态段寄存器 TR 跟 LDTR 类似,也不能直接指定任务状态段 TSS
在存储器空间的位置。其格式如表 2 所示。
TSS 段也需要两次定位:
- TR (选择子)定位 GDT 中 TSS 段的(真正的)描述符。该描述符会被装入 TR 的高速缓冲寄存器中(如表 2 所示);其高 32 位的 Base 值指示 TSS 段在存储器的起始地址,20 位的 Limit 值指示 TSS 段的大小,12 位的 Attribute 值说明 TSS 段的属性。
- 利用该描述符,定位 TSS 段在存储器中的位置。
控制寄存器
保护模式新增加的 4 个 32 位控制寄存器 CR0、CR1、CR2 和 CR3 是为了控制微处理器的工作方式和分段管理机制及分页管理机制。其格式如表 3 所示。
表 3:CR0~CR3 寄存器
控制寄存器 CR0
CR0 的主要功能是选择微处理器的工作方式和存储器的管理模式。各位的含义如下:
保护模式允许位 PE
PE 位控制微处理器是进入实模式还是保护模式。置 0 表示实模式;置 1 则表示保护模式。系统开机或重启时 PE 清零,微处理器处于实模式。若要进入保护模式,必须通过程序将 PE 置 1。
分页管理启用位 PG
PG 控制禁用还是开启分页管理机制。置 0 表示禁用,此时由分段机制形成的线性地址就作为物理地址;置 1 则表示开启,此时线性地址还不是物理地址,需要通过分页转换才能形成物理地址。
表 4 列出了不同 PE/PG 的组合下微处理器的工作方式。
表 4:微处理器的工作方式与 PE/PG 的选择
- 协处理器操作控制位(MP、EM、TS、ET)
CR0 中的位 1 ~ 位 4 分别标记为 MP(算术存在位)、EM(模拟位)、TS(任务切换位)和 ET(扩展类型位),它们控制浮点协处理器的操作。
控制寄存器 CR2
CR2 由分页管理机制使用,用于报告发生页故障时的出错信息。如果某页不在存储器中,则在页转换时会发生缺页故障,此时,微处理器把引起页故障的线性地址保存在 CR2 中。操作系统的页故障处理程序通过检查 CR2 的内容,就可查出是线性地址空间中的哪一页引起的故障。
控制寄存器 CR3
CR3 也由分页管理机制使用,用于保存"页表目录"的起始物理地址
。CR3 的高 20 位提供页表目录的基地址,低 12 位“不用”(这里的“不用”并不是指真的不用,而是从 CR3 取 32 位数据时,低 12 位全“取”为 0)。
改变功能的寄存器
段寄存器
段寄存器在实模式下用作段基址,但在保护模式下用作段选择子(仍然是 16 位)。选择子并不直接指定存储器地址,而是选择一个定义存储器段的段基址、大小和属性的描述符。
值得注意的是,在保护模式下,每个段寄存器都有一个相应的高速缓存寄存器
(可参见《32 位微型计算机接口技术及应用》一书第 3.3.4 节),它对一般编程人员是不可见的。
标志寄存器
标志寄存器 EFLAGS 长度扩展到 32 位,新增加了 5 位。具体参考上文的“标志寄存器”小节。