第13课 从保护模式返回实模式

  前几节课我们演示了从实模式进入到保护模式,那么从保护模式返回到实模式具体怎么操作呢?

  先将上一节的程序列出:

  1 %include "inc.asm"
  2 
  3 org 0x9000
  4 
  5 jmp CODE16_SEGMENT
  6 
  7 [section .gdt]
  8 ; GDT definition
  9 ;                                 段基址,       段界限,       段属性
 10 GDT_ENTRY       :     Descriptor    0,            0,           0
 11 CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32
 12 VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32
 13 DATA32_DESC     :     Descriptor    0,    Data32SegLen  - 1,   DA_DR + DA_32
 14 STACK_DESC      :     Descriptor    0,      TopOfStackInit,    DA_DRW + DA_32        
 15 ; GDT end
 16 
 17 GdtLen    equ   $ - GDT_ENTRY
 18 
 19 GdtPtr:
 20           dw   GdtLen - 1
 21           dd   0
 22           
 23           
 24 ; GDT Selector
 25 
 26 Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
 27 VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0
 28 Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
 29 StackSelector     equ (0x0004 << 3) + SA_TIG + SA_RPL0
 30 
 31 ; end of [section .gdt]
 32 
 33 TopOfStackInit    equ  0x7c00
 34 
 35 [section .dat]
 36 [bits 32]
 37 DATA32_SEGMENT:
 38     DTOS                 db    "D.T.OS!", 0
 39     DTOS_OFFSET          equ   DTOS - $$
 40     HELLO_WORLD          db    "Hello World!", 0
 41     HELLO_WORLD_OFFSET   equ  HELLO_WORLD - $$
 42 
 43 Data32SegLen  equ $ - DATA32_SEGMENT
 44 
 45 [section .s16]
 46 [bits 16]
 47 CODE16_SEGMENT:
 48     mov ax, cs
 49     mov ds, ax
 50     mov es, ax
 51     mov ss, ax
 52     mov sp, TopOfStackInit
 53     
 54     ; initialize GDT for 32 bits code segment
 55     mov esi, CODE32_SEGMENT
 56     mov edi, CODE32_DESC
 57     
 58     call InitDescItem
 59     
 60     mov esi, DATA32_SEGMENT
 61     mov edi, DATA32_DESC
 62     
 63     call InitDescItem
 64     
 65     ; initialize GDT pointer struct
 66     mov eax, 0
 67     mov ax, ds
 68     shl eax, 4
 69     add eax, GDT_ENTRY
 70     mov dword [GdtPtr + 2], eax
 71 
 72     ; 1. load GDT
 73     lgdt [GdtPtr]
 74     
 75     ; 2. close interrupt
 76     cli 
 77     
 78     ; 3. open A20
 79     in al, 0x92
 80     or al, 00000010b
 81     out 0x92, al
 82     
 83     ; 4. enter protect mode
 84     mov eax, cr0
 85     or eax, 0x01
 86     mov cr0, eax
 87     
 88     ; 5. jump to 32 bits code
 89     jmp dword Code32Selector : 0
 90 
 91     
 92 ; esi    --> code segment label
 93 ; edi    --> descriptor label
 94 InitDescItem:
 95     push eax
 96     
 97     mov eax, 0
 98     mov ax, cs
 99     shl eax, 4
100     add eax, esi
101     mov word [edi + 2], ax
102     shr eax, 16
103     mov byte [edi + 4], al
104     mov byte [edi + 7], ah
105     
106     pop eax
107     
108     ret
109     
110     
111 [section .s32]
112 [bits 32]
113 CODE32_SEGMENT:
114     mov ax, VideoSelector
115     mov gs, ax
116     
117     mov ax, StackSelector
118     mov ss, ax
119     
120     mov ax, Data32Selector
121     mov ds, ax
122     
123     mov ebp, DTOS_OFFSET
124     mov bx, 0x0C
125     mov dh, 12
126     mov dl, 33
127     
128     call PrintString
129     
130     mov ebp, HELLO_WORLD_OFFSET
131     mov bx, 0x0C
132     mov dh, 13
133     mov dl, 30
134     
135     call PrintString
136     
137     jmp $
138 
139 ; ds:ebp   --> string address
140 ; bx       --> attribute
141 ; dx       --> dh : row, dl : col
142 PrintString:
143     push ebp
144     push eax
145     push edi 
146     push cx
147     push dx
148     
149 print:
150     mov cl, [ds:ebp]
151     cmp cl, 0
152     je end
153     mov eax, 80
154     mul dh
155     add al, dl
156     shl eax, 1
157     mov edi, eax
158     mov ah, bl
159     mov al, cl
160     mov [gs:edi], ax
161     inc ebp
162     inc dl
163     jmp print
164     
165 end:
166     pop dx
167     pop cx
168     pop edi
169     pop eax
170     pop ebp
171     
172     ret
173 
174 Code32SegLen    equ    $ - CODE32_SEGMENT

上一节中,我们跳到32位保护模式后,并没有设置栈顶指针esp,但是程序依然可以正常运行,这时怎么回事呢?原因是我们在第52行设置了栈顶指针,而我们的程序中,16位的实模式和32位的保护模式使用的栈是一样的,因此,无需重新设置程序也可以正常运行。如果在32位保护时使用的栈和16位实模式使用的栈不一样的话,就不能这样操作了,而必须在进入32位保护模式后设置esp栈顶指针。

猜你喜欢

转载自www.cnblogs.com/wanmeishenghuo/p/9462704.html