80386 和 保护模式
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
80386 和保护模式
___William Liu
Intel CPU 一般可以运行在两种模式之下,即实模式和保护模式。早期的 Intel CPU ( 8086 , 8088 )只能工作在实模式之下,系统中只能运行单个任务,而且只能使用实地址模式。对于 Intel 80386 以上的芯片则还可以运行在 32 位的保护模式之下。在保护模式之下的 CPU 可以支持多任务;支持 4GB 的物理内存;支持 64TB 的虚拟内存;支持内存的页式管理和段式管理以及支持特权级。
本文档将首先介绍 Intel 80386 CPU 的几个内部寄存器,然后再由浅入深的分别介绍保护模式下的段式管理,页式管理,虚拟内存,多任务以及特权级管理等几个方面。
Intel 80386 CPU 的内部寄存器
这一部分先大致介绍一下 386 的内部寄存器,具体细节在后面的几节中再详细说明。一般来说, CPU 设计用来系统编程的系统寄存器包括如下几类:
•标志寄存器 (EFLAGS)
•内存管理寄存器 (GDTR , LDTR , IDTR , TR)
•控制寄存器 (CR0 , CR1 , CR2 , CR3 , CR4)
•兼容 8086 通用寄存器( EAX , EBX , ECX , EDX )
•兼容 8086 段寄存器( CS , DS , ES , SS , FS , GS )
•兼容 8086 数据寄存器( ESI , EDI , EIP , ESP )
下面分别加以介绍:
1) 标志寄存器 EFLAGS :
跟 8086/8088 的 FLAGS 大致差不多。只不过位宽由 16bit 变成了 32bit ,负责的状态标志也多了一些。见图一所示:
图一: EFLAGS 的结构
其中系统标志: VM -虚拟 8086 模式; RF -恢复标志; NT -任务嵌套标志;IOPL - I/O 特权级标志; IF -中断允许标志。
2) 内存管理寄存器:
一共有 4 个,用于分段内存管理,都是用于存放指针的,只是所指的再内存单元中的内容有所不同。
GDTR 全局描述符表寄存器( Global Descriptor Table Register ),存放的是一个指向内存单元列表的指针,用于指向全局段描述表( GDT ),如图二所示。共 48bit ,高 32bit 是 GDT 的基址,低 16bit 描述 GDT 的长度。由于每项 8Byte ,所以共可以有 2^(16)/8=2^13 项。
IDTR 中断描述符表寄存器( Interrupt Descriptor Table Register ),存放的是也一个指向内存单元列表的指针,用于指向全局中断描述符表( IDT ),如图二所示。跟 GDTR 一样,共 48bit 。
LDTR 局部描述符表寄存器( Local Descriptor Table Register ),存放的是LDT 的段选择字。用于从 GDT 中索引出当前任务的局部描述符表( LDT ),如图二所示。共 16bit ,高 13bit 刚好可以索引到 GDT 的最大限长。 TI 位置1 , RPL 是请求特权级( Request Privilege Level )用于特权检查。
TR 任务寄存器( Task Register ),跟 LDTR 一样,存放的是任务状态段 TSS ( Task State Segment )的段选择字。用于从 GDT 中索引出当前任务的 TSS ,如图二所示。共 16bit 。
图二:系统内存管理寄存器
3) 系统控制寄存器:
386 CPU 共四个,分别是 CR0 、 CR1 、 CR2 、 CR3 , 486 以后又增设了 CR4 。如图三所示。
其中, CR0 是用于系统整体的控制。 CR1 保留。 CR2 用于保存页面转换时出错的线性地址。 CR3 存放页目录基址。 CR4 用于各种 CPU 级联相关。
图三:系统控制寄存器
需要注意的几个位是:
PE : CR0 的 0bit , Protect Enable 。使能 386 的保护模式。
PG : CR0 的 31bit , Paging 。 386 进入保护模式之后,启动分页机制。
Page-Directory Base : CR3 的 12 - 31bit 存放页目录首地址。每个任务只能唯一一个
Page-Fault Linear Address : CR2 线性地址错误。可以用于虚拟内存中
4) 与 8086 兼容的系列寄存器:
所有通用寄存器 EAX , EBX , ECX , EDX 和所有数据寄存器 EIP , ESP ,ESI , EDI 除了数据位由原来的 16bit 编程 32bit 外,功能基本没有变化。
当然为了保持对 16 位机的支持,你同样可以使用 AX , AH , AL , IP , SP ,SI , DI 等等
至于段寄存器 CS , DS , ES , FS , GS , SS 。你会发现名字都没有变化,事实上大小也是 16bit ,只是增加了几个。事实上, 386 在运行实模式时这些段寄存器跟 8086 是完全一样的。在运行于保护模式下时,他们同样用来指示段的地址,只不过里面存放的是段选择符,通过在 LDT 或者 GDT 中检索,间接的指示段地址。
保护模式下的段式管理
段式管理的目的是根据段基址值和段内数据的偏移值,生成数据在内存中的线性地址。在实模式中该线性地址既是实际的物理地址;在保护模式下,如果用户选择了使用分页管理机制,那么该线性地址还要经过页式变换才能生成最后的物理地址。
我们知道在实模式下:
物理地址=线性地址=段基址值(由段寄存器给出)× 16 +偏移地址
但是在保护模式下,就没有这么简单了 :P
在保护模式下,用户要使用段式管理,必须至少维护好一张 GDT 列表(通过 GDTR 来指示),和若干张 LDT 列表(可以没有)。如果我们要访问数据段中偏移值为 XX (放于 ESI 中)的变量。 CPU 的操作过程如下:
1 ) CPU 首先读取 DS 中的段选择字。注意这里 DS 中存放的不再是段基址了,而是保护模式下的段选择字,格式如图四所示(是不是觉得跟 LDTR 和 TR 的格式一样 ^_^ )