Intel 80386运行模式
一般CPU只有一种运行模式,能够支持多个程序在各自独立的内存空间中并发执行,
且有用户特权级和内核特权级的区分,让一般应用不能破坏操作系统内核和执行特权指令。
80386处理器有四种运行模式:实模式、保护模式、SMM模式和虚拟8086模式。
这里对涉及ucore的实模式、保护模式做一个简要介绍。
实模式
这是个人计算机早期的8086处理器采用的一种简单运行模式,
当时微软的MS-DOS操作系统主要就是运行在8086的实模式下。
80386加电启动后处于实模式运行状态,在这种状态下软件可访问的物理内存空间不能超过1MB,
且无法发挥Intel 80386以上级别的32位CPU的4GB内存管理能力。
实模式将整个物理内存看成分段的区域,程序代码和数据位于不同区域,
操作系统和用户程序并没有区别对待,而且每一个指针都是指向实际的物理地址。
这样用户程序的一个指针如果指向了操作系统区域或其他用户程序区域,
并修改了内容,那么其后果就很可能是灾难性的。
对于ucore其实没有必要涉及,这主要是Intel x86的向下兼容需求导致其一直存在。
其他一些CPU,比如ARM、MIPS等就没有实模式,
而是只有类似保护模式这样的CPU模式。
保护模式
保护模式的一个主要目标是确保应用程序无法对操作系统进行破坏。
实际上,80386就是通过在实模式下初始化控制寄存器(如GDTR,LDTR,IDTR与TR等管理寄存器)以及页表,
然后再通过设置CR0寄存器使其中的保护模式使能位置位,从而进入到80386的保护模式。
当80386工作在保护模式下的时候,其所有的32根地址线都可供寻址,物理寻址空间高达4GB。
在保护模式下,支持内存分页机制,提供了对虚拟内存的良好支持。
保护模式下80386支持多任务,还支持优先级机制,不同的程序可以运行在不同的特权级上。
特权级一共分0~3四个级别,操作系统运行在最高的特权级0上,应用程序则运行在比较低的级别上;
配合良好的检查机制后,既可以在任务间实现数据的安全共享也可以很好地隔离各个任务。
Intel 80386内存架构
地址是访问内存空间的索引。
一般而言,内存地址有两个:
一个是CPU通过总线访问物理内存用到的物理地址,
一个是我们编写的应用程序所用到的逻辑地址(也有人称为虚拟地址)。
比如如下C代码片段:
int boo=1;//变量
int* foo = &a;//a的地址
这里的boo是一个整型变量,
foo变量是一个指向a的地址的整型指针变量,
foo中储存的内容就是a的逻辑地址。
80386是32位的处理器,即可以寻址的物理内存地址空间为2^32=4G字节。
为更好理解面向80386处理器的ucore操作系统,
需要用到三个地址空间的概念:
物理地址、
线性地址和
逻辑地址。
物理内存地址
物理内存地址空间是处理器提交到总线上用于访问计算机系统中的内存和外设的最终地址。
一个计算机系统中只有一个物理地址空间.
线性地址空间
线性地址空间是80386处理器通过段(Segment)机制控制下的形成的地址空间。
在操作系统的管理下,每个运行的应用程序有相对独立的一个或多个内存空间段,
每个段有各自的起始地址和长度属性,
大小不固定,这样可让多个运行的应用程序之间相互隔离,实现对地址空间的保护。
在操作系统完成对80386处理器段机制的初始化和配置
(主要是需要操作系统通过特定的指令和操作建立全局描述符表,完成虚拟地址与线性地址的映射关系)后,
80386处理器的段管理功能单元负责把虚拟地址转换成线性地址,
在没有下面介绍的页机制启动的情况下,这个线性地址就是物理地址。
相对而言,段机制对大量应用程序分散地使用大内存的支持能力较弱。
所以Intel公司又加入了页机制,每个页的大小是固定的(一般为4KB),
也可完成对内存单元的安全保护,隔离,
且可有效支持大量应用程序分散地使用大内存的情况。
在操作系统完成对80386处理器页机制的初始化和配置
(主要是需要操作系统通过特定的指令和操作建立页表,完成虚拟地址与线性地址的映射关系)后,
应用程序看到的逻辑地址先被处理器中的段管理功能单元转换为线性地址,
然后再通过80386处理器中的页管理功能单元把线性地址转换成物理地址。
页机制和段机制有一定程度的功能重复,但Intel公司为了向下兼容等目标,使得这两者一直共存。
上述三种地址的关系如下:
分段机制启动、分页机制未启动:逻辑地址--->段机制处理--->线性地址=物理地址
分段机制和分页机制都启动:逻辑地址--->段机制处理--->线性地址--->页机制处理--->物理地址
Intel 80386寄存器
80386的寄存器可以分为8组:
通用寄存器,
段寄存器,
指令指针寄存器,
标志寄存器,
系统地址寄存器,
控制寄存器,
调试寄存器,
测试寄存器,
它们的宽度都是32位。
一般程序员看到的寄存器包括通用寄存器,段寄存器,指令指针寄存器,标志寄存器。
A. 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)。
它们的含义如下:
EAX:累加器
EBX:基址寄存器
ECX:计数器
EDX:数据寄存器
ESI:源地址指针寄存器
EDI:目的地址指针寄存器
EBP:基址指针寄存器
ESP:堆栈指针寄存器
![](https://i-blog.csdnimg.cn/blog_migrate/b2a90e504739e56c06637fad44563105.png)
B. Segment Register(段寄存器,也称 Segment Selector,段选择符,段选择子):
除了8086的4个段外(CS,DS,ES,SS),
80386还增加了两个段FS,GS,
这些段寄存器都是16位的,
用于不同属性内存段的寻址,它们的含义如下:
CS:代码段(Code Segment)
DS:数据段(Data Segment)
ES:附加数据段(Extra Segment)
SS:堆栈段(Stack Segment)
FS:附加段
GS: 附加段
![](https://i-blog.csdnimg.cn/blog_migrate/44ead46f21d75683bf4d0a21dff59914.png)
C. Instruction Pointer(指令指针寄存器):
EIP的低16位就是8086的IP,
它存储的是下一条要执行指令的内存地址,
在分段地址转换中,
表示指令的段内偏移地址。
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://i-blog.csdnimg.cn/blog_migrate/e0ca8516d5b397148b7621a04aeaf8ff.png)
Flag Register(标志寄存器):
EFLAGS,和8086的16位标志寄存器相比,
增加了4个控制位,
这20位控制/标志位的位置如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/7fa579e180fe8bd8f45ca0a91f0f84d8.png)
相关的控制/标志位含义是:
1. CF(Carry Flag): 进位标志位;
2. PF(Parity Flag): 奇偶标志位;
3. AF(Assistant Flag):辅助进位标志位;
4. ZF(Zero Flag): 零标志位;
5. SF(Singal Flag): 符号标志位;
6. IF(Interrupt Flag):中断允许标志位,由CLI,STI两条指令来控制;
设置IF位使CPU可识别外部(可屏蔽)中断请求,
复位IF位则禁止中断,
IF位对不可屏蔽外部中断和故障中断的识别没有任何作用;
7. DF(Direction Flag):向量标志位,由CLD,STD两条指令来控制;
8. OF(Overflow Flag): 溢出标志位;
9. IOPL(I/O Privilege Level):I/O特权级字段,它的宽度为2位,它指定了I/O指令的特权级。
如果当前的特权级别在数值上小于或等于IOPL,那么I/O指令可执行。
否则,将发生一个保护性故障中断;
a. NT(Nested Task):控制中断返回指令IRET,它宽度为1位。若NT=0,则用堆栈中保存的