本程式示範如何在 80386 以上處理器上,從實模式(Real Mode)切換至虛擬 8086 模式(Virtual 8086 Mode, V86)。V86 模式允許在保護模式下執行實模式程式(如 DOS 程式),是 Windows 3.x/9x/NTVDM 等系統支援 DOS 相容性的核心機制。程式碼為片段,展示關鍵步驟:計算記憶體邊界、建立 GDT 描述符、載入 IDTR、切換 CR0 暫存器(PE 位元)等。
INT 12h 取得常規記憶體(KB),INT 15h, AH=88h 取得擴充記憶體(KB),換算為位元組並對齊段邊界。ES:[2Ch] 取得環境區段落,推算程式佔用記憶體上界。fill1_gdt 程序設定代碼/資料段描述符基址與限制,準備進入保護模式所需的全域描述符表。LGDT/LIDT,但 SIDT 指令已用於讀取 IDTR 內容。CR0 的 PE 位元(Bit 0),處理器進入保護模式。EFLAGS 的 VM 位元(Bit 17)置 1,通常透過 IRET 從特權級 0 返回特權級 3 任務時自動載入含 VM=1 的 EFLAGS,即進入 V86 模式。.model small
.386p
.data
base_memory dd ?
new_base dd 0
new_base1 dd 0
.code
mov cs:psp_seg,ds
mov ax,seg base_memory
mov ds,ax
mov es,ax
mov ds,ax
int 12h
movzx eax,ax
shl eax,0ah
add eax,0fffh
and ax,0f000h
mov base_memory,eax
mov ah,88h
int 15h
add ax,400h
movzx eax,ax
shl eax,0ah
and ax,0f000h
mov bx,cs:psp_seg
mov es,bx
mov si,2ch
cmp bx,es:[si]
jb ignore
mov bx,es:[si]
ignore:
movzx ebx,bx
shl ebx,4
add ebx,0fffh
and bx,0f000h
mov ecx,base_memory
sub ecx,ebx
sub eax,ecx
sub eax,010000h
mov new_base,eax
shr eax,4
mov new_base1,eax
call fill1_gdt
psp_seg dw ?
fill1_gdt proc near
movzx eax,ax
shl eax,4
mov ebx,eax
shr ebx,10h
add [si+2],ax
adc [si+4],bl
fill1_gdt endp
end
| 指令/暫存器 | 用途 |
|---|---|
INT 12h | 取得常規記憶體大小(KB),回傳 AX |
INT 15h, AH=88h | 取得擴充記憶體大小(KB),回傳 AX |
SIDT | 儲存 IDTR 內容至記憶體 |
CR0.PE | 保護模式啟用位元 (Bit 0) |
EFLAGS.VM | 虛擬 8086 模式位元 (Bit 17) |
LGDT / LIDT | 載入 GDTR / IDTR(程式碼片段未含,實作時必須補上) |
; 1. 關閉中斷
cli
; 2. 建立 GDT(含 Null、Code32、Data32、Code16、Data16、TSS 等描述符)
; 3. LGDT 載入 GDTR
; 4. LIDT 載入 IDTR(可選,保護模式需重新設定 IDT)
; 5. 啟用 A20 線(透過鍵盤控制器或 Fast A20 Gate)
; 6. 設定 CR0.PE = 1 進入保護模式
; 7. 遠跳轉至 32-bit 程式碼段刷新 CS 基址
; 8. 載入資料段暫存器 (DS, ES, FS, GS, SS) 為 32-bit 資料段選擇子
; 9. 建立/載入 TSS,設定 TR
; 10. 設定 IDT 門描述符對應 V86 模式所需中斷向量
; 11. 配置分頁(可選,V86 通常需分頁以攔截 I/O 指令)
; 12. 準備一個含 VM=1 的 EFLAGS 映像於堆疊
; 13. IRET 返回 CPL=3,處理器載入 EFLAGS.VM=1,進入 V86 模式