(第三章 8)通过调用门进行有特权级变换的转移(一)
下面代码中,
和TSS相关用红色标记;
调用门本身用深绿色标记;
调用门指向的段用浅绿色标记;
?
; ==========================================
; pmtest5.asm
; 编译方法:nasm pmtest5.asm -o pmtest5.com
; ==========================================
?
%include"pm.inc"; 常量, 宏, 以及一些说明
?
org0100h
jmpLABEL_BEGIN
?
[SECTION .gdt]
; GDT
; ? ? ? ? ? ? ? ? ? ? ? ? ? ?段基址, ? ? ? ? ? 段界限 ? ? , 属性
LABEL_GDT: ? ? ? ? ? ? Descriptor 0, ? ? ? ? ? ? ? ? 0, 0 ? ;空描述符
LABEL_DESC_NORMAL: ? ? Descriptor 0, ? ? ? ? ? ?0ffffh, DA_DRW ? ;Normal描述符
LABEL_DESC_CODE32: ? ? Descriptor 0, ? ?SegCode32Len-1, DA_C+DA_32 ? ;非一致,32
LABEL_DESC_CODE16: ? ? Descriptor 0, ? ? ? ? ? ?0ffffh, DA_C ? ;非一致,16
LABEL_DESC_CODE_DEST: ?Descriptor 0, ?SegCodeDestLen-1, DA_C+DA_32 ? ;非一致,32
LABEL_DESC_CODE_RING3: Descriptor 0, SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3
LABEL_DESC_DATA: ? ? ? Descriptor 0, ? ? DataLen-1, DA_DRW ? ? ? ? ? ? ;Data
LABEL_DESC_STACK: ? ? ?Descriptor 0, ? ? ? ?TopOfStack, DA_DRWA+DA_32 ? ;Stack,32
LABEL_DESC_STACK3: ? ? Descriptor 0, ? ? ? TopOfStack3, DA_DRWA+DA_32+DA_DPL3
LABEL_DESC_LDT: ? ? ? ?Descriptor 0, ? ? ? ? ?LDTLen-1, DA_LDT ? ;LDT
LABEL_DESC_TSS: ? ? ? ?Descriptor 0, ? ? ? ? ?TSSLen-1, DA_386TSS ? ;TSS
LABEL_DESC_VIDEO: ? ? ?Descriptor 0B8000h, ? ? ?0ffffh, DA_DRW+DA_DPL3
?
; 门 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?目标选择子, ? ? ? 偏移, DCount, 属性
LABEL_CALL_GATE_TEST:Gate ?SelectorCodeDest, ? ? ? ? ?0, ? ? ?0, DA_386CGate + DA_DPL3
; GDT 结束
?
GdtLenequ$ - LABEL_GDT; GDT长度
GdtPtrdwGdtLen - 1; GDT界限
dd0; GDT基地址
?
; GDT 选择子
SelectorNormalequLABEL_DESC_NORMAL- LABEL_GDT
SelectorCode32equLABEL_DESC_CODE32- LABEL_GDT
SelectorCode16equLABEL_DESC_CODE16- LABEL_GDT
SelectorCodeDestequLABEL_DESC_CODE_DEST- LABEL_GDT
SelectorCodeRing3equLABEL_DESC_CODE_RING3- LABEL_GDT + SA_RPL3
SelectorDataequLABEL_DESC_DATA- LABEL_GDT
SelectorStackequLABEL_DESC_STACK- LABEL_GDT
SelectorStack3equLABEL_DESC_STACK3- LABEL_GDT + SA_RPL3
SelectorLDTequLABEL_DESC_LDT- LABEL_GDT
SelectorTSSequLABEL_DESC_TSS- LABEL_GDT
SelectorVideoequLABEL_DESC_VIDEO- LABEL_GDT
?
SelectorCallGateTestequLABEL_CALL_GATE_TEST- LABEL_GDT + SA_RPL3
; END of [SECTION .gdt]
?
[SECTION .data1] ; 数据段
ALIGN32
[BITS32]
LABEL_DATA:
SPValueInRealModedw0
; 字符串
PMMessage:db"In Protect Mode now. ^-^", 0; 进入保护模式后显示此字符串
OffsetPMMessageequPMMessage - $$
StrTest:db"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
OffsetStrTestequStrTest - $$
DataLenequ$ - LABEL_DATA
; END of [SECTION .data1]
?
?
; 全局堆栈段
[SECTION .gs]
ALIGN32
[BITS32]
LABEL_STACK:
times 512 db 0
TopOfStackequ$ - LABEL_STACK - 1
; END of [SECTION .gs]
?
?
; 堆栈段ring3
[SECTION .s3]
ALIGN32
[BITS32]
LABEL_STACK3:
times 512 db 0
TopOfStack3equ$ - LABEL_STACK3 - 1
; END of [SECTION .s3]
?
?
; TSS ---------------------------------------------------------
[SECTION .tss]
ALIGN32
[BITS32]
LABEL_TSS:
DD0; Back
DDTopOfStack; 0 级堆栈 -->除了0级堆栈外,其他字段没做任何初始化。因为本例中只用到这部分
DDSelectorStack; ? ? ? ? -->除了0级堆栈外,其他字段没做任何初始化。因为本例中只用到这部分
?
DD0; 1 级堆栈
DD0;?
DD0; 2 级堆栈
DD0;?
DD0; CR3
DD0; EIP
DD0; EFLAGS
DD0; EAX
DD0; ECX
DD0; EDX
DD0; EBX
DD0; ESP
DD0; EBP
DD0; ESI
DD0; EDI
DD0; ES
DD0; CS
DD0; SS
DD0; DS
DD0; FS
DD0; GS
DD0; LDT
DW0; 调试陷阱标志
DW$ - LABEL_TSS + 2; I/O位图基址
DB0ffh; I/O位图结束标志
TSSLenequ$ - LABEL_TSS
; TSS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
?
?
[SECTION .s16]
[BITS16]
LABEL_BEGIN:
movax, cs
movds, ax
moves, ax
movss, ax
movsp, 0100h
?
mov[LABEL_GO_BACK_TO_REAL+3], ax
mov[SPValueInRealMode], sp
?
; 初始化 16 位代码段描述符
movax, cs
movzxeax, ax
shleax, 4
addeax, LABEL_SEG_CODE16
movword [LABEL_DESC_CODE16 + 2], ax
shreax, 16
movbyte [LABEL_DESC_CODE16 + 4], al
movbyte [LABEL_DESC_CODE16 + 7], ah
?
; 初始化 32 位代码段描述符
xoreax, eax
movax, cs
shleax, 4
addeax, LABEL_SEG_CODE32
movword [LABEL_DESC_CODE32 + 2], ax
shreax, 16
movbyte [LABEL_DESC_CODE32 + 4], al
movbyte [LABEL_DESC_CODE32 + 7], ah
?
; 初始化测试调用门的代码段描述符
xoreax, eax
movax, cs
shleax, 4
addeax, LABEL_SEG_CODE_DEST
movword [LABEL_DESC_CODE_DEST + 2], ax
shreax, 16
movbyte [LABEL_DESC_CODE_DEST + 4], al
movbyte [LABEL_DESC_CODE_DEST + 7], ah
?
; 初始化数据段描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_DATA
movword [LABEL_DESC_DATA + 2], ax
shreax, 16
movbyte [LABEL_DESC_DATA + 4], al
movbyte [LABEL_DESC_DATA + 7], ah
?
; 初始化堆栈段描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_STACK
movword [LABEL_DESC_STACK + 2], ax
shreax, 16
movbyte [LABEL_DESC_STACK + 4], al
movbyte [LABEL_DESC_STACK + 7], ah
?
; 初始化堆栈段描述符(ring3)
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_STACK3
movword [LABEL_DESC_STACK3 + 2], ax
shreax, 16
movbyte [LABEL_DESC_STACK3 + 4], al
movbyte [LABEL_DESC_STACK3 + 7], ah
?
; 初始化 LDT 在 GDT 中的描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_LDT
movword [LABEL_DESC_LDT + 2], ax
shreax, 16
movbyte [LABEL_DESC_LDT + 4], al
movbyte [LABEL_DESC_LDT + 7], ah
?
; 初始化 LDT 中的描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_CODE_A
movword [LABEL_LDT_DESC_CODEA + 2], ax
shreax, 16
movbyte [LABEL_LDT_DESC_CODEA + 4], al
movbyte [LABEL_LDT_DESC_CODEA + 7], ah
?
; 初始化Ring3描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_CODE_RING3
movword [LABEL_DESC_CODE_RING3 + 2], ax
shreax, 16
movbyte [LABEL_DESC_CODE_RING3 + 4], al
movbyte [LABEL_DESC_CODE_RING3 + 7], ah
?
; 初始化 TSS 描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_TSS
movword [LABEL_DESC_TSS + 2], ax
shreax, 16
movbyte [LABEL_DESC_TSS + 4], al
movbyte [LABEL_DESC_TSS + 7], ah
?
; 为加载 GDTR 作准备
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_GDT; eax <- gdt 基地址
movdword [GdtPtr + 2], eax; [GdtPtr + 2] <- gdt 基地址
?
; 加载 GDTR
lgdt[GdtPtr]
?
; 关中断
cli
?
; 打开地址线A20
inal, 92h
oral, 00000010b
out92h, al
?
; 准备切换到保护模式
moveax, cr0
oreax, 1
movcr0, eax
?
; 真正进入保护模式
jmpdword SelectorCode32:0; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 ?处
?
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
?
LABEL_REAL_ENTRY:; 从保护模式跳回到实模式就到了这里
movax, cs
movds, ax
moves, ax
movss, ax
?
movsp, [SPValueInRealMode]
?
inal, 92h; ┓
andal, 11111101b; ┣ 关闭 A20 地址线
out92h, al; ┛
?
sti; 开中断
?
movax, 4c00h; ┓
int21h; ┛回到 DOS
; END of [SECTION .s16]
?
?
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS32]
?
LABEL_SEG_CODE32:
movax, SelectorData
movds, ax; 数据段选择子
movax, SelectorVideo
movgs, ax; 视频段选择子
?
movax, SelectorStack
movss, ax; 堆栈段选择子
?
movesp, TopOfStack
?
?
; 下面显示一个字符串
movah, 0Ch; 0000: 黑底 ? ?1100: 红字
xoresi, esi
xoredi, edi
movesi, OffsetPMMessage; 源数据偏移
movedi, (80 * 10 + 0) * 2; 目的数据偏移。屏幕第 10 行, 第 0 列。
cld
.1:
lodsb
testal, al
jz.2
mov[gs:edi], ax
addedi, 2
jmp.1
.2:; 显示完毕
?
callDispReturn
?
; Load TSS
movax, SelectorTSS
ltrax; 在任务内发生特权级变换时要切换堆栈,而内层(高特权级)堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器TR。
?
pushSelectorStack3
pushTopOfStack3
pushSelectorCodeRing3
push0
retf; Ring0 -> Ring3,历史性转移!将打印数字 '3'。
?
; ------------------------------------
DispReturn:
pusheax
pushebx
moveax, edi
movbl, 160
divbl
andeax, 0FFh
inceax
movbl, 160
mulbl
movedi, eax
popebx
popeax
?
ret
; DispReturn 结束---------------------
?
SegCode32Lenequ$ - LABEL_SEG_CODE32
; END of [SECTION .s32]
?
?
[SECTION .sdest]; 调用门目标段
[BITS32]
LABEL_SEG_CODE_DEST:
movax, SelectorVideo
movgs, ax; 视频段选择子(目的)
movedi, (80 * 12 + 0) * 2; 屏幕第 12 行, 第 0 列。
movah, 0Ch; 0000: 黑底 ? ?1100: 红字
moval, 'C'
mov[gs:edi], ax
; Load LDT
movax, SelectorLDT
lldtax
jmpSelectorLDTCodeA:0; 跳入局部任务,将打印字母 'L'。
;retf
SegCodeDestLenequ$ - LABEL_SEG_CODE_DEST
; END of [SECTION .sdest]
?
?
; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
[SECTION .s16code]
ALIGN32
[BITS16]
LABEL_SEG_CODE16:
; 跳回实模式:
movax, SelectorNormal
movds, ax
moves, ax
movfs, ax
movgs, ax
movss, ax
?
moveax, cr0
andal, 11111110b
movcr0, eax
?
LABEL_GO_BACK_TO_REAL:
jmp0:LABEL_REAL_ENTRY; 段地址会在程序开始处被设置成正确的值
?
Code16Lenequ$ - LABEL_SEG_CODE16
?
; END of [SECTION .s16code]
?
?
; LDT
[SECTION .ldt]
ALIGN32
LABEL_LDT:
; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 段基址 ? ? ? 段界限 ? ? , ? 属性
LABEL_LDT_DESC_CODEA:Descriptor ? ? ? 0, ? ? CodeALen - 1, ? DA_C + DA_32; Code, 32 位
?
LDTLenequ$ - LABEL_LDT
?
; LDT 选择子
SelectorLDTCodeAequLABEL_LDT_DESC_CODEA- LABEL_LDT + SA_TIL
; END of [SECTION .ldt]
?
?
; CodeA (LDT, 32 位代码段)
[SECTION .la]
ALIGN32
[BITS32]
LABEL_CODE_A:
movax, SelectorVideo
movgs, ax; 视频段选择子(目的)
?
movedi, (80 * 13 + 0) * 2; 屏幕第 13 行, 第 0 列。
movah, 0Ch; 0000: 黑底 ? ?1100: 红字
moval, 'L'
mov[gs:edi], ax
?
; 准备经由16位代码段跳回实模式
jmpSelectorCode16:0
CodeALenequ$ - LABEL_CODE_A
; END of [SECTION .la]
?
?
; CodeRing3
[SECTION .ring3]
ALIGN32
[BITS32]
LABEL_CODE_RING3:
movax, SelectorVideo
movgs, ax; 视频段选择子(目的)
?
movedi, (80 * 14 + 0) * 2; 屏幕第 14 行, 第 0 列。
movah, 0Ch; 0000: 黑底 ? ?1100: 红字
moval, '3'
mov[gs:edi], ax
?
callSelectorCallGateTest:0; 测试调用门(有特权级变换),将打印字母 'C'。
jmp$
SegCodeRing3Lenequ$ - LABEL_CODE_RING3
; END of [SECTION .ring3]