虛幻模式
在虛幻的方式利用瞭如何在 Intel 和 AMD 處理器的載入和儲存的資訊來描述段兩個事實。
-
處理器將在移動期間獲取的描述符資訊快取記憶體在保護模式下的選擇器暫存器中。
這些資訊儲存在選擇器暫存器本身的架構不可見部分中。 -
在真實模式中,選擇器暫存器稱為段暫存器,但除此之外,它們指定相同的暫存器組,因此它們也具有不可見的部分。這些部分用固定值填充,但是對於從剛剛載入的值派生的基數。
在這種觀點中,真實模式只是保護模式的一種特殊情況:其中段的資訊,例如基數和限制,在沒有 GDT / LDT 的情況下被提取,但仍然從段暫存器隱藏部分讀取。
通過切換保護模式並製作 GDT 可以建立具有所需屬性的段,例如 0 的基數和 4GiB 的限制。
通過連續載入選擇器暫存器,這些屬性被快取記憶體,然後可以以真實模式切換回來並具有段暫存器,通過該段暫存器訪問整個 32 位地址空間。
BITS 16
jmp 7c0h:__START__
__START__:
push cs
pop ds
push ds
pop ss
xor sp, sp
lgdt [GDT] ;Set the GDTR register
cli ;We don't have an IDT set, we can't handle interrupts
;Entering protected mode
mov eax, cr0
or ax, 01h ;Set bit PE (bit 0) of CR0
mov cr0, eax ;Apply
;We are now in Protected mode
mov bx, 08h ;Selector to use, RPL = 0, Table = 0 (GDT), Index = 1
mov fs, bx ;Load FS with descriptor 1 info
mov gs, bx ;Load GS with descriptor 1 info
;Exit protected mode
and ax, 0fffeh ;Clear bit PE (bit0) of CR0
mov cr0, eax ;Apply
sti
;Back to real mode
;Do nothing
cli
hlt
GDT:
;First entry, number 0
;Null descriptor
;Used to store a m16&32 object that tells the GDT start and size
dw 0fh ;Size in byte -1 of the GDT (2 descriptors = 16 bytes)
dd GDT + 7c00h ;Linear address of GDT start (24 bits)
dw 00h ;Pad
dd 0000ffffh ;Base[15:00] = 0, Limit[15:00] = 0ffffh
dd 00cf9200h ;Base[31:24] = 0, G = 1, B = 1, Limit[19:16] = 0fh,
;P = 1, DPL = 0, E = 0, W = 1, A = 0, Base[23:16] = 00h
TIMES 510-($-$$) db 00h
dw 0aa55h
注意事項
- 一旦重新載入段暫存器,即使具有相同的值,處理器也會根據當前模式重新載入隱藏屬性。這就是為什麼上面的程式碼使用
fs
和gs
來儲存擴充套件段:這種暫存器不太可能被各種 16 位服務使用/儲存/恢復。 lgdt
指令不會載入指向 GDT 的遠指標,而是載入 24 位(可以被覆蓋為 32 位) 線性地址。這不是近地址,而是實體地址 (因為必須禁用分頁)。這就是GDT+7c00h
的原因。- 上面的程式是一個載入程式(對於 MBR,它沒有 BPB),其設定
cs
/ds
/ss
TP 7C00h 處,並開始從 0 位置的計數器,以便在偏移的位元組 X 在檔案中是在偏移量 X 在段 7C00h 處和在將線性地址 7C00h 處+ X 。 - 必須禁用中斷,因為在保護模式下短時間往返沒有設定 IDT。
- 程式碼使用 hack 來儲存 6 個位元組的程式碼。
lgdt
載入的結構儲存在… GDT 本身,在空描述符(第一個描述符)中。
有關 GDT 描述符的說明,請參閱“ 英特爾手冊”第 3A 卷第 3.4.3 章。