🚩 為什麼這一步至關重要?

到目前為止,我們都受限於 16 位元的「實模式(Real Mode)」。在那裡,我們只能存取約 1MB 的記憶體,且沒有任何硬體層級的權限保護。

進入 32 位元保護模式後,我們將獲得:

  1. 4GB 的定址空間:直接存取現代記憶體,不再需要煩人的段偏移計算。
  2. 硬體保護機制:透過特權等級(Privilege Levels)保護核心不被使用者程式破壞。
  3. 為 C 語言鋪路:現代編譯器(如 GCC)輸出的 32-bit 代碼必須在此模式下運行。

1. 核心機制:GDT (Global Descriptor Table)

在保護模式下,CPU 不再使用 Segment * 16 + Offset 的公式,而是透過 GDT 這張「權限清單」來決定記憶體的屬性。

🔍 深度解析:段描述符位元 (The Magic Bits)

我們在定義 GDT 時,會看到兩組神祕的位元設定。這就是決定段屬性的關鍵:

A. 存取權限位元 (Access Byte)

決定了這段記憶體是「代碼」還是「資料」,以及誰能讀寫它。

位元 (Bit) 名稱 說明 程式碼段 (1010b) 資料段 (0010b)
7 P (Present) 必須為 1 才是有效的描述符。 1 1
6-5 DPL 特權等級。00 為最高 (Kernel), 11 為最低 (User)。 00 00
4 S (System) 1 代表代碼/資料段,0 代表系統專用段。 1 1
3 Ex (Executable) 核心位元:1 為程式碼,0 為資料。 1 0
2 DC 描述段的生長方向或一致性。 0 0
1 RW 程式碼段:1 可讀;資料段:1 可寫。 1 1
0 Ac (Accessed) CPU 自動設定,初始化通常設為 0。 0 0

B. 標誌位元 (Flags)

決定了記憶體段的大小計算方式。

位元 (Bit) 名稱 說明 設定值
7 G (Granularity) 0 為 1B 單位;1 為 4KB 單位 (讓 Limit 達到 4GB)。 1
6 D/B (Size) 1 代表 32-bit 定址;0 代表 16-bit。 1
5 L (Long mode) 1 代表 64-bit。在 32-bit 開發中必須為 0。 0

2. 實作:定義 GDT (gdt.asm)

gdt_start:
; the GDT table requires an empty GDT as first entry
gdt_null:        ; 1. 強制性的空描述符 (8 bytes)
    dd 0x0
    dd 0x0

gdt_code:        ; 2. 程式碼段描述符
    dw 0xffff    ; Limit (0-15 bits)
    dw 0x0       ; Base (0-15 bits)
    db 0x0       ; Base (16-23 bits)
    db 10011010b ; Access Byte (Present, Ring 0, Code, Exec/Read)
    db 11001111b ; Flags + Limit (4KB granularity, 32-bit)
    db 0x0       ; Base (24-31 bits)

gdt_data:        ; 3. 資料段描述符
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b ; Access Byte (Present, Ring 0, Data, Read/Write)
    db 11001111b
    db 0x0

gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start - 1 ; GDT 大小
    dd gdt_start               ; GDT 起始位址

; 常數定義,方便段暫存器載入
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start