1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
;============================================================================
;简单的切换到保护模式实例
;MASM9.00 + link 5.60 TAB = 8
;编译: ml /c /omf pm.asm
;链接: link pm.obj;
;============================================================================
.686p
Include pm.inc ;保护模式的结构定义
DataSeg Segment use16
GDT label byte ;全局描述符表
Dummy: Descriptor 0, 0, 0 ;空的描述符
;============================================================================
; ;段基址 ;段界限 ;属性
CodeDesc: Descriptor 0, 0ffffh, DA_C ;非一致代码段16位
VideoDesc: Descriptor 0b8000h, 0ffffh, DA_DRW ;显存段(可读写)
GDT_Len equ $-GDT ;GDT长度
GDT_Ptr word GDT_Len -1 ;GDTR伪描述符
dword 0
SelectorCode equ CodeDesc - GDT ;代码段选择子偏移
SelectorVideo equ VideoDesc - GDT ;视频段选择子偏移
;============================================================================
DataSeg Ends
;============================================================================
;程序入口段, 初始化GDTR 和一个代码段描述符, 然后跳到保护模式
;============================================================================
CodeSeg Segment use16 ;16位代码段
Jmain Proc
xor eax, eax
mov ax, DataSeg
mov ds, ax
;----------------------------------------------------------------------------
;初始化 CodeDesc描述符的基址
xor eax, eax
mov ax, cs
shl eax, 4
mov word ptr ds:[CodeDesc+2], ax ;段基址低地址
shr eax, 16
mov byte ptr ds:[CodeDesc+4], al ;段基址高地址低位
mov byte ptr ds:[CodeDesc+7], ah ;段基址高地址高位
;----------------------------------------------------------------------------
;初始化并加载GDTR伪描述符
xor eax, eax
mov ax, ds
shl eax, 4 ;GTDR伪描述符的段地址
add eax, offset GDT
mov dword ptr ds:[GDT_Ptr+2], eax ;GTDR伪描述符基址
lgdt fword ptr ds:[GDT_Ptr]
;----------------------------------------------------------------------------
cli
_EnableA20 ;打开A20地址线
mov eax, cr0
or eax, 1
mov cr0, eax ;开启Cr0的分段标记正式进入保护模式
;这行代码有着特殊的意义, 由此进入保护模式
Jmp16 SelectorCode, <offset _Protect >
;----------------------------------------------------------------------------
;现在已经进入了保护模式(进入历史性的时刻)
;----------------------------------------------------------------------------
;进入保护模式就写一个字符就可以
_Protect:
mov ax, SelectorVideo
mov es, ax
mov edi, (80*11+40) * 2 ;屏幕的第11行第40列
mov ah, 0ch ;属性
mov al, 'J' ;字符
mov word ptr es:[edi], ax ;写入一个字符串 Joen
add edi,2
mov al, 'o'
mov word ptr es:[edi], ax
add edi,2
mov al, 'e'
mov word ptr es:[edi], ax
add edi,2
mov al, 'n'
mov word ptr es:[edi], ax
mov eax, cr0
and al, 0feh ;关闭PE分段位, 进入实模式
mov cr0, eax
Jmp16 <SEG _Real>, < offset _Real > ;又跳回实模式
;----------------------------------------------------------------------------
;又跳回保护模式了
;----------------------------------------------------------------------------
_Real: mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
_DisableA20 ;关闭A20地址线
sti
mov ax, 4c00h
int 21h ;退出程序
Jmain Endp
CodeSeg Ends
;----------------------------------------------------------------------------
End Jmain
|