15 Global Descriptor Table
16 bit mode 是以 segment based 的方式 access memory。32 bit mode 將 logic address 轉成 physical address 的方式跟 16 bit mode 不同。在 32 bit mode 下,segment register 的值代表的是 global descriptor table 中某個 segment descriptor 的 index。
segment descriptor 是個 8 byte 的 structure,包含以下資訊:
- base address (32 bits):定義 segment 從 physical memory 的起始位置
- segment limit (20 bit):segment 的 size
- flags:這些 flag 會影響 CPU 如何解讀 segment,例如 privilige level 跟這塊 segment 是不是 read-only 或 write-only 等。
下圖是 segment descriptor 的結構:
最簡單的 segment configuration 稱為 basic flat mode,是由兩個重疊的 segment 組成,一個是給 code 使用,另一個是放 data。這兩個 segment 會 cover 整個 4GB 的 memory。那也因為這兩個 segment 位置是重疊的,當然不可能有什麼保護機制(保護一個 segment 不被另一個 segment 亂搞之類的)。
GDT 的 descriptor entry 就是用來描述每個 segment 的。除了 code 跟 data segment 之外,GDT 的第一個 descriptor 必須要是 null descriptor,內容是 8 byte 的 0。這是在轉換到 protcted mode 時,如果不小心忘記設定 segment register,會讓我們剛好 access 到 null descriptor。而 CPU 在 access 到 null descriptor 的時候會 raise exception(interrupt)讓我們知道有錯誤。
code segment 的 descriptor configuration:
- Base:
0x0
- Limit:
0xffff
- Present:1,表示這個 segment 是 present 在 memory 中。這個 config 之後會用於 virtual memory。
- Privilege:0,ring 0 是最高 privilige
- Descriptor type:1,code 或 data segment
- Type:
- Code:1,因為這是 code segment
- Confirming:0,比較低 privilege 的 segment 不能 call 這個 segment 的 code,這是 memory protection 的關鍵
- Readable:1,1 為 readable,0 為 execute only
- Accessed:0,這個參數通常用在 virtual memory 的 debug
- Other flags:
- Granularity:1,這會將 Limit 乘以 4K(16 * 16 * 16),所以
0xffff
的 limit 會變成0xffff000
。 - 32-bit default:1,因為我們的 segment 會放 32-bit code。0 則是 16-bit。這實際上是設定 operation 的 default size,例如 push
0x4
到 stack 的時候,會自動被擴展成 32-bit 的數字。 - 64-bit code segment:0,32-bit CPU 不會用到
- AVL:0,這是可以設給自己使用的 bit
- Granularity:1,這會將 Limit 乘以 4K(16 * 16 * 16),所以
因為我們的 data segment 跟 code segment 位置是重疊的,所以除了以下的 type flag 之外,data segment 的 configuration 跟 code segment 是一樣的:
- Code:0
- Expand down:0
- Writable:1
- Accessed:0
Define the GDT in Assembly
我們會用 db
、dw
、dd
這幾個指令來放 bytes、建立 GDT。
CPU 需要知道 GDT 有多長,我們會用 GDT descriptor 來描述 GDT,GDT descriptor 包含:
- GDT size (16 bit)
- GDT address (32 bit)
1 | gdt_start: |