从ring0到ring3再到ring0(pmtest5.asm)

; ==========================================
; pmtest5.asm
; 编译方法:nasm pmtest5.asm -o pmtest5.com
; ==========================================

%include "pm.inc" ; 常量, 宏, 以及一些说明

org 0100h
 jmp LABEL_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 ;实际基址在s16实模式中
LABEL_DESC_CODE_RING3: Descriptor        0, SegCodeRing3Len - 1, DA_C + DA_32 + DA_DPL3 ; 非一致代码段, 32
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; Stack, 32 位
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 ;Gate为宏,于Descriptor类似
; GDT 结束

GdtLen  equ $ - LABEL_GDT ; GDT长度
GdtPtr  dw GdtLen - 1 ; GDT界限
  dd 0  ; GDT基地址

; GDT 选择子
SelectorNormal  equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorCode32  equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorCode16  equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT
SelectorCodeRing3 equ LABEL_DESC_CODE_RING3 - LABEL_GDT + SA_RPL3
SelectorData  equ LABEL_DESC_DATA  - LABEL_GDT
SelectorStack  equ LABEL_DESC_STACK - LABEL_GDT
SelectorStack3  equ LABEL_DESC_STACK3 - LABEL_GDT + SA_RPL3
SelectorLDT  equ LABEL_DESC_LDT  - LABEL_GDT
SelectorTSS  equ LABEL_DESC_TSS  - LABEL_GDT
SelectorVideo  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", 0
OffsetStrTest  equ StrTest - $$
DataLen   equ $ - LABEL_DATA
; END of [SECTION .data1]


; 全局堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
 times 512 db 0
TopOfStack equ $ - LABEL_STACK - 1
; END of [SECTION .gs]                                        //内层ring0级堆栈段


; 堆栈段ring3
[SECTION .s3]
ALIGN 32
[BITS 32]
LABEL_STACK3:
 times 512 db 0
TopOfStack3 equ $ - LABEL_STACK3 - 1
; END of [SECTION .s3]                                     //外层ring3级堆栈段


; TSS ---------------------------------------------------------------------------------------------
[SECTION .tss]
ALIGN 32
[BITS 32]
LABEL_TSS:
  DD 0   ; Back
  DD TopOfStack  ; 0 级堆栈                              //内层ring0级堆栈放入Tss中
  DD SelectorStack  ;
  DD 0   ; 1 级堆栈
  DD 0   ;
  DD 0   ; 2 级堆栈
  DD 0   ;                                                        //Tss中最高只能放入Ring2级堆栈,ring3级堆栈不需要放入
  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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


[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   ; 堆栈段选择子                                           //ss esp 指向内层ring0堆栈

 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

 ; Load TSS
 mov ax, SelectorTSS                                    // ltr 是ring0级指令,只能运行在ring0级代码段中在ring0中需要手动加载tss实现堆栈切换。在call中是系统自动调用tss切换的
 ltr ax ;                                                      //在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器 TR。

 push SelectorStack3
 push TopOfStack3                                                    //执行retf指令时系统会自动在第四步切换到ring3级的这个堆栈
 push SelectorCodeRing3                                           //retf 时,需要检查该选择子得rpl,看是否需要变换特权级
 push 0                                                                   //特权转换使用retf使用之前,压入ss,sp,cs,ip 到内层Ring0堆栈  push 0 表示ip为0.    0为偏移量

  retf    ; Ring0 -> Ring3,历史性转移!将打印数字 '3'。  //使用retf 实现从ring0-->ring3。

                                                                              //retf 这个指令实际上要执行很多的内部操作。详情请见:http://www.cnblogs.com/wanghj-dz/archive/2011/04/24/2026174.html

; ------------------------------------------------------------------------
DispReturn:                                                            //打印一个回车,return表示回车
 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:                                            //ring0级代码段
 mov ax, SelectorVideo
 mov gs, ax   ; 视频段选择子(目的)

 mov edi, (80 * 12 + 0) * 2 ; 屏幕第 12 行, 第 0 列。
 mov ah, 0Ch   ; 0000: 黑底    1100: 红字
 mov al, 'C'
 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
[SECTION .ldt]
ALIGN 32
LABEL_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]


; CodeA (LDT, 32 位代码段)
[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:
 mov ax, SelectorVideo
 mov gs, ax   ; 视频段选择子(目的)

 mov edi, (80 * 13 + 0) * 2 ; 屏幕第 13 行, 第 0 列。
 mov ah, 0Ch   ; 0000: 黑底    1100: 红字
 mov al, 'L'
 mov [gs:edi], ax

 ; 准备经由16位代码段跳回实模式
 jmp SelectorCode16:0
CodeALen equ $ - LABEL_CODE_A
; END of [SECTION .la]


; CodeRing3
[SECTION .ring3]
ALIGN 32
[BITS 32]
LABEL_CODE_RING3:                                                                          //ring3级代码段
 mov ax, SelectorVideo
 mov gs, ax   ; 视频段选择子(目的)

 mov edi, (80 * 14 + 0) * 2 ; 屏幕第 14 行, 第 0 列。
 mov ah, 0Ch   ; 0000: 黑底    1100: 红字
 mov al, '3'
 mov [gs:edi], ax

 call SelectorCallGateTest:0 ; 测试调用门(有特权级变换),将打印字母 'C'。   //使用call调用门实现特权转换,实现从ring3---->ring0。
 jmp $                                                                                                //详情请见:http://www.cnblogs.com/wanghj-dz/archive/2011/04/24/2026174.html
SegCodeRing3Len equ $ - LABEL_CODE_RING3                                     //因为处在3级的代码中,调用门也要设置为3级,通过调用门可以跳掉0级代码
; END of [SECTION .ring3]

-------------------------------------------------------------------------------------------------------------------------------------------------------------

 

我感觉:首先是[section .gdt] 里面有所有的段描述符,求gdt长度,gdtptr,选择子

                    [section .data]     

                    [section .stack]

                    [section .tss]   最后都是求得各段的大小

                    [section  .s16]  实模式,初始化所有的段描述符

                      。。。。

posted on 2011-04-23 20:01  wanghj_dz  阅读(2532)  评论(0编辑  收藏  举报

导航