位址轉譯與 TLB (Address Translation & TLB)

Overview Table

主題 核心內容 書頁
位址轉譯符號 N=2n(VA 空間)、M=2m(PA 空間)、P=2p(頁大小);VA = VPN+VPO;PA = PPN+PPO p.850
轉譯機制 MMUPTBR 找 page table,以 VPN 索引 PTE,PPN 串接 VPO 得 PA;PPO = VPO p.850-851
Page hit / fault 流程 hit 純硬體 5 步;fault 需 OS 介入 7 步(victim 換出、新頁換入、重新執行指令) p.851-852
Cache 與 VM 整合 多數系統用 physically addressed cache,先轉譯再查 cache;PTE 本身也可被 cache p.853
TLB MMU 內的小型 virtually addressed PTE cache,高關聯度;TLBI = VPN 低 t 位、TLBT = 其餘位 p.853-855
多層 page table 單層表太大(32-bit/4KB/4B PTE → 4MB);k 層階層化,null PTE 的子表可不存在 p.855-857
End-to-end 範例 n=14, m=12, P=64;TLB 4-way 16 entries;cache direct-mapped 16 sets、4B block p.857-860
Core i7 轉譯 48-bit VA、52-bit PA;4 層 page table;CR3 存 L1 表基底;36-bit VPN 切成 4 個 9-bit p.861-864
Linux VM area (vm_area_struct) 組織;task_struct → mm_struct(pgd, mmap)→ area list p.864-867
Linux page fault 三段檢查:位址合法?→ 權限合法?→ 正常 fault(換頁後重跑指令) p.867-869

頁層級保護:PTE 權限位 (p.849)

位址轉譯硬體每次都要讀 PTE,因此在 PTE 加上權限位 (permission bits) 就能以頁為單位控管存取:

保護「免費」搭上轉譯的便車:因為每次記憶體存取本來就要查 PTE,權限檢查不需額外的記憶體存取。

9.6 位址轉譯基礎 (p.849-851)

符號整理(Figure 9.11)

符號 意義 符號 意義
N=2n virtual address space 位址數 PPO physical page offset
M=2m physical address space 位址數 PPN physical page number
P=2p page size(bytes) CO cache 內 byte offset
VPO virtual page offset CI cache index
VPN virtual page number CT cache tag
TLBI TLB index TLBT TLB tag

形式化定義:位址轉譯是 N 元素 VAS 到 M 元素 PAS 的映射

MAP:VASPAS

MAP(A)=A 若虛擬位址 A 的資料在實體位址 A;MAP(A)= 若不在實體記憶體。

硬體轉譯流程(Figure 9.12)

              n-1        p p-1      0
  VA:        [    VPN     |   VPO   ]
                  |            |
   PTBR ──> Page  v            |
            Table[VPN] ─> PTE  |
                  | (valid=1)  |  valid=0 → page fault
                  v            v
  PA:        [    PPN     |   PPO   ]
              m-1        p p-1      0

Page hit 流程(純硬體,Figure 9.13a)

  1. Processor 產生 VA 送給 MMU。
  2. MMU 產生 PTEA(PTE address)向 cache/main memory 請求。
  3. Cache/memory 回傳 PTE 給 MMU。
  4. MMU 組出 PA 送給 cache/memory。
  5. Cache/memory 回傳資料字給 processor。

Page fault 流程(硬體 + OS,Figure 9.13b)

1-3. 同上。4. PTE 的 valid bit = 0 → MMU 觸發例外,控制權轉給 kernel 的 page fault handler。5. Handler 選出 victim page;若已被修改(dirty)則先寫回磁碟(page out)。6. Handler 將新頁 page in,並更新記憶體中的 PTE。7. Handler 返回原行程,重新執行 faulting instruction;這次變成 page hit。

Page hit:                          Page fault:
CPU ──VA──> MMU ──PTEA──> Mem      CPU ──VA──> MMU ──PTEA──> Mem
            MMU <──PTE─── Mem                  MMU <──PTE──── Mem (valid=0)
            MMU ──PA────> Mem                  MMU ──Exception──> Fault handler
CPU <─Data───────────────Mem                  handler: victim page ──> Disk
                                              handler: new page  <── Disk
                                              return & restart instruction
Page hit 完全由硬體處理;page fault 必須由硬體(觸發例外)與 OS kernel(換頁)合作完成,見 08-Exceptional-Control-Flow/01-Exceptions

9.6.1 Cache 與 VM 的整合 (p.853)

實際硬體會將「轉譯」與「cache 查找」部分重疊(p.866 Aside):Core i7 的 12-bit VPO 恰好等於 L1 cache 的 CI+CO(6+6 bits)。CPU 把 VPN 送 MMU 查 TLB 的同時,把 VPO 送 L1 cache 選 set 並讀出 8 個 tag;TLB 回傳 PPN 後直接比對 tag。這不是巧合,而是刻意的設計。

9.6.2 用 TLB 加速位址轉譯 (p.853-855)

每次 CPU 產生 VA,MMU 都要讀一次 PTE——最壞情況多一次記憶體存取(數十至數百 cycle);即使 PTE 在 L1 也要數個 cycle。解法:在 MMU 內放一個小型 PTE cache,即 TLB (translation lookaside buffer)

     n-1          p+t p+t-1    p p-1      0
VA: [  TLBT (tag)   | TLBI(idx) |   VPO   ]
     └────────── VPN ──────────┘

TLB hit(Figure 9.16a,常見情形):

  1. CPU 產生 VA → 2-3. MMU 從 TLB 取得 PTE → 4. MMU 組 PA 送 cache/memory → 5. 回傳資料。
    全部步驟都在晶片內的 MMU 完成,因此很快。

TLB miss(Figure 9.16b):MMU 必須向 L1 cache/memory 發 PTEA 取 PTE,新取得的 PTE 存入 TLB(可能覆蓋既有 entry),再組 PA 完成存取。


9.6.3 多層 Page Table (p.855-857)

單層表的問題:32-bit 位址空間、4 KB 頁、4-byte PTE → page table 大小 = 232/212×4B=4MB,且須常駐記憶體;64-bit 空間更不可行。

兩層範例(32-bit、4KB 頁、4B PTE,Figure 9.17):

省記憶體的兩個機制:

  1. null L1 PTE → 子表不存在(典型程式的 4 GB 空間大多未配置)。
  2. 只有 level 1 表須常駐;level 2 表可由 VM 系統按需建立、換入換出。

k 層一般化(Figure 9.18):VA 切成 k 個 VPN + 一個 VPO;VPN i 索引第 i 層表;第 j 層(1jk1)PTE 指向第 j+1 層表基底;第 k 層 PTE 才含 PPN(或磁碟區塊位址);PPO = VPO 不變。

VA: [ VPN 1 | VPN 2 | ... | VPN k |  VPO ]
       |       |             |       |
       v       v             v       |
  L1 PT ──> L2 PT ──> ... ──> Lk PT  |
  (PTBR/CR3)              PTE→ PPN   |
                               v     v
PA:              [    PPN    |  PPO  ]
「查 k 次 PTE 很慢」的例外:TLB 會 cache 各層的 PTE,實務上多層轉譯不比單層明顯慢 (p.857)。

9.6.4 End-to-End 轉譯範例 (p.857-860)

假設:byte-addressable、1-byte 存取、n=14m=12P=64(p=6);TLB 4-way、16 entries(→ 4 sets);L1 d-cache 為 physically addressed、direct-mapped、4-byte block、16 sets。

推導欄位寬度:

VA (14 bits): [ TLBT(6) | TLBI(2) |  VPO(6) ]
              └────── VPN(8) ─────┘
PA (12 bits): [  CT(6)  |  CI(4)  |  CO(2)  ]
              └ PPN(6) ┘└──── PPO(6) ─────┘

手算流程(VA = 0x03D4,Figure 9.20 快照):

步驟 動作
1 展開位元、切欄位 VPN=0x0F、VPO=0x14、TLBI=0x3、TLBT=0x03
2 查 TLB set 3、tag 0x03 TLB hit,回傳 PPN=0x0D
3 PA = PPN ‖ VPO PA = 0x354
4 切 PA 欄位 CT=0x0D、CI=0x5、CO=0x0
5 查 cache set 5、tag 相符 Cache hit,回傳 byte 0x36

其他可能路徑 (p.860):TLB miss → 到 page table 取 PTE;PTE invalid → page fault,kernel 換頁後重跑指令;PTE valid 但 cache miss → 到 main memory 取 block。

考試手算固定套路:寫出 VA 位元 → 切 VPN/VPO → 切 TLBT/TLBI → 查 TLB(miss 才查 page table;invalid 即 page fault)→ 串接 PPN‖VPO 得 PA → 切 CT/CI/CO → 查 cache。Practice Problem 9.4 即同型題。

9.7 個案研究:Intel Core i7 / Linux (p.861-865)

記憶體系統概觀(Figure 9.21)

元件 規格
L1 d-TLB 64 entries、4-way
L1 i-TLB 128 entries、4-way
L2 unified TLB 512 entries、4-way
L1 d-cache / i-cache 各 32 KB、8-way、64 B block(physically addressed)
L2 unified cache 256 KB、8-way
L3 unified cache 8 MB、16-way(所有 core 共享)

TLB 為 virtually addressed;各 cache 為 physically addressed。核心間以 QuickPath 點對點連結通訊。

Core i7 位址轉譯(Figure 9.22, 9.25)

VA(48): [ VPN1(9) | VPN2(9) | VPN3(9) | VPN4(9) | VPO(12) ]
             |         |         |         |        |
CR3 ──> L1 PT ──> L2 PT ──> L3 PT ──> L4 PT        |
     (page global (page upper (page middle (page    |
      directory)   directory)  directory)  table)  |
       512 GB/項    1 GB/項     2 MB/項    4 KB/項  |
                                        PTE → PPN(40)
                                             v      v
PA(52):                            [ PPN(40) | PPO(12) ]

PTE 格式(Figure 9.23, 9.24)

Level 1-3 PTE(每項指向一個 4 KB 子表)與 Level 4 PTE(指向 4 KB 實體頁)欄位:

欄位 意義 層級
P 子表/子頁是否在實體記憶體(Linux 恆為 1) 全部
R/W 所有可達頁為 read-only 或 read/write 全部
U/S user 或 supervisor mode 才能存取(保護 kernel) 全部
WT 子表/子頁 write-through 或 write-back 政策 全部
CD 停用/啟用 cache 全部
A reference bit:MMU 讀寫時設定、軟體清除 → 供頁替換演算法 全部
PS 頁大小 4 KB 或 4 MB(僅 level 1 定義) L1
D dirty bit:MMU 寫入時設定、軟體清除 → 決定 victim 是否須寫回 僅 L4
G global page:task switch 時不從 TLB 逐出 僅 L4
Base addr 子表/子頁實體基底位址的最高 40 位 → 強制 4 KB 對齊 全部
XD execute disable:禁止從可達頁取指令(64-bit 新增,降低 buffer overflow 攻擊風險) 全部
XD bit 讓 kernel 把「可執行」限制在唯讀 code segment,與 03-Machine-Level-Programs/06-Buffer-Overflow-and-Pointer-Safety 中的 stack 不可執行防禦直接相關。

9.7.2 Linux 虛擬記憶體系統 (p.864-867)

Kernel virtual memory

每個行程的位址空間 = 使用者部分(code、data、heap、shared library、stack)+ user stack 之上的 kernel virtual memory:

Areas(Figure 9.27)

Linux 把虛擬記憶體組織成 area(又稱 segment) 的集合:一段已配置的連續虛擬記憶體,其頁彼此相關(code、data、heap、shared library、stack 各是一個 area)。

task_struct        mm_struct         vm_area_struct 串列
+--------+        +--------+        +----------+
|  mm ---+------->| pgd ---+--CR3   | vm_end   |    對應一個 area
|  ...   |        | mmap --+------->| vm_start |    (shared libs / data
+--------+        +--------+        | vm_prot  |     / text ...)
                                    | vm_flags |
                                    | vm_next -+--> 下一個 area struct
                                    +----------+
結構/欄位 意義
task_struct 每行程一個;含 PID、user stack 指標、執行檔名、PC 等
mm_struct 描述 VM 現況;pgd 指向 level 1 表(page global directory)基底,mmap 指向 area struct 串列
vm_start / vm_end area 的起點/終點
vm_prot area 內所有頁的讀寫權限
vm_flags 頁是共享 (shared) 或私有 (private) 等
vm_next 串列中下一個 area struct

Linux Page Fault 處理(Figure 9.28, p.868-869)

MMU 轉譯位址 A 觸發 page fault 後,kernel handler 依序判斷:

page fault on VA = A
  |
  |-- (1) A 落在某個 area 內嗎?(比對各 vm_start/vm_end)
  |        否 --> segmentation fault,終止行程
  |
  |-- (2) 存取方式合法嗎?(寫唯讀頁?user mode 讀 kernel 記憶體?)
  |        否 --> protection exception,終止行程
  |
  '-- (3) 合法位址 + 合法操作 => 正常 page fault:
          選 victim -> dirty 則換出 -> 換入新頁 -> 更新 page table
          -> handler 返回,CPU 重跑 faulting instruction(這次正常轉譯)
area 串列的線性搜尋在 area 很多時(行程可用 mmap 建立任意多個 area)代價高;實務上 Linux 在串列上疊一棵樹來搜尋 (p.868)。

Exam/Test Patterns

情境 / 關鍵字 答案
給 n、m、P,求 VPN/VPO/PPN/PPO 位元數 VPO = PPO = log2P;VPN = nlog2P;PPN = mlog2P(Practice 9.3 型)
為何 PPO 不必轉譯? 虛擬頁與實體頁大小相同(P bytes),故 PPO = VPO 直接照抄
TLB 有 T=2t 個 set,TLBI/TLBT 怎麼切? TLBI = VPN 最低 t 位;TLBT = VPN 其餘高位(注意是切 VPN,不是整個 VA)
Page hit 誰處理?page fault 誰處理? hit 全由硬體 (MMU);fault 由硬體觸發例外 + OS kernel handler 換頁後重跑指令
為何 cache 多用 physical addressing? 多行程可同時共存/共享 block;保護檢查已併入轉譯,cache 不需處理
TLB miss 之後一定 page fault 嗎? 否。TLB miss 只是去記憶體讀 PTE;PTE valid 就沒有 fault(也可能接著 cache miss)
單層 page table 太大怎麼辦? 多層階層:null 上層 PTE → 子表不存在;只有 level 1 表須常駐
多層表要查 k 次 PTE,不會很慢? TLB 會 cache 各層 PTE,實務上不明顯變慢
Core i7 幾層 page table?VPN 怎麼切? 4 層;36-bit VPN 切 4×9 bits,VPO 12 bits;CR3 指向 L1 表(屬行程 context)
A bit / D bit 誰設誰清?用途? MMU 設定、kernel(軟體)清除;A 供頁替換參考,D 決定 victim 是否須先寫回
XD bit 的用途 禁止從該 PTE 可達頁取指令,把執行限制在唯讀 code 段以降低 buffer overflow 攻擊風險
寫入唯讀頁 / user 讀 kernel 頁,Linux 如何處理? fault handler 第 2 步判定不合法 → protection exception(SIGSEGV),終止行程
存取不在任何 area 的位址 fault handler 第 1 步判定 → segmentation fault
VPO 同時送 L1 cache 的技巧 轉譯與 set 選擇重疊:VPO(12) = CI(6)+CO(6),TLB 回 PPN 後只需比 tag