保护模式10:输入输出保护敏感指令

http://www.joenchen.com/archives/210

保护模式10:输入输出保护敏感指令

为了支持多任务, X86体系不但需要实现任务的隔离与共享, 前面几篇我们已经有了一些体验, 但是仅仅任务隔离与保护还是不够的, 还需要对输入/输出进行保护, 这样一个没有权限的程序就不能随便的去访问一些端口,也不能够随便的执行一些指令. 本篇我们就来具体看看实现细节!




X86除了上一篇介绍的特权指令外, 还有这个敏感指令, 特权指令的话, 只能在特权模式下执行, 也就是0环, 其他环执行就异常. 敏感指令的话, 需要查看IOPL.


X86将一系列的指令归类为IO敏感指令, 这些指令想要得到执行, 必须在CPL <= IOPL的情况下. 在其他情况下, 则产生通用保护异常(#GP), 敏感指令有这么几条, CLI, STI, IN, INS, OUT, OUTS…除了CLI, STI以外这几条指令, 除了CPL <= IOPL不满足产生异常, IN, INS, OUT, OUTS, 在CPL > IOPL的情况下, 如果IO许可位图是允许的也是可以访问的.


这里又搞出一个 I/O许可位图, I/O许可位图处于当前TSS中. 所以可以每个任务有自己特别的I/O许可位图.这样可以有效的区分不同的任务实现高精度的控制, 不过好像Windows也没有利用这个特性, 据说是太慢了??


I/O许可位图由二进制串组成, 每一位对应一个IO地址, 从0开始计数. 和中断号一样. 如果位串的该位为0, 那么在CPL <= IOPL的情况下也允许执行, 否则#(GP). I/O许可位图有很多, 因为X86支持的I/O地址空间为64K,  最长可以到64K,所以I/O许可位图最长为8K(64K/8),但是一般任务根本用不了这么多的位图. 所以一般这样分配, 从TSS的104字节开始, 列出自己想填写的I/O许可位图, 对于不想列出的后面部分以0FF结束就可以了.


还有有可能在读取I/O许可位图的时候, 读取的位图位4位, 比如INSD, 一下操作4个地址空间, 需要4个位图, 那么很有可能在读取低位的在一个字节, 读取高位的时候又在一个字节. 所以X86为了避免这种情况, 每次读取I/O许可位图的时候是2个字节2个字节读取的, 这样. 不管多坏的情况也不可能超过2个字节. 这样在结尾加个0ffh也就比较好理解了, 如果不加那就越界了. 加其他的值也不好区分, 只有每个位加1才不会曲解原来的I/O许可位图.


除了上面说的, 还有就是对IOPL, Eflags中的标记位进行保护了, 如果这些标记位允许随意更改, 那么上面谈的就形同虚设了,所以只有特权级为0的程序才能够修改IOPL和VM位, 相对于IOPL更内层的特权级才能够修改IF位. 如果特权级不符合要求, 修改这些位的话, 也不会异常, CPU会忽略. OK差不多就是这么多东西了!


老套路,说完这个基本的概念, 就该说说这个演示代码的逻辑了. 这个演示代码的话,和以前都是一样首先初始化进入保护模式应该初始化的东西, 然后进入保护模式过渡段, 然后在保护模式的过渡段中跳到Demo段中,在这里装载了自己的TR和初始化了TSS中的LDTR, 初始化了演示代码段的 SS:ESP, CS:EIP. LDTR. DS, 等等.然后通过任务门切换到_TestCodeBegin中, 第一次切换的代码, 很显然在CPL == IOPL的情况下, 写一系列端口是没有问题的,所以不会异常, 第二次则因为违反了I/O许可位图规定而产生异常. (#GP), 第3次CPL >= IOPL, 可是使用了CLI, 还是要异常的, 第4次, CPL == IOPL 但是执行0环才可以执行的指令还是要产生异常!


试验完了. 就跳回过渡段, 然后回到实模式下. 整个世界清静了.. 还是和以前一样, 有图有真相!


http://www.joenchen.com/JoenTools/IOPL.rar






;============================================================================
;演示保护模式下的IO保护
;编译选项请参见 makefile  TAB = 8
;============================================================================
.686p
Include pm.inc
option casemap:none
Stack_Len equ 1024 ;堆栈大小
;============================================================================
GdtSeg Segment use16 ;全局描述符表
; ;段基址 ;段界限 ;属性
Dummy: Descriptor 0, 0, 0 ;空的描述符
Normal: Descriptor 0, 0ffffh, DA_DRW ;规范段描述符
g_DataDesc: Descriptor 0,     0fffffh, DA_DRWG or DA_DPL3 ;全局4G数据段
g_IdtCode32Desc:        Descriptor      0,      IdtCodeSegLen-1, DA_CR or DA_32 or DA_DPL1 ;中断处理函数描述符
g_CodeTempDesc: Descriptor 0, 0ffffh, DA_C ;非一致代码段16位
g_CodeSwitchDesc: Descriptor 0, DemoCodeSegLen-1, DA_C or DA_32 ;数据段
g_VideoDesc: Descriptor 0b8000h,0ffffh, DA_DRW or DA_DPL3 ;显存段(可读写)
g_DemoTssDesc: Descriptor 0, DemoTssSegLen-1, DA_386TSS   ;演示任务TSS段描述符
g_TestTssDesc: Descriptor 0, TestTssSegLen-1, DA_386TSS ;测试任务TSS段描述符
g_DemoLdtDesc: Descriptor 0, LdtDemoSegLen-1, DA_LDT ;演示任务的LDT描述符
g_TestLdtDesc: Descriptor 0, LdtTestSegLen -1, DA_LDT ;测试代码段的LDT描述符
;----------------------------------------------------------------------------
;任务门 段选择子 入口 参数个数 属性
g_TestTask: Gate g_TestTssSelector, 0, 0, DA_TaskGate ;386任务门指向任务描述符
g_DemoTask: Gate g_DemoTssSelector, 0, 0, DA_TaskGate or DA_DPL2 ;386任务门指向任务描述符
GDTLen equ $ - GdtSeg ;GDT长度
;----------------------------------------------------------------------------
GDT_Ptr word GDTLen-1 ;VGDT
dword 0
_IDT_Ptr        fword   0                       ;VIDT
_RegSp word ? ;用于保存SS:SP
_RegSs word ?
;----------------------------------------------------------------------------
NormalSelector equ Normal - GdtSeg ;规范段选择子
g_DataSelector equ g_DataDesc - GdtSeg or SA_RPL3 ;全局数据段
g_CodeTempSelector equ g_CodeTempDesc - GdtSeg ;临时代码段选择子
g_DemoCodeSelector equ g_CodeSwitchDesc - GdtSeg ;任务切换代码段
g_VideoSelector equ g_VideoDesc   - GdtSeg ;LDT视频段选择子
g_DemoTssSelector equ g_DemoTssDesc - GdtSeg ;TSS演示段描述符选择子
g_DemoLdtSelector equ g_DemoLdtDesc - GdtSeg ;演示代码段LDT描述符
g_TestTssSelector equ g_TestTssDesc - GdtSeg ;TSS测试段描述符选择子
g_TestLdtSelector equ g_TestLdtDesc - GdtSeg ;测试代码段的LDT
g_TestTaskSelector equ g_TestTask - GdtSeg ;测试代码任务门
g_DemoTaskSelector equ g_DemoTask - GdtSeg or SA_RPL2 ;演示任务任务门
g_IdtCodeSelector equ g_IdtCode32Desc - GdtSeg or SA_RPL1 ;中断处理代码
GdtSeg Ends
;============================================================================
LdtTestSeg Segment use32 ;测试任务段的LDT
;  ;段基址   ;段界限 ;属性
L_TestStack1Desc: Descriptor 0,     Stack_Len-1, DA_DRW or DA_DPL1 or DA_32 ;1环堆栈段
L_TestStack2Desc: Descriptor 0,     Stack_Len-1, DA_DRW or DA_DPL2 or DA_32 ;1环堆栈段
L_TestStack3Desc: Descriptor 0,     Stack_Len-1, DA_DRW or DA_DPL3 or DA_32 ;1环堆栈段
L_TestCode1Desc: Descriptor 0,TestCodeSegLen-1, DA_C or DA_32 or DA_DPL1 ;32位测试代码段
L_TestCode2Desc: Descriptor 0,TestCodeSegLen-1, DA_C or DA_32 or DA_DPL2 ;32位测试代码段
L_TestCode3Desc: Descriptor 0,TestCodeSegLen-1, DA_C or DA_32 or DA_DPL3 ;32位测试代码段
;----------------------------------------------------------------------------
L_TestCode1Selector equ L_TestCode1Desc - LdtTestSeg + SA_RPL1 + SA_TIL ;32位测试代码段选择子
L_TestCode2Selector equ L_TestCode2Desc - LdtTestSeg + SA_RPL2 + SA_TIL ;32位测试代码段选择子
L_TestCode3Selector equ L_TestCode3Desc - LdtTestSeg + SA_RPL3 + SA_TIL ;32位测试代码段选择子
L_TestStack1Selector equ L_TestStack1Desc - LdtTestSeg + SA_RPL1 + SA_TIL ;测试任务段的1环选择子
L_TestStack2Selector equ L_TestStack2Desc - LdtTestSeg + SA_RPL2 + SA_TIL ;测试任务段的1环选择子
L_TestStack3Selector equ L_TestStack3Desc - LdtTestSeg + SA_RPL3 + SA_TIL ;测试任务段的1环选择子
LdtTestSegLen equ $ - LdtTestSeg
LdtTestSeg Ends
;============================================================================
LdtDemoSeg Segment use32 ;演示代码段LDT
;  ;段基址   ;段界限 ;属性
L_DemoCodeDesc: Descriptor 0,DemoCodeSegLen-1, DA_C or DA_32 ;32位代码段
L_DemoStackDesc: Descriptor 0,     Stack_Len-1, DA_DRW or DA_32 ;演示代码段选择子


L_DemoStackSelector equ L_DemoStackDesc - LdtDemoSeg + SA_TIL ;演示代码堆栈选择子
L_DemoCodeSelector equ L_DemoCodeDesc - LdtDemoSeg + SA_TIL ;演示代码代码段选择子
LdtDemoSegLen equ $ - LdtDemoSeg
LdtDemoSeg Ends
;============================================================================
IdtSeg Segment use32 ;中断描述符表


repeat          13
        Gate    g_IdtCodeSelector,  _IdtOther,0,  DA_386TGate ;0-Ch陷阱门处理地址
endm
Gate    g_IdtCodeSelector,  _IdtGp,   0,  DA_386TGate ;d通用故障处理
repeat          242
        Gate    g_IdtCodeSelector,  _IdtOther,0,  DA_386TGate ;e-256h陷阱门处理地址
endm
IdtSegLen equ $ - IdtSeg
IdtSeg Ends
;============================================================================
IdtCodeSeg Segment use32 ;中断处理代码


_IdtOther equ $ - IdtCodeSeg
IdtOther Proc ;其他类型的错误处理


;----------------------------------------------------------------------------
;edi, 已经被初始化了
lea esi, SzOther
mov ecx, sizeof SzOther ;显示其他错误字符串
cld


@@: lodsb
mov ah, 0ch
stosw
loop @b


iretd
IdtOther Endp


;----------------------------------------------------------------------------
_IdtGp equ $ - IdtCodeSeg ;通用故障处理
IdtGp Proc


;----------------------------------------------------------------------------
;显示错误字符串
mov esi, TestDataSeg
shl esi, 4
lea ecx, SzEroor
add esi, ecx ;esi-->字符串
mov ecx, sizeof SzEroor
cld
@@: lodsb
mov ah, 0ah
stosw
loop @b
;----------------------------------------------------------------------------
;将任务从忙置为闲
mov esi, GdtSeg
shl esi, 4
lea ecx, g_DemoTssDesc
add esi, ecx


mov al, byte ptr ds:[esi+5]
and al, 0f0h
or al, 9h ;将任务置为可用
mov byte ptr ds:[esi+5], al
;----------------------------------------------------------------------------
mov esp, Stack_Len ;跳过堆栈
;因为iretd中不能够作为任务返回, 所以这里使用JMP
Jmp32 g_DemoTaskSelector, 0


IdtGp Endp


IdtCodeSegLen equ $ - IdtCodeSeg
IdtCodeSeg Ends
;============================================================================
DemoTssSeg Segment use32 ;演示任务TSS段
DemoTss TSS <0>
byte 0ffh
DemoTssSegLen equ $ - DemoTssSeg
DemoTssSeg Ends
;============================================================================
DemoStackSeg Segment use32 ;演示代码段堆栈
byte Stack_Len dup (0)
DemoStackSeg Ends
;============================================================================
DemoCodeSeg Segment use32 ;演示代码段


_DemoBegin equ $ - DemoCodeSeg
DemoBegin Proc ;32位代码段入口


;----------------------------------------------------------------------------
;初始化自己的TSS, 用于在任务门中返回
mov ax, g_DataSelector ;全局数据段
mov ds, ax


mov ax, g_DemoLdtSelector
lldt ax ;装载LDTR


mov ax, L_DemoStackSelector
mov ss, ax
mov esp, Stack_Len ;置SS:ESP


xor edi, edi
mov edi, DemoTssSeg
shl edi, 4
lea ecx, DemoTss
add edi, ecx
mov word ptr ds:[edi+TSS.regLdtr], g_DemoLdtSelector;写入自己的LDTR


mov ax, g_DemoTssSelector
ltr ax ;装载演示段TR
;----------------------------------------------------------------------------
;初始化演示代码的TSS, 用于进行任务门转移
mov edi, TestTssSeg
shl edi, 4
lea ecx, StTestTss
add edi, ecx


;初始化TSS的SS:ESP
mov word ptr ds:[edi+TSS.regSs], L_TestStack1Selector
mov dword ptr ds:[edi+TSS.regEsp], Stack_Len
mov word ptr ds:[edi+TSS.regDs], g_DataSelector


;ds:esi-->>数据段--指向ds:SzCpl1, 5行5列
mov esi, TestDataSeg
shl esi, 4
lea eax, SzCpl1
add esi, eax
mov dword ptr ds:[edi+TSS.regEsi], esi
mov dword ptr ds:[edi+TSS.regEbx], 5 * 80 * 2 + 5 * 2
mov dword ptr ds:[edi+TSS.regEdi], 5 * 80 * 2 + (5 + sizeof SzCpl1 ) * 2


mov word ptr ds:[edi+TSS.regCs], L_TestCode1Selector
mov dword ptr ds:[edi+TSS.regEip], _TestCodeBegin
mov dword ptr ds:[edi+TSS.regEflags], IOPL1
mov word ptr ds:[edi+TSS.regLdtr], g_TestLdtSelector


;通过任务门转移到 测试任务TestCodeSeg-->_TestCodeBegin
CALL32 g_TestTaskSelector, 0
;----------------------------------------------------------------------------
;中断处理是1环的, 这里会异常, 所以填写1环的堆栈
mov word ptr ds:[edi+TSS.regSs], L_TestStack2Selector
mov dword ptr ds:[edi+TSS.regEsp], Stack_Len;初始化TSS的SS:ESP


mov word ptr ds:[edi+TSS.regSs1], L_TestStack1Selector
mov dword ptr ds:[edi+TSS.regEsp1], Stack_Len


;ds:esi-->>数据段--指向ds:SzCpl1, 5行5列
mov esi, TestDataSeg
shl esi, 4
lea eax, SzCpl2
add esi, eax
mov dword ptr ds:[edi+TSS.regEsi], esi
mov dword ptr ds:[edi+TSS.regEbx], 6 * 80 * 2 + 5 * 2
mov dword ptr ds:[edi+TSS.regEdi], 6 * 80 * 2 + ( 5 + sizeof SzCpl2 ) * 2
mov word ptr ds:[edi+TSS.regDs], g_DataSelector


mov word ptr ds:[edi+TSS.regCs], L_TestCode2Selector
mov dword ptr ds:[edi+TSS.regEip], _TestCodeBegin
mov dword ptr ds:[edi+TSS.regEflags], IOPL1 ;TSS的IOPL值
mov word ptr ds:[edi+TSS.regLdtr], g_TestLdtSelector


;通过任务门转移到 测试任务TestCodeSeg-->_TestCodeBegin
CALL32 g_TestTaskSelector, 0
;----------------------------------------------------------------------------
;这里再次测试敏感指令, 特权级位2 IOPL=1 会异常
mov word ptr ds:[edi+TSS.regSs], L_TestStack2Selector
mov dword ptr ds:[edi+TSS.regEsp], Stack_Len;初始化TSS的SS:ESP


mov word ptr ds:[edi+TSS.regSs1], L_TestStack1Selector
mov dword ptr ds:[edi+TSS.regEsp1], Stack_Len


;ds:esi-->>数据段--指向ds:SzCpl1, 5行5列
mov esi, TestDataSeg
shl esi, 4
lea eax, SzCpl3
add esi, eax
mov dword ptr ds:[edi+TSS.regEsi], esi
mov dword ptr ds:[edi+TSS.regEbx], 7 * 80 * 2 + 5 * 2
mov dword ptr ds:[edi+TSS.regEdi], 7 * 80 * 2 + ( 5 + sizeof SzCpl3 ) * 2
mov word ptr ds:[edi+TSS.regDs], g_DataSelector


mov word ptr ds:[edi+TSS.regCs], L_TestCode2Selector
mov dword ptr ds:[edi+TSS.regEip], _TestCode2Begin
mov dword ptr ds:[edi+TSS.regEflags], IOPL1 ;TSS的IOPL值
mov word ptr ds:[edi+TSS.regLdtr], g_TestLdtSelector


;通过任务门转移到 测试任务TestCodeSeg-->_TestCodeBegin
CALL32 g_TestTaskSelector, 0
;----------------------------------------------------------------------------
;这里再次测试敏感指令, 特权级位2 IOPL=2 但是执行了只有在0环才能够执行的特权指令
mov word ptr ds:[edi+TSS.regSs], L_TestStack2Selector
mov dword ptr ds:[edi+TSS.regEsp], Stack_Len;初始化TSS的SS:ESP


mov word ptr ds:[edi+TSS.regSs1], L_TestStack1Selector
mov dword ptr ds:[edi+TSS.regEsp1], Stack_Len


;ds:esi-->>数据段--指向ds:SzCpl1, 5行5列
mov esi, TestDataSeg
shl esi, 4
lea eax, SzCpl4
add esi, eax
mov dword ptr ds:[edi+TSS.regEsi], esi
mov dword ptr ds:[edi+TSS.regEbx], 8 * 80 * 2 + 5 * 2
mov dword ptr ds:[edi+TSS.regEdi], 8 * 80 * 2 + ( 5 + sizeof SzCpl4 ) * 2
mov word ptr ds:[edi+TSS.regDs], g_DataSelector


mov word ptr ds:[edi+TSS.regCs], L_TestCode2Selector
mov dword ptr ds:[edi+TSS.regEip], _TestCode2Begin
mov dword ptr ds:[edi+TSS.regEflags], IOPL2 ;TSS的IOPL值
mov word ptr ds:[edi+TSS.regLdtr], g_TestLdtSelector


;通过任务门转移到 测试任务TestCodeSeg-->_TestCodeBegin
CALL32 g_TestTaskSelector, 0
;----------------------------------------------------------------------------
;返回实模式
Jmp32 g_CodeTempSelector, _GoToProtect
DemoBegin Endp
;----------------------------------------------------------------------------
DemoCodeSegLen equ $ - DemoCodeSeg
DemoCodeSeg Ends
;============================================================================
TestStackSeg Segment use32
byte Stack_Len dup (0)
TestStackSeg Ends
;============================================================================
TestDataSeg Segment use32 ;测试代码段的数据段
SzCpl1 byte "Test Task1, CPL = 1; IOPL = 1!", 0
SzCpl2 byte "Test Task2, CPL = 2; IOPL = 1!", 0
SzCpl3 byte "Test Task3, CPL = 2; IOPL = 1!", 0
SzCpl4 byte "Test Task4, CPL = 2; IOPL = 2!", 0
SzEroor byte "#GP Error !", 0
SzOther byte "Other Error!", 0
TestDataSegLen equ $ - TestDataSeg
TestDataSeg Ends
;============================================================================
TestTssSeg Segment use32 ;测试任务TSS段
StTestTss TSS <0>
IoMap label byte ;IO许可位图
byte 8 dup ( 0ffh ) ;端口00h-3fh
byte 11111011b ;端口40h-47h
byte 3 dup ( 0ffh ) ;端口48h-5fh
byte 11111101b ;端口60h-67h
byte 0 ;端口68h-6fh
byte 0ffh ;端口结束标记
TestTssSegLen equ $ - TestTssSeg
TestTssSeg Ends
;============================================================================
TestCodeSeg Segment use32 ;测试代码段
;----------------------------------------------------------------------------
_MakeBeep Proc uses ebx esi edi ecx _dwPitch:dword;直接操作端口发出声音


;初始化定时器, 是向端口43H输出数据0B6H即可
mov al, 10110110y ;b6h
out 43h, al         ; Timer 8253-5 (AT: 8254.2).


;向硬件定时器2(42h)端口写入1193167控制发声频率
mov eax, _dwPitch
out 42h, al
mov al, ah
out 42h, al


;打开扬声器
in al, 61h
or   al, 11y
out 61h, al
DO_DELAY 20000h ;Bochs上面这个延时就可用了
;关闭扬声器
in al, 61h
and al, 11111100y
out 61h, al
ret
_MakeBeep Endp
;----------------------------------------------------------------------------
        ;显示一条信息_lpStr:字符串首地址
        ;_dwXY开始显示地址
_PrintMessage   Proc    uses esi edi  _lpStr:dword, _dwXY:dword


        mov     esi, _lpStr
        xor     ecx, ecx
;----------------------------------------------------------------------------
@@:     mov     al, byte ptr ds:[esi]
        inc     esi
        inc     ecx
        or      al, al
        jnz     @b                                      ;ecx == 字符串长度
        dec     ecx
;----------------------------------------------------------------------------
        mov     esi, _lpStr
        mov     edi, _dwXY
@@:     lodsb
        mov     ah, 0ch                                 ;属性红色字
        stosw
        loop    @b
        ret
_PrintMessage   Endp
;----------------------------------------------------------------------------
;测试代码段入口, 测试一系列敏感指令
_TestCodeBegin equ $ - TestCodeSeg
TestCodeBegin Proc


mov ax, g_VideoSelector
mov es, ax


Invoke _PrintMessage, esi,ebx 


Invoke _MakeBeep, TONE_1 ;发出个声音
;----------------------------------------------------------------------------
;此处证明了通过任务门, 可以用iretd返回, 或使用jmp32跳回去
iretd
;通过任务门切换回演示任务
;Jmp32 g_DemoTaskSelector, 0
;----------------------------------------------------------------------------
jmp TestCodeBegin
TestCodeBegin Endp
;----------------------------------------------------------------------------
;测试代码2入口, 测试一系列敏感指令
_TestCode2Begin equ $ - TestCodeSeg
TestCode2Begin Proc


mov ax, g_VideoSelector
mov es, ax


Invoke _PrintMessage, esi,ebx ;打印当前CPL和IOPL


cli
clts
iretd
jmp TestCode2Begin
TestCode2Begin Endp
TestCodeSegLen equ $ - TestCodeSeg
TestCodeSeg Ends


;============================================================================
;16位段, 由实模式跳入
;============================================================================
g_Code16Seg Segment use16
_GoToProtect Proc ;返回实模式
mov ax, NormalSelector
mov fs, ax ;规范选择子
mov es, ax
mov ds, ax
mov ss, ax
clts ;清除任务标记


mov eax, cr0 ;关PE位, 进入实模式
and al, 0feh
mov cr0, eax


;刷新段选择子缓冲区, 退回实模式
Jmp16 <seg StartCodeSeg >, < offset _RealProtect >
_GoToProtect Endp
;----------------------------------------------------------------------------
_ProtectEntry Proc ;实模式跳入入口


;16位转32位代码段
Jmp16 g_DemoCodeSelector, <_DemoBegin >
;----------------------------------------------------------------------------
_ProtectEntry Endp
g_Code16Seg Ends
;============================================================================
;起始代码段初始化保护模式的各个结构, 然后跳入保护模式
;============================================================================
StartCodeSeg Segment use16
_InitGdt Proc uses es ;初始化全局描述符表


xor eax, eax
mov ax, GdtSeg
mov es, ax ;es-->全局描述符表
;----------------------------------------------------------------------------
shl eax, 4
mov dword ptr es:[GDT_Ptr+2], eax ;初始化VGDT描述符
;----------------------------------------------------------------------------
xor eax, eax
mov ax, g_Code16Seg ;初始化十六位的代码段
shl eax, 4
mov word ptr es:[g_CodeTempDesc+2], ax ;段基址低位
shr eax, 16
mov byte ptr es:[g_CodeTempDesc+4], al ;段基址高地址低位
mov byte ptr es:[g_CodeTempDesc+7], ah ;段基址高地址高位
;----------------------------------------------------------------------------
xor eax, eax
mov ax, DemoTssSeg ;初始化演示TSS段描述符
shl eax, 4
mov word ptr es:[g_DemoTssDesc+2], ax
shr eax, 16
mov byte ptr es:[g_DemoTssDesc+4], al
mov byte ptr es:[g_DemoTssDesc+7], ah
;----------------------------------------------------------------------------
xor eax, eax
mov ax, TestTssSeg ;初始化测试TSS段描述符
shl eax, 4
mov word ptr es:[g_TestTssDesc+2], ax
shr eax, 16
mov byte ptr es:[g_TestTssDesc+4], al
mov byte ptr es:[g_TestTssDesc+7], ah
;----------------------------------------------------------------------------
xor eax, eax
mov ax, DemoCodeSeg ;初始化任务切换段
shl eax, 4
mov word ptr es:[g_CodeSwitchDesc+2], ax
shr eax, 16
mov byte ptr es:[g_CodeSwitchDesc+4], al
mov byte ptr es:[g_CodeSwitchDesc+7], ah
;----------------------------------------------------------------------------
xor eax, eax
mov ax, LdtTestSeg ;初始化测试代码段的LDT
shl eax, 4
mov word ptr es:[g_TestLdtDesc+2], ax
shr eax, 16
mov byte ptr es:[g_TestLdtDesc+4], al
mov byte ptr es:[g_TestLdtDesc+7], ah
;----------------------------------------------------------------------------
xor eax, eax
mov ax, LdtDemoSeg ;初始化测试代码段的LDT
shl eax, 4
mov word ptr es:[g_DemoLdtDesc+2], ax
shr eax, 16
mov byte ptr es:[g_DemoLdtDesc+4], al
mov byte ptr es:[g_DemoLdtDesc+7], ah
;----------------------------------------------------------------------------
xor eax, eax
mov ax, IdtCodeSeg ;初始化测试代码段的LDT
shl eax, 4
mov word ptr es:[g_IdtCode32Desc+2], ax
shr eax, 16
mov byte ptr es:[g_IdtCode32Desc+4], al
mov byte ptr es:[g_IdtCode32Desc+7], ah
;----------------------------------------------------------------------------
lgdt fword ptr es:[GDT_Ptr] ;装载GDT
;----------------------------------------------------------------------------
ret
_InitGdt Endp
;----------------------------------------------------------------------------
_InitDemoLdt Proc uses es ;初始化演示代码段LDT


mov ax, LdtDemoSeg
mov es, ax
;----------------------------------------------------------------------------
xor eax, eax
mov ax, DemoStackSeg ;初始化演示代码段堆栈
shl eax, 4
mov word ptr es:[L_DemoStackDesc+2], ax
shr eax, 16
mov byte ptr es:[L_DemoStackDesc+4], al
mov byte ptr es:[L_DemoStackDesc+7], ah
;----------------------------------------------------------------------------
xor eax, eax
mov ax, DemoCodeSeg ;初始化32位代码段
shl eax, 4
mov word ptr es:[L_DemoCodeDesc+2], ax
shr eax, 16
mov byte ptr es:[L_DemoCodeDesc+4], al
mov byte ptr es:[L_DemoCodeDesc+7], ah
;----------------------------------------------------------------------------
ret
_InitDemoLdt Endp
;----------------------------------------------------------------------------
_InitTestLdt Proc uses es ;初始化测试代码段LDT


mov ax, LdtTestSeg
mov es, ax
;----------------------------------------------------------------------------
xor eax, eax
mov ax, TestStackSeg ;初始化1环堆栈段
shl eax, 4
mov word ptr es:[L_TestStack1Desc+2], ax
mov word ptr es:[L_TestStack2Desc+2], ax
mov word ptr es:[L_TestStack3Desc+2], ax
shr eax, 16
mov byte ptr es:[L_TestStack1Desc+4], al
mov byte ptr es:[L_TestStack2Desc+4], al
mov byte ptr es:[L_TestStack3Desc+4], al


mov byte ptr es:[L_TestStack1Desc+7], ah
mov byte ptr es:[L_TestStack2Desc+7], ah
mov byte ptr es:[L_TestStack3Desc+7], ah
;----------------------------------------------------------------------------
xor eax, eax
mov ax, TestCodeSeg ;初始化测试代码段
shl eax, 4
mov word ptr es:[L_TestCode1Desc+2], ax
mov word ptr es:[L_TestCode2Desc+2], ax
mov word ptr es:[L_TestCode3Desc+2], ax
shr eax, 16
mov byte ptr es:[L_TestCode1Desc+4], al
mov byte ptr es:[L_TestCode2Desc+4], al
mov byte ptr es:[L_TestCode3Desc+4], al


mov byte ptr es:[L_TestCode1Desc+7], ah
mov byte ptr es:[L_TestCode2Desc+7], ah
mov byte ptr es:[L_TestCode3Desc+7], ah
;----------------------------------------------------------------------------


ret
_InitTestLdt Endp
;----------------------------------------------------------------------------
_InitIdt Proc uses ds ;初始化中断描述符表
local _Vidt:fword


xor eax,eax
mov ax, GdtSeg
mov ds, ax
;----------------------------------------------------------------------------
sidt fword ptr ds:[_IDT_Ptr] ;保存IDT


mov word ptr ss:[_Vidt], IdtSegLen ;IDT长度
mov eax, IdtSeg
shl eax, 4
mov dword ptr ss:[_Vidt+2], eax
cli
lidt fword ptr ss:[_Vidt] ;装载IDT
;----------------------------------------------------------------------------
ret
_InitIdt Endp
;----------------------------------------------------------------------------
Jmain Proc


call _InitGdt ;初始化GDT全局描述符
call _InitDemoLdt ;初始化演示代码段LDT
call _InitTestLdt ;初始化测试代码段LDT
call _InitIdt ;初始化IDT
;----------------------------------------------------------------------------
mov ax, GdtSeg
mov ds, ax


mov ds:[_RegSs], ss
mov ds:[_RegSp], sp ;保存SS:SP


_EnableA20 ;开A20地址线
mov eax, cr0
or eax, 1
mov cr0, eax ;开启分段, 进入保护模式


xor ax, ax
mov es, ax
;----------------------------------------------------------------------------
Jmp16 g_CodeTempSelector, <offset _ProtectEntry>;跳入保护模式


Jmain Endp
;----------------------------------------------------------------------------
_RealProtect Proc                                    ;返回保护模式


        mov     ax, GdtSeg
        mov     ds, ax
        lss sp, dword ptr ds:[_RegSp] ;恢复SS:SP
        lidt fword ptr ds:[_IDT_Ptr] ;恢复IDT


        _DisableA20                                     ;关A20地址线, 开中断
        sti
        mov     ax, 4c00h
        int     21h
_RealProtect Endp
StartCodeSeg Ends


End Jmain
文章发表于 2011-09-28 07:11:14, 所属分类 保护模式 。您可以通过订阅RSS 2.0来跟踪该文章的评论。 本文Trackback地址:http://www.joenchen.com/archives/210/trackback。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值