2003 — QEMU 與 Xen:虛擬化的兩條道路合流#
案件摘要#
2003 年,兩位學界工程師各自發表了影響深遠的虛擬機系統:Fabrice Bellard 一人以一己之力寫出 QEMU,用動態二進位轉譯實現跨 ISA 的全系統模擬;劍橋大學的 Xen hypervisor 用半虛擬化繞過 x86 的虛擬化缺陷。兩條看似不同的路,在 2007 年與 KVM 合流,並隨 Intel VT-x(2005)抵達終極解法。
前因 -- 為什麼會有這個案子#
- VMware 的封閉與昂貴:1999–2003 年 VMware 是 x86 虛擬化唯一成熟方案,閉源且商用授權昂貴;學界與開源社群需要自由的替代品。
- 跨 ISA 模擬的需求:嵌入式開發(ARM/PowerPC)、作業系統研究、legacy 系統(Old Mac、SPARC)都需在 x86 上模擬其他架構——現有模擬器(Bochs 純直譯)慢到不可用。
- Bellard 的前科:Fabrice Bellard 曾贏得 FFmpeg(2000)的作者聲望;2003 年發表 QEMU 論文,其 TCG 動態二進位轉譯比 Bochos 快 \(10\times\) 以上。
- x86 仍不可虛擬化(2003):VT-x 尚未問世,敏感非特權指令的破口仍在;劍橋開發者選擇另一條路——修改 Guest OS 原始碼,讓它主動配合 hypervisor(paravirtualization)。
線索與推理 -- 數學式、程式、理論#
QEMU 的動態二進位轉譯(TCG)#
QEMU 的執行模型:
- TB(Translation Block):guest 程式碼被切成 basic block(以分支/跳轉結尾)。
- TCG(Tiny Code Generator):把 guest TB 編譯成 host 機器碼,快取在 code cache。
- TB chaining:轉譯後的 TB 直接跳到下一個已轉譯的 TB,避免回到執行迴圈:
攤提後的效能模型:
其中 \(c\) 為 code quality factor, \(k\) 為 TB 重複執行次數。對比純直譯的 \(c \approx 10\) ,TCG 快一個數量級。
全系統模擬:跨 ISA 互模擬#
QEMU 的核心設計是guest 與 host ISA 解耦:CPU 狀態(暫存器、PC、flags)用架構無關的 CPUState 結構表示,TCG 把 guest ISA 翻成 host ISA:
這使得任意組合的 \(n \times m\) 模擬只需 \(n + m\) 個前端/後端——與 1995 年 JVM 的 Write Once Run Anywhere 數學結構完全同構,只是這次模擬的是完整電腦(CPU + 裝置 + 中斷 + MMU)而非單一語言。
Xen 的半虛擬化(paravirtualization)#
Xen 的策略:修改 Guest OS 原始碼,把敏感指令改為顯式的 hypercall(類似系統呼叫但呼叫 hypervisor):
- Ring compression:x86 只有 ring 0–3,Xen 把自己放在 ring 0,Guest kernel 放在 ring 1,應用程式在 ring 3——壓縮了特權環的使用:
- 特權環壓縮的代價:Guest kernel 的每次特權操作(頁表更新、中斷處理)都要經 ring 1 → ring 0 的切換,但由於是顯式呼叫,Xen 可以用批次(batch)與驗證(validate)最佳化。
- Dom0/DomU 架構:Xen 的特權域 Dom0 負責後端驅動(磁碟、網路),非特權域 DomU 透過前後端驅動與共享記憶體通訊。
硬體輔助虛擬化:Intel VT-x(2005)/ AMD-V 的終極解法#
2005–2006 年,晶片廠在硬體中新增 Guest 模式(non-root mode):
- Intel VT-x:新增 VMX root/non-root mode、VMCS(虛擬機控制結構)記錄 VM 狀態;
VMLAUNCH/VMRESUME進入 guest,敏感指令在 guest 模式自動 VM-exit trap 進 hypervisor。 - AMD-V:類似機制(SVM mode、VMCB)。
數學上,硬體輔助使 x86 恢復 Popek–Goldberg 條件:
此後:Xen 的 HVM 模式(不需改 Guest OS)、KVM 直接用 VT-x、VMware 逐步棄用 binary translation——三條路殊途同歸。
QEMU-KVM 合流(2007)#
KVM(2006 併入 Linux kernel,2007 穩定)是 Linux 的 Type 1 hypervisor 模組,負責 CPU 與記憶體虛擬化(直接用 VT-x);但它借用 QEMU 作為裝置模型(device model,模擬磁碟、網卡、顯示卡):
QEMU 從「轉譯者」轉型為「裝置模擬器 + 通用虛擬機框架」,TCG 退居「無 KVM 時的 fallback」與跨 ISA 模擬用途。
Python 展示簡單二進位轉譯範例#
以下用 Python 模擬「把 guest 指令碼轉譯為 Python 函式」的動態二進位轉譯:
# Guest ISA:一個簡單的堆疊機指令集
# PUSH n / ADD / MUL / DUP / PRINT / HALT
GUEST_CODE = ['PUSH 2', 'PUSH 3', 'MUL', 'DUP', 'ADD', 'PRINT', 'HALT']
def translate(tb):
"""把 guest 指令轉譯為 Python 原始碼(模擬 TCG 生成 host 碼)"""
lines, stack_depth = [], 0
for ins in tb:
op, *args = ins.split()
if op == 'PUSH':
lines.append(f" st.append({args[0]})")
elif op == 'ADD':
lines.append(" st.append(st.pop() + st.pop())")
elif op == 'MUL':
lines.append(" st.append(st.pop() * st.pop())")
elif op == 'DUP':
lines.append(" st.append(st[-1])")
elif op == 'PRINT':
lines.append(" print(st.pop())")
elif op == 'HALT':
lines.append(" return")
return "def host_code(st):\n" + "\n".join(lines)
# 動態「編譯」:exec 生成 host 函式(等同 TCG 生成機器碼並放入 code cache)
exec(translate(GUEST_CODE))
cache = {} # translation cache
cache[tuple(GUEST_CODE)] = host_code
# 執行:直接呼叫編譯後的「機器碼」,重複執行攤提編譯成本
st = []
for _ in range(3): # 執行 3 次,只編譯 1 次
cache[tuple(GUEST_CODE)](st)
# 輸出:12 12 12 (2*3=6, DUP 得 6,6, ADD 得 12)
(註:本例展示的是「編譯一次、執行多次」的攤提模型——真實 TCG 的本質相同:把 guest basic block 編成 host 機器碼、快取、並用 direct jump 串鏈(TB chaining)。)
結案 -- 後果與影響#
- QEMU 成為開源虛擬化的基石:模擬幾乎所有 ISA(ARM、RISC-V、PowerPC、s390x),是作業系統教學、嵌入式開發、跨架構測試的標準工具;2008 年起與 KVM 合流成為 Linux 雲端生態的標準配備。
- Xen 成為 2006 年 Amazon EC2 的底座,撑起第一代公有雲;後來逐步讓位給 KVM(AWS 部分轉向 Nitro/KVM)。
- VT-x/AMD-V 使硬體輔助虛擬化成為所有現代 CPU 的標準配備,也催生了容器與 microVM(Firecracker 2018)。
- Bellard 的傳奇延續:FFmpeg、TCC、計算 \(\pi\) 的世界紀錄——一人之力改寫多個領域。
關鍵人物與文獻#
- Fabrice Bellard:QEMU、FFmpeg、TCC 的作者。
- Keir Fraser & Ian Pratt:劍橋 Xen 計畫主持人。
- Avi Kivity:KVM 的原作者(2006)。
- Bellard, F., QEMU, a Fast and Portable Dynamic Translator, USENIX ATC 2005 (FREENIX)。
- Barham et al., Xen and the Art of Virtualization, SOSP 2003。
- Kivity et al., kvm: the Linux Virtual Machine Monitor, Ottawa Linux Symposium 2007。