虛擬化與容器

Popek-Goldberg 要求(Popek-Goldberg requirements)

/ POH-pek GOLD-berg /

1974 年,兩位研究者 Gerald Popek 與 Robert Goldberg 寫下了一台 CPU 必須遵守、才能讓陷阱與模擬式虛擬化「有可能成立」的規則。這是這個領域最接近定理的東西,它回答了一個尖銳的問題:給定一顆處理器的指令集,你究竟能不能在它上面造出一個高效的超管理器?他們的答案把整個問題化約成「指令集如何對待兩類指令」。

他們的分類是:特權指令(privileged)是那種在使用者模式下執行會陷入、但在核心模式下執行就能跑的指令(正是作業系統倚賴的那套機制)。敏感指令(sensitive)則是那種要嘛改變硬體的設定(控制敏感)、要嘛依當前特權或設定而有不同行為(行為敏感)的指令——簡言之,任何「在乎」那個超管理器必須加以虛擬化的機器狀態的指令。於是那條招牌定理美得很簡單:一台機器是「經典可虛擬化」的(你能造出高效的陷阱與模擬超管理器),若且唯若每一條敏感指令同時也是一條特權指令。若此成立,你讓客體跑在非特權下,每條危險指令都會陷入,超管理器再模擬它。若某條敏感指令「不是」特權指令,它就會不陷入地溜過去——而你的超管理器對它視而不見。

這正是經典 32 位元 x86 不是經典可虛擬化的原因:它有一組臭名昭著、約十七條的敏感卻非特權指令。教科書上的例子是 popf,它載入旗標暫存器;在核心模式下它能改變中斷致能旗標,但在使用者模式下執行時,它會默默忽略那一部分而「不」陷入——於是客體想改變中斷狀態的嘗試就這樣消失了、無人察覺。面對這點,工程師們改用二進位翻譯(即時改寫客體那些有風險的指令,VMware 的做法)或半虛擬化(修改客體,讓它明確呼叫超管理器,Xen 的做法),直到 Intel VT-x 與 AMD-V 加入一個硬體模式,實質上讓 x86 滿足了這些要求。

x86 指令 popf 是教科書上的犯規者:在核心模式下它能清除中斷致能旗標,但在使用者模式下它會默默丟棄那個改動、而不引發錯誤。一個讓客體跑在使用者模式的陷阱與模擬超管理器,根本看不到客體的這個嘗試,於是無法將它虛擬化。

popf 在經典 x86 上敏感卻非特權——這正是打破陷阱與模擬的那道缺口。

這條定理給的是「經典」陷阱與模擬高效運作的充分條件;它並沒有說 x86 在任何絕對意義上不可虛擬化——二進位翻譯、半虛擬化、以及後來的硬體輔助全都繞過了它。「非經典可虛擬化」是精確的說法;說「不可能」則是錯的。

又称
Popek and Goldberg virtualization requirementsclassical virtualizability theoremPopek-Goldberg 虛擬化條件