; ========================================== |
= |
; ========================================== |
; pmtest4.asm |
<> |
; pmtest3.asm |
; 编译方法:nasm pmtest4.asm -o pmtest4.com |
|
; 编译方法:nasm pmtest3.asm -o pmtest3.com |
; ========================================== |
= |
; ========================================== |
|
|
|
%include "pm.inc" ; 常量, 宏, 以及一些说明 |
|
%include "pm.inc" ; 常量, 宏, 以及一些说明 |
|
|
|
org 0100h |
|
org 0100h |
jmp LABEL_BEGIN |
|
jmp LABEL_BEGIN |
|
|
|
[SECTION .gdt] |
|
[SECTION .gdt] |
; GDT |
|
; GDT |
; 段基址, 段界限 , 属性 |
<> |
; 段基址, 段界限 , 属性 |
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 |
|
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 |
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描述符 |
|
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描述符 |
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C+DA_32; 非一致代码段,32 |
|
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段, 32 |
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代码段,16 |
|
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代码段, 16 |
LABEL_DESC_CODE_DEST: Descriptor 0,SegCodeDestLen-1, DA_C+DA_32; 非一致代码段,32 |
|
|
LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW ; Data |
|
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW+DA_DPL1 ; Data |
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32;Stack, 32 位 |
|
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA + DA_32; Stack, 32 位 |
LABEL_DESC_LDT: Descriptor 0, LDTLen-1, DA_LDT ; LDT |
|
LABEL_DESC_LDT: Descriptor 0, LDTLen - 1, DA_LDT ; LDT |
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址 |
|
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址 |
|
|
|
; 门 目标选择子,偏移,DCount, 属性 |
|
|
LABEL_CALL_GATE_TEST: Gate SelectorCodeDest, 0, 0, DA_386CGate+DA_DPL0 |
|
|
; GDT 结束 |
= |
; GDT 结束 |
|
|
|
GdtLen equ $ - LABEL_GDT ; GDT长度 |
|
GdtLen equ $ - LABEL_GDT ; GDT长度 |
GdtPtr dw GdtLen - 1 ; GDT界限 |
|
GdtPtr dw GdtLen - 1 ; GDT界限 |
dd 0 ; GDT基地址 |
|
dd 0 ; GDT基地址 |
|
|
|
; GDT 选择子 |
|
; GDT 选择子 |
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT |
|
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT |
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT |
|
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT |
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT |
|
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT |
SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT |
+- |
|
SelectorData equ LABEL_DESC_DATA - LABEL_GDT |
= |
SelectorData equ LABEL_DESC_DATA - LABEL_GDT |
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT |
|
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT |
SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT |
|
SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT |
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT |
|
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT |
|
+- |
|
SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT |
|
|
; END of [SECTION .gdt] |
= |
; END of [SECTION .gdt] |
|
|
|
[SECTION .data1] ; 数据段 |
|
[SECTION .data1] ; 数据段 |
ALIGN 32 |
|
ALIGN 32 |
[BITS 32] |
|
[BITS 32] |
LABEL_DATA: |
|
LABEL_DATA: |
SPValueInRealMode dw 0 |
|
SPValueInRealMode dw 0 |
; 字符串 |
|
; 字符串 |
PMMessage: db "In Protect Mode now. ^-^", 0 ; 进入保护模式后显示此字符串 |
|
PMMessage: db "In Protect Mode now. ^-^", 0 ; 进入保护模式后显示此字符串 |
OffsetPMMessage equ PMMessage - $$ |
|
OffsetPMMessage equ PMMessage - $$ |
StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0 |
|
StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0 |
OffsetStrTest equ StrTest - $$ |
|
OffsetStrTest equ StrTest - $$ |
DataLen equ $ - LABEL_DATA |
|
DataLen equ $ - LABEL_DATA |
; END of [SECTION .data1] |
|
; END of [SECTION .data1] |
|
|
|
|
|
|
; 全局堆栈段 |
|
; 全局堆栈段 |
[SECTION .gs] |
|
[SECTION .gs] |
ALIGN 32 |
|
ALIGN 32 |
[BITS 32] |
|
[BITS 32] |
LABEL_STACK: |
|
LABEL_STACK: |
times 512 db 0 |
|
times 512 db 0 |
|
|
|
TopOfStack equ $ - LABEL_STACK - 1 |
|
TopOfStack equ $ - LABEL_STACK - 1 |
|
|
|
; END of [SECTION .gs] |
|
; END of [SECTION .gs] |
|
|
|
|
|
|
[SECTION .s16] |
|
[SECTION .s16] |
[BITS 16] |
|
[BITS 16] |
LABEL_BEGIN: |
|
LABEL_BEGIN: |
mov ax, cs |
|
mov ax, cs |
mov ds, ax |
|
mov ds, ax |
mov es, ax |
|
mov es, ax |
mov ss, ax |
|
mov ss, ax |
mov sp, 0100h |
|
mov sp, 0100h |
|
|
|
mov [LABEL_GO_BACK_TO_REAL+3], ax |
|
mov [LABEL_GO_BACK_TO_REAL+3], ax |
mov [SPValueInRealMode], sp |
|
mov [SPValueInRealMode], sp |
|
|
|
; 初始化 16 位代码段描述符 |
|
; 初始化 16 位代码段描述符 |
mov ax, cs |
|
mov ax, cs |
movzx eax, ax |
|
movzx eax, ax |
shl eax, 4 |
|
shl eax, 4 |
add eax, LABEL_SEG_CODE16 |
|
add eax, LABEL_SEG_CODE16 |
mov word [LABEL_DESC_CODE16 + 2], ax |
|
mov word [LABEL_DESC_CODE16 + 2], ax |
shr eax, 16 |
|
shr eax, 16 |
mov byte [LABEL_DESC_CODE16 + 4], al |
|
mov byte [LABEL_DESC_CODE16 + 4], al |
mov byte [LABEL_DESC_CODE16 + 7], ah |
|
mov byte [LABEL_DESC_CODE16 + 7], ah |
|
|
|
; 初始化 32 位代码段描述符 |
|
; 初始化 32 位代码段描述符 |
xor eax, eax |
|
xor eax, eax |
mov ax, cs |
|
mov ax, cs |
shl eax, 4 |
|
shl eax, 4 |
add eax, LABEL_SEG_CODE32 |
|
add eax, LABEL_SEG_CODE32 |
mov word [LABEL_DESC_CODE32 + 2], ax |
|
mov word [LABEL_DESC_CODE32 + 2], ax |
shr eax, 16 |
|
shr eax, 16 |
mov byte [LABEL_DESC_CODE32 + 4], al |
|
mov byte [LABEL_DESC_CODE32 + 4], al |
mov byte [LABEL_DESC_CODE32 + 7], ah |
|
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 |
|
xor eax, eax |
mov ax, ds |
|
mov ax, ds |
shl eax, 4 |
|
shl eax, 4 |
add eax, LABEL_DATA |
|
add eax, LABEL_DATA |
mov word [LABEL_DESC_DATA + 2], ax |
|
mov word [LABEL_DESC_DATA + 2], ax |
shr eax, 16 |
|
shr eax, 16 |
mov byte [LABEL_DESC_DATA + 4], al |
|
mov byte [LABEL_DESC_DATA + 4], al |
mov byte [LABEL_DESC_DATA + 7], ah |
|
mov byte [LABEL_DESC_DATA + 7], ah |
|
|
|
; 初始化堆栈段描述符 |
|
; 初始化堆栈段描述符 |
xor eax, eax |
|
xor eax, eax |
mov ax, ds |
|
mov ax, ds |
shl eax, 4 |
|
shl eax, 4 |
add eax, LABEL_STACK |
|
add eax, LABEL_STACK |
mov word [LABEL_DESC_STACK + 2], ax |
|
mov word [LABEL_DESC_STACK + 2], ax |
shr eax, 16 |
|
shr eax, 16 |
mov byte [LABEL_DESC_STACK + 4], al |
|
mov byte [LABEL_DESC_STACK + 4], al |
mov byte [LABEL_DESC_STACK + 7], ah |
|
mov byte [LABEL_DESC_STACK + 7], ah |
|
|
|
; 初始化 LDT 在 GDT 中的描述符 |
|
; 初始化 LDT 在 GDT 中的描述符 |
xor eax, eax |
|
xor eax, eax |
mov ax, ds |
|
mov ax, ds |
shl eax, 4 |
|
shl eax, 4 |
add eax, LABEL_LDT |
|
add eax, LABEL_LDT |
mov word [LABEL_DESC_LDT + 2], ax |
|
mov word [LABEL_DESC_LDT + 2], ax |
shr eax, 16 |
|
shr eax, 16 |
mov byte [LABEL_DESC_LDT + 4], al |
|
mov byte [LABEL_DESC_LDT + 4], al |
mov byte [LABEL_DESC_LDT + 7], ah |
|
mov byte [LABEL_DESC_LDT + 7], ah |
|
|
|
; 初始化 LDT 中的描述符 |
|
; 初始化 LDT 中的描述符 |
xor eax, eax |
|
xor eax, eax |
mov ax, ds |
|
mov ax, ds |
shl eax, 4 |
|
shl eax, 4 |
add eax, LABEL_CODE_A |
|
add eax, LABEL_CODE_A |
mov word [LABEL_LDT_DESC_CODEA + 2], ax |
|
mov word [LABEL_LDT_DESC_CODEA + 2], ax |
shr eax, 16 |
|
shr eax, 16 |
mov byte [LABEL_LDT_DESC_CODEA + 4], al |
|
mov byte [LABEL_LDT_DESC_CODEA + 4], al |
mov byte [LABEL_LDT_DESC_CODEA + 7], ah |
|
mov byte [LABEL_LDT_DESC_CODEA + 7], ah |
|
|
|
; 为加载 GDTR 作准备 |
|
; 为加载 GDTR 作准备 |
xor eax, eax |
|
xor eax, eax |
mov ax, ds |
|
mov ax, ds |
shl eax, 4 |
|
shl eax, 4 |
add eax, LABEL_GDT ; eax <- gdt 基地址 |
|
add eax, LABEL_GDT ; eax <- gdt 基地址 |
mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址 |
|
mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址 |
|
|
|
; 加载 GDTR |
|
; 加载 GDTR |
lgdt [GdtPtr] |
|
lgdt [GdtPtr] |
|
|
|
; 关中断 |
|
; 关中断 |
cli |
|
cli |
|
|
|
; 打开地址线A20 |
|
; 打开地址线A20 |
in al, 92h |
|
in al, 92h |
or al, 00000010b |
|
or al, 00000010b |
out 92h, al |
|
out 92h, al |
|
|
|
; 准备切换到保护模式 |
|
; 准备切换到保护模式 |
mov eax, cr0 |
|
mov eax, cr0 |
or eax, 1 |
|
or eax, 1 |
mov cr0, eax |
|
mov cr0, eax |
|
|
|
; 真正进入保护模式 |
|
; 真正进入保护模式 |
jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处 |
|
jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处 |
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
|
|
LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里 |
|
LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里 |
mov ax, cs |
|
mov ax, cs |
mov ds, ax |
|
mov ds, ax |
mov es, ax |
|
mov es, ax |
mov ss, ax |
|
mov ss, ax |
|
|
|
mov sp, [SPValueInRealMode] |
|
mov sp, [SPValueInRealMode] |
|
|
|
in al, 92h ; ┓ |
|
in al, 92h ; ┓ |
and al, 11111101b ; ┣ 关闭 A20 地址线 |
|
and al, 11111101b ; ┣ 关闭 A20 地址线 |
out 92h, al ; ┛ |
|
out 92h, al ; ┛ |
|
|
|
sti ; 开中断 |
|
sti ; 开中断 |
|
|
|
mov ax, 4c00h ; ┓ |
|
mov ax, 4c00h ; ┓ |
int 21h ; ┛回到 DOS |
|
int 21h ; ┛回到 DOS |
; END of [SECTION .s16] |
|
; END of [SECTION .s16] |
|
|
|
|
|
|
[SECTION .s32]; 32 位代码段. 由实模式跳入. |
|
[SECTION .s32]; 32 位代码段. 由实模式跳入. |
[BITS 32] |
|
[BITS 32] |
|
|
|
LABEL_SEG_CODE32: |
|
LABEL_SEG_CODE32: |
mov ax, SelectorData |
|
mov ax, SelectorData |
mov ds, ax ; 数据段选择子 |
|
mov ds, ax ; 数据段选择子 |
mov ax, SelectorVideo |
|
mov ax, SelectorVideo |
mov gs, ax ; 视频段选择子 |
|
mov gs, ax ; 视频段选择子 |
|
|
|
mov ax, SelectorStack |
|
mov ax, SelectorStack |
mov ss, ax ; 堆栈段选择子 |
|
mov ss, ax ; 堆栈段选择子 |
|
|
|
mov esp, TopOfStack |
|
mov esp, TopOfStack |
|
|
|
|
|
|
; 下面显示一个字符串 |
|
; 下面显示一个字符串 |
mov ah, 0Ch ; 0000: 黑底 1100: 红字 |
|
mov ah, 0Ch ; 0000: 黑底 1100: 红字 |
xor esi, esi |
|
xor esi, esi |
xor edi, edi |
|
xor edi, edi |
mov esi, OffsetPMMessage ; 源数据偏移 |
|
mov esi, OffsetPMMessage ; 源数据偏移 |
mov edi, (80 * 10 + 0) * 2 ; 目的数据偏移。屏幕第 10 行, 第 0 列。 |
|
mov edi, (80 * 10 + 0) * 2 ; 目的数据偏移。屏幕第 10 行, 第 0 列。 |
cld |
|
cld |
.1: |
|
.1: |
lodsb |
|
lodsb |
test al, al |
|
test al, al |
jz .2 |
|
jz .2 |
mov [gs:edi], ax |
|
mov [gs:edi], ax |
add edi, 2 |
|
add edi, 2 |
jmp .1 |
|
jmp .1 |
.2: ; 显示完毕 |
|
.2: ; 显示完毕 |
|
|
|
call DispReturn |
|
call DispReturn |
|
|
|
; 测试调用门(无特权级变换),将打印字母 'C' |
+- |
|
call SelectorCallGateTest:0 |
|
|
;call SelectorCodeDest:0 |
|
|
|
|
|
; Load LDT |
= |
; Load LDT |
mov ax, SelectorLDT |
|
mov ax, SelectorLDT |
lldt ax |
|
lldt ax |
|
|
|
jmp SelectorLDTCodeA:0 ; 跳入局部任务,将打印字母 'L'。 |
<> |
jmp SelectorLDTCodeA:0 ; 跳入局部任务 |
|
= |
|
; ------------------------------------------------------------------------ |
|
; ------------------------------------------------------------------------ |
DispReturn: |
|
DispReturn: |
push eax |
|
push eax |
push ebx |
|
push ebx |
mov eax, edi |
|
mov eax, edi |
mov bl, 160 |
|
mov bl, 160 |
div bl |
|
div bl |
and eax, 0FFh |
|
and eax, 0FFh |
inc eax |
|
inc eax |
mov bl, 160 |
|
mov bl, 160 |
mul bl |
|
mul bl |
mov edi, eax |
|
mov edi, eax |
pop ebx |
|
pop ebx |
pop eax |
|
pop eax |
|
|
|
ret |
|
ret |
; DispReturn 结束--------------------------------------------------------- |
|
; DispReturn 结束--------------------------------------------------------- |
|
|
|
SegCode32Len equ $ - LABEL_SEG_CODE32 |
|
SegCode32Len equ $ - LABEL_SEG_CODE32 |
; END of [SECTION .s32] |
|
; END of [SECTION .s32] |
|
+- |
|
|
|
|
[SECTION .sdest]; 调用门目标段 |
|
|
[BITS 32] |
|
|
|
|
|
LABEL_SEG_CODE_DEST: |
|
|
;jmp $ |
|
|
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 |
|
|
|
|
|
retf |
|
|
|
|
|
SegCodeDestLen equ $ - LABEL_SEG_CODE_DEST |
|
|
; END of [SECTION .sdest] |
|
|
|
= |
|
|
|
|
; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式 |
|
; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式 |
[SECTION .s16code] |
|
[SECTION .s16code] |
ALIGN 32 |
|
ALIGN 32 |
[BITS 16] |
|
[BITS 16] |
LABEL_SEG_CODE16: |
|
LABEL_SEG_CODE16: |
; 跳回实模式: |
|
; 跳回实模式: |
mov ax, SelectorNormal |
|
mov ax, SelectorNormal |
mov ds, ax |
|
mov ds, ax |
mov es, ax |
|
mov es, ax |
mov fs, ax |
|
mov fs, ax |
mov gs, ax |
|
mov gs, ax |
mov ss, ax |
|
mov ss, ax |
|
|
|
mov eax, cr0 |
|
mov eax, cr0 |
and al, 11111110b |
|
and al, 11111110b |
mov cr0, eax |
|
mov cr0, eax |
|
|
|
LABEL_GO_BACK_TO_REAL: |
|
LABEL_GO_BACK_TO_REAL: |
jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值 |
|
jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值 |
|
|
|
Code16Len equ $ - LABEL_SEG_CODE16 |
|
Code16Len equ $ - LABEL_SEG_CODE16 |
|
|
|
; END of [SECTION .s16code] |
|
; END of [SECTION .s16code] |
|
|
|
|
|
|
; LDT |
|
; LDT |
[SECTION .ldt] |
|
[SECTION .ldt] |
ALIGN 32 |
|
ALIGN 32 |
LABEL_LDT: |
|
LABEL_LDT: |
; 段基址 段界限 , 属性 |
<> |
; 段基址 段界限 属性 |
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位 |
|
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位 |
|
= |
|
LDTLen equ $ - LABEL_LDT |
|
LDTLen equ $ - LABEL_LDT |
|
|
|
; LDT 选择子 |
|
; LDT 选择子 |
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL |
|
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL |
; END of [SECTION .ldt] |
|
; END of [SECTION .ldt] |
|
|
|
|
|
|
; CodeA (LDT, 32 位代码段) |
|
; CodeA (LDT, 32 位代码段) |
[SECTION .la] |
|
[SECTION .la] |
ALIGN 32 |
|
ALIGN 32 |
[BITS 32] |
|
[BITS 32] |
LABEL_CODE_A: |
|
LABEL_CODE_A: |
mov ax, SelectorVideo |
|
mov ax, SelectorVideo |
mov gs, ax ; 视频段选择子(目的) |
|
mov gs, ax ; 视频段选择子(目的) |
|
|
|
mov edi, (80 * 13 + 0) * 2 ; 屏幕第 13 行, 第 0 列。 |
<> |
mov edi, (80 * 12 + 0) * 2 ; 屏幕第 10 行, 第 0 列。 |
mov ah, 0Ch ; 0000: 黑底 1100: 红字 |
= |
mov ah, 0Ch ; 0000: 黑底 1100: 红字 |
mov al, 'L' |
|
mov al, 'L' |
mov [gs:edi], ax |
|
mov [gs:edi], ax |
|
|
|
; 准备经由16位代码段跳回实模式 |
|
; 准备经由16位代码段跳回实模式 |
jmp SelectorCode16:0 |
|
jmp SelectorCode16:0 |
CodeALen equ $ - LABEL_CODE_A |
|
CodeALen equ $ - LABEL_CODE_A |
; END of [SECTION .la] |
|
; END of [SECTION .la] |