半虛擬化(paravirtualization)
/ PA-ra-vir-tu-al-i-za-tion /
半虛擬化(paravirtualization)採取與全虛擬化不同的態度。它不去騙客體以為自己在真實硬體上,而是對客體說實話——你是一台虛擬機器——並修改客體作業系統,讓它主動配合超管理器。字首 para 意為「在旁、並肩」:客體與超管理器並肩工作,而非被它欺瞞。這就像舞台魔術師對演員藏起鋼索,相對於乾脆告訴演員鋼索在哪,讓演員更順暢地走到定位的差別。
其機制的核心是超呼叫(hypercall)。在半虛擬化的客體裡,那些原本得靠捕捉或轉譯來處理的昂貴、彆扭操作,在客體原始碼中被換成對超管理器的明確呼叫——超呼叫之於超管理器,正如系統呼叫之於核心。所以客體不再「執行一道特權指令並期望它陷入」,而是直接請求超管理器:請幫我更新分頁表、或請幫我送出這個網路封包。由於客體願意配合,超管理器省下了捕捉與模擬棘手指令的成本,設計也能更乾淨、更快,尤其在輸入輸出方面。Xen 讓這個做法廣為人知。
明顯的代價是你必須修改客體作業系統,這對 Linux 之類的開源核心沒問題,但對你無法更動的封閉作業系統就辦不到。實務上界線已經模糊:現代系統常跑一個「大致以硬體虛擬化為主、但對最受惠於配合的裝置輸入輸出採用半虛擬化驅動程式(如 virtio)」的客體。所以今日的半虛擬化,較少以「整套作業系統的修改」存活,而較多以「在一個原本由硬體輔助的客體裡、知道超管理器存在的配合式驅動程式」存活。
一個半虛擬化的 Linux 客體需要送出一個網路封包。它不去一個暫存器一個暫存器地戳一張模擬網卡(那會陷入很多次),而是發出一次 virtio 超呼叫,把封包直接交給超管理器——往返次數少得多,快得多。
配合式的客體透過超呼叫直接請求超管理器,跳過裝置模擬。
半虛擬化需要修改客體作業系統,所以它無法像全虛擬化那樣執行一套未經修改的封閉原始碼系統。它在現代的遺產是「用在硬體輔助客體裡的半虛擬化驅動程式(virtio)」,而非整套作業系統的改寫。