什麼是 Virtualization
Virtualiztion 就是模擬一個執行的環境,使跑在裏頭的程式有賓至如歸的感受、有家的感覺 :)。由模擬的範圍的不同,又可以把
Virtualization 分做多種,有興趣的可以參考 [1],接下來討論的集中於模擬一整台實體機器的 platform
virtualization。藉由 virtualization,我們可以在一台實體機器中模擬出多個虛擬機器,各自安裝不同的 OS,以遂行吾等
種種不可告人之目的。會想在一台實體機器上模擬出虛擬機器的常見理由如下:
(1) Developer: 開發跨平台程式、或開發 OS 的人,可藉此模擬目標環境,減少測試的不便
(2) 平行計算: 想研究 Grid,又沒有多台實體機器可用,至少可藉此擁有多台虛擬機器。
(3) Service Provider: 由於把 VM 從一台實體機器轉移到另一台非常容易,可增加整體系統管理的方便性、大幅減低災後恢復需
要的時間。
(4) 我: 靠 VM 可以同時執行 Windows 及 Unix,兼得兩家之長。
問題是 x86 架構並非實現 virtualization 的理想環境
適合實現 virtualization 的架構,應該要能讓執行於其內的 VM:1. 與執行在真正的實體機器的處境相同 2. 能有辦法使VM之間
不互相干擾 3. 能保有與執行在真正實體機器上幾乎相同的效率。對於實體架構應具備怎樣的條件,才能實現上述的理想,Popek 和
Goldberg 在 1974 年寫了篇經典的論文加以分析 (wiki 這篇簡介非常棒,請參閱 [2] )。關鍵在於,凡是會影響 VM 本身基
本狀態、或會受 VM 基本狀態直接影響的指令 (文中稱為 sensitive instruction,簡單的聯想就是凡是在 VM 裏直接執行,
會干擾到上頭的 host OS 的指令) ,都同時是 privilege instruction 的話,這個架構就是宜於實現上述
virtualization 理想的架構。所謂的 privilege instruction 就是可以由 Ring 0 程式執行,但位於
user-land 的 Ring 3 程式要是執行的話,會引發類似 General Protection Fault (以下簡稱 GPF)
等 exception 的指令。換句話說,要是 user-land 程式 (例如對 host OS 來說,VM 就是 user-land 程
式) 嘗試執行會干擾 host OS 的 sensitive instruction 時,host OS 都能藉由 GPF 事先得知的話,這個
架構就算是適合實現 virtualization 的架構。
很不幸的,x86 架構不是。x86 至少有 17 個 sensitive 指令 [2] 是不會引發 exception 的非
privilege 指令。這意味著在 x86 下實作 VM 時,VM 必須逐行檢查每個接下來要執行的指令是不是這 17 個指令的其中之一,如果
是就另外加以模擬,如果不是,才直接放行讓它執行。「檢查接下來的指令是不是那 17 個指令之一」意味著多大的執行能力浪費,大家可以稍加想像。更何
況 x86 保留 CISC 的遺風,每個指令的長度相差甚遠,要找「下一個指令」在哪裏是要花力氣的。這就是為什麼執行在 VM 裏的程式通常會跑得
很慢的主要原因。對於尋找隱藏在機器碼裏的這些不定時炸彈,每家的 VM 產品各有不同的做法,也因此在執行不同性質的 guest 程式時,這些
VM 的效率互有短長。這種技術一般稱為 dynamic recompilation,因為它主要的職責在於動態把待執行的程式碼
"compile" 成不含 sensitive 指令的版本供 CPU 執行。此時再請大家想像一下 x86 受此窘境時「理想的架構」在做什麼。答
案是什麼也不用做,閉著眼睛把程式碼全部丟給 CPU 執行就對了,真有問題時會有 exception,寫個 exception handler
去等著處理模擬的工作就行了。從另一個角度來說,x86 的例子是用軟體去檢查 sensitive 指令的存在、而理想架構是用硬體去檢查。這就是效
率天差地遠的主要原因。
Virtualization 型式的分類
1. Full Virtualization
從老老實實什麼都模擬的 bochs,到想辦法有效率的找出 sensitive 指令並加以處理 (即所謂的 full
virtualization with dynamic recompilation) 的 VMware、Virtual PC 屬於此類。受先天
所限,效率有限。
2. Paravirtualization
x86 先天不良,runtime 才來動態找 sensitive 指令很花時間怎麼辦?有一種作法是反過來修改 guest OS (這是因為
在整個 VM 裏,理論上會執行 sensitive 指令的只有 guest OS,一般的 application 理論上都是通過 OS 提供
的 system call 在間接處理 I/O 等 sensitive 工作)。也就是說,把 runtime 在做的事情提前到
compile 產生 bianry 的階段來做,弄出一個沒有 sensitive 指令的 guest OS 來用 (sensitive 指令改
由呼叫 VM 的 functional call 取代)。這樣一來實際在 VM 中執行時就可以不用花時間去檢查待執行的程式碼,因此可以擁有
near native 的效能。這種方式的代表作就是 xen。缺點就是裏頭執行的 guest OS 得是特別修改,有支援 xen 的版本。
3. Native Virtualization
嫌修改軟體麻煩?行,另一個辦法是改硬體。只要能弄出一個具備某種機制的新版 x86,能有辦法靠硬體來偵測這些 sensitive 指令,自然
就能讓 VM 執行未經修改的 guest OS 也能保有 near native 的效率。這一點,Intel 和 AMD 都想到,而且實做
了。Intel 這邊的技術叫做 VT-x
(Vanderpool),AMD 的則叫 AMD-V (Pacifica),指令集雖然不同,但做到的事非常相近。簡單來說,它讓原本只有
Ring 0~Ring 3 的 x86 架構,多出了 root mode 及 non-root mode。兩種 mode 都有 Ring 0~
3,差別是後者所執行的 sensitive 指令可以被前者所監控。很明顯的,後者就是給 guest OS 用的,而前者則是為了 Host
OS / VM 所量身訂做的。這種技術又被稱為 Hardware-assisted virtualization [3]。眼尖的話,你可能早已
在 Virtual PC 的設定頁面裏看到過這個字眼,事實上 Virtual PC 2007、Xen 3.0 等新一代的 VM 軟體都已經支援
這種模式,凡是支援這種模式,並且在這種模式運作的 VM,都能夠以 near native 的效率執行未經修改的 guest OS。聽起來很棒對
不對?只可惜只有相當新的 Intel / AMD CPU 支援這種東西。要多新才有?請參考 http://wiki.xensource.com/xenwiki/IntelVT
結論就是真的要很新啦 ^^; 殘念
結論
讓 x86 走上理想架構之路的 native virtualization 無疑是使用 x86 玩虛擬的終極王道。事實上所有的主流 VM 產
品,像是 Virtual PC、Xen,乃至於擁有相當高評價的 Virtual Iron 通通都已朝向這個方向發展,而後者更是只支援
hardware-assisted virtualization。目前市場所趨,包含商用產品在內,所有產品的基本型方案都是免費的。所以想玩
VM 而又有錢的話,撈出鈔票新電腦買一台回家就對了!要是沒錢可是又想要有效率,就優先考慮 Xen。沒錢偏又要玩 Windows,就只好乖乖用
Virtual PC 之類的方案了。
最後,請各位熱血玩家參考一下這份充滿熱血的 VM 方案比較表,熱血指數 100 分
http://en.wikipedia.org/wiki/Comparison_of_virtual_machines
References
1. Virtualization 的分類及其主要用途 http://en.wikipedia.org/wiki/Virtualization
2. Popek 和 Goldberg 對適合實現 virtualization 的架構的分析
http://en.wikipedia.org/wiki/Popek_and_Goldberg_virtualization_requirements
3. Xen 及 Virtualization 技術 http://en.wikipedia.org/wiki/Xen