第 10章 保护模式及其编程
10.1 保护模式基础
10.2 虚拟内存管理
10.3 特权级保护
10.4 任务
10.5 中断和异常
10.6 虚拟 8086模式
10.7 操作系统类指令
10.1 保护模式基础在保护模式下,
寻址高达 4GB的物理地址空间
支持存储器分段管理机制和分页管理机制
支持多任务
支持 4个特权级和配套的特权检查机制
区分不同级别的代码
10.1.1 32位 CPU内部结构
CPU有 8个处理单元:执行单元,分段单元,分页单元,总线单元,指令预取单元,指令译码单元,高速缓存单元和浮点运算单元 。
1.总线单元
总线单元是 CPU与存储器和 I/O的接口
总线接口对外提供,32位(或 64位)数据总线,32位(或 36位)地址总线以及控制总线
总线单元负责完成所有外部总线操作,
能够产生控制地址锁存器和数据总线收发器工作的控制信号。
2.指令预取单元指令预取单元实现指令流队列的机制
CPU可以预取 16字节的指令代码预取进来的指令要保存在 FIFO队列中
3.指令译码单元指令译码单元接收 FIFO队列的输出指令译码单元将接收到的机器代码指令译码为微代码指令,并供执行单元使用
4.执行单元执行单元取出译码后的指令并执行该操作,
包括:
算术逻辑单元 ALU
寄存器组
专用乘法器
移位器
控存( ROM)
5.分段和分页单元分段和分页单元负责地址产生、地址转换和对总线接口单元的段检查。
CPU存储器管理的分段单元用硬件进行高速地址计算,完成逻辑地址到线性地址的转换和保护性检查;
分页单元实现保护模式下的分页机制,它可以将线性地址转换成物理地址,并由总线单元输出。
6.浮点运算单元浮点运算单元集成在 80486及以上的 CPU中 ;
对于 80386,需要另外一个数学运算协处理器 80387来执行浮点运算。
7.高速缓存单元高速缓存单元将最近被访问的内存单元的内容保存在 CPU内部的 Cache中 。
下次访问这些内存单元时,CPU直接访问
Cache就可以存取这些单元的内容 。
由于 Cache的访问速度比内存快,高速缓存单元能够显著提高程序的运行速度 。
10.1.2 三种运行模式
CPU具有三种运行模式:实模式、保护模式和虚拟 8086模式,关系如下:
1.实模式
CPU被复位(加电)时,自动进入实模式。
实模式不支持硬件上的多任务切换
CPU不能对内存进行分页管理
实模式也不支持特权级
DOS操作系统运行于实模式下
2.保护模式实模式下对一系列的寄存器进行设置,就可以进入保护模式 。
CPU提供了段式和页式内存管理功能
CPU支持多任务和特权级
Windows/Linux操作系统运行于保护模式下
3.虚拟 8086模式虚拟 8086模式是为了在 Windows/Linux系统中执行 DOS程序而设计的,它是一种经过,修改,的保护模式。
4.特权级在保护模式下,CPU有 4个特权级( 0~ 3),
操作系统运行在高的特权级( 0) 上,而应用程序运行在低的特权级( 3) 上。
10.1.3 寄存器
32位 CPU支持的寄存器有以下几种:
1.通用 32位寄存器分别是,EAX,EBX,ECX,EDX,ESI,EDI,
EBP,ESP。
主要用于算术运算、逻辑运算以及对内存操作数的寻址。
2.标志寄存器标志寄存器 EFLAGS也扩展为 32位,位 11到位 0
和 8086完全相同。这里主要扩展了 4个标志位:
V86模式位 VM( 位 17)
此位为 1时,表示当前 CPU正工作在 V86模式下;
此位为 0,表示当前 CPU工作在实模式或保护模式下 。
嵌套任务位 N( 位 14)
当前的任务嵌套在其他任务中,此位为 1,否则为 0
恢复位 RF( 位 16)
I/O域 IOPL( 位 13和 12)
3.指令指针寄存器 EIP和堆栈指针寄存器 ESP
指令指针寄存器 EIP,它总是下一条要执行的指令的偏移地址,偏移地址指的是这条指令在代码段中的位置 。
堆栈指针寄存器 ESP,用于存放当前堆栈段中栈顶的偏移地址 。
他们的低 16位分别是 IP和 SP
4.调试寄存器 DR
调试寄存器提供高级的调试功能例如:可以设置一个数据断点,在程序访问某个数据时激活调试程序。
5.测试寄存器 TR
测试寄存器提供对 TLB的测试。
6.全局描述符表寄存器全局描述符表 GDT是用来定义全局存储器空间的一种机制,它用段描述符说明一个全局存储器中的段,每个 GDT最多含有
8192个描述符 ( 8192?8?64KB) 。
用全局描述符表寄存器 GDTR指出 GDT的位置和大小 。
GDTR是 48位的寄存器。其最低 16位是限长,
给出 GDT的字节大小;其高 32位是基址,
指出 GDT在物理存储器中存放的基地址。
例如,GDTR=0E003F0003FFH,则说明 GDT的地址为 0E003F000H,长度为 3FFH+1=400H。
其中可容纳 400H/8=80H个段描述符。
7.中断描述符表寄存器中断描述符表 IDT中保存着中断门描述符;
IDT最多包含 256个门描述符,CPU最多支持
256个中断 。
中断描述符表寄存器 IDTR是 48位的寄存器。
其最低 16位是限长,给出 IDT的字节大小;
其高 32位是基址,指出 IDT在物理存储器中存放的基地址。
中断描述符表寄存器例如:
IDTR=0E003F40007FFH,则说明 IDT的地址为 0E003F400H,长度为 7FFH+1=800H。 其中可容纳 800H/8=100H个中断门描述符 。
8.局部描述符表寄存器局部描述符表 LDT含有与系统中某一个任务相关的各个段的描述符;
局部描述符表寄存器 LDTR并不直接指出 LDT
的位置和大小,而是指向一个 LDT描述符,
由 LDT描述符指出 LDT的位置和大小。
9.任务寄存器 TR
任务寄存器 TR在保护模式的任务切换机制中使用。
TR是 16位的选择符,其内容为索引值,它选中的是 TSS描述符。
任务状态段 TSS中包含启动任务所必需的信息。它在存储器的基地址和限长(大小)由 TSS描述符指出,TSS描述符放在全局描述符表 GDT中,而 TR内容指出了 TSS描述符在 GDT中的顺序号。
10.控制寄存器存在着 4个系统控制寄存器 CR0~ CR3。 CR0的低 5
位是系统控制标志,被称为机器状态字 MSW。
MSW中各位的含意:
PE,保护模式允许标志
等于 0为实模,等于 1为保护模式
MP,运算协处理器存在位
等于 1表示系统中有运算协处理器 。
MSW中各位的含意(续)
EM,等于 1时系统用软件模拟器执行数学运算
TS,任务切换标志。
当任务切换时,自动设置此位为 1
PG:
等于 1时,存储器管理单元允许分页;
等于 0时,分页功能被关闭,线性地址等于物理地址。
11.段寄存器 CS,DS,ES,SS,FS,GS
32位 CPU有 6个段寄存器,比 16位 CPU增加了
FS和 GS两个段寄存器。
在实模式下,它们的用法和 16位 CPU相同
在保护模式下,段寄存器不直接存放段基址,
而是存放一个索引,由索引从 GDT或 LDT中找到段描述符,从而确定关于这个段的全部描述信息。这个索引被称为段选择符。
段寄存器(续)
选择符的格式 如下
RPL,请求特权级,2位二进制数字,求特权级是将要访问的段的特权级。
TI,表指示符。为 0时,从 GDT中选择描述符;
为 1时,从 LDT中选择描述符。
Index,索引。指出要访问描述符在段描述符表中的顺序号。
10.1.4 显示 CPU寄存器的值要取得 GDTR,IDTR,TR,LDT寄存器的值,
分别使用 SGDT,SIDT,STR,SLDT指令,
这些指令将寄存器的内容保存到内存单元中 。
程序举例,cpuregs.asm
10.2 虚拟内存管理如果程序要访问的内容不在内存中,CPU会产生一个异常,由操作系统的存储器管理程序来处理,将所需的内容装入内存中 。 这就是所谓的虚拟存储器,它并不完全是真正的内存空间,也称做虚拟内存 。
10.2.1 段式内存管理功能将虚拟地址转换为线性地址,由 CPU的分段部件完成。
虚拟地址:程序指令中使用的地址,由段和偏移两个部分组成
线性地址:段的基地址再加上偏移量
物理地址:从微处理器引脚上输出的地址信号
虚拟地址到线性地址,再到物理地址的转换过程
3.段描述符段描述符用于描述代码段、数据段和堆栈段。段描述符的格式如图,
段描述符段描述符位于 GDT或 LDT中,占 64位,
由以下几个部分组成:
段基址 ( 32位 )
限长 ( 20位 )
访问权限 ( 8位 )
属性 ( 4位 )
访问权限字节访问权限字节 定义如下
P,存在位
等于 1时表示该段己装入内存;
等于 0时表示该段没有在内存中,访问这个段会产生段异常。
DPL,描述符特权级,说明这个段的特权级访问权限字节
S,描述符类型位
为 1时,这个段为代码段、数据段或堆栈段;
为 0时,为系统段描述符。
E,可执行位,区分代码段和数据段
S=0且 E=1时,这是一个代码段,可执行。
S=0且 E=0时,这是一个数据段或堆栈段,不可执行。
E=0时,后面的两位为 ED和 W;
若 E=1时,后面的两位为 C和 R。
访问权限字节
ED,扩展方向位
为 0时,段从低地址向高地址扩展,偏移量小于等于限长。
为 1时,段从高地址向低地址扩展,偏移量必须大于限长。
W,写允许位
为 0时,不允许对这个数据段写入;
为 1时,允许对这个数据段写入。
访问权限字节
C,一致位
为 0时,这个段不是一致代码段
为 1时,这个段是一致代码段
R,读允许位
为 0时,不允许读这个段的内容
为 1时,允许读这个段的内容
A,访问位
为 1表示段已被访问过
为 0表示段未被访问过。
属性位属性位包括 G,D,AVL等
G,粒度位 。
G?1时,限长以页为单位;
G?0时,限长以字节为单位 。
D,默认操作数宽度 。
D?1时,为 32位数据操作段;
D?1时,为 16位数据操作段 。
AVL,可用位 。
这一位保留给操作系统或应用程序来使用段描述符高速缓存
在读写内存单元时,CPU需要检查段描述符的内容是否和当前操作相一致,CPU的运行效率极大地降低。为解决这个问题,CPU在内部设置了段描述符高速缓存。
在指令执行过程中,只有段寄存器的值发生改变时,才需要到 GDT或 LDT中装入段描述符。如果段寄存器的值不改变,高速缓存中的段描述符可以被直接引用,这样就避免了到主存中频繁读取段描述符。提高了 CPU的效率。
10.2.2 页式内存管理功能
段式内存管理是将形如 DS:[EBX]的虚拟地址,
由 DS的段基址再加上偏移部分,就得到了线性地址 。
分页管理将分段管理机制得到的线性地址转换为物理地址 。
使用分页机制的好处:
可以把每个活动任务当前所必需的少量页面放在内存中,而不必将整个段调入内存,从而提高了内存的使用效率 。
1.分页
页的长度固定为 4KB
页与页之间没有重叠
页式内存简化了存储器管理
不能充分地利用内存,会产生碎片
2.线性地址到物理地址的映射线性地址按页为单位映射到物理地址
每一个线性页面只能映射到一个物理页面上
多个线性页面可以映射到同一个物理页面上
3.线性地址转换为物理地址的过程
32位线性地址被划分为 3个部分:
页目录索引 ( 10位 ),对页目录的索引页表索引 ( 10位 ),对页表的索引字节索引 ( 12位 ),线性地址在页面内的偏移 。
线性地址转换为物理地址的过程图线性地址转换为物理地址的过程
以 PDBR的值作为页目录的基地址,定位到页目录 。
用线性地址中的页目录索引( 10位)在页目录表中找到一个页表描述符。
页表描述符的高 20位给出了页表的基地址 。
线性地址中的页表索引( 10位),指示了被访问的页在页表中的序号。
页描述符的高 20位给出了物理页面的基地址。
物理页面的基地址再加上线性地址中的 12位字节索引,
便得到 32位线性地址对应的 32位物理地址。
4.片内转换检测缓冲器 TLB
为了提高转换效率,CPU内部设置了片内转换检测缓冲器 TLB,其中保存了 32个页描述符,
它们都是最近使用过的。
在从线性地址转换为物理地址时,
如果线性地址的页描述符已在 TLB中,则无需再经二级转换就可以直接引用。
如果线性地址的页描述符没有在 TLB中,则需要访问页目录表和页表来取得页表描述符和页描述符,
最后将这个页描述符存在 TLB中。
5.页表项页表项就是在分页转换时用到的页表描述符和页描述符,它们都是 32位的,其格式:
页表项的低 12位提供保护功能和统计信息 。
U/S位,R/W位,P位实现页保护机制;
而 D位和 A位提供统计信息 。
页表项
U/S,用户 /管理员位
U/S=0时,只有操作系统程序可以访问该页,
而不允许用户程序访问
U/S=1时,允许用户程序访问该页
R/W,读写位
R/W?0,用户程序对页面只有读权限,不能写入;
R/W?1时,可读 /写页表项
P,存在位。
P=1,页表或页存在于物理内存中;
P=0,页表或页没有在物理内存中。
A,访问标志。
如果对某页表或页访问过,CPU设置页表项中的 A位为 1。
D,写入位。
D=1时表示对该页进行过写操作,
D=0时表示对该页还没有进行过写操作。
AVL占 3位,可以由操作系统使用
7,Pentium的 4MB页面
Pentium的页表项增加了 3个属性位,SIZ,PCD和
PWT。
SIZ( Size) 页尺寸位:
SIZ=0时,页面的大小为 4KB。
SIZ=1时,页面的大小为 4MB。
PCD位:
PCD=0时,允许页被缓存 ;
PCD=1时,禁止页被缓存 。
PWT位:
PWT=0时,使用回写策略;
PWT=1时,使用通写策略。
通写策略指的是指令将数据写到页面 Cache时,立即更新内存中的页面;
回写策略指的是指令将数据写到页面 Cache后就认为指令已经完成,以后再将页面 Cache中的数据更新到内存中。
8,Pentium的物理地址扩展功能第 5位 PAE位为 1时,就启动物理地址扩展功能
线性地址仍然为 32位,分为 4个部分:
PDPT索引 ( 2位 )
页目录索引 ( 9位 )
页表索引 ( 9位 )
字节索引 ( 12位 )
页表项,从原来的 4字节扩展为 8字节
页目录和页表的大小仍然为 4KB
PAE功能启用且 SIZ?1时,线性地址的格式如图
9,Pentium III的页面大小扩展功能
在分页状态下,PAE=0,PSE=1时,就启用了 PSE功能。
启用 PSE时,PAE功能必须关闭。
启用 PSE功能时,由页目录项中的 SIZ位(也称 PS位)来确定页面的大小。
10.3 特权级保护保护模式下设置了 0,1,2,3共 4个特权级,
以区分操作系统程序和应用程序。
可以阻止用户程序对操作系统的非法访问
保证高特权级的代码或数据不被低特权级的程序所破坏 。
10.3.1 对数据访问的保护
为段寄存器赋值时的检查
当前是否在物理存储器
段类型是否与目标段选择符类型一致
当前程序是否具有可以访问这个段的特权级
访问内存时的检查
操作数的偏移量是否超出段的边界
操作是否与段的保护属性匹配
10.3.2 对程序转移的保护
1,直接转移的保护
程序控制在同一代码段内转移时,只需要检查限长,保证程序转移后的目标地址不超过当前代码段的边界 。
如果要进行段间调用或跳转,则需使用远跳转或远调用指令,这时既要检查限长,还要检查特权级 CPL和 DPL 。
CPL=DPL,允许跳转和调用 。 转移后,CPL没有改变
CPL<DPL,禁止。高特权级的程序不能直接转移到低特权级的程序 ;
CPL>DPL,此时要检查段描述符的 C位。
如果 C位为 1,表示这是一致代码段,允许转移,
CPL并不改变。
如果 C位等于 0,则禁止转移。
2.间接转移的保护间接转移采用 JMP/CALL X:Y指令,
X指门选择符
10.3.3 门门可以看做是一种转换机构。门有 4种类型:
调用门 (用来改变任务或者程序的特权级别 )
调用门中包含了入口点的虚地址:
目标选择符
偏移量
任务门 (用来执行任务切换 )
中断门 (指出中断服务程序的入口地址 )
陷阱门 (指出中断服务程序的入口地址 )
1.系统描述符门描述符属于系统描述符,格式如下
16种系统描述符类型见书 352页
2.调用门调用门描述符中的参数计数值表示,
有多少个参数必须从主程序的堆栈复制到被调用子程序的堆栈。
在使用调用门时,CPU也要进行权限检查,
权限检查时要依据以下几个因素:
1.当前特权级 CPL
2.请求特权级 RPL
3,DPLGATE,即门描述符的 DPL
4.DPLCODE,即目标代码段描述符的 DPL
5.CCODE,即目标代码段描述符的 C位
使用 CALL指令时,CPU检查以下两个条件,
DPLGATE≥MAX ( CPL,RPL)
DPLCODE≤CPL
使用 JMP指令时,CPU检查以下两个条件,
DPLGATE≥MAX ( CPL,RPL)
CCODE为 1且 DPLCODE≤CPL 或 CCODE为 0且 DPLCODE= CPL
只有条件满足了才能使用调用门
10.4 任务完成某项功能的多个程序的集合称为任务
CPU允许系统中存在多个任务
任务能以分时的方式使各程序轮流执行,
用户感觉到所有的任务是在同时运行
在保护模式下每个任务是独立的
系统中至少存在一个任务
10.4.1 任务状态段每个任务都由两个部分组成:
任务执行环境 TES
任务执行环境包括一个代码段、堆栈段和数据段等,
任务在每一个特权级上执行时都有一个堆栈段
每个任务都有一个 LDT描述符表,构成一个局部地址空间,局部空间的数据和代码不能被其他任务访问。
任务状态段 TSS
2.任务状态段 TSS
TSS中保存了任务的各种状态信息
TSS描述符中规定了任务状态段的基地址和任务状态符的大小,格式如下:
TSS的基本格式
TSS的基本格式由 104字节( 000H~ 065H)
组成,这些字节可分为:
寄存器保存区域
内层堆栈指针区域
地址映射寄存器区域
链接字段
调试陷阱位 T
I/O许可位图寄存器保存区域
用于保存
通用寄存器
段寄存器
指令指针
标志寄存器
当 TSS对应的任务正在执行时,保存区域中的值是无意义的;
在当前任务挂起时,这些寄存器的当前值就保存在该区域。
内层堆栈指针区域
TSS的内层堆栈指针区域中有 3个堆栈指针,
分别指向 0级,1级和 2级堆栈的栈顶。
当特权级提升时,从 TSS中取出相应级别的堆栈指针装入 SS及 ESP寄存器,以切换到高特权级的堆栈,而原先 SS及 ESP的内容则保存在这个新的堆栈中。
当高特权级向低特权级转移时,CPU并不把高特权级的堆栈指针 SS:ESP保存到 TSS中。
地址映射寄存器区域
TSS中保存了任务的 CR3和 LDTR。
在任务切换时,处理器自动从新任务的 TSS
中取出这两个字段,分别装入到寄存器
CR3和 LDTR。
这样就改变了虚拟地址空间到物理地址空间的映射 。
链接字段链接字段位于在 TSS偏移 0开始的双字中,
其高 16位未用
低 16位保存前一任务的 TSS的选择符调试陷阱位 T
在 TSS内偏移 64H处的 16位是为任务提供的属性。最低位 T表示调试陷阱位 。
发生任务切换时,如果新任务的 T位为 1,那么在切换到新任务后,立即产生调试陷阱。
I/O许可位图任务使用的 I/O许可位图也存放在 TSS中,
以作为 TSS的扩展部分 。
在 TSS内偏移 66H处的字用于存放 I/O许可位图在 TSS内的偏移 ( 从 TSS的头开始计算 ) 。
10.4.2 任务切换
1,直接任务切换
段间跳转指令 JMP X:Y或段间调用指令 CALL
X:Y可以用来执行任务切换。
在中断 /异常或者执行 IRET指令时也可能发生任务切换。
2.间接任务切换
通过任务门可以进行任务的间接切换任务 A到 B的切换步骤
检查目标任务 B状态段的限长
把寄存器现场保存到当前任务 A的 TSS
把指示目标任务(任务 B) TSS的选择符装入 TR
寄存器中,同时把对应 TSS的描述符装入 TR的高速缓冲寄存器中
恢复当前任务(任务 B) 的寄存器现场
把 CR0中的 TS标志置为 1
任务 A到 B的切换步骤(续)
把 TSS中的 CS选择符的 RPL作为当前任务特权级,设置为 CPL
装载 LDTR寄存器
装载代码段寄存器 CS,堆栈段寄存器 SS
和各数据段寄存器及其高速缓冲寄存器。
任务内特权级变化时 TSS中堆栈指针的使用在特权级提升时:
TSS中相应的堆栈指针对 SS及 ESP寄存器进行初始化,建立起一个空栈
把低特权级程序的 SS及 ESP寄存器的值压入堆栈
从低特权级堆栈复制以双字为单位的调用参数到高特权级堆栈中
调用的返回地址被压入堆栈
RET指令及步骤
CALL指令不能向低特权级转移;
RET指令不能向高特权级转移。
RET指令所使用的返回地址的选择符也只能是代码段描述符,而不能是系统描述符或门描述符 。
执行,RETF n”指令时,步骤如下:
RET指令先从堆栈中弹出返回地址
为返回低特权级代码,跳过高特权级堆栈中的
RET指令(续)
参数,再从高特权级栈中弹出指向低特权级堆栈的指针,并装入 SS及 ESP,切换到低特权级堆栈。
调整 ESP,跳过主程序压入到低特权级堆栈的参数。
检查数据段寄存器 DS,ES,FS及 GS,以保证寻址的段在低特权级是可访问的 。
返回到主程序的下一条指令执行。
立即数 n规定了堆栈中要跳过的参数的字节数。
10.4.3 输入 /输出保护
CPU采用 I/O特权级 IOPL和 TSS段中 I/O许可位图的方法来控制输入 /输出,实现输入 /输出保护 。
1,I/O敏感指令
在 EFLAGS寄存器中,有两位是输入 /输出特权级 IOPL。 CPL≤IOPL 时,可以执行
I/O敏感指令。
EFLAGS标志寄存器中的 IOPL
任务状态段中的 I/O许可位图也影响 I/O
敏感指令的执行。
I/O敏感指令列表
2,I/O许可位图
I/O许可位图就是一个二进制位串
位串中的每一位对应一个 I/O地址
如果位串中的第 n位为 0,那么 I/O地址 n就可以由任何特权级的程序访问,而不加限制;
如果第 n位为 1,I/O地址 n只能由在 IOPL特权级或更高特权级运行的程序访问。
一条 I/O指令最多可涉及 4个 I/O地址
这条指令用到的所有 I/O地址的许可位都必须为 0,
才允许访问
3.对 IOPL的保护
EFLAGS中的 IOPL,VM和 IF位不能随便更改
只有在高特权级程序中执行的 IRET,POPF,
CLI和 STI等指令才能改变它们,如图
10.4.4 编写驱动程序修改 I/O位图
修改任务 I/O位图的内核驱动程序 举例:
giveio.c
执行过程见书 368页。
10.5 中断和异常
中断分为内部中断和外部中断两大类。
外部中断通常称为,中断,;
内部中断通常称为,异常,;
通常在两条指令之间响应中断或异常;
CPU最多处理 256种中断或异常。
10.5.1 中断和异常的类型
1,中断
中断是由异步的外部事件引起的,
中断信号来自于 CPU外部
CPU有两根引脚 INTR和 NMI接受外部中断请求信号 。
INTR接受可屏蔽中断请求
NMI接受不可屏蔽中断请求
标志寄存器 EFLAGS中的 IF标志决定是否响应
INTR的中断请求
IF=0时,CPU不响应 INTR信号
CPU在响应中断请求时,从外部硬件读出一个 8位的中断类型号,来区分外部中断的来源 。
对来自 NMI的中断请求,CPU不检查 IF标志 。
在响应 NMI中断时,不从外部硬件接收中断类型号,
其中断类型号固定为 2。
2,异常
异常是 CPU在执行指令期间检测到不正常的或非法的操作所引起的
发生异常时,在对该异常处理完毕前,引起该异常的指令就不能成功地被执行 ;
异常发生后,处理器,根据异常号码,转到相应的异常处理程序。
根据引起异常的程序是否可被恢复和恢复点的不同,把异常分为:
故障
陷阱
中止故障
故障是在引起异常的指令之前,把异常情况通知给系统的一种异常。
故障是可排除的。
当控制转移到故障处理程序时,在堆栈中保存的断点 CS及 EIP的值指向引起故障的指令。
在故障排除后,执行 IRET可以返回到引起故障的程序。
陷阱
陷阱是在引起异常的指令执行之后触发的一种异常。
陷阱处理后,要返回到引起陷阱的指令的下一条指令。
中止
中止是在系统出现严重的不可恢复的事件时触发的一种异常。
产生中止后,系统要重新启动才能恢复正常运行状态。
2.异常类型号
每一种异常被赋予一个异常类型号
某些异常以出错码的形式提供一些附加信息传递给异常处理程序
一个号码如果已经作为异常类型号,就不能再作为中断类型号使用。
异常类型号列表见书 371页
3.故障类异常
( 1)除法出错故障(异常 0)
当执行 DIV指令或 IDIV指令时,如果除数等于 0或者除数太小,以至于得到的商超过了操作数能容纳的范围,那么就产生这一故障。
除法出错故障没有出错码。
( 2)边界检查故障(异常 5)
如果 BOUND指令发现被测试的值超过了指令中给定的范围,那么就发生边界检查故障 。
边界检查故障不提供出错码 。
故障类异常
( 3)非法操作码故障(异常 6)
如果 CS和 EIP所指向的不是一个合法的指令,那么就发生非法操作码故障。 有下列情况:
操作码字段的内容不是一个合法的 CPU指令代码;
要求使用内存操作数的场合,使用了寄存器操作数;
不能被加锁的指令前使用了 LOCK前缀 。 非法操作码故障不提供操作码 。
故障类异常
( 4)无浮点处理器故障(异常 7)
这个故障用来模拟数字协处理器。
该故障在下列两种情况下产生:
执行浮点指令时,控制寄存器 CR0中的 EM位或 TS位为 1;
执行 WAIT指令时,控制寄存器 CR0中 TS位及 EM位都为 1。
EM位为 1,CPU必须用整数指令来模拟符点计算;
TS位为 1,CPU必须将上一个任务的浮点运算现场保存起来,再恢复当前任务浮点运算的现场 。
故障类异常
( 5)无效 TSS故障(异常 0AH)
当发生任务切换时,需要使用任务状态段 TSS。
如果当前程序的特权级不能访问该 TSS,或者 TSS
中保存的 LDTR,CS,DS等寄存器不正确,就发生无效 TSS故障。
无效 TSS故障提供了一个出错码,格式故障类异常
高 13位是选择符的索引部分;
TI位是选择符的 TI位;
EXT位等于 1时,表示故障由外部事件引起 。
IDT位等于 1时,表示故障由于读取 IDT表引起 。
引起无效 TSS故障的原因如下:
TSS描述符中的段限长小于 103;
无效的 LDT描述符,或者 LDT描述符的 P位为 0;
堆栈段不是一个可写段;
堆栈段选择符索引的描述符超出描述符表界限;
故障类异常
引起无效 TSS故障的原因如下 ( 续 ),
堆栈段 DPL与新的 CPL不匹配;
堆栈段选择符的 RPL不等于 CPL;
代码段选择符索引的描述符超出描述符表界限;
代码段选择符不指向代码段;
非一致代码段的 DPL不等于新的 CPL;
一致代码段的 DPL大于新的 CPL;
对应 DS,ES,FS或 GS的选择符指向一个不可读段
( 如系统段 ) ;
对应 DS,ES,FS或 GS的选择符索引的描述符超出描述符表的界限 。
故障类异常
( 6)段不存在故障(异常 0BH)
在给 CS,DS,ES,FS或 GS赋值时(不含 SS),
如果发现这些段寄存器指向的段描述符其他字段的值有效,而 P位为 0,产生段不存在故障。
段不存在故障提供了一个包含引起该故障的段选择符的出错代码。
故障类异常
( 7) 堆栈段故障 ( 异常 0CH)
当处理器检测到与 SS段有关的问题时,就发生堆栈段故障 。 出现故障的情况如下:
在堆栈操作时,偏移超出段界限所规定的范围 。
出错码为 0。
在由特权级变换所引起的对高特权级堆栈的操作时,
偏移超出段界限所规定的范围,高特权级堆栈段的段描述符中的 P位为 1。
此时出错码中包含高特权级堆栈的选择符 。
装入到 SS寄存器的段描述符中的 P位为 0。
此时出错码中包含有对应的选择符 。
故障类异常
( 8)通用保护故障(异常 0DH)
除了明确列出的段异常外,其他的段异常都被视为通用保护故障。
通用保护故障可分为如下两类:
违反保护方式,但程序无需中止的异常。
出错码为 0
违反保护方式,并导致程序终止的异常。
出错码可能为 0,也可能不为 0。
故障类异常
( 9)页故障(异常 0EH)
启用分页机制后,线性地址要经过分页机制转换才能成为物理地址。转换过程中出现异常的原因:
页目录表项或页表项中的 P=0,对应的物理页不在内存中;
发现试图违反页保护属性 ( U/S,R/W) 的规定而对页进行访问 。
提供出错码故障类异常
( 10) 协处理器出错 ( 异常 10H)
协处理器出错故障指示协处理器发生了未被屏蔽的数字错误,如上溢或下溢。
协处理器出错故障不提供出错码。
4.陷阱类异常
调试陷阱
断点陷阱
溢出调试陷阱调试异常有故障类型,也有陷阱类型调试异常不提供出错码。几种陷阱如下:
断点陷阱
调试程序可利用,INT 3”指令实现程序断点。
,INT 3”指令被看成是一种陷阱,而不是一个故障。
,INT 3”陷阱不提供出错码。
溢出
INTO指令提供有条件的陷阱,
如果 OF标志为 1,那么 INTO指令产生陷阱;
否则不产生陷阱,继续执行 INTO后面的指令。
溢出陷阱不提供出错码。
5.中止类异常
( 1)双重故障异常(异常 8)
当系统正在处理一个异常时,如果又遇到另一个不能处理的异常,CPU就产生一个双重故障,
双重故障属于中止类异常,出错码为 0。
当正处理一个段故障异常时,又产生一个页故障。
这时通知给系统的是一个页故障异常。
如果正在处理一个段故障或页故障时,又一个段故障被检测到,或者如果正处理一个页故障时,又一个页故障被检测到,那么就引起双重故障。
中止类异常双重故障通常指示系统表出现严重的问题,需要重启系统。
( 2)协处理器段越界(异常 9)
协处理器段越界异常也属于中止类异常,引起该异常的指令不能被重新执行。
当浮点指令操作数超出段界限时,产生该异常。
协处理器段越界异常不提供出错码。
10.5.2 中断门和陷阱门
中断描述符表 IDT所含的描述符只能是中断门、陷阱门和任务门。
中断门中断门和陷阱门
陷阱门
任务门前面已有介绍。
10.5.3 中断和异常的处理过程在中断或异常产生后,CPU依据中断类型号或异常号进行中断响应或异常处理 。 步骤如下:
( 1) 如果是异常处理,首先根据异常类型确定返回地址 。 如果有出错代码,则按照出错码格式构造出错码,并把出错码压入堆栈 。
对于故障,CS:EIP指向引起故障的指令;
对于陷阱,CS:EIP指向引起陷阱的指令的下一条指令 。
中断和异常的处理过程
( 2)判断中断类型号要索引的门描述符是否超出 IDT的界限。
若超出界限,就触发通用保护故障,出错码如右:
( 3)再从 IDT中取得对应的门描述符,分解出选择符、偏移量和属性字节,并进行有关检查。
中断和异常的处理过程
如果是由 INT n指令或 INTO指令引起转移,还要检查该描述符中的 DPL是否满足 CPL≤DPL GATE;
对于其他的异常或中断,则不检查 CPL≤DPL GATE条件。
( 4)根据门描述符类型,分别转入中断或异常处理程序。
如果门描述符是中断门或陷阱门,那么控制转移到当前任务的一个处理程序过程,并且可以变换特权级,从中断门和陷阱门中获取指向处理程序的 48位地址指针( 16位段,32位偏移)。
如果门描述符是任务门,后面的章节会讲到。
中断和异常的处理过程取得 48位地址指针后,CPU执行以下步骤:
( 1)若段选择符为 0,则产生通用保护故障;
( 2)在 GDT/LDT中取对应的描述符;
( 3)若描述符不是一个代码段描述符,则产生通用保护故障;
( 4)若代码段( C?0) 且 DPL>CPL,则产生通用保护故障;
( 5)调整段选择符的 RPL?0( 不修改门中的段选择符,在 CPU内部调整);
中断和异常的处理过程
( 6) 把段选择符装入 CS;
( 7) 若偏移超过段长,则产生通用保护故障;
( 8) EFLAGS压入堆栈;
( 9) CS压入堆栈; EIP压入堆栈;这里的
CS:EIP是指中断 /异常的返回地址;
( 10) 置 TF?0,NT?0;
( 11) 若为中断门,则使 IF?0;
( 12) 若有出错码,则把出错码压入堆栈;
( 13) 把偏移装入 EIP,跳转到处理程序 。
中断和异常的处理过程
中断或异常可以转移到同一特权级或高特权级。
是否要转移到高特权级,由代码段的描述符中的类型( C位)及 DPL字段决定:
如果 C位 =1(一致性代码段),则不改变特权级。
如果 C位 =0(非一致性代码段)且 DPL<CPL,则特权级提升。
如果 C位 =0且 DPL=CPL,则不改变特权级。
如果 C位 =0且 DPL>CPL,产生通用保护异常,因为不能通过中断或异常而降低特权级。
中断和异常的处理过程通过中断门的转移和通过陷阱门的转移之间的差别只是对 IF标志的处理。
对于中断门,在转移过程中把 IF置为 0;
对于陷阱门,在转移过程中保持 IF位不变。
中断和异常的处理过程在有出错码的情况下,转入处理程序之前还要把出错码压入堆栈。下面给出四种情况:
第 1,3种情况没有出错码;
第 2,4种情况有出错码。
10.5.4 通过任务门的转移如果以中断类型号为索引,在中断描述符中取出的是一个任务门描述符,那么控制转移到新的任务。
将任务门放在 IDT表中,在响应对应的中断或异常时,可根据该任务门实现任务的自动调度。
这种任务调度由 CPU直接执行,速度快,开销小。
各种转移方式的比较第一种情况(使用中断门或陷阱门 )
没有进行任务切换
对当前任务的状态可直接进行访问
处理程序必须存在于当前任务的地址空间中第二种情况(使用任务门)
要进行任务切换
转移到处理程序要花费较长时间
访问原任务的状态较为复杂
3.中断或异常处理后的返回指令 IRET用于从中断或异常处理程序中返回。
该指令的执行根据任务嵌套标志 NT位是否为 1分为两种情形,
NT位为 1时,IRET执行的是嵌套任务的返回。
这种情形在通过任务门转入的处理程序返回时出现。
NT位为 0时,IRET执行的是当前任务内的返回。
这种情形在通过中断门或陷阱门转入的处理程序返回时出现
4.各种转移途径的总结
JMP,CALL,INT和 IRET指令都可以引起任务切换 。
这些切换是主动的任务切换;
在执行这些指令时,转移到一个新的任务 。
中断和异常引起的任务切换是被动的任务切换 。
可能在程序执行的任何时候发生 。
任务内特权级变换的途径如下图
任务内相同特权级转移 如下图
10.5.5 结构化异常处理
构化异常处理,是 Windows操作系统提供处理程序错误或异常的机制。
例如 C/C++中的 _try{},_finally{}和
_try{},_except {}等功能举例:
C语言的结构化异常处理程序 seh.c
汇编程序捕获并处理异常程序 except.asm
10.6 虚拟 8086模式
V86模式是保护模式下的一种工作方式。
寻址的地址空间是 1MB,地址为 20位;
程序中使用的内存地址由两部分构成,16位段和 16位偏移。
在保护模式下,当标志寄存器 EFLAGS中的 VM位为 1时,处理器就处于 V86模式。
1.虚拟 8086任务
V86监控程序和在 V86模式下的 8086程序构成的任务称为虚拟 8086任务,即 V86任务。
V86任务形成一个由处理器硬件和监控程序组成的,虚拟 8086” 。
V86监控程序控制 V86外部界面、中断和 I/O。
CPU把 V86任务作为与其他任务具有同等地位的一个任务。
V86任务中,V86程序在 V86模式下运行,而 V86
监控程序在保护模式下运行
2.内存映射
在 V86模式下,程序只能使用 1MB的内存。
由段值乘以 16加上偏移构成 20位地址,
这是线性地址。经过转换后,得到物理地址。
CPU可同时运行多个 V86任务,这些任务的内存被映射到不同的物理内存上,相互之间互不影响。
3,V86模式下的敏感指令
指令 CLI和 STI的敏感条件不变,如果
IOPL<3,那么执行 CLI或 STI指令将引起通用保护故障。
输入 /输出指令 IN,INS,OUT或 OUTS是否执行由 I/O许可位图对应位决定。如果输入 /输出指令所使用的 I/O地址对应的 I/O
许可位图内的各位都为 0,则输入输出指令可正常执行,否则引起通用保护故障。
10.6.2 虚拟 8086模式的进入和退出保护模式和 V86模式之间的切换如图虚拟 8086模式的进入和退出离开 V86模式 ( 2种 )
在 V86任务内离开 V86模式
任务切换离开 V86模式进入 V86模式 ( 2种 )
通过 IRET指令进入 V86模式
通过任务切换进入 zV86模式
10.7 操作系统类指令系统指令可分为以下几类:
在实模式和任何特权级下可执行的指令
仅在实模式及特权级 0下可执行的指令
仅在保护模式下可执行的指令课本 394和 395页列出了这些指令
10.7.1 在实模式和任何特权级下可执行的指令
1,读取全局描述符表寄存器指令格式,SGDT QWORD PTR DST
功能:把全局描述符表寄存器 GDTR的内容保存到内存单元 DST。
说明:
DST是 48位的内存操作数 。
GDTR中的 16位限长存入 DST的低字,而 32位基地址存入 DST的高双字 。
在实模式和任何特权级下可执行的指令
2,读取中断描述符表寄存器指令格式,SIDT QWORD PTR DST
功能:把中断描述符表寄存器 GDTR的内容保存到内存单元 DST。
说明:
DST是 48位的内存操作数 。
IDTR中的 16位限长存入 DST的低字,而 32位基地址存入 DST的高双字 。
在实模式和任何特权级下可执行的指令
3,读取机器状态字指令格式,SMSW DST
功能:把机器状态字的内容保存到内存单元或寄存器中 。
说明:
DST可以是 16位的内存操作数或寄存器;
机器状态字是 CR0的低 16位 。
在实模式和任何特权级下可执行的指令
4,读取性能计数器指令格式,RDPMC
功能:读取由 ECX指定的 40位时间戳计数器,
放入 EDX:EAX中 。
说明,EDX存放模式寄存器的高 8位,EAX存放模式寄存器的低 32位 。
10.7.2 仅在实模式及特权级 0下可执行的指令
1,清任务切换标志指令格式,CLTS
功能:把 CR0控制寄存器中的 TS标志清零 。
说明,TS标志置为 1,表示已发生过任务切换,
在当前任务使用协处理器指令时,产生陷阱 。
由陷阱处理程序完成协处理器现场的保存和恢复,随后执行 CLTS指令清除 TS标志,使得当前任务后续使用的协处理器指令不再产生故障 。
仅在实模式及特权级 0下可执行的指令(续)
2,暂停指令格式,HLT
功能:使处理器暂停执行 。
说明:系统进入暂停状态后,只有接收到一个外部中断或系统复位信号,才能离开暂停状态 。
仅在实模式及特权级 0下可执行的指令(续)
3,设置全局描述符表寄存器指令格式,LGDT QWORD PTR SRC
功能:把存储器中的 6字节内容装入到全局描述符表寄存器 GDTR中 。
说明,SRC是 48位内存操作数 。
仅在实模式及特权级 0下可执行的指令(续)
4,设置中断描述符表寄存器指令格式,LIDT QWORD PTR SRC
功能:把存储器中的 6字节内容装入到中断描述符表寄存器 IDTR中 。
说明,SRC是 48位内存操作数仅在实模式及特权级 0下可执行的指令(续)
5,设置机器状态字指令格式,LMSW DST
功能:把 DST的内容装载到机器状态字 。
说明:
DST是 16位的内存操作数或寄存器 。
该指令可将机器状态字中的 PE位置为 1,以进入保护模式 。
可以通过给 CR0赋值的方法来设置机器状态字 。
仅在实模式及特权级 0下可执行的指令(续)
6,系统寄存器数据传送指令格式,MOV DST,SRC
功能:实现控制寄存器 /调试寄存器 /测试寄存器和 32位通用寄存器之间的数据传送 。
说明,SRC和 DST中有一个是通用寄存器另一个是控制寄存器,调试寄存器或者调试寄存器 。
10.7.3 仅在保护模式下可执行的指令
1.设置局部描述符表寄存器指令格式,LLDT SRC
功能:把 SRC中的内容作为指示局部描述符表 LDT
的选择符装入到 LDTR寄存器 。
说明:
SRC可以是 16位通用寄存器或存储单元 。
该指令只能在特权级 0执行 。
仅在保护模式下可执行的指令(续)
2,读取局部描述符表寄存器指令格式,SLDT DST
功能:把局部描述符表寄存器 LDTR的内容存储到存储单元 DST中说明:操作数 DST可以是 16位通用寄存器或存储单元 。
仅在保护模式下可执行的指令(续 )
3,设置任务寄存器指令格式,LTR SRC
功能:将 SRC的内容作为选择符装载到任务寄存器 TR。
说明:
SRC可以是 16位通用寄存器或存储单元 。
该指令只能在特权级 0下执行 。
仅在保护模式下可执行的指令(续)
4,读取任务寄存器指令格式,STR DST
功能:把 TR中的选择符存储到 DST。
说明:
DST可以是 16位通用寄存器或存储单元 。
TR中的值总是当前任务的 TSS状态段的选择符 。
仅在保护模式下可执行的指令(续)
5,调整请求特权级指令格式,ARPL OPRD1,OPRD2
功能:根据 OPRD2选择符来调整 OPRD1选择符的请求特权级,即 RPL。
说明,OPRD1可以是 16位通用寄存器或存储单元,OPRD2是 16位通用寄存器仅在保护模式下可执行的指令(续)
6,读取存取权限指令格式,LAR OPRD1,OPRD2
功能:将 OPRD2选择符指向的描述符内的属性字段装入 OPRD1。
说明:
OPRD1可以是 16位或 32位通用寄存器,OPRD2
是 16位或 32位通用寄存器或存储单元 。
OPRD1和 OPRD2的大小必须一致 。
仅在保护模式下可执行的指令(续)
7,读取段界限指令格式,LSL OPRD1,OPRD2
功能:将 OPRD2选择符指向的描述符内的限长装入 OPRD1。
说明:
OPRD1可以是 16位或 32位通用寄存器,OPRD2
是 16位或 32位通用寄存器或存储单元 。
OPRD1和 OPRD2的尺寸必须一致 。
仅在保护模式下可执行的指令(续)
8,读检验指令格式,VERR OPRD
功能:判断 OPRD选择符的段是否可读 。
说明,OPRD可以是 16位通用寄存器或存储单元,也可以是 32位通用寄存器或存储单元 。
仅在保护模式下可执行的指令(续)
9,写检验指令格式,VERW OPRD
功能:判断 OPRD选择符的段是否可写 。 说明,OPRD可以是 16位通用寄存器或存储单元,也可以是 32位通用寄存器或存储单元 。
仅在保护模式下可执行的指令(续)
10,不写回方式清除 Cache项指令格式,INVD
功能:清除 CPU内的指令 Cache和数据 Cache,
并且向外部 Cache电路发送一个特殊的总线信号,迫使它也清除 Cache。 CPU内的
Cache不写回到内存中仅在保护模式下可执行的指令(续)
11,写回方式清除 Cache项指令格式,WBINVD
功能:清除 CPU内的指令 Cache和数据 Cache,并且向外部 Cache电路发送一个特殊的总线信号,
迫使它也清除 Cache。 CPU内的 Cache写回到内存中 。
说明:
执行这个指令会清空 Cache项,Cache中的内容写回到内存中 。
WBINVD指令只能在保护模式的特权级 0下执行 。
仅在保护模式下可执行的指令(续)
12,清除 TLB表项指令格式,INVLPG OPRD
功能,CPU的 TLB保存最近使用过的 32个页表项 。
说明:
INVLPG指令首先找到内存操作数 OPRD所在的物理内存页面,再将该页面的 TLB表项 Cache清除掉 。
INVLPG指令只能在保护模式的特权级 0下执行 。
仅在保护模式下可执行的指令(续)
13,退出系统管理模式指令格式,RSM
功能:使 CPU退出系统管理模式 。
仅在保护模式下可执行的指令(续)
14,读取模式寄存器指令格式,RDMSR
功能:读取由 ECX指定的 64位模式寄存器,
放入 EDX:EAX中 。
说明,EDX存放模式寄存器的高 32位,EAX
存放模式寄存器的低 32位 。
仅在保护模式下可执行的指令(续)
15,设置模式寄存器指令格式,WRMSR
功能:将 EDX:EAX写入 ECX指定的模式寄存器 。
说明,EDX存放模式寄存器的高 32位,EAX
存放模式寄存器的低 32位 。
仅在保护模式下可执行的指令(续)
16,读取性能计数器指令格式,RDTSC
功能:读取 64位时间戳计数器,放入
EDX:EAX中 。
说明,EDX存放时间戳计数器的高 32位,
EAX存放时间戳计数器的低 32位 。
仅在保护模式下可执行的指令(续)
17,锁总线指令前缀格式,LOCK
功能:使后续的一条指令能独占总线 。
说明,LOCK前缀通常和 BTS一起使用
10.1 保护模式基础
10.2 虚拟内存管理
10.3 特权级保护
10.4 任务
10.5 中断和异常
10.6 虚拟 8086模式
10.7 操作系统类指令
10.1 保护模式基础在保护模式下,
寻址高达 4GB的物理地址空间
支持存储器分段管理机制和分页管理机制
支持多任务
支持 4个特权级和配套的特权检查机制
区分不同级别的代码
10.1.1 32位 CPU内部结构
CPU有 8个处理单元:执行单元,分段单元,分页单元,总线单元,指令预取单元,指令译码单元,高速缓存单元和浮点运算单元 。
1.总线单元
总线单元是 CPU与存储器和 I/O的接口
总线接口对外提供,32位(或 64位)数据总线,32位(或 36位)地址总线以及控制总线
总线单元负责完成所有外部总线操作,
能够产生控制地址锁存器和数据总线收发器工作的控制信号。
2.指令预取单元指令预取单元实现指令流队列的机制
CPU可以预取 16字节的指令代码预取进来的指令要保存在 FIFO队列中
3.指令译码单元指令译码单元接收 FIFO队列的输出指令译码单元将接收到的机器代码指令译码为微代码指令,并供执行单元使用
4.执行单元执行单元取出译码后的指令并执行该操作,
包括:
算术逻辑单元 ALU
寄存器组
专用乘法器
移位器
控存( ROM)
5.分段和分页单元分段和分页单元负责地址产生、地址转换和对总线接口单元的段检查。
CPU存储器管理的分段单元用硬件进行高速地址计算,完成逻辑地址到线性地址的转换和保护性检查;
分页单元实现保护模式下的分页机制,它可以将线性地址转换成物理地址,并由总线单元输出。
6.浮点运算单元浮点运算单元集成在 80486及以上的 CPU中 ;
对于 80386,需要另外一个数学运算协处理器 80387来执行浮点运算。
7.高速缓存单元高速缓存单元将最近被访问的内存单元的内容保存在 CPU内部的 Cache中 。
下次访问这些内存单元时,CPU直接访问
Cache就可以存取这些单元的内容 。
由于 Cache的访问速度比内存快,高速缓存单元能够显著提高程序的运行速度 。
10.1.2 三种运行模式
CPU具有三种运行模式:实模式、保护模式和虚拟 8086模式,关系如下:
1.实模式
CPU被复位(加电)时,自动进入实模式。
实模式不支持硬件上的多任务切换
CPU不能对内存进行分页管理
实模式也不支持特权级
DOS操作系统运行于实模式下
2.保护模式实模式下对一系列的寄存器进行设置,就可以进入保护模式 。
CPU提供了段式和页式内存管理功能
CPU支持多任务和特权级
Windows/Linux操作系统运行于保护模式下
3.虚拟 8086模式虚拟 8086模式是为了在 Windows/Linux系统中执行 DOS程序而设计的,它是一种经过,修改,的保护模式。
4.特权级在保护模式下,CPU有 4个特权级( 0~ 3),
操作系统运行在高的特权级( 0) 上,而应用程序运行在低的特权级( 3) 上。
10.1.3 寄存器
32位 CPU支持的寄存器有以下几种:
1.通用 32位寄存器分别是,EAX,EBX,ECX,EDX,ESI,EDI,
EBP,ESP。
主要用于算术运算、逻辑运算以及对内存操作数的寻址。
2.标志寄存器标志寄存器 EFLAGS也扩展为 32位,位 11到位 0
和 8086完全相同。这里主要扩展了 4个标志位:
V86模式位 VM( 位 17)
此位为 1时,表示当前 CPU正工作在 V86模式下;
此位为 0,表示当前 CPU工作在实模式或保护模式下 。
嵌套任务位 N( 位 14)
当前的任务嵌套在其他任务中,此位为 1,否则为 0
恢复位 RF( 位 16)
I/O域 IOPL( 位 13和 12)
3.指令指针寄存器 EIP和堆栈指针寄存器 ESP
指令指针寄存器 EIP,它总是下一条要执行的指令的偏移地址,偏移地址指的是这条指令在代码段中的位置 。
堆栈指针寄存器 ESP,用于存放当前堆栈段中栈顶的偏移地址 。
他们的低 16位分别是 IP和 SP
4.调试寄存器 DR
调试寄存器提供高级的调试功能例如:可以设置一个数据断点,在程序访问某个数据时激活调试程序。
5.测试寄存器 TR
测试寄存器提供对 TLB的测试。
6.全局描述符表寄存器全局描述符表 GDT是用来定义全局存储器空间的一种机制,它用段描述符说明一个全局存储器中的段,每个 GDT最多含有
8192个描述符 ( 8192?8?64KB) 。
用全局描述符表寄存器 GDTR指出 GDT的位置和大小 。
GDTR是 48位的寄存器。其最低 16位是限长,
给出 GDT的字节大小;其高 32位是基址,
指出 GDT在物理存储器中存放的基地址。
例如,GDTR=0E003F0003FFH,则说明 GDT的地址为 0E003F000H,长度为 3FFH+1=400H。
其中可容纳 400H/8=80H个段描述符。
7.中断描述符表寄存器中断描述符表 IDT中保存着中断门描述符;
IDT最多包含 256个门描述符,CPU最多支持
256个中断 。
中断描述符表寄存器 IDTR是 48位的寄存器。
其最低 16位是限长,给出 IDT的字节大小;
其高 32位是基址,指出 IDT在物理存储器中存放的基地址。
中断描述符表寄存器例如:
IDTR=0E003F40007FFH,则说明 IDT的地址为 0E003F400H,长度为 7FFH+1=800H。 其中可容纳 800H/8=100H个中断门描述符 。
8.局部描述符表寄存器局部描述符表 LDT含有与系统中某一个任务相关的各个段的描述符;
局部描述符表寄存器 LDTR并不直接指出 LDT
的位置和大小,而是指向一个 LDT描述符,
由 LDT描述符指出 LDT的位置和大小。
9.任务寄存器 TR
任务寄存器 TR在保护模式的任务切换机制中使用。
TR是 16位的选择符,其内容为索引值,它选中的是 TSS描述符。
任务状态段 TSS中包含启动任务所必需的信息。它在存储器的基地址和限长(大小)由 TSS描述符指出,TSS描述符放在全局描述符表 GDT中,而 TR内容指出了 TSS描述符在 GDT中的顺序号。
10.控制寄存器存在着 4个系统控制寄存器 CR0~ CR3。 CR0的低 5
位是系统控制标志,被称为机器状态字 MSW。
MSW中各位的含意:
PE,保护模式允许标志
等于 0为实模,等于 1为保护模式
MP,运算协处理器存在位
等于 1表示系统中有运算协处理器 。
MSW中各位的含意(续)
EM,等于 1时系统用软件模拟器执行数学运算
TS,任务切换标志。
当任务切换时,自动设置此位为 1
PG:
等于 1时,存储器管理单元允许分页;
等于 0时,分页功能被关闭,线性地址等于物理地址。
11.段寄存器 CS,DS,ES,SS,FS,GS
32位 CPU有 6个段寄存器,比 16位 CPU增加了
FS和 GS两个段寄存器。
在实模式下,它们的用法和 16位 CPU相同
在保护模式下,段寄存器不直接存放段基址,
而是存放一个索引,由索引从 GDT或 LDT中找到段描述符,从而确定关于这个段的全部描述信息。这个索引被称为段选择符。
段寄存器(续)
选择符的格式 如下
RPL,请求特权级,2位二进制数字,求特权级是将要访问的段的特权级。
TI,表指示符。为 0时,从 GDT中选择描述符;
为 1时,从 LDT中选择描述符。
Index,索引。指出要访问描述符在段描述符表中的顺序号。
10.1.4 显示 CPU寄存器的值要取得 GDTR,IDTR,TR,LDT寄存器的值,
分别使用 SGDT,SIDT,STR,SLDT指令,
这些指令将寄存器的内容保存到内存单元中 。
程序举例,cpuregs.asm
10.2 虚拟内存管理如果程序要访问的内容不在内存中,CPU会产生一个异常,由操作系统的存储器管理程序来处理,将所需的内容装入内存中 。 这就是所谓的虚拟存储器,它并不完全是真正的内存空间,也称做虚拟内存 。
10.2.1 段式内存管理功能将虚拟地址转换为线性地址,由 CPU的分段部件完成。
虚拟地址:程序指令中使用的地址,由段和偏移两个部分组成
线性地址:段的基地址再加上偏移量
物理地址:从微处理器引脚上输出的地址信号
虚拟地址到线性地址,再到物理地址的转换过程
3.段描述符段描述符用于描述代码段、数据段和堆栈段。段描述符的格式如图,
段描述符段描述符位于 GDT或 LDT中,占 64位,
由以下几个部分组成:
段基址 ( 32位 )
限长 ( 20位 )
访问权限 ( 8位 )
属性 ( 4位 )
访问权限字节访问权限字节 定义如下
P,存在位
等于 1时表示该段己装入内存;
等于 0时表示该段没有在内存中,访问这个段会产生段异常。
DPL,描述符特权级,说明这个段的特权级访问权限字节
S,描述符类型位
为 1时,这个段为代码段、数据段或堆栈段;
为 0时,为系统段描述符。
E,可执行位,区分代码段和数据段
S=0且 E=1时,这是一个代码段,可执行。
S=0且 E=0时,这是一个数据段或堆栈段,不可执行。
E=0时,后面的两位为 ED和 W;
若 E=1时,后面的两位为 C和 R。
访问权限字节
ED,扩展方向位
为 0时,段从低地址向高地址扩展,偏移量小于等于限长。
为 1时,段从高地址向低地址扩展,偏移量必须大于限长。
W,写允许位
为 0时,不允许对这个数据段写入;
为 1时,允许对这个数据段写入。
访问权限字节
C,一致位
为 0时,这个段不是一致代码段
为 1时,这个段是一致代码段
R,读允许位
为 0时,不允许读这个段的内容
为 1时,允许读这个段的内容
A,访问位
为 1表示段已被访问过
为 0表示段未被访问过。
属性位属性位包括 G,D,AVL等
G,粒度位 。
G?1时,限长以页为单位;
G?0时,限长以字节为单位 。
D,默认操作数宽度 。
D?1时,为 32位数据操作段;
D?1时,为 16位数据操作段 。
AVL,可用位 。
这一位保留给操作系统或应用程序来使用段描述符高速缓存
在读写内存单元时,CPU需要检查段描述符的内容是否和当前操作相一致,CPU的运行效率极大地降低。为解决这个问题,CPU在内部设置了段描述符高速缓存。
在指令执行过程中,只有段寄存器的值发生改变时,才需要到 GDT或 LDT中装入段描述符。如果段寄存器的值不改变,高速缓存中的段描述符可以被直接引用,这样就避免了到主存中频繁读取段描述符。提高了 CPU的效率。
10.2.2 页式内存管理功能
段式内存管理是将形如 DS:[EBX]的虚拟地址,
由 DS的段基址再加上偏移部分,就得到了线性地址 。
分页管理将分段管理机制得到的线性地址转换为物理地址 。
使用分页机制的好处:
可以把每个活动任务当前所必需的少量页面放在内存中,而不必将整个段调入内存,从而提高了内存的使用效率 。
1.分页
页的长度固定为 4KB
页与页之间没有重叠
页式内存简化了存储器管理
不能充分地利用内存,会产生碎片
2.线性地址到物理地址的映射线性地址按页为单位映射到物理地址
每一个线性页面只能映射到一个物理页面上
多个线性页面可以映射到同一个物理页面上
3.线性地址转换为物理地址的过程
32位线性地址被划分为 3个部分:
页目录索引 ( 10位 ),对页目录的索引页表索引 ( 10位 ),对页表的索引字节索引 ( 12位 ),线性地址在页面内的偏移 。
线性地址转换为物理地址的过程图线性地址转换为物理地址的过程
以 PDBR的值作为页目录的基地址,定位到页目录 。
用线性地址中的页目录索引( 10位)在页目录表中找到一个页表描述符。
页表描述符的高 20位给出了页表的基地址 。
线性地址中的页表索引( 10位),指示了被访问的页在页表中的序号。
页描述符的高 20位给出了物理页面的基地址。
物理页面的基地址再加上线性地址中的 12位字节索引,
便得到 32位线性地址对应的 32位物理地址。
4.片内转换检测缓冲器 TLB
为了提高转换效率,CPU内部设置了片内转换检测缓冲器 TLB,其中保存了 32个页描述符,
它们都是最近使用过的。
在从线性地址转换为物理地址时,
如果线性地址的页描述符已在 TLB中,则无需再经二级转换就可以直接引用。
如果线性地址的页描述符没有在 TLB中,则需要访问页目录表和页表来取得页表描述符和页描述符,
最后将这个页描述符存在 TLB中。
5.页表项页表项就是在分页转换时用到的页表描述符和页描述符,它们都是 32位的,其格式:
页表项的低 12位提供保护功能和统计信息 。
U/S位,R/W位,P位实现页保护机制;
而 D位和 A位提供统计信息 。
页表项
U/S,用户 /管理员位
U/S=0时,只有操作系统程序可以访问该页,
而不允许用户程序访问
U/S=1时,允许用户程序访问该页
R/W,读写位
R/W?0,用户程序对页面只有读权限,不能写入;
R/W?1时,可读 /写页表项
P,存在位。
P=1,页表或页存在于物理内存中;
P=0,页表或页没有在物理内存中。
A,访问标志。
如果对某页表或页访问过,CPU设置页表项中的 A位为 1。
D,写入位。
D=1时表示对该页进行过写操作,
D=0时表示对该页还没有进行过写操作。
AVL占 3位,可以由操作系统使用
7,Pentium的 4MB页面
Pentium的页表项增加了 3个属性位,SIZ,PCD和
PWT。
SIZ( Size) 页尺寸位:
SIZ=0时,页面的大小为 4KB。
SIZ=1时,页面的大小为 4MB。
PCD位:
PCD=0时,允许页被缓存 ;
PCD=1时,禁止页被缓存 。
PWT位:
PWT=0时,使用回写策略;
PWT=1时,使用通写策略。
通写策略指的是指令将数据写到页面 Cache时,立即更新内存中的页面;
回写策略指的是指令将数据写到页面 Cache后就认为指令已经完成,以后再将页面 Cache中的数据更新到内存中。
8,Pentium的物理地址扩展功能第 5位 PAE位为 1时,就启动物理地址扩展功能
线性地址仍然为 32位,分为 4个部分:
PDPT索引 ( 2位 )
页目录索引 ( 9位 )
页表索引 ( 9位 )
字节索引 ( 12位 )
页表项,从原来的 4字节扩展为 8字节
页目录和页表的大小仍然为 4KB
PAE功能启用且 SIZ?1时,线性地址的格式如图
9,Pentium III的页面大小扩展功能
在分页状态下,PAE=0,PSE=1时,就启用了 PSE功能。
启用 PSE时,PAE功能必须关闭。
启用 PSE功能时,由页目录项中的 SIZ位(也称 PS位)来确定页面的大小。
10.3 特权级保护保护模式下设置了 0,1,2,3共 4个特权级,
以区分操作系统程序和应用程序。
可以阻止用户程序对操作系统的非法访问
保证高特权级的代码或数据不被低特权级的程序所破坏 。
10.3.1 对数据访问的保护
为段寄存器赋值时的检查
当前是否在物理存储器
段类型是否与目标段选择符类型一致
当前程序是否具有可以访问这个段的特权级
访问内存时的检查
操作数的偏移量是否超出段的边界
操作是否与段的保护属性匹配
10.3.2 对程序转移的保护
1,直接转移的保护
程序控制在同一代码段内转移时,只需要检查限长,保证程序转移后的目标地址不超过当前代码段的边界 。
如果要进行段间调用或跳转,则需使用远跳转或远调用指令,这时既要检查限长,还要检查特权级 CPL和 DPL 。
CPL=DPL,允许跳转和调用 。 转移后,CPL没有改变
CPL<DPL,禁止。高特权级的程序不能直接转移到低特权级的程序 ;
CPL>DPL,此时要检查段描述符的 C位。
如果 C位为 1,表示这是一致代码段,允许转移,
CPL并不改变。
如果 C位等于 0,则禁止转移。
2.间接转移的保护间接转移采用 JMP/CALL X:Y指令,
X指门选择符
10.3.3 门门可以看做是一种转换机构。门有 4种类型:
调用门 (用来改变任务或者程序的特权级别 )
调用门中包含了入口点的虚地址:
目标选择符
偏移量
任务门 (用来执行任务切换 )
中断门 (指出中断服务程序的入口地址 )
陷阱门 (指出中断服务程序的入口地址 )
1.系统描述符门描述符属于系统描述符,格式如下
16种系统描述符类型见书 352页
2.调用门调用门描述符中的参数计数值表示,
有多少个参数必须从主程序的堆栈复制到被调用子程序的堆栈。
在使用调用门时,CPU也要进行权限检查,
权限检查时要依据以下几个因素:
1.当前特权级 CPL
2.请求特权级 RPL
3,DPLGATE,即门描述符的 DPL
4.DPLCODE,即目标代码段描述符的 DPL
5.CCODE,即目标代码段描述符的 C位
使用 CALL指令时,CPU检查以下两个条件,
DPLGATE≥MAX ( CPL,RPL)
DPLCODE≤CPL
使用 JMP指令时,CPU检查以下两个条件,
DPLGATE≥MAX ( CPL,RPL)
CCODE为 1且 DPLCODE≤CPL 或 CCODE为 0且 DPLCODE= CPL
只有条件满足了才能使用调用门
10.4 任务完成某项功能的多个程序的集合称为任务
CPU允许系统中存在多个任务
任务能以分时的方式使各程序轮流执行,
用户感觉到所有的任务是在同时运行
在保护模式下每个任务是独立的
系统中至少存在一个任务
10.4.1 任务状态段每个任务都由两个部分组成:
任务执行环境 TES
任务执行环境包括一个代码段、堆栈段和数据段等,
任务在每一个特权级上执行时都有一个堆栈段
每个任务都有一个 LDT描述符表,构成一个局部地址空间,局部空间的数据和代码不能被其他任务访问。
任务状态段 TSS
2.任务状态段 TSS
TSS中保存了任务的各种状态信息
TSS描述符中规定了任务状态段的基地址和任务状态符的大小,格式如下:
TSS的基本格式
TSS的基本格式由 104字节( 000H~ 065H)
组成,这些字节可分为:
寄存器保存区域
内层堆栈指针区域
地址映射寄存器区域
链接字段
调试陷阱位 T
I/O许可位图寄存器保存区域
用于保存
通用寄存器
段寄存器
指令指针
标志寄存器
当 TSS对应的任务正在执行时,保存区域中的值是无意义的;
在当前任务挂起时,这些寄存器的当前值就保存在该区域。
内层堆栈指针区域
TSS的内层堆栈指针区域中有 3个堆栈指针,
分别指向 0级,1级和 2级堆栈的栈顶。
当特权级提升时,从 TSS中取出相应级别的堆栈指针装入 SS及 ESP寄存器,以切换到高特权级的堆栈,而原先 SS及 ESP的内容则保存在这个新的堆栈中。
当高特权级向低特权级转移时,CPU并不把高特权级的堆栈指针 SS:ESP保存到 TSS中。
地址映射寄存器区域
TSS中保存了任务的 CR3和 LDTR。
在任务切换时,处理器自动从新任务的 TSS
中取出这两个字段,分别装入到寄存器
CR3和 LDTR。
这样就改变了虚拟地址空间到物理地址空间的映射 。
链接字段链接字段位于在 TSS偏移 0开始的双字中,
其高 16位未用
低 16位保存前一任务的 TSS的选择符调试陷阱位 T
在 TSS内偏移 64H处的 16位是为任务提供的属性。最低位 T表示调试陷阱位 。
发生任务切换时,如果新任务的 T位为 1,那么在切换到新任务后,立即产生调试陷阱。
I/O许可位图任务使用的 I/O许可位图也存放在 TSS中,
以作为 TSS的扩展部分 。
在 TSS内偏移 66H处的字用于存放 I/O许可位图在 TSS内的偏移 ( 从 TSS的头开始计算 ) 。
10.4.2 任务切换
1,直接任务切换
段间跳转指令 JMP X:Y或段间调用指令 CALL
X:Y可以用来执行任务切换。
在中断 /异常或者执行 IRET指令时也可能发生任务切换。
2.间接任务切换
通过任务门可以进行任务的间接切换任务 A到 B的切换步骤
检查目标任务 B状态段的限长
把寄存器现场保存到当前任务 A的 TSS
把指示目标任务(任务 B) TSS的选择符装入 TR
寄存器中,同时把对应 TSS的描述符装入 TR的高速缓冲寄存器中
恢复当前任务(任务 B) 的寄存器现场
把 CR0中的 TS标志置为 1
任务 A到 B的切换步骤(续)
把 TSS中的 CS选择符的 RPL作为当前任务特权级,设置为 CPL
装载 LDTR寄存器
装载代码段寄存器 CS,堆栈段寄存器 SS
和各数据段寄存器及其高速缓冲寄存器。
任务内特权级变化时 TSS中堆栈指针的使用在特权级提升时:
TSS中相应的堆栈指针对 SS及 ESP寄存器进行初始化,建立起一个空栈
把低特权级程序的 SS及 ESP寄存器的值压入堆栈
从低特权级堆栈复制以双字为单位的调用参数到高特权级堆栈中
调用的返回地址被压入堆栈
RET指令及步骤
CALL指令不能向低特权级转移;
RET指令不能向高特权级转移。
RET指令所使用的返回地址的选择符也只能是代码段描述符,而不能是系统描述符或门描述符 。
执行,RETF n”指令时,步骤如下:
RET指令先从堆栈中弹出返回地址
为返回低特权级代码,跳过高特权级堆栈中的
RET指令(续)
参数,再从高特权级栈中弹出指向低特权级堆栈的指针,并装入 SS及 ESP,切换到低特权级堆栈。
调整 ESP,跳过主程序压入到低特权级堆栈的参数。
检查数据段寄存器 DS,ES,FS及 GS,以保证寻址的段在低特权级是可访问的 。
返回到主程序的下一条指令执行。
立即数 n规定了堆栈中要跳过的参数的字节数。
10.4.3 输入 /输出保护
CPU采用 I/O特权级 IOPL和 TSS段中 I/O许可位图的方法来控制输入 /输出,实现输入 /输出保护 。
1,I/O敏感指令
在 EFLAGS寄存器中,有两位是输入 /输出特权级 IOPL。 CPL≤IOPL 时,可以执行
I/O敏感指令。
EFLAGS标志寄存器中的 IOPL
任务状态段中的 I/O许可位图也影响 I/O
敏感指令的执行。
I/O敏感指令列表
2,I/O许可位图
I/O许可位图就是一个二进制位串
位串中的每一位对应一个 I/O地址
如果位串中的第 n位为 0,那么 I/O地址 n就可以由任何特权级的程序访问,而不加限制;
如果第 n位为 1,I/O地址 n只能由在 IOPL特权级或更高特权级运行的程序访问。
一条 I/O指令最多可涉及 4个 I/O地址
这条指令用到的所有 I/O地址的许可位都必须为 0,
才允许访问
3.对 IOPL的保护
EFLAGS中的 IOPL,VM和 IF位不能随便更改
只有在高特权级程序中执行的 IRET,POPF,
CLI和 STI等指令才能改变它们,如图
10.4.4 编写驱动程序修改 I/O位图
修改任务 I/O位图的内核驱动程序 举例:
giveio.c
执行过程见书 368页。
10.5 中断和异常
中断分为内部中断和外部中断两大类。
外部中断通常称为,中断,;
内部中断通常称为,异常,;
通常在两条指令之间响应中断或异常;
CPU最多处理 256种中断或异常。
10.5.1 中断和异常的类型
1,中断
中断是由异步的外部事件引起的,
中断信号来自于 CPU外部
CPU有两根引脚 INTR和 NMI接受外部中断请求信号 。
INTR接受可屏蔽中断请求
NMI接受不可屏蔽中断请求
标志寄存器 EFLAGS中的 IF标志决定是否响应
INTR的中断请求
IF=0时,CPU不响应 INTR信号
CPU在响应中断请求时,从外部硬件读出一个 8位的中断类型号,来区分外部中断的来源 。
对来自 NMI的中断请求,CPU不检查 IF标志 。
在响应 NMI中断时,不从外部硬件接收中断类型号,
其中断类型号固定为 2。
2,异常
异常是 CPU在执行指令期间检测到不正常的或非法的操作所引起的
发生异常时,在对该异常处理完毕前,引起该异常的指令就不能成功地被执行 ;
异常发生后,处理器,根据异常号码,转到相应的异常处理程序。
根据引起异常的程序是否可被恢复和恢复点的不同,把异常分为:
故障
陷阱
中止故障
故障是在引起异常的指令之前,把异常情况通知给系统的一种异常。
故障是可排除的。
当控制转移到故障处理程序时,在堆栈中保存的断点 CS及 EIP的值指向引起故障的指令。
在故障排除后,执行 IRET可以返回到引起故障的程序。
陷阱
陷阱是在引起异常的指令执行之后触发的一种异常。
陷阱处理后,要返回到引起陷阱的指令的下一条指令。
中止
中止是在系统出现严重的不可恢复的事件时触发的一种异常。
产生中止后,系统要重新启动才能恢复正常运行状态。
2.异常类型号
每一种异常被赋予一个异常类型号
某些异常以出错码的形式提供一些附加信息传递给异常处理程序
一个号码如果已经作为异常类型号,就不能再作为中断类型号使用。
异常类型号列表见书 371页
3.故障类异常
( 1)除法出错故障(异常 0)
当执行 DIV指令或 IDIV指令时,如果除数等于 0或者除数太小,以至于得到的商超过了操作数能容纳的范围,那么就产生这一故障。
除法出错故障没有出错码。
( 2)边界检查故障(异常 5)
如果 BOUND指令发现被测试的值超过了指令中给定的范围,那么就发生边界检查故障 。
边界检查故障不提供出错码 。
故障类异常
( 3)非法操作码故障(异常 6)
如果 CS和 EIP所指向的不是一个合法的指令,那么就发生非法操作码故障。 有下列情况:
操作码字段的内容不是一个合法的 CPU指令代码;
要求使用内存操作数的场合,使用了寄存器操作数;
不能被加锁的指令前使用了 LOCK前缀 。 非法操作码故障不提供操作码 。
故障类异常
( 4)无浮点处理器故障(异常 7)
这个故障用来模拟数字协处理器。
该故障在下列两种情况下产生:
执行浮点指令时,控制寄存器 CR0中的 EM位或 TS位为 1;
执行 WAIT指令时,控制寄存器 CR0中 TS位及 EM位都为 1。
EM位为 1,CPU必须用整数指令来模拟符点计算;
TS位为 1,CPU必须将上一个任务的浮点运算现场保存起来,再恢复当前任务浮点运算的现场 。
故障类异常
( 5)无效 TSS故障(异常 0AH)
当发生任务切换时,需要使用任务状态段 TSS。
如果当前程序的特权级不能访问该 TSS,或者 TSS
中保存的 LDTR,CS,DS等寄存器不正确,就发生无效 TSS故障。
无效 TSS故障提供了一个出错码,格式故障类异常
高 13位是选择符的索引部分;
TI位是选择符的 TI位;
EXT位等于 1时,表示故障由外部事件引起 。
IDT位等于 1时,表示故障由于读取 IDT表引起 。
引起无效 TSS故障的原因如下:
TSS描述符中的段限长小于 103;
无效的 LDT描述符,或者 LDT描述符的 P位为 0;
堆栈段不是一个可写段;
堆栈段选择符索引的描述符超出描述符表界限;
故障类异常
引起无效 TSS故障的原因如下 ( 续 ),
堆栈段 DPL与新的 CPL不匹配;
堆栈段选择符的 RPL不等于 CPL;
代码段选择符索引的描述符超出描述符表界限;
代码段选择符不指向代码段;
非一致代码段的 DPL不等于新的 CPL;
一致代码段的 DPL大于新的 CPL;
对应 DS,ES,FS或 GS的选择符指向一个不可读段
( 如系统段 ) ;
对应 DS,ES,FS或 GS的选择符索引的描述符超出描述符表的界限 。
故障类异常
( 6)段不存在故障(异常 0BH)
在给 CS,DS,ES,FS或 GS赋值时(不含 SS),
如果发现这些段寄存器指向的段描述符其他字段的值有效,而 P位为 0,产生段不存在故障。
段不存在故障提供了一个包含引起该故障的段选择符的出错代码。
故障类异常
( 7) 堆栈段故障 ( 异常 0CH)
当处理器检测到与 SS段有关的问题时,就发生堆栈段故障 。 出现故障的情况如下:
在堆栈操作时,偏移超出段界限所规定的范围 。
出错码为 0。
在由特权级变换所引起的对高特权级堆栈的操作时,
偏移超出段界限所规定的范围,高特权级堆栈段的段描述符中的 P位为 1。
此时出错码中包含高特权级堆栈的选择符 。
装入到 SS寄存器的段描述符中的 P位为 0。
此时出错码中包含有对应的选择符 。
故障类异常
( 8)通用保护故障(异常 0DH)
除了明确列出的段异常外,其他的段异常都被视为通用保护故障。
通用保护故障可分为如下两类:
违反保护方式,但程序无需中止的异常。
出错码为 0
违反保护方式,并导致程序终止的异常。
出错码可能为 0,也可能不为 0。
故障类异常
( 9)页故障(异常 0EH)
启用分页机制后,线性地址要经过分页机制转换才能成为物理地址。转换过程中出现异常的原因:
页目录表项或页表项中的 P=0,对应的物理页不在内存中;
发现试图违反页保护属性 ( U/S,R/W) 的规定而对页进行访问 。
提供出错码故障类异常
( 10) 协处理器出错 ( 异常 10H)
协处理器出错故障指示协处理器发生了未被屏蔽的数字错误,如上溢或下溢。
协处理器出错故障不提供出错码。
4.陷阱类异常
调试陷阱
断点陷阱
溢出调试陷阱调试异常有故障类型,也有陷阱类型调试异常不提供出错码。几种陷阱如下:
断点陷阱
调试程序可利用,INT 3”指令实现程序断点。
,INT 3”指令被看成是一种陷阱,而不是一个故障。
,INT 3”陷阱不提供出错码。
溢出
INTO指令提供有条件的陷阱,
如果 OF标志为 1,那么 INTO指令产生陷阱;
否则不产生陷阱,继续执行 INTO后面的指令。
溢出陷阱不提供出错码。
5.中止类异常
( 1)双重故障异常(异常 8)
当系统正在处理一个异常时,如果又遇到另一个不能处理的异常,CPU就产生一个双重故障,
双重故障属于中止类异常,出错码为 0。
当正处理一个段故障异常时,又产生一个页故障。
这时通知给系统的是一个页故障异常。
如果正在处理一个段故障或页故障时,又一个段故障被检测到,或者如果正处理一个页故障时,又一个页故障被检测到,那么就引起双重故障。
中止类异常双重故障通常指示系统表出现严重的问题,需要重启系统。
( 2)协处理器段越界(异常 9)
协处理器段越界异常也属于中止类异常,引起该异常的指令不能被重新执行。
当浮点指令操作数超出段界限时,产生该异常。
协处理器段越界异常不提供出错码。
10.5.2 中断门和陷阱门
中断描述符表 IDT所含的描述符只能是中断门、陷阱门和任务门。
中断门中断门和陷阱门
陷阱门
任务门前面已有介绍。
10.5.3 中断和异常的处理过程在中断或异常产生后,CPU依据中断类型号或异常号进行中断响应或异常处理 。 步骤如下:
( 1) 如果是异常处理,首先根据异常类型确定返回地址 。 如果有出错代码,则按照出错码格式构造出错码,并把出错码压入堆栈 。
对于故障,CS:EIP指向引起故障的指令;
对于陷阱,CS:EIP指向引起陷阱的指令的下一条指令 。
中断和异常的处理过程
( 2)判断中断类型号要索引的门描述符是否超出 IDT的界限。
若超出界限,就触发通用保护故障,出错码如右:
( 3)再从 IDT中取得对应的门描述符,分解出选择符、偏移量和属性字节,并进行有关检查。
中断和异常的处理过程
如果是由 INT n指令或 INTO指令引起转移,还要检查该描述符中的 DPL是否满足 CPL≤DPL GATE;
对于其他的异常或中断,则不检查 CPL≤DPL GATE条件。
( 4)根据门描述符类型,分别转入中断或异常处理程序。
如果门描述符是中断门或陷阱门,那么控制转移到当前任务的一个处理程序过程,并且可以变换特权级,从中断门和陷阱门中获取指向处理程序的 48位地址指针( 16位段,32位偏移)。
如果门描述符是任务门,后面的章节会讲到。
中断和异常的处理过程取得 48位地址指针后,CPU执行以下步骤:
( 1)若段选择符为 0,则产生通用保护故障;
( 2)在 GDT/LDT中取对应的描述符;
( 3)若描述符不是一个代码段描述符,则产生通用保护故障;
( 4)若代码段( C?0) 且 DPL>CPL,则产生通用保护故障;
( 5)调整段选择符的 RPL?0( 不修改门中的段选择符,在 CPU内部调整);
中断和异常的处理过程
( 6) 把段选择符装入 CS;
( 7) 若偏移超过段长,则产生通用保护故障;
( 8) EFLAGS压入堆栈;
( 9) CS压入堆栈; EIP压入堆栈;这里的
CS:EIP是指中断 /异常的返回地址;
( 10) 置 TF?0,NT?0;
( 11) 若为中断门,则使 IF?0;
( 12) 若有出错码,则把出错码压入堆栈;
( 13) 把偏移装入 EIP,跳转到处理程序 。
中断和异常的处理过程
中断或异常可以转移到同一特权级或高特权级。
是否要转移到高特权级,由代码段的描述符中的类型( C位)及 DPL字段决定:
如果 C位 =1(一致性代码段),则不改变特权级。
如果 C位 =0(非一致性代码段)且 DPL<CPL,则特权级提升。
如果 C位 =0且 DPL=CPL,则不改变特权级。
如果 C位 =0且 DPL>CPL,产生通用保护异常,因为不能通过中断或异常而降低特权级。
中断和异常的处理过程通过中断门的转移和通过陷阱门的转移之间的差别只是对 IF标志的处理。
对于中断门,在转移过程中把 IF置为 0;
对于陷阱门,在转移过程中保持 IF位不变。
中断和异常的处理过程在有出错码的情况下,转入处理程序之前还要把出错码压入堆栈。下面给出四种情况:
第 1,3种情况没有出错码;
第 2,4种情况有出错码。
10.5.4 通过任务门的转移如果以中断类型号为索引,在中断描述符中取出的是一个任务门描述符,那么控制转移到新的任务。
将任务门放在 IDT表中,在响应对应的中断或异常时,可根据该任务门实现任务的自动调度。
这种任务调度由 CPU直接执行,速度快,开销小。
各种转移方式的比较第一种情况(使用中断门或陷阱门 )
没有进行任务切换
对当前任务的状态可直接进行访问
处理程序必须存在于当前任务的地址空间中第二种情况(使用任务门)
要进行任务切换
转移到处理程序要花费较长时间
访问原任务的状态较为复杂
3.中断或异常处理后的返回指令 IRET用于从中断或异常处理程序中返回。
该指令的执行根据任务嵌套标志 NT位是否为 1分为两种情形,
NT位为 1时,IRET执行的是嵌套任务的返回。
这种情形在通过任务门转入的处理程序返回时出现。
NT位为 0时,IRET执行的是当前任务内的返回。
这种情形在通过中断门或陷阱门转入的处理程序返回时出现
4.各种转移途径的总结
JMP,CALL,INT和 IRET指令都可以引起任务切换 。
这些切换是主动的任务切换;
在执行这些指令时,转移到一个新的任务 。
中断和异常引起的任务切换是被动的任务切换 。
可能在程序执行的任何时候发生 。
任务内特权级变换的途径如下图
任务内相同特权级转移 如下图
10.5.5 结构化异常处理
构化异常处理,是 Windows操作系统提供处理程序错误或异常的机制。
例如 C/C++中的 _try{},_finally{}和
_try{},_except {}等功能举例:
C语言的结构化异常处理程序 seh.c
汇编程序捕获并处理异常程序 except.asm
10.6 虚拟 8086模式
V86模式是保护模式下的一种工作方式。
寻址的地址空间是 1MB,地址为 20位;
程序中使用的内存地址由两部分构成,16位段和 16位偏移。
在保护模式下,当标志寄存器 EFLAGS中的 VM位为 1时,处理器就处于 V86模式。
1.虚拟 8086任务
V86监控程序和在 V86模式下的 8086程序构成的任务称为虚拟 8086任务,即 V86任务。
V86任务形成一个由处理器硬件和监控程序组成的,虚拟 8086” 。
V86监控程序控制 V86外部界面、中断和 I/O。
CPU把 V86任务作为与其他任务具有同等地位的一个任务。
V86任务中,V86程序在 V86模式下运行,而 V86
监控程序在保护模式下运行
2.内存映射
在 V86模式下,程序只能使用 1MB的内存。
由段值乘以 16加上偏移构成 20位地址,
这是线性地址。经过转换后,得到物理地址。
CPU可同时运行多个 V86任务,这些任务的内存被映射到不同的物理内存上,相互之间互不影响。
3,V86模式下的敏感指令
指令 CLI和 STI的敏感条件不变,如果
IOPL<3,那么执行 CLI或 STI指令将引起通用保护故障。
输入 /输出指令 IN,INS,OUT或 OUTS是否执行由 I/O许可位图对应位决定。如果输入 /输出指令所使用的 I/O地址对应的 I/O
许可位图内的各位都为 0,则输入输出指令可正常执行,否则引起通用保护故障。
10.6.2 虚拟 8086模式的进入和退出保护模式和 V86模式之间的切换如图虚拟 8086模式的进入和退出离开 V86模式 ( 2种 )
在 V86任务内离开 V86模式
任务切换离开 V86模式进入 V86模式 ( 2种 )
通过 IRET指令进入 V86模式
通过任务切换进入 zV86模式
10.7 操作系统类指令系统指令可分为以下几类:
在实模式和任何特权级下可执行的指令
仅在实模式及特权级 0下可执行的指令
仅在保护模式下可执行的指令课本 394和 395页列出了这些指令
10.7.1 在实模式和任何特权级下可执行的指令
1,读取全局描述符表寄存器指令格式,SGDT QWORD PTR DST
功能:把全局描述符表寄存器 GDTR的内容保存到内存单元 DST。
说明:
DST是 48位的内存操作数 。
GDTR中的 16位限长存入 DST的低字,而 32位基地址存入 DST的高双字 。
在实模式和任何特权级下可执行的指令
2,读取中断描述符表寄存器指令格式,SIDT QWORD PTR DST
功能:把中断描述符表寄存器 GDTR的内容保存到内存单元 DST。
说明:
DST是 48位的内存操作数 。
IDTR中的 16位限长存入 DST的低字,而 32位基地址存入 DST的高双字 。
在实模式和任何特权级下可执行的指令
3,读取机器状态字指令格式,SMSW DST
功能:把机器状态字的内容保存到内存单元或寄存器中 。
说明:
DST可以是 16位的内存操作数或寄存器;
机器状态字是 CR0的低 16位 。
在实模式和任何特权级下可执行的指令
4,读取性能计数器指令格式,RDPMC
功能:读取由 ECX指定的 40位时间戳计数器,
放入 EDX:EAX中 。
说明,EDX存放模式寄存器的高 8位,EAX存放模式寄存器的低 32位 。
10.7.2 仅在实模式及特权级 0下可执行的指令
1,清任务切换标志指令格式,CLTS
功能:把 CR0控制寄存器中的 TS标志清零 。
说明,TS标志置为 1,表示已发生过任务切换,
在当前任务使用协处理器指令时,产生陷阱 。
由陷阱处理程序完成协处理器现场的保存和恢复,随后执行 CLTS指令清除 TS标志,使得当前任务后续使用的协处理器指令不再产生故障 。
仅在实模式及特权级 0下可执行的指令(续)
2,暂停指令格式,HLT
功能:使处理器暂停执行 。
说明:系统进入暂停状态后,只有接收到一个外部中断或系统复位信号,才能离开暂停状态 。
仅在实模式及特权级 0下可执行的指令(续)
3,设置全局描述符表寄存器指令格式,LGDT QWORD PTR SRC
功能:把存储器中的 6字节内容装入到全局描述符表寄存器 GDTR中 。
说明,SRC是 48位内存操作数 。
仅在实模式及特权级 0下可执行的指令(续)
4,设置中断描述符表寄存器指令格式,LIDT QWORD PTR SRC
功能:把存储器中的 6字节内容装入到中断描述符表寄存器 IDTR中 。
说明,SRC是 48位内存操作数仅在实模式及特权级 0下可执行的指令(续)
5,设置机器状态字指令格式,LMSW DST
功能:把 DST的内容装载到机器状态字 。
说明:
DST是 16位的内存操作数或寄存器 。
该指令可将机器状态字中的 PE位置为 1,以进入保护模式 。
可以通过给 CR0赋值的方法来设置机器状态字 。
仅在实模式及特权级 0下可执行的指令(续)
6,系统寄存器数据传送指令格式,MOV DST,SRC
功能:实现控制寄存器 /调试寄存器 /测试寄存器和 32位通用寄存器之间的数据传送 。
说明,SRC和 DST中有一个是通用寄存器另一个是控制寄存器,调试寄存器或者调试寄存器 。
10.7.3 仅在保护模式下可执行的指令
1.设置局部描述符表寄存器指令格式,LLDT SRC
功能:把 SRC中的内容作为指示局部描述符表 LDT
的选择符装入到 LDTR寄存器 。
说明:
SRC可以是 16位通用寄存器或存储单元 。
该指令只能在特权级 0执行 。
仅在保护模式下可执行的指令(续)
2,读取局部描述符表寄存器指令格式,SLDT DST
功能:把局部描述符表寄存器 LDTR的内容存储到存储单元 DST中说明:操作数 DST可以是 16位通用寄存器或存储单元 。
仅在保护模式下可执行的指令(续 )
3,设置任务寄存器指令格式,LTR SRC
功能:将 SRC的内容作为选择符装载到任务寄存器 TR。
说明:
SRC可以是 16位通用寄存器或存储单元 。
该指令只能在特权级 0下执行 。
仅在保护模式下可执行的指令(续)
4,读取任务寄存器指令格式,STR DST
功能:把 TR中的选择符存储到 DST。
说明:
DST可以是 16位通用寄存器或存储单元 。
TR中的值总是当前任务的 TSS状态段的选择符 。
仅在保护模式下可执行的指令(续)
5,调整请求特权级指令格式,ARPL OPRD1,OPRD2
功能:根据 OPRD2选择符来调整 OPRD1选择符的请求特权级,即 RPL。
说明,OPRD1可以是 16位通用寄存器或存储单元,OPRD2是 16位通用寄存器仅在保护模式下可执行的指令(续)
6,读取存取权限指令格式,LAR OPRD1,OPRD2
功能:将 OPRD2选择符指向的描述符内的属性字段装入 OPRD1。
说明:
OPRD1可以是 16位或 32位通用寄存器,OPRD2
是 16位或 32位通用寄存器或存储单元 。
OPRD1和 OPRD2的大小必须一致 。
仅在保护模式下可执行的指令(续)
7,读取段界限指令格式,LSL OPRD1,OPRD2
功能:将 OPRD2选择符指向的描述符内的限长装入 OPRD1。
说明:
OPRD1可以是 16位或 32位通用寄存器,OPRD2
是 16位或 32位通用寄存器或存储单元 。
OPRD1和 OPRD2的尺寸必须一致 。
仅在保护模式下可执行的指令(续)
8,读检验指令格式,VERR OPRD
功能:判断 OPRD选择符的段是否可读 。
说明,OPRD可以是 16位通用寄存器或存储单元,也可以是 32位通用寄存器或存储单元 。
仅在保护模式下可执行的指令(续)
9,写检验指令格式,VERW OPRD
功能:判断 OPRD选择符的段是否可写 。 说明,OPRD可以是 16位通用寄存器或存储单元,也可以是 32位通用寄存器或存储单元 。
仅在保护模式下可执行的指令(续)
10,不写回方式清除 Cache项指令格式,INVD
功能:清除 CPU内的指令 Cache和数据 Cache,
并且向外部 Cache电路发送一个特殊的总线信号,迫使它也清除 Cache。 CPU内的
Cache不写回到内存中仅在保护模式下可执行的指令(续)
11,写回方式清除 Cache项指令格式,WBINVD
功能:清除 CPU内的指令 Cache和数据 Cache,并且向外部 Cache电路发送一个特殊的总线信号,
迫使它也清除 Cache。 CPU内的 Cache写回到内存中 。
说明:
执行这个指令会清空 Cache项,Cache中的内容写回到内存中 。
WBINVD指令只能在保护模式的特权级 0下执行 。
仅在保护模式下可执行的指令(续)
12,清除 TLB表项指令格式,INVLPG OPRD
功能,CPU的 TLB保存最近使用过的 32个页表项 。
说明:
INVLPG指令首先找到内存操作数 OPRD所在的物理内存页面,再将该页面的 TLB表项 Cache清除掉 。
INVLPG指令只能在保护模式的特权级 0下执行 。
仅在保护模式下可执行的指令(续)
13,退出系统管理模式指令格式,RSM
功能:使 CPU退出系统管理模式 。
仅在保护模式下可执行的指令(续)
14,读取模式寄存器指令格式,RDMSR
功能:读取由 ECX指定的 64位模式寄存器,
放入 EDX:EAX中 。
说明,EDX存放模式寄存器的高 32位,EAX
存放模式寄存器的低 32位 。
仅在保护模式下可执行的指令(续)
15,设置模式寄存器指令格式,WRMSR
功能:将 EDX:EAX写入 ECX指定的模式寄存器 。
说明,EDX存放模式寄存器的高 32位,EAX
存放模式寄存器的低 32位 。
仅在保护模式下可执行的指令(续)
16,读取性能计数器指令格式,RDTSC
功能:读取 64位时间戳计数器,放入
EDX:EAX中 。
说明,EDX存放时间戳计数器的高 32位,
EAX存放时间戳计数器的低 32位 。
仅在保护模式下可执行的指令(续)
17,锁总线指令前缀格式,LOCK
功能:使后续的一条指令能独占总线 。
说明,LOCK前缀通常和 BTS一起使用