2008年2月7日 星期四

IA-32 Architecture (2/4) - Protected Mode Memory Architecture

簡介

在 IA-32 架構中,protected mode 是標準的記憶體架構,不但支援 segmentation,還支援 paging。

首先,memory address 的轉換是必須要知道的,以下先用一張圖來說明:


在 protected mode 支援了複雜的 segmentation 機制,其中 segment 單元會將 logical address 轉為 32-bit linear address,而 paging 單元會將 32-bit linear address 轉為 32-bit physical address。

若是沒有 paging 的機制,則 logical address 會直接轉換為 32-bit physical address。

接著以下用一張圖說明 segment 單元將 logical address 轉為 32-bit linear address 的過程:


在 segment register 中儲存的是 segment descriptor table 的索引值,用來取得相對應的 segment descriptor;而 segment descriptor 中則包含了 32-bit segment base address、size、存取權限 .... 等資訊

【註】descriptor table 包含了許多 segment descriptor,而每一個 segment descriptor 都有其 index 作為識別。

除了之外,為了將 logical address 轉為相對應的 linear address,還需要加入一個 offset 值,而 offset 則可以是 16-bit 或是 32-bit 的數值。


Segment Registers

每一個 segment register 都分為 visible 與 invisible 兩個部分,而我們一般提到的 segment register 都是指其 visible 的部分(長度為 16 bits),也其為 segment selector,以下用一張圖來說明:


其中 segment selector 共分為三個部分:
  1. Index
    使用 index 就可以取得在 local descriptor table(或是 global descriptor table) 中的 segment descriptor。
    根據上面的圖,可以看出 index 的長度為 13 bits,因此可以從 descriptor table 取得 8192(213) 個不同的 segment descriptor
  2. Table Indicator (TI)
    用來決定哪種 descriptor table 要被使用:
    0:global descriptor table
    1:local descriptor table
  3. Requester Privilege Level (RPL)
    設定資料的存取權限之用。數值越小,存取權限越大,例如:Linux kernel 使用 0,而一般程式使用 3。

Segment Descriptors

顧名思義,segment descriptor 所提供的是 segment 的相關屬性,包含了 32-bit base address、20-bit segment 長度、各種控制、狀態資訊 .... 等等,以下用一張圖來表示:


以下針對上圖的各欄位進行說明:

Base Address

由上圖三個紅色部分所組成的,長度為 32-bit,因此最大可以指向實體記憶體空間為 4GB 的 segment。
而若要轉為 linear address,就必須要加上 offset 值。

G(granularity bit)

用來指定 segment size 的單位。

有兩種情況:
  1. G = 0,則每單位為 1 byte
  2. G = 1,則每單位為 4KB。

Segment Limit

由上圖的兩個藍色部分所組成,長度為 20-bit,用來指定每個 segment 的大小,但須搭配上面的 G bit,因此會有兩種情形:
  1. G = 0,則可定址空間為 1 byte ~ 1 MB(220 x 1 byte)
  2. G = 1,則可定址空間為 4 KB ~ 4 GB(220 x 4KB)

D/B bit

若在 CS(code segment) 中,此 bit 稱為 D bit。會有以下兩種情形:
  1. D = 0,則運算元與 offset 長度預設為 16 bits
  2. D = 1,則運算元與 offset 長度預設為 32 bits。

若在 DS(data segment) 中,此 bit 稱為 B bit,作為控制 stack 的長度與 stack pointer 之用。會有以下兩種情形:
  1. B = 0,則 stack 相關的操作會使用 SP register,而 stack 空間上限為 0xFFFF
  2. B = 1,則 stack 相關的操作會使用 ESP register,而 stack 空間上限為 0xFFFFFFFF。

一般來說,在 protected mode 中,B = 1(set);若在 real mode 中,則 B = 0(clear)。

S bit

用來判斷 segment 屬於 system segment 或是 application segment。會有以下兩種情形:
  1. S = 0,則屬於 system segment
  2. S = 1,則屬於 application(code or data) segment。

DPL(Descriptor Privilege Level)

定義 segment 的權限等級。

Type

用來判斷 segment 的類型。

以 application segment 為例,分為 code segment 與 data segment。

假設是 data segment(儲存資料的記憶體位址),Type 可以將其定義為 read-only、read-write .... 等等不同類型;若是 code segment(儲存指令的記憶體位址),則 Type 可以定義為 execute-only、execute/read-only .... 等等不同類型。

P bit

用來判斷是否此 segment 是存在的的。

假設 P = 1,當有 segment selector 讀進此 segment register 時,CPU 會產生 segment-not-present 的例外。


Segment Descriptor Table

segment descriptor table 即為儲存 segment descriptor 的陣列,其中的每個 segment descriptor 都有所屬的特定 index。

而 descriptor table 一共可以分為以下三種類型:
  1. GDT(Global Descriptor Table)
  2. LDT(Local Descriptor Table)
  3. IDT(Interrupt Descriptor Table)

每個 descriptor table 的大小介於 8 bytes ~ 64 KB 之間。

其中 IDT(Interrupt Descriptor Table) 是作為中斷處理之用;而 GDT(Global Descriptor Table) 與 LDT(Local Descriptor Table) 最多可以包含 213 = 8192 個長度為 8 bits 的 segment descriptor。

另外,每個 descriptor table 都有一個相對應的 register,而這個 register 作用是在於儲存 32-bit 的 linear base address 與 16-bit 的 descriptor table 大小,分別是:
  • GDT => GDTR
  • LDT => LDTR

這兩個 register 有指令可以使用他們(load => lgdt、lldt,store => sgdt、sldt),不過通常這個部分都是由 OS 來作。

最後描述一下 GDT 與 LDT 的差異所在:
  • GDT(Global Descriptor Table)
    數量只有一個,所有在系統中的 task 都可以使用此 table 中的 descriptor,通常 GDT 中所包含的都是給 OS 所用的 code 及 data。
  • LDT(Local Descriptor Table)
    數量可以有多個,每個 LDT 中所包含的 descriptor 都是屬於某支程式,而有些 LDT 的 descriptor 可能包含 code、data、stack .... 等等。


Segmentation Models

在 IA-32 架構下,單一 segment 最大可以擴展到 4GB。若是將 segment base address 設定為 0,並設定其 size 為 4 GB,就可以達成 segment 的大小為 4 GB 的目的,而這種作法在 UNIX 或 Linux 都見的到,稱為 flat model

另外還有一種稱為 multisegment model,以下先用一張圖來表示:


一般的程式可能會使用超過 6 個 segment,在正常的情況下,相關的 segment 資訊都會讀入 segment descriptor 中(超過 6 個),但每一次可用的僅有 6 個 segment(因為僅有 6 個 segment register),若要啟用尚未使用的 segment,只要將指向 segment 的 selector 讀入 segment register,CPU 就可以從相對應的 descriptor table 中存取該 segment。

沒有留言:

張貼留言