配色: 字号:
第11章 保护模式下的程序设计简介
2022-10-30 | 阅:  转:  |  分享 
  
本章主要教学内容1.保护模式下的各种伪指令;2.实模式与保护模式的切换;3.控制转移、中断和异常;4.输入/输出保护、分页机制等。 本章主要
教学目的及要求1.理解保护模式下的各种伪指令及编程;2.掌握实模式与保护模式的切换方法;3.掌握中断和异常的相关概念、编程方法;4
.了解输入/输出保护和分页机制。11.1 保护模式编程基础11.1.1 处理器类型伪指令11.1.2 A20地址线的使用 为
了访问地址在1M以上的存储单元,应先打开控制地址线A20的“门”。这种设置与实模式下只使用最低端的1M字节存储空间有关,与处理器是
否工作在实模式或保护方式无关,即使在关闭地址线A20时,也可进入保护模式。;打开A20:PUSH AXIN AL,
92HOR AL, 00000010BOUT 92H, ALPOP AX;关闭A20:PUSH
AXIN AL, 92HAND AL, 11111101BOUT 92H, ALPOP AX 代
码11.1.3 头文件 头文件中,列举描述的数据结构比较全面,并不是在编写每个保护模式下的汇编语言程序时全部用到的,如
果一个程序没有使用某部分内容可不引用。公用过程----GDT初始化(InitGDT.inc)清单 ;GDT初始化InitGDT
PROC PUSH DS MOV AX, GDT
Seg MOV DS, AX MOV CX, GD
TNum MOV SI, OFFSET EFFGDTAgain: MOV
AX, [SI].BaseL MOVZX EAX, AX SHL
EAX, 4 SHLD EDX, EAX, 16
MOV WORD PTR [SI].BaseL, AX MOV BYT
E PTR [SI].BaseM, DL MOV BYTE PTR [SI].BaseH
, DH ADD SI, SIZE Desc LOOP
Again POP DS MOV BX,
16 MOV AX, GDTSeg MUL
BX MOV WORD PTR VGDTR.Base, AX
MOV WORD PTR VGDTR.Base+2, DX RETInitGDT
ENDP公用过程----文件InitLDT.inc清单 ;初始化LDT;入口参数:FS:SI=第一个要初始化的描述符,CX=
要初始化的描述符数InitLDT PROC MOV AX, WORD PTR FS
:[SI].BaseL MOVZX EAX, AX SHL
EAX, 4 SHLD EDX, EAX, 16
MOV WORD PTR FS:[SI].BaseL, AX MOV
BYTE PTR FS:[SI].BaseM, DL MOV BYTE PTR FS:
[SI].BaseH, DH ADD SI, SIZE Desc
LOOP InitLDT RETInitLDT ENDP公用过程----文
件InitIDT.inc清单 ;初始化IDTInitIDT PROC MOV BX
, 16 MOV AX, IDTSeg MUL BX
MOV WORD PTR VIDTR.Base, AX MO
V WORD PTR VIDTR.Base+2, DX RETInitIDT EN
DP 11.2 实模式与保护模式之间的切换11.2.1 两种模式之间切换1.从实模式切换到保护模式 首先,必须完成使GDTR
指向该GDT。然后,由实模式切换到保护模式原则上只要把控制寄存器CR0中的PE位置1即可,利用下面三条指令完成对PE位的设置。
MOV EAX, CR0 OR EAX, 1 MOV CR0, EAX 在实际情况下,紧
接着这三条指令,安排一条段间转移指令:JUMP16 Code_Sel, 2.从保护模式切换到实模
式 从保护模式切换到实模式的过程类似于从实模式切换到保护模式。原则上只要把控制寄存器CR0中的PE位清0即可。实际上
,在此之后也要安排一条段间转移指令,一方面清指令预取队列,另一方面把实模式下代码段的段值送CS。这条段间转移指令在保护方式下被预取
并在实模式下被执行。【例11-1】只有一个代码段的实模式和保护模式之间切换。步骤:(1)切换前的准备工作;(2)切换到保护方式;(
3)切换回实模式。 源程序如下: 11.2.2 两种模式切换实例;加载头文件386h.incINCLUDE 386H.IN
C;16位数据段DSEG SEGMENT USE16GDT LABEL BYTE ;全
局描述符表DUMMY S_DESC <> ;空描述符Code S_DESC <0FFFFH,,
,ATCE,,>Code_Sel = Code-GDT Data S_DESC <0FFFFH,0,1
1H,ATDW,,>Data_Sel = Datas-GDT GDTLen = $-GDT VGDTR
PDesc DSEG ENDS;16位代码段CSEG SEG
MENT USE16 ''Real'' ASSUME CS:CSEG, DS:DSEGStart
PROC MOV AX, DSEG MOV DS, AX
MOV BX, 16 MUL BX AD
D AX, OFFSET GDT ADC DX, 0 ;界限已在定义时设
置好 MOV WORD PTR VGDTR.Base, AX MOV WOR
D PTR VGDTR.Base+2, DX MOV AX, CSEG ;设置代码段描述符
MUL BX MOV WORD PTR Code.BaseL, AX
MOV BYTE PTR Code.BaseM, DL MOV BYTE PTR Cod
e.BaseH, DH MOV AX, DSEGMUL BX MOV WORD PTR D
ata.BaseL, AX MOV BYTE PTR Data.BaseM, DL MOV BYTE PTR Data.Bas
eH, DH LGDT QWORD PTR VGDTR ;加载GDTR CLI ;关中断 EA20
;打开地址线A20 MOV EAX, CR0 ;切换到保护方式 OR
EAX, 1MOV CR0, EAX JUMP16 Code_Sel, Virtual
: ;现在开始在保护方式下运行 ┇ ;此处为保护模式下的功能代码部分 MOV
EAX, CR0;切换回实模式 AND AL, 11111110B MOV CR0, EAX JUMP16
, Real: ;现在又回到实
模式 DA20 ;关闭地址线A20 STI ;开中断
┇ ;此处为实模式下的功能代码部分 MOV AH, 4CH ;结束程序 INT
21HStart ENDPlCSEG ENDS ;代码段定义结束 END St
art【例11-2】多个代码段的实模式与保护模式之间切换。步骤:(1)切换到保护方式前的准备工作;(2)切换到保护方式的一个32位
代码段;(3)再切换到保护方式下的一个16位代码段;(4)切换回实模式。 源程序如下: ;加载头文件386h.incINCLUDE
386H.INC;16位数据段DSegMain SEGMENT USE16GDT
LABEL BYTE ;全局描述符表DUMMY S_DESC <> ;空描述符N
ormal S_DESC <0FFFFH,,,ATDW,,> ;规范段描述符Normal_Sel
= Normal-GDT ;规范段描述符选择子Code32 S_DESC Len-1,,,ATCE,D32,> ;32位代码段描述符Code32_Sel = Code32-GDT
;32位代码段选择子Code16 S_DESC <0FFFFH,,,ATCE,,> ;
16位代码段描述符Code16_Sel = Code16-GDT ;16位代码段选择子Stacks
S_DESC ;堆栈段描述符Stacks_Sel
= Stacks-GDT ;堆栈段描述符选择子GDTLen = $-GDT
;全局描述符表长度VGDTR PDesc ;伪描述
符SaveSP DW ? ;用于保存SP寄存器SaveSS DW
? ;用于保存SS寄存器DSegMain ENDS;16位堆栈段StackSeg SEG
MENT PARA STACK USE16StackLen = 256
DB StackLen DUP(0)StackSeg ENDS;16位代码段CSegMain
SEGMENT USE16 ''Real'' ASSUME CS: CSegM
ain, DS: DSegMainStart PROC
MOV AX, DSegMain MOV DS, AX
MOV BX, 16 ;准备要加载到GDTR的伪描述符
MUL BX ADD AX, OFFSET G
DT ;计算并设置基地址 ADC DX, 0
;界限已在定义时设置好 MOV WORD PTR VGDTR.Base, A
X MOV WORD PTR VGDTR.Base+2, DX
MOV AX, CSeg32 ;设置32位代码段描述符
MUL BX MOV WORD PTR Code32
.BaseL, AX MOV BYTE PTR Code32.BaseM, D
LMOV BYTE PTR Code32.BaseH, DHMOV AX, CSeg16 ;设置16位
代码段描述符MUL BXMOV WORD PTR Code16.BaseL, AX ;代码段开始偏移为0MO
V BYTE PTR Code16.BaseM, DL ;代码段界限已在定义时设置好MOV BYTE PTR Co
de16.BaseH, DHMOV AX, SS ;设置堆栈段描述符MOV WORD PTR SaveSS,
AX ;保护堆栈寄存器MOV WORD PTR SaveSP, SPMOV AX, StackSeg
;设置堆栈段描述符MUL BXMOV WORD PTR Stacks.BaseL, AXMOV
BYTE PTR Stacks.BaseM, DLMOV BYTE PTR Stacks.BaseH, DHLG
DT QWORD PTR VGDTR ;加载GDTRCLI ;关中断EA20 ;打
开地址线A20MOV EAX, CR0 ;切换到保护方式OR AL, 1OR AL, 1MOV
CR0, EAXJUMP16 Code32_Sel, ;清指令预取队列并进入保护方式ToRea
l: ;现在又回到实模式MOV AX, DsegMain ;恢复数据段MOV DS, AXMOV
SP, SaveSP ;恢复堆栈段MOV SS, SaveSSDA20 ;关闭地址线A20STI
;开中断MOV AX, 4C00H ;结束程序INT 21HStart
ENDPCSegMain ENDS;32位代码段CSeg32 SEGMENT USE32 ''PM32''
ASSUME CS:CSeg32Pro32 PROC MO
V AX, Stacks_Sel ;设置32位程序使用的堆栈 MOV SS, AX
MOV ESP, StackLen ┇ ;此处
为32位功能代码部分 JUMP32 Code16_Sel, Pro3
2 ENDPC32Len = $CSeg32 ENDS;16位代码段CSeg16 SEG
MENT USE16 ''PM16'' ASSUME CS:CSeg16Pro16 PRO
C ┇ ;此处为16位功能代码部分 MOV AX, Norma
l_sel ;转向规范段 MOV DS, AX
MOV ES, AX MOV SS, AX MOV
EAX, CR0 AND AL, 11111110B M
OV CR0, EAX JMP FAR PTR ToRealPro16 EN
DPCSeg16 ENDS END Start11.3 控制转移控制转移基本上分为两大类
: 同一任务内的控制转移 任务间的控制转移,也就是任务切换同一任务内的控制转移又分为: 段内转
移 特权级不变的段间转移 特权级切换的段间转移11.3.1 任务内无特权级切换的转移 具有段间转移功
能的指令统称为段间转移指令。 在保护模式下,段间转移的目标位置由选择子和偏移构成的地址表示,称为目标地址指针。在32位代码段
中,目标地址指针内的偏移用32位表示,所以也称为48位全指针。 如果指令JMP和CALL在指令中直接含有目标地址指针,
那么就是段间直接转移;如果指令中含有指向包含目标地址指针的门描述符或TSS描述符的指针,那么就是段间间接转移。段间转移指令中的指针
只有选择子部分有效,用于指示调用门、任务门或TSS描述符,而偏移部分不起作用。 1.段间转移指令 (1)判断目标地址指针内选
择子指示的描述符是否为空描述符,如果为空描述符则产生保护错误。 (2)从全局或局部描述符表内读出目标代码段描述符。由选择子内
的TI位,确定使用全局描述符表还是局部描述符表。 (3)根据情况,检测描述符类型是否正确;调整RPL。 (4)把目标代
码段描述符内的有关内容装载到CS高速缓冲寄存器。 (5)判断目标地址指针内的偏移是否越出代码段的界限,如果超出目标代码段界限
则产生地址越界保护错误。 (6)装载CS段寄存器和指令指针寄存器EIP;CPL存入CS内选择子的RPL字段。 2. 转移步骤
所谓任务内无特权级切换的转移指:在转移到新的代码段时,CPL保持不变。利用段间转移指令可实现任务内无特权级切换的转移,利用
INT指令和IRET指令也可实现任务内无特权级切换的转移。3.任务内无特权级切换的转移在把选择子装入数据段寄存器DS、ES、FS或
GS时,要进行如下检测:(1)选择子不能为空;(2)选择子指定的描述符必须是数据段描述符、可读可执行的代码段或一 致可读的可执
行代码段的描述符;(3)对于数据段和可读可执行代码段,要求CPL<=DPL,RPL<=DPL;(4)对应的段必须存在。若装入的选择
子不满足上述要求,则会产生异常。4.装载数据段和堆栈段寄存器时的特权检测在把选择子装入堆栈段寄存器SS时要进行如下检测:(1)选择
子不能为空;(2)选择子指定的描述符必须是可读写的数据段描述符;(3)要求CPL=DPL=RPL;(4)对应段必须存在。若装入的选
择子不满足上述条件,则在装入SS时就会引起异常。4.装载数据段和堆栈段寄存器时的特权检测1.任务内不同特权级的切换(1)通过调用门
的转移11.3.2任务内不同特权级的切换 调用门描述符转移的入口点包含目标地址的段及偏移量的48位全指针。在执行通过任务门
的段间转移指令JMP或段间调用指令CALL时,指令所含指针内的选择子用于确定调用门,而偏移量被丢弃;把调用门内的48位全指针作为目
标地址指针进行转移。(2)堆栈切换 在通过调用门向内层转移时,不仅特权级发生切换,控制转移到一个新的代码段,堆栈段也切换到内
层堆栈段。TSS中包含有指向0级、1级和2级堆栈的指针。在特权级发生向内层切换时,根据切换到的特权级使用TSS中相应的堆栈指针对S
S及ESP寄存器进行初始化。在建立起内层堆栈后,处理器先把外层堆栈的指针SS及ESP寄存器内容压入内层堆栈,使得当向外层返回时恢复
外层堆栈。 段间返回指令RET从堆栈中弹出返回地址,采用调整ESP的方法跳过相应的在调用之前压入堆栈的参数。返回地址的选择子
指示待返回的代码段描述符,从而确定返回的代码段。 (3)向外层返回段间返回指令完成返回的步骤如下:①RET指令先从堆栈中弹出返回地
址。 ②为向外层返回,跳过内层堆栈中的参数,再从内层栈中弹出指向外层 堆栈的指针,并装入SS及ESP,以恢复外层堆栈。③调整ES
P,跳过在相应的调用之前压入到外层堆栈的参数。④检查数据段寄存器DS、ES、FS及GS,以保证寻址的段在外层是可访问 的,如果段
寄存器寻址的段在外层是不可访问的,那么装入一个空选 择子,以避免在返回时发生保护空洞。⑤返回外层继续执行。11.3.3 任务切换
1.通过TSS进行任务切换: 段间转移指令JMP或段间调用指令CALL所含指针的选择子指示一个可用任务状态段TSS描述符时,
正常情况下就发生从当前任务到由该可用TSS对应任务的切换。2.通过任务门进行任务切换: 任务门内的选择子指示某个任务的TSS
描述符。当段间转移指令JMP或段间调用指令CALL所含指针的选择子指示一个任务门时,正常情况下就发生任务切换,即从当前任务切换到由
任务门内的选择子所指示的TSS描述符对应的任务。 3.任务切换过程(1)测试目标任务状态段的界限。(2)把寄存器现场保存到当前任务
的TSS。(3)把指示目标任务TSS的选择子装入TR寄存器中。同时把对应TSS的描 述符装入TR的高速缓冲寄存器中。(4)
基本恢复当前任务的寄存器现场。(5)进行链接处理。(6)把CR0中的TS标志置为1,产生自陷。由自陷处理程序完成有关协处
理器现场的保存和恢复。(7)把TSS中的CS选择子的RPL作为当前任务特权级设置为CPL。(8)装载LDTR寄存器。(9)装载代码
段寄存器CS、堆栈段寄存器SS和各数据段寄存器及其高速 缓冲寄存器。(10)把调试寄存器DR7中的局部启用位置为0,以清除
局部于原任务的各个断点和方式。 11.3.6 任务切换的实例步骤:(1)实模式下初始化;(2)切换到保护模式;(3)设置TR对应临
时任务,特权级为0;(4)直接切换到特权级为2任务;(5)将入口参数压入堆栈,经调用门进入特权级为0的子程序;(6)从堆栈中取出入
口参数并处理;(7)从特权级为0的子程序返回特权级为2的代码段;(8)为切换回实模式作部分准备工作;(9)经任务门切换到特权级为0
的任务;(10)准备返回实模式;(11)切换到实模式;(12)实模式下的恢复工作。【例11-3】通过TSS段、任务门实现任务内特权
级切换,并实现参数传递。11.4 中断和异常 1.中断11.4.1 80386的中断和异常 80386系统中的中断是由异步
的外部事件引起的。外部事件及中断响应与正执行的指令没有关系。,80386有两根引脚INTR和NMI接受外部中断请求信号。INTR接
受可屏蔽中断请求。NMI接受不可屏蔽中断请求。在80386中,标志寄存器EFLAGS中的IF标志决定是否屏蔽可屏蔽中断请求。 2
.异常 异常是80386在执行指令期间检测到不正常的或非法的条件所引起的。 80386识别多种不同类别的异常,并赋予每一种类
别以不同的中断向量号。异常发生后,根据中断向量号,转相应的中断处理程序。 根据引起异常的程序是否可被恢复和恢复点不同,把异
常分为故障(Fault)、陷阱(Trap)和中止(Abort)。把对应的异常处理程序分别称为故障处理程序、陷阱处理程序和中止处理程
序。 3.优先级11.4.2 异常类型1.80386识别的异常2.故障类异常(1)除法出错故障(异常0)。(2)边界检查故障(异常
5)。 (3)非法操作码故障(异常6)。 (4)设备不可用故障(异常7)。(5)无效TSS故障(异常0AH)。 (6)段不存在故障
(异常0BH)。(7)堆栈段故障(异常0CH)。 (8)通用保护故障(异常0DH)。 (9)页故障(异常0EH)。(10)协处理器
出错(异常10H)。 3.陷阱类异常(1)调试陷阱(异常1)。 (2)单字节INT3(异常3)。 (3)溢出(异常4)。4
.中止类异常(1)双重故障异常(异常8)。 (2)协处理器段越界(异常9)。 11.4.3 中断和异常的转移方法1.中断描述符表I
DT 80386使用中断描述符表IDT,整个系统仅有一张IDT。中断描述符表寄存器IDTR指示IDT在内存中的位置。I
DT最大长度是2K。 80386把中断向量号作为中断描述符表IDT中描述符的索引。IDT所含的描述符只能是中断门、陷阱门和任
务门。2.中断响应和异常处理的步骤 首先,判断中断向量号要索引的门描述符是否超出IDT的界限。若超出界限,就引起通用保护故
障,出错码为中断向量号乘8再加2。 其次,从IDT中取得对应的门描述符,分解出选择子、偏移量和描述符属性类型,并进行有关检查
。 最后,根据门描述符类型,分情况转入中断或异常处理程序。(1)若选择子为空,则产生通用保护故障;(2)取对应的描述符;(3
)若非存储段描述符,则产生通用保护故障;(4)若非一致代码段且DPL 6)把描述符装入CS;(7)若入口偏移越界,则产生通用保护故障;(8)EFLAGS压入堆栈;(9)CS压入堆栈;(10)EIP压入
堆栈;(11)使TF=0,NT=0;(12)若为中断门,则使IF=0;(13)若有出错码,则把出错码压入堆栈;(14)转入处理程序
。 3.通过中断门或陷阱门的转移 如果中断向量号所只是的门描述符是任务门描述符,那么控制转移到一个作为独立的任务方式出现的处
理程序。任务门中的选择子是指向描述对应处理程序任务的TSS段的选择子,即该选择子指示一个可用的286TSS或386TSS。4.通过
任务门的转移 在当前任务之内的处理程序较为简单,并可以很快地转移到处理程序,但处理程序要负责保存及恢复处理器的寄存器
等内容。转到不同任务的处理程序要花费较长时间,保存及恢复处理器寄存器内容的开销作为任务切换的一部分。 有些异常必须由
中断门或陷阱门进行处理。5.转移方法的比较6.中断或异常处理后的返回 中断返回指令IRET用于从中断或异常处理程序的返回。该
指令的执行根据任务嵌套标志NT位是否为1分为两种情形。 NT=1,表示是嵌套任务的返回。当前TSS中的链接字段保存有前一任务
的TSS的选择子,取出该选择子进行任务切换就完成返回。 NT=0,表示当前任务内的返回。这种情形在由通过中断门或陷阱门转入的
中断或异常处理程序返回时出现。11.4.4 中断处理的实例【例11-4】编写28H号中断的服务程序。;加载头文件386h.incI
NCLUDE 386H.INC;部分常量定义EOICOM = 20H ;外部中断处理
结束命令ICREGP = 20H ;中断控制寄存器端口地址IMREGP =
21H ;中断屏蔽寄存器端口地址;16位全局描述符表数据段GDTSeg SEGMENT PARA USE16 G
DT LABEL BYTE ;全局描述符表GDTDUMMY S_DESC <>
;空描述符Normal S_DESC <0FFFFH,,,ATDW,,> ;规范段描述符Normal_Sel
= Normal-GDT ;规范段描述符选择子EFFGDT LABE
L BYTEDemoCode S_DESC > ;演示代码段
描述符DemoCode_Sel = DemoCode-GDT ;演示代码段的选择子DemoData
S_DESC
;演示数据段描述符DemoData_Sel
= DemoData-GDT ;演示数据段的选择子DemoStack S_DESC

;演示堆栈段描述符DemoStack_Sel =
DemoStack-GDT ;演示堆栈段的选择子 TICode S_DESC 1,TICodeSeg,,ATCE,,>
;28H中断代码段描述符TICode_Sel = TICode-GDT
;28H中断代码段选择子TIData S_DESC Seg,,ATDW,,>
;28H中断数据段描述符TIData_Sel = TIData-GDT ;28H中断
数据段选择子;其它中断或异常处理程序代码段描述符Other Desc therCodeSeg,,ATCE,,>Other_Sel = Other-GDT
;其它中断或异常代码段选择子GDTLen = $-GDT ;全局描述符表长度G
DTNum = ($-EFFGDT)/(SIZE Desc) ;需特殊处理的描述符数GDTSeg
ENDS;16位中断描述符表数据段IDTSeg SEGMENT PARA USE16 IDT
LABEL BYTE ;中断描述符表 REPT 28H ;00H~27H的陷阱
门描述符 Gate
ENDM;对应28H中断处理程序的门描述符Gate ,AT386IGate,> REPT 216 ; 从29H~0FFH的陷阱门描述符Gate therBegin,Other_Sel,,AT386TGate,> ENDMIDTLen
= $-IDTIDTSeg ENDS;其它中断或异常处理程序的代码段OtherCodeSeg
SEGMENT PARA USE16 ASSUME CS:Other
CodeSegOtherBegin PROC FAR ┇ ;此处为保
护模式下未处理中断的功能代码部分OtherBegin ENDPOtherCodeLen = $Othe
rCodeSeg ENDS;28H中断处理程序的数据段TIDataSeg SEGMENT PARA USE16
┇ ;数据定义TIDataLen = $TIDataSeg
ENDS; 28H中断处理程序的代码段TICodeSeg SEGMENT PARA USE16
ASSUME CS:TICodeSeg,DS:TIDataSegTIBegin PROC
FAR PUSH EAX ;保护现场 PUS
H DS PUSH FS PUSH GS
┇ ;中断服务功能代码 POP GS ;
恢复现场 POP FS POP DS
POP EAX IRETD ;中断返回TIBegin END
PTICodeLen = $TICodeSeg ENDS;演示任务的堆栈段DemoStackS
eg SEGMENT PARA USE16DemoStackLen = 1024
DB DemoStackLen DUP(0)DemoStackSeg ENDS;演
示任务的数据段DemoDataSeg SEGMENT PARA USE16Flag DB
0DemoDataLen = $DemoDataSeg ENDS;演示任务的代码段DemoCodeSe
g SEGMENT PARA USE16 ASSUME CS:DemoCod
eSeg,DS:DemoDataSegDemoBegin PROC FAR MOV
AX, DemoStack_Sel ;置堆栈 MOV SS, AX
MOV SP, DemoStackLen ;置数据段 MOV AX,
DemoData_Sel MOV DS, AX MOV
ES, AX MOV FS, AX MOV GS,
AX ┇ ;中断准备功能代码 STI ;开中断
┇ ;循环等待中断完成 CLI ;关中断 M
OV AX, Normal_Sel ;恢复实模式段描述符高速缓存 MOV
DS, AX MOV ES, AX MOV FS, A
X MOV GS, AX MOV SS, AX
MOV EAX, CR0 ;准备返回实模式 AND AL,
11111110B MOV CR0, EAX JUMP16
, DemoBegin ENDPDemoCodeLen =
$DemoCodeSeg ENDS;实模式数据段RDataSeg SEGMENT PARA USE
16 VGDTR PDesc ;GDT伪描述符VIDTR PD
esc ;IDT伪描述符NORVIDTR PDesc <3FFH,> ;用于保存原I
DTR值SPVar DW ? ;用于保存实模式下的SPSSVar DW
? ;用于保存实模式下的SSIMaskRegV DB ? ;用于保存原中断屏蔽寄存器值RDat
aSeg ENDS;实模式代码段RCodeSeg SEGMENT PARA USE16 ''Real''
ASSUME CS:RCodeSeg,DS:RDataSegStart PROC
MOV AX, RDataSeg MOV DS, AX
CLD CALL InitGDT ;初始化全局描述符表GDT
CALL InitIDT ;初始化中断描述符表IDT MOV
SSVar, SS ;保存堆栈指针 MOV SPVar, SP
SIDT QWORD PTR NORVIDTR ;保存IDTR IN
AL, IMREGP MOV BYTE PTR IMaskRegV, AL
LGDT QWORD PTR VGDTR ;装载GDTR CLI ;关中断
LIDT QWORD PTR VIDTR ;装载IDTR
MOV EAX, CR0 OR AL, 1 MOV
CR0, EAXJUMP16 , Real:
MOV AX, RDataSeg MOV DS,AX
LSS SP, DWORD PTR SPVar ;又回到实模式 LIDT QWORD
PTR NORVIDTR MOV AL, IMaskRegV
OUT IMREGP, AL STI MOV AX,
4C00H INT 21HStart ENDPINCLUDE
InitGDT.incINCLUDE InitIDT.incRCodeSeg ENDS
END Start11.5 操作系统类指令1.存储全局描述符表寄存器指令 存
储全局描述符表寄存器指令的格式如下: SGDT QWORD PTR DST 其中操作数DST是48位(6
字节)的存储器操作数。该指令的功能是把全局描述符表寄存器GDTR的内容存储到存储单元DST。GDTR中的16位界限存入DST的低字
,GDTR中的32位基地址存入DST的高双字。该指令对标志没有影响。 2.存储中断描述符表寄存器指令 存储中断描述符表寄存
器指令的格式如下: SIDT QWORD PTR DST 其中操作数DST是48位(6字节)的存储器操作数
。该指令的功能是把中断描述符表寄存器IDTR的内容存储到存储单元DST。IDTR中的16位界限存入DST的低字,IDTR中的32位
基地址存入DST的高双字。该指令对标志没有影响。3.存储机器状态字指令 存储机器状态字指令的格式如下: SM
SW DST 其中操作数DST可以是16位(字)的存储器操作数或寄存器。该指令的功能是把机器状态字的内容存储到DST。
该指令对标志没有影响。11.5.2 实模式及特权级0下可执行的指令 1.清任务切换标志指令 每当任务切换时,控制寄存器CR0
中的任务切换标志TS被自动置1。清任务切换标志指令的功能是把TS标志清0,该指令的格式如下: CLTS 该
指令仅影响TS标志,对其它标志没有影响。2.暂停指令 暂停指令的格式如下: HLT 该指令使处理器
暂停执行。暂停之后的系统,只有在接受一个已经启用的中断或让系统复位,才能重新启动。该指令对标志没有影响。3.装载全局描述符表和中断
描述符表寄存器的指令 装载全局描述符表寄存器指令的格式如下: LGDT QWORD PTR SRC
SRC是48位的存储器操作数。功能是把存储器中的伪描述符装入到全局描述符表寄存器GDTR中。该指令对标志没有影响。 装载
中断描述符表寄存器指令的格式如下: LIDT QWORD PTR SRC SRC是48位的存储器操作
数。功能是把存储器中的伪描述符装入到中断描述符表寄存器IDTR中。该指令对标志没有影响。4.装载机器状态字指令 装载机器状态
字指令的格式如下: LMSW DST DST可以是16位(字)的存储器操作数或寄存器。功能是把DST的内
容装载到机器状态字。该指令对标志没有影响。5.控制寄存器数据传送指令 控制寄存器数据传送指令的一般格式如下: M
OV DST,SRC 实现80386的控制寄存器和32位通用寄存器之间的数据传送。操作数SRC和DST可以是803
86使用的三个控制寄存器和任一32位通用寄存器,但不能同时是控制寄存器。该指令对标志没有影响。 一般格式与上面的控制寄存器数
据传送指令的格式相同。实现80386的调试寄存器和32位通用寄存器之间的数据传送。操作数SRC和DST可以是80386使用的6个调
试寄存器和任一32位通用寄存器,但不能同时为调试寄存器。该指令不影响标志。 80386可用的6个调试寄存器为:DR0、DR1
、DRW、DR3、DR6和DR7。6.调试寄存器数据传送指令指令 一般格式与上面的控制寄存器数据传送指令的格式相同。实现80
386的测试寄存器和32位通用寄存器之间的数据传送。80386使用的2个测试寄存器是TR6和TR7。7.测试寄存器数据传送指令1.
装载和存储局部描述符表寄存器指令11.5.3 只能在保护模式下执行的指令 装载指令的格式如下: LLDT SR
C SRC可以是16位通用寄存器或存储单元。功能是把SRC中的内容作为指示局部描述符表LDT的选择子装入到LDTR寄存器。
该指令不影响标志。 存储指令的格式如下: SLDT DST DST可以是16位通用寄存器或存储单元。
功能是把局部描述符表寄存器 LDTR的内容存储到存储单元DST中,该指令不影响标志。 2.装载和存储任务寄存器指令 装载指令
的格式如下: LTR SRC SRC可以是16位通用寄存器或存储单元。功能是将SRC作为指示TSS描述符
的选择子装载到任务寄存器TR。 存储指令的格式如下: STR DST DST可以是16位通用寄存器或存
储单元。功能是把TR所含的指示当前任务TSS描述符的选择子存储到DST。该指令不影响标志。3.调整申请特权级指令 指令的格式
如下: ARPL OPRD1,OPRD2 OPRD1可以是16位通用寄存器或存储单元,OPRD2是16位通用寄
存器。该指令把操作数OPRD1和OPRD2视为两个选择子,用OPRD2的申请特权级(RPL)去检查OPRD1的RPL。选择子OPR
D1和OPRD2的RPL分别由它们的最低2个位规定。如果OPRD1的RPL小于OPRD2的RPL,那么零标志ZF被置1,并把OPR
D2的RPL值赋予OPRD1的RPL(使两个操作数的最低2位相等);否则,零标志ZF被清0。OPRD1和OPRD2都可为空选择子。
该指令只影响ZF标志。 指令的格式如下: LAR OPRD1,OPRD2 OPRD1可以是16位或
32位通用寄存器,OPRD2是16位、32位通用寄存器或存储单元。OPRD1和OPRD2的尺寸必须一致。 4.装载存取权指令
指令的格式如下: LSL OPRD1,OPRD2 OPRD1可以是16位或32位通用寄存器,OPRD2
是16位、32位通用寄存器或存储单元。OPRD1和OPRD2的尺寸必须一致。5.装载段界限指令 读检验指令的一般格式如下:
VERR OPRD OPRD是16位、32位通用寄存器或存储单元。 写读检验指令的一般格式如下:
VERW OPRD OPRD可以是16位、32位通用寄存器或存储单元。 6.读写检验指令1.I/O敏感指令
11.6.1 输入/输出保护11.6 输入/输出保护2.I/O许可位图 I/O许可位图规定了I/O空间中的哪些地址可以由在任
何特权级执行的程序所访问。I/O许可位图存放在任务状态段TSS中。 I/O许可位图由二进制位串组成。位串中的每一位依次对应一
个I/O地址,位串的第0位对应I/O地址0,位串的第n位对应I/O地址n。如果位串中的某位为0,那么对应的I/O地址可以由在任何特
权级执行的程序访问;否则对应的I/O地址只能由在IOPL特权级或更内层特权级执行的程序访问。如果在I/O外层特权级执行的程序访问位
串中位值为1的位所对应的I/O地址,那么将引起通用保护异常。(1)若CPL<=IOPL,则直接转步骤(8);(2)取得I/O位图开
始偏移;(3)计算I/O地址对应位所在字节在I/O许可位图内的偏移;(4)计算位偏移以形成屏蔽码值,即计算I/O地址对应位在字节中
的第几位;(5)把字节偏移加上位图开始偏移,再加1,所得值与TSS界限比较,若越界, 则产生出错码为0的通用保护故障;(6)若
不越界,则从位图中读对应字节及下一个字节;(7)把读出的两个字节与屏蔽码进行与运算,若结果不为0表示检查未通过, 则产生出错码
为0的通用保护故障;(8)进行I/O访问。 3.I/O访问许可检查细节 80386对EFLAGS中的这三个字段的处理比较特殊
,只有在较高特权级执行的程序才能执行IRET、POPF、CLI和STI等指令改变它们。11.6.2 重要标志保护11.6.3 输入
输出保护的实例【例11-5】下面给出一个用于演示输入输出保护的实例。演示内容包括:I/O许可位图的作用、I/O敏感指令引起的异常和特权指令引起的异常;使用段间调用指令CALL通过任务门调用任务,实现任务嵌套。程序实现步骤如下:(1)在实模式下做必要准备后,切换到保护模式;(2)进入保护模式的临时代码段后,将演示任务的TSS段描述符装入TR,并设置演示任 务的堆栈;(3)进入演示代码段,演示代码段的特权级是0;(4)通过任务门调用测试任务1。测试任务1能够顺利进行;(5)通过任务门调用测试任务2。测试任务2演示由于违反I/O许可位图规定而导致通用 保护异常;(6)通过任务门调用测试任务3。测试任务3演示I/O敏感指令如何引起通用保护异常;(7)通过任务门调用测试任务4。测试任务4演示特权指令如何引起通用保护异常;(8)从演示代码转临时代码,准备返回实模式;(9)返回实模式,并作结束处理。【例11-6】下面给出一个演示如何启用分页管理机制的实例。该实例演示内容包括:初始化页目录表和部分页表;启用分页管理机制;关闭分页管理机制等。该实例假设系统至少有4M字节物理内存。11.7 分页机制的实例步骤:(1)在实模式下为进入保护模式作初始化;(2)切换到保护模式后进入临时代码段,将部分演示代码传送到预定的内存,然后转演示代码段;(3)建立页目录表;(4)建立页表;(5)启用分页管理机制;(6)演示在分页管理机制启用后的程序执行和数据存取;(7)关闭分页管理机制;(8)退出保护模式,结束。 虚拟8086模式是保护模式下的一种工作方式,简称为V86模式。 在V86模式下,处理器类似于8086。寻址的地址空间是1M字节;段寄存器的内容作为段值解释;20位存储单元地址由段值乘以16加偏移构成。在V86模式下,代码段总是可写的,这与实模式相同,同理,数据段也是可执行的,只不过可能会发生异常。 11.8 虚拟8086模式11.8.1 V86模式1.V86模式2.V86任务 8086程序可以直接在V86模式下运行,而V86模式受到称为V86监控程序的控制。V86监控程序和在V86模式下的8086程序构成的任务称为虚拟8086任务,或者简称为V86任务。 1.离开V8611.8.2 进入和离开V86模式(1)在V86任务内离开V86模式 如果对应的门描述符是386中断门或386陷阱门,那么就发生在当前V86任务内从V86模式到保护模式的转换。80386要求执行这种中断/异常处理程序时的CPL必须等于0。 (2)任务切换离开V86模式 如果对应的门描述符是任务门,那么就发生从当前V86任务到其它任务的切换,也就离开了当前V86任务的V86方式。 2.进入V86(1)过IRET指令进入V86模式 通过在中断/异常处理结束时使用IRET指令返回被中断的程序继续执行。(2)通过任务切换进入V86模式 通过任务切换的途径,可以从其它任务进入V86任务内的V86模式。本章小结 本章介绍保护模式下的程序设计。 保护模式下的每一个应用程序有其独立的4GB虚拟地址空间,这就要求编写保护模式下的应用程序时,必须格守保护模式下的程序设计规范,否则会引起内存保护模式错误。 80x86系列微型计算机启动时默认进入实模式,所以必须由程序完成从实模式到保护模式的切换。任务切换利用段间转移指令通过任务门或直接通过任务状态段,可以切换到别的任务。 8086/8088将中断分为内部中断和外部中断两大类。为了保证操作系统的安全,保护模式下的80386支持四个特权级 。 虚拟8086模式是保护模式下的一种工作方式,也称为V8086模式,或者简称为V86模式。
献花(0)
+1
(本文系籽油荃面原创)