0%

操作系统:Intel 80386运行模式、内存架构与寄存器

Intel 80386运行模式

一般CPU只有一种运行模式,能够支持多个程序在各自独立的内存空间中并发执行,且有用户特权级和内核特权级的区分,让一般应用不能破坏操作系统内核和执行特权指令。

80386处理器有四种运行模式:实模式、保护模式、SMM模式和虚拟8086模式。

实模式

这是个人计算机早期的8086处理器采用的一种简单运行模式,当时微软的MS-DOS操作系统主要就是运行在8086的实模式下。80386加电启动后处于实模式运行状态,在这种状态下软件可访问的物理内存空间不能超过1MB且无法发挥Intel 80386以上级别的32位CPU的4GB内存管理能力。实模式将整个物理内存看成分段的区域,程序代码和数据位于不同区域,操作系统和用户程序并没有区别对待,而且每一个指针都是指向实际的物理地址。这样指针就可以随便寻址,造成笋干爆炸

保护模式

保护模式的一个主要目标是确保应用程序无法对操作系统进行破坏。(这就是跟上面的实模式最大的不同)。实际上,80386就是通过在实模式下初始化控制寄存器(如GDTR,LDTR,IDTR与TR等管理寄存器)以及页表,然后再通过设置CR0寄存器使其中的保护模式使能位置位,从而进入到80386的保护模式。

全局描述符表寄存器 (Global Descriptor Table Register,GDTR):指向全局段描述符表 GDT

局部描述符表寄存器 (Local Descriptor Table Register,LDTR):指向局部段描述符表LDT

中断门描述符表寄存器 (Interrupt Descriptor Table Register, IDTR):指向一张包含中断处理子程序入口点的表(IDT)

任务寄存器 (Task Register,TR):这个寄存器指向当前任务信息存放处,这些信息是处理器进行任务切换所需要的。

Intel 80386内存架构

地址是访问内存空间的索引。一般而言,内存地址有两个:一个是CPU通过总线访问物理内存用到的物理地址,一个是我们编写的应用程序所用到的逻辑地址(也有人称为虚拟地址)。比如如下C代码片段:

1
2
int boo=1;
int *foo=&boo;

这里的boo是一个整型变量,foo变量是一个指向boo地址的整型指针变量,foo中储存的内容就是boo的逻辑地址。
80386是32位的处理器,即可以寻址的物理内存地址空间为2^32=4G字节。为更好理解面向80386处理器的ucore操作系统,需要用到三个地址空间的概念:物理地址、线性地址和逻辑地址

物理地址

物理地址是CPU提交到总线上用于访问内存和外设的最终地址。一个计算机系统中只有一个物理地址空间。

线性地址

线性地址空间是80386处理器通过段(Segment)机制控制下的形成的地址空间。操作系统将物理地址切分成相对独立的一个或多个内存空间段,每个段有自己的起始地址和长度,大小不固定,这样可让多个运行的应用程序之间相互隔离,实现对地址空间的保护。

在操作系统完成对80386处理器段机制的初始化和配置(主要是需要操作系统通过特定的指令和操作建立全局描述符表,完成虚拟地址与线性地址的映射关系)后,80386处理器的段管理功能单元负责把虚拟地址转换成线性地址,在没有下面介绍的页机制启动的情况下,这个线性地址就是物理地址。

相对而言,段机制对大量应用程序分散地使用大内存的支持能力较弱。所以Intel公司又加入了页机制,每个页的大小是固定的(一般为4KB),也可完成对内存单元的安全保护,隔离,且可有效支持大量应用程序分散地使用大内存的情况。

段机制与页机制

在操作系统完成对80386处理器页机制的初始化和配置(主要是需要操作系统通过特定的指令和操作建立页表,完成虚拟地址与线性地址的映射关系)后,应用程序看到的逻辑地址先被处理器中的段管理功能单元转换为线性地址,然后再通过80386处理器中的页管理功能单元把线性地址转换成物理地址。

页机制和段机制有一定程度的功能重复,但Intel公司为了向下兼容等目标,使得这两者一直共存。

上述三种地址的关系如下:

  • 分段机制启动、分页机制未启动:逻辑地址—->段机制处理—->线性地址=物理地址
  • 分段机制和分页机制都启动:逻辑地址—->段机制处理—->线性地址—->页机制处理—->物理地址

Intel 80386寄存器

80386的寄存器可以分为8组:通用寄存器,段寄存器,指令指针寄存器,标志寄存器,系统地址寄存器,控制寄存器,调试寄存器,测试寄存器,它们的宽度都是32位。一般程序员看到的寄存器包括通用寄存器,段寄存器,指令指针寄存器,标志寄存器。

General Register(通用寄存器)

EAX/EBX/ECX/EDX/ESI/EDI/ESP/EBP这些寄存器的低16位就是8086的 AX/BX/CX/DX/SI/DI/SP/BP,对于AX,BX,CX,DX这四个寄存器来讲,可以单独存取它们的高8位和低8位 (AH,AL,BH,BL,CH,CL,DH,DL)。它们的含义如下:

1
2
3
4
5
6
7
8
EAX:累加器
EBX:基址寄存器
ECX:计数器
EDX:数据寄存器
ESI:源地址指针寄存器
EDI:目的地址指针寄存器
EBP:基址指针寄存器
ESP:堆栈指针寄存器

img

Segment Register(段寄存器,也称 Segment Selector,段选择符,段选择子)

除了8086的4个段外(CS,DS,ES,SS),80386还增加了两个段FS,GS,这些段寄存器都是16位的,用于不同属性内存段的寻址,它们的含义如下:

1
2
3
4
5
6
CS:代码段(Code Segment)
DS:数据段(Data Segment)
ES:附加数据段(Extra Segment)
SS:堆栈段(Stack Segment)
FS:附加段
GS 附加段

img

Instruction Pointer(指令指针寄存器)

EIP的低16位就是8086的IP,它存储的是下一条要执行指令的内存地址,在分段地址转换中,表示指令的段内偏移地址。

img

Flag Register(标志寄存器):EFLAGS,和8086的16位标志寄存器相比,增加了4个控制位,这20位控制/标志位的位置如下图所示:

img

相关的控制/标志位含义是:

1
2
3
4
5
6
7
8
9
10
CF(Carry Flag):进位标志位;
PF(Parity Flag):奇偶标志位;
AF(Assistant Flag):辅助进位标志位;
ZF(Zero Flag):零标志位;
SF(Singal Flag):符号标志位;
IF(Interrupt Flag):中断允许标志位,CLISTI两条指令来控制;设置IF位使CPU可识别外部(可屏蔽)中断请求,复位IF位则禁止中断,IF位对不可屏蔽外部中断和故障中断的识别没有任何作用;
DF(Direction Flag):向量标志位,由CLDSTD两条指令来控制;
OF(Overflow Flag):溢出标志位;
IOPL(I/O Privilege Level)I/O特权级字段,它的宽度为2,它指定了I/O指令的特权级。如果当前的特权级别在数值上小于或等于IOPL,那么I/O指令可执行。否则,将发生一个保护性故障中断;
NT(Nested Task):控制中断返回指令IRET,它宽度为1位。若NT=0,则用堆栈中保存的值恢复EFLAGSCSEIP从而实现中断返回;若NT=1,则通过任务切换实现中断返回。在ucore中,设置NT0

还有一些应用程序无法访问的控制寄存器,如CR0,CR2,CR3…,将在后续章节逐一讲解。