pmtest5.asm

发布时间:2014-10-25 2:23:30
来源:分享查询网

; ==============带特权级变换的调用门==============; pmtest5.asm; 编译方法:nasm pmtest5.asm -o pmtest5.com;; 执行过程:                  门;    16位实模式---->CODE32(ring0)---->CODE_RING3(ring3)----------->CODE_DEST(ring0)---->LDT(ring0)---->16位保护模式;                                        打印‘3’           打印‘G’            打印‘L’         返回实模式;; ========================================== %include "pm.inc" ; 常量, 宏, 以及一些说明 org 0100h jmp LABEL_BEGIN ;========================数据结构 GDT 和 GATE=================================[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  ; 非一致代码段, 32LABEL_DESC_CODE16: Descriptor        0,              0ffffh, DA_C    ; 非一致代码段, 16LABEL_DESC_CODE_DEST: Descriptor        0,  SegCodeDestLen - 1, DA_C + DA_32  ; 非一致代码段, 32LABEL_DESC_CODE_RING3: Descriptor        0, SegCodeRing3Len - 1, DA_C + DA_32 + DA_DPL3 ; 非一致代码段, 32LABEL_DESC_DATA: Descriptor        0,   DataLen - 1, DA_DRW   ; DataLABEL_DESC_STACK: Descriptor        0,          TopOfStack, DA_DRWA + DA_32  ; Stack, 32 位LABEL_DESC_STACK3: Descriptor        0,         TopOfStack3, DA_DRWA + DA_32 + DA_DPL3; Stack, 32 位LABEL_DESC_LDT:  Descriptor        0,          LDTLen - 1, DA_LDT   ; LDTLABEL_DESC_TSS:  Descriptor        0,          TSSLen - 1, DA_386TSS   ; TSSLABEL_DESC_VIDEO: Descriptor  0B8000h,              0ffffh, DA_DRW + DA_DPL3  ; 显存首地址 ;    门                              目标选择子,              偏移,        DCount,                    属性LABEL_CALL_GATE_TEST: Gate    SelectorCodeDest,          0,            0,                    DA_386CGate + DA_DPL3;    看到了吗,门指向了下面的一个GDT选择子; GDT 结束 GdtLen  equ $ - LABEL_GDT ; GDT长度GdtPtr  dw GdtLen - 1 ; GDT界限  dd 0  ; GDT基地址 ; GDT 选择子SelectorNormal  equ LABEL_DESC_NORMAL - LABEL_GDTSelectorCode32  equ LABEL_DESC_CODE32 - LABEL_GDTSelectorCode16  equ LABEL_DESC_CODE16 - LABEL_GDTSelectorCodeDest  equ LABEL_DESC_CODE_DEST - LABEL_GDTSelectorCodeRing3  equ LABEL_DESC_CODE_RING3 - LABEL_GDT + SA_RPL3SelectorData  equ LABEL_DESC_DATA  - LABEL_GDTSelectorStack  equ LABEL_DESC_STACK - LABEL_GDTSelectorStack3  equ LABEL_DESC_STACK3 - LABEL_GDT + SA_RPL3SelectorLDT  equ LABEL_DESC_LDT  - LABEL_GDTSelectorTSS  equ LABEL_DESC_TSS  - LABEL_GDTSelectorVideo  equ LABEL_DESC_VIDEO - LABEL_GDT ;门也有选择子,看来选择子不是与段一一对应的!;; 选择子----->段; 选择子----->门(目标选择子)------->段SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT + SA_RPL3; END of [SECTION .gdt]   ;============================数据段======================================[SECTION .data1]ALIGN 32[BITS 32]LABEL_DATA:SPValueInRealMode dw 0; 字符串PMMessage:  db "In Protect Mode now. ^-^", 0 ; 进入保护模式后显示此字符串OffsetPMMessage  equ PMMessage - $$StrTest:  db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0OffsetStrTest  equ StrTest - $$DataLen   equ $ - LABEL_DATA; END of [SECTION .data1]   ;=======================全局堆栈段 ring0=========================[SECTION .gs]ALIGN 32[BITS 32]LABEL_STACK: times 512 db 0TopOfStack equ $ - LABEL_STACK - 1; END of [SECTION .gs]   ;=======================堆栈段ring3===========================[SECTION .s3]ALIGN 32[BITS 32]LABEL_STACK3: times 512 db 0TopOfStack3 equ $ - LABEL_STACK3 - 1; END of [SECTION .s3]   ;=========================任务状态栈 TTS========================;在此程序中,只是用了高特权级目标代码段的栈地址。所以没有完全初始化TTS;[SECTION .tss]ALIGN 32[BITS 32]LABEL_TSS:  DD 0   ; Back  DD TopOfStack  ; 0 级堆栈---|  DD SelectorStack  ; ------------|  DD 0   ; 1 级堆栈   DD 0   ;   DD 0   ; 2 级堆栈  DD 0   ;   DD 0   ; CR3  DD 0   ; EIP  DD 0   ; EFLAGS  DD 0   ; EAX  DD 0   ; ECX  DD 0   ; EDX  DD 0   ; EBX  DD 0   ; ESP  DD 0   ; EBP  DD 0   ; ESI  DD 0   ; EDI  DD 0   ; ES  DD 0   ; CS  DD 0   ; SS  DD 0   ; DS  DD 0   ; FS  DD 0   ; GS  DD 0   ; LDT  DW 0   ; 调试陷阱标志  DW $ - LABEL_TSS + 2  ; I/O位图基址  DB 0ffh   ; I/O位图结束标志TSSLen  equ $ - LABEL_TSS; TSS ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;==========================程序首先执行的初始化16位代码段==========================[SECTION .s16][BITS 16]LABEL_BEGIN: mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, 0100h  mov [LABEL_GO_BACK_TO_REAL+3], ax mov [SPValueInRealMode], sp  ; 初始化 16 位代码段描述符 mov ax, cs movzx eax, ax shl eax, 4 add eax, LABEL_SEG_CODE16 mov word [LABEL_DESC_CODE16 + 2], ax shr eax, 16 mov byte [LABEL_DESC_CODE16 + 4], al mov byte [LABEL_DESC_CODE16 + 7], ah  ; 初始化 32 位代码段描述符 xor eax, eax mov ax, cs shl eax, 4 add eax, LABEL_SEG_CODE32 mov word [LABEL_DESC_CODE32 + 2], ax shr eax, 16 mov byte [LABEL_DESC_CODE32 + 4], al mov byte [LABEL_DESC_CODE32 + 7], ah  ; 初始化测试调用门的代码段描述符 xor eax, eax mov ax, cs shl eax, 4 add eax, LABEL_SEG_CODE_DEST mov word [LABEL_DESC_CODE_DEST + 2], ax shr eax, 16 mov byte [LABEL_DESC_CODE_DEST + 4], al mov byte [LABEL_DESC_CODE_DEST + 7], ah  ; 初始化数据段描述符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_DATA mov word [LABEL_DESC_DATA + 2], ax shr eax, 16 mov byte [LABEL_DESC_DATA + 4], al mov byte [LABEL_DESC_DATA + 7], ah  ; 初始化堆栈段描述符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_STACK mov word [LABEL_DESC_STACK + 2], ax shr eax, 16 mov byte [LABEL_DESC_STACK + 4], al mov byte [LABEL_DESC_STACK + 7], ah  ; 初始化堆栈段描述符(ring3) xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_STACK3 mov word [LABEL_DESC_STACK3 + 2], ax shr eax, 16 mov byte [LABEL_DESC_STACK3 + 4], al mov byte [LABEL_DESC_STACK3 + 7], ah  ; 初始化 LDT 在 GDT 中的描述符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_LDT mov word [LABEL_DESC_LDT + 2], ax shr eax, 16 mov byte [LABEL_DESC_LDT + 4], al mov byte [LABEL_DESC_LDT + 7], ah  ; 初始化 LDT 中的描述符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_CODE_A mov word [LABEL_LDT_DESC_CODEA + 2], ax shr eax, 16 mov byte [LABEL_LDT_DESC_CODEA + 4], al mov byte [LABEL_LDT_DESC_CODEA + 7], ah  ; 初始化Ring3描述符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_CODE_RING3 mov word [LABEL_DESC_CODE_RING3 + 2], ax shr eax, 16 mov byte [LABEL_DESC_CODE_RING3 + 4], al mov byte [LABEL_DESC_CODE_RING3 + 7], ah  ; 初始化 TSS 描述符 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_TSS mov word [LABEL_DESC_TSS + 2], ax shr eax, 16 mov byte [LABEL_DESC_TSS + 4], al mov byte [LABEL_DESC_TSS + 7], ah  ; 为加载 GDTR 作准备 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_GDT  ; eax <- gdt 基地址 mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址  ; 加载 GDTR lgdt [GdtPtr]  ; 关中断 cli  ; 打开地址线A20 in al, 92h or al, 00000010b out 92h, al  ; 准备切换到保护模式 mov eax, cr0 or eax, 1 mov cr0, eax  ; 真正进入保护模式 jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;下面是从保护模式返回实模式后执行的代码段;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LABEL_REAL_ENTRY: mov ax, cs mov ds, ax mov es, ax mov ss, ax  mov sp, [SPValueInRealMode]  in al, 92h  ; ┓ and al, 11111101b ; ┣ 关闭 A20 地址线 out 92h, al  ; ┛  sti   ; 开中断  mov ax, 4c00h  ; ┓ int 21h  ; ┛回到 DOS; END of [SECTION .s16]   ;==========================================================================[SECTION .s32]; 32 位代码段. 由实模式跳入.[BITS 32] LABEL_SEG_CODE32: mov ax, SelectorData mov ds, ax   ; 数据段选择子 mov ax, SelectorVideo mov gs, ax   ; 视频段选择子  mov ax, SelectorStack mov ss, ax   ; 堆栈段选择子  mov esp, TopOfStack  ; 下面显示一个字符串 mov ah, 0Ch   ; 0000: 黑底    1100: 红字 xor esi, esi xor edi, edi mov esi, OffsetPMMessage ; 源数据偏移 mov edi, (80 * 10 + 0) * 2 ; 目的数据偏移。屏幕第 10 行, 第 0 列。 cld.1: lodsb test al, al jz .2 mov [gs:edi], ax add edi, 2 jmp .1.2: ; 显示完毕  call DispReturn ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;加载TSS,准备由Ring3进入Ring0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov ax, SelectorTSS ltr ax ; 奇怪,将上面两句注释掉也可以在dos下执行并不出错; 在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。   ;;;;;;;;;;;;;;;;;;;;;;;;;;Ring0-->Ring3根本用不到TTS。这里模拟从Ring3段进入Ring0段后,返回的情形;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; push SelectorStack3 push TopOfStack3 push SelectorCodeRing3 push 0 retf    ; Ring0 -> Ring3,历史性转移!将打印数字 '3'。 ; ------------------------------------------------------------------------DispReturn: push eax push ebx mov eax, edi mov bl, 160 div bl and eax, 0FFh inc eax mov bl, 160 mul bl mov edi, eax pop ebx pop eax  ret; DispReturn 结束--------------------------------------------------------- SegCode32Len equ $ - LABEL_SEG_CODE32; END of [SECTION .s32]   ;========================调用门目标段========================[SECTION .sdest][BITS 32] LABEL_SEG_CODE_DEST: mov ax, SelectorVideo mov gs, ax   ; 视频段选择子(目的)  mov edi, (80 * 13 + 1) * 2 ; 屏幕第 12 行, 第 0 列。 mov ah, 0Ch   ; 0000: 黑底    1100: 红字 mov al, 'G' mov [gs:edi], ax  ; Load LDT mov ax, SelectorLDT lldt ax  jmp SelectorLDTCodeA:0 ; 跳入局部任务,将打印字母 'L'。  ;retf SegCodeDestLen equ $ - LABEL_SEG_CODE_DEST; END of [SECTION .sdest]   ;=====================================================================; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式[SECTION .s16code]ALIGN 32[BITS 16]LABEL_SEG_CODE16: ; 跳回实模式: mov ax, SelectorNormal mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax  mov eax, cr0 and al, 11111110b mov cr0, eax LABEL_GO_BACK_TO_REAL: jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值 Code16Len equ $ - LABEL_SEG_CODE16 ; END of [SECTION .s16code]   ;===========================数据结构LDT========================; LDT[SECTION .ldt]ALIGN 32LABEL_LDT:;                                         段基址       段界限     ,   属性LABEL_LDT_DESC_CODEA: Descriptor        0,     CodeALen - 1,   DA_C + DA_32 ; Code, 32 位 LDTLen  equ $ - LABEL_LDT ; LDT 选择子SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL; END of [SECTION .ldt]   ;========================LDT的局部任务代码段=========================; CodeA (LDT, 32 位代码段)[SECTION .la]ALIGN 32[BITS 32]LABEL_CODE_A: mov ax, SelectorVideo mov gs, ax   ; 视频段选择子(目的)  mov edi, (80 * 14 + 3) * 2 ; 屏幕第 13 行, 第 0 列。 mov ah, 0Ch   ; 0000: 黑底    1100: 红字 mov al, 'L' mov [gs:edi], ax  ; 准备经由16位代码段跳回实模式 jmp SelectorCode16:0CodeALen equ $ - LABEL_CODE_A; END of [SECTION .la]   ;===================由Ring0进入Ring3=====================; CodeRing3[SECTION .ring3]ALIGN 32[BITS 32]LABEL_CODE_RING3: mov ax, SelectorVideo mov gs, ax   ; 视频段选择子(目的)  mov edi, (80 * 12 + 0) * 2 ; 屏幕第 14 行, 第 0 列。 mov ah, 0Ch   ; 0000: 黑底    1100: 红字 mov al, '3' mov [gs:edi], ax ;我们马上就要有Ring3进入Ring0了 call SelectorCallGateTest:0 ; 测试调用门(有特权级变换),将打印字母 'C'。 jmp $SegCodeRing3Len equ $ - LABEL_CODE_RING3; END of [SECTION .ring3]

返回顶部
查看电脑版