;程序名
;演示在任务内如何进行特权级变换
;
INCLUDE 386CD.ASM ;参见实例3
;
.386p
;------------------------------------
;全局描述符表GDT
GDTSEGSEGMENT PARA USE16
GDT LABEL BYTE
DUMMY DESCRIPTOR <>
NORMAL DESCRIPTOR <0FFFFH,0,0,ATDW,0>
NORMAL_SEL = NORMAL - GDT
EFFGDT LABEL BYTE
;演示任务状态段TSS描述符
DEMOTSS DESCRIPTOR <DemoTSSLEN-1,DemoTSSSEG,,AT386TSS,>
DemoTSS_SEL = DEMOTSS - GDT
;演示任务LDT段描述符
DEMOLDTD DESCRIPTOR <DemoLDTLEN-1,DemoLDTSEG,,ATLDT,>
DemoLDT_SEL = DEMOLDTD - GDT
;临时代码段描述符
TEMPCODE DESCRIPTOR <0FFFFH,TempCodeSEG,,ATCE,>
TempCode_SEL = TEMPCODE - GDT
;视频缓冲区段描述符(DPL=3)
VIDEOBUFF DESCRIPTOR <0FFFFH,,,0F00H+ATDW+DPL3,0>
Video_SEL = VIDEOBUFF - GDT
GDNUM = ($- EFFGDT)/(SIZE DESCRIPTOR)
GDTLEN = $ - GDT
GDTSEG ENDS
;------------------------------------------------------
;演示任务局部描述符表LDT
DemoLDTSEG SEGMENT PARA USE16
DEMOLDT LABEL BYTE
;0级堆栈段描述符(32位段)
DEMOSTACK0 DESCRIPTOR <DemoStack0LEN-1,DemoStack0SEG,,ATDW+D32,>
DemoStack0_SEL = (DemoStack0 - DEMOLDT) + TIL
;1级堆栈段描述符(DPL=1)
DEMOSTACK1 DESCRIPTOR <DemoStack1LEN-1,DemoStack1SEG,,ATDW + D32+DPL1,>
DemoStack1_SEL = (DemoStack1 - DEMOLDT)+TIL+RPL1
;3级堆栈段描述符(DPL=3)
DEMOSTACK3 DESCRIPTOR <DemoStack3LEN-1,DemoStack3SEG,,ATDW + DPL3,>
DemoStack3_SEL = (DemoStack3 - DEMOLDT)+ TIL + RPL3
;演示代码段描述符(32位段,DPL=3)
DEMOCODE DESCRIPTOR <DemoCodeLEN-1,DemoCodeSEG,,ATCE+D32+DPL3,>
DemoCode_SEL = (DEMOCODE - DEMOLDT)+ TIL +RPL3
;过渡代码段描述符(32位段)
T32CODE DESCRIPTOR <T32CodeLEN-1,T32CodeSEG,,ATCE+D32,>
T32Code_SEL = (T32CODE-DEMOLDT)+TIL
;显示子程序代码段描述符(32位段,DPL =1 )
ECHOSUBR DESCRIPTOR <EchoSUBRLEN-1,EchoSUBRSEG,,ATCER+D32+DPL1,>
Echo_SEL1 = (ECHOSUBR - DEMOLDT)+TIL+RPL1
Echo_SEL3 = (ECHOSUBR - DEMOLDT)+TIL+RPL3
DemoLDNUM = ($-DEMOLDT)/(SIZE DESCRIPTOR)
;指向过渡代码段内T32Begin点的调用门(DPL=0)
TOT32GATEA GATE <T32Begin,T32Code_SEL,0,AT386CGAT,0>
ToT32A_SEL = (TOT32GATEA - DemoLDT)+TIL
;指向过渡代码段内T32End点的调用门(DPL=3)
TOT32GATEB GATE <T32End,T32Code_SEL,0,AT386CGAT+DPL3,0>
ToT32B_SEL = (TOT32GATEB -DEMOLDT)+TIL
;指向显示子程序的调用门(DPL=3)
TOECHOGATE GATE <EchoSUB,Echo_SEL3,0,AT386CGAT+DPL3,0>
ToEcho_SEL = (TOECHOGATE - DemoLDT)+TIL
DemoLDTLEN = $ - DemoLDT
DemoLDTSEG ENDS
;------------------------------------------------------------
;演示任务的TSS段
DemoTSSSEG SEGMENT PARA USE16
DD 0 ;BACK
DW DemoStack0LEN,0 ;0级堆栈指针
DW DemoStack0_SEL,0 ;初始化
DW DemoStack1LEN,0 ;1级堆栈指针
DW DemoStack1_SEL,0 ;初始化
DD ? ;2级堆栈指针
DW ?,0 ;未初始化
DD 0 ;CR3
DD ? ;EIP
DD ? ;EFLAGS
DD ? ;EAX
DD ? ;ECX
DD ? ;EDX
DD ? ;EBX
DD ? ;ESP
DD ? ;EBP
DD ? ;ESI
DD ? ;EDI
DW ?,0 ;ES
DW ?,0 ;CS
DW ?,0 ;SS
DW ?,0 ;DS
DW ?,0 ;FS
DW ?,0 ;GS
DW DemoLDT_SEL,0 ;LDT
DW 0
DW $+2 ;指向I/O许可位图
DB 0FFH ;I/O许可位图结束标志
DemoTSSLEN=$
DemoTSSEG ENDS
;----------------------------------------------
;演示任务0级堆栈段(32位段)
DemoStack0SEG SEGMENT PARA USE32
DemoStack0LEN = 512
DB DemoStck0LEN DUP (0)
DemoStack0SEG ENDS
;--------------------------------------------------
;演示任务1级堆栈段(16位段)
DemoStack1SEG SEGMENT PARA USE32
DemoStack1LEN =512
DB DemoStack1LEN DUP (0)
DemoStack1SEG ENDS
;----------------------------------------------------
;演示任务3级堆栈段(16位段)
DemoStack3SEG SEGMENT PARA USE16
DemoStack3LEN = 512
DB DemoStack3LEN DUP (0)
DemoStack3SEG ENDS
;------------------------------------------------------
;演示任务显示子程序代码段(32位段,1级)
EchoSUBRSEG SEGMENT PARA USE32
MESSAGE DB 'CPL=',0
ASSUME CS:EchoSUBRSEG
;显示调用程序的执行特权级
EchoSUB PROC FAR
CLD
PUSH EBP
MOV EBP,ESP
MOV AX,Echo_SEL1 ;子程序代码段是可读段
MOV DS,AX ;采用RPL=1的选择子
MOV AX,Video_SEL
MOV ES,AX ;视频缓冲区段基地址00000000H
MOV EDI,0B8000H ;视频缓冲区段B8000H开始
MOV ESI,OFFSET MESSAGE
MOV AH,17H ;置显示属性
EchoSUB1:
LODSB
OR AL,AL
JZ EchoSUB2
STOSW ;显示字符串
JMP EchoSUB1
EchoSUB2:
MOV EAX,[EBP+8] ;从堆栈中取调用程序的选择子
AND AL,3 ;调用程序的CPL在CS的RPL字段
ADD AL,'0'
MOV AH,17H
STOSW ;显示之
POP EBP
RETF ;返回
EchoSUB ENDP
EchoSUBRLEN = $
EchoSUBRSEG ENDS
;----------------------------------------------------------
;演示任务的演示代码段(32位段,3级)
DemoCodeSEG SEGMENT PARA USE32
ASSUME CS:DemoCodeSEG
DemoBegin:
;显示当前特权级(变换到1级)
CALL32 ToEcho_SEL,0
;转到过渡代码段(变换到0级)
CALL32 ToT32B_SEL,0
DemoCodeLEN = $
DemoCodeSEG ENDS
;--------------------------------------------------------
演示任务的过渡代码段(32位段,0级)
T32CODESEG SEGMENT PARA USE32
ASSUME CS:T32CODESEG
T32Begin:
;建立0级堆栈
MOV AX,DemoStack0_SEL
MOV SS,AX
MOV ESP,DemoStack0LEN
;压入3级堆栈指针
PUSH DWORD PTR DemoStack3_SEL
PUSH DWORD PTR DemoStack3LEN
;压入入口点
PUSH DWORD PTR DemoCode_SEL
PUSH OFFSET DemoBegin
;利用RET实现转3级的演示代码段
RETF
T32End:;转临时代码段
JUMP32 TempCode_SEL,<OFFSET ToReal>
T32CodeLEN = $
T32CODESEG ENDS
;-----------------------------------------------
;临时代码段(16位段,0级)
TempCodeSEG SEGMENT PARA USE16
ASSUME CS:TempCodeSEG
Virtual:;装载TR
MOV AX,DemoTSS_SEL
LTR AX
;装载LDTR
MOV BX,DemoLDT_SEL
LLDT BX
;通过调用门转过渡段
JUMP16 ToT32A_SEL,0
ToReal:;准备切换回实方式
MOV AX,Normal_SEL
MOV DS,AX ;把规范段描述符
MOV ES,AX ;装入各数据段寄存器
MOV FS,AX
MOV GS,AX
MOV SS,AX
;
MOV EAX,CR0
AND EAX,0FFFEH
MOV CR0,EAX ;返回实方式
JUMP16 <SEG REAL>,<OFFSET REAL>
TempCodeLEN = $
TempCodeSEG ENDS
;===========================================
;实方式下的数据段
RDataSEG SEGMENT PARA USE16
VGDTR PDESC <GDTLEN-1,>
SPVAR DW ?
SSVAR DW ?
RDataSEG ENDS
;--------------------------------------------------
;实方式下的代码段
RCodeSEG SEGMENT PARA USE16
ASSUME CS:RCodeSEG,DS:RDataSEG
Start:
MOV AX,RDataSEG
MOV DS,AX
CLD
CALL INIT_GDT ;初始化GDT
;
MOV AX,DemoLDTSEG
MOV FS,AX
MOV SI,OFFSET DemoLDT
CALL INIT_LDT ;初始化LDT
;
MOV SSVAR,SS
MOV SPVAR,SP
;装载GDTR和切换到保护方式
LGDT QWORD PTR VGDTR
CLI
MOV EAX,CR0
OR AX,1
MOV CR0,EAX
JUMP16 TempCode_SEL,<OFFSET Virtual>
Real:
MOV AX,RDATASEG
MOV DS,AX
LSS SP,DWORD PTR SPVAR
STI
MOV AX,4C00H
INT 21H
;-----------------------------------------
;初始化全局描述符表的子程序
;(1)把定义时预置的段值转换成32位段基地址并置入描述符内相应字段
;(2)初始化为GDTR准备的伪描述符
INIT_GDT PROC NEAR
PUSH DS
MOV AX,GDTSEG
MOV DS,AX
MOV CX,GDNUM ;GDNUM 是初始化的描述符个数
MOV SI,OFFSET EFFGDT ;EFFGDT是开始偏移
INITG:MOV AX,[SI].BASEL ;取出预置的段值
MOVZX EAX,AX ;扩展到32位
SHL EAX,4
SHLD EDX,EAX,16 ;分解到2个16位寄存器
MOV [SI].BASEL,AX
MOV [SI].BASEM,DL ;置入描述符相应字段
MOV [SI].BASEH,DH
ADD SI,SIZE DESCRIPTOR ;调整到下一描述符
LOOP INITG
POP DS
;
MOV BX,16 ;初始化为GDTR准备的伪描述符
MOV AX,GDTSEG
MUL BX
MOV WORD PTR VGDTR.BASE,AX
MOV WORD PTR VGDTR.BASE+2,DX
RET
INIT_GDT ENDP
;
;初始化演示任务局部描述符表的子程序
;把定义时预置的段值转换成32位段基地址并置入描述符内相应字段
;入口参数:FS:SI=第一个要初始化的描述符
;CX=要初始化的描述符个数
INIT_LDT PROC
ILDT:MOV AX,FS:[SI].BASEL
MOVZX,EAX,AX
SHL EAX,4
SHLD EDX,EAX,16
MOV FS:[SI].BASEL,AX
MOV FS:[SI].BASEM,DL
MOV FS:[SI].BASEH,DH
ADD SI,SIZE DESCRIPTOR
LOOP ILDT
RET
INIT_LDT ENDP
RCodeSEG ENDS
END Start