RFC-0128:引入 `zx_vcpu_kick` | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | 新的系統呼叫 `zx_vcpu_kick`,可讓執行中的 vCPU 退出主機並返回使用者空間。 |
Gerrit 變更 | |
作者 | |
審查人員 | |
提交日期 (年-月-日) | 2021-08-26 |
審查日期 (年-月-日) | 2021-09-25 |
摘要
我們建議新增 zx_vcpu_kick
這個新的系統呼叫,可讓執行中的 vCPU 退出主機並返回使用者空間。此外,我們建議將 zx_vcpu_resume
重新命名為 zx_vcpu_enter
,以便保持命名一致。
提振精神
執行 VCPU 時,在呼叫 zx_vcpu_enter
時可能會無限期封鎖。這會導致虛擬機器管理員發生問題,因為要徹底關閉 VCPU,虛擬機器管理員需要系統呼叫函式將控制權交還給呼叫執行緒,才能安全釋放所有相關資源。
此外,為了簡化整合測試,您可以使用方法強制 VCPU 退出訪客。這樣一來,您就能更精簡準確地編寫測試。
相關人員
導師:cpu
審查者:adanis、tamird、jamesr
諮詢對象:dgreenaway、brunodalbo
社交化:在即時通訊串中討論設計,這是解決連線團隊在 netemul 測試中遇到的問題的一部分。
設計
此提案包含對 Zircon 系統呼叫介面進行的下列變更:
- 新增
zx_vcpu_kick
- 將
zx_vcpu_resume
重新命名為zx_vcpu_enter
其中 zx_vcpu_enter
和 zx_vcpu_kick
的定義如下:
/// Enter a VCPU, and start or continue execution.
/// Rights: handle must be of type ZX_OBJ_TYPE_VCPU and have ZX_RIGHT_EXECUTE.
// @blocking
zx_status_t zx_vcpu_enter(
zx_handle_t handle,
uint32_t options,
zx_port_packet_t* packet
);
/// Exit from the current or next call to |vcpu_enter|.
/// Rights: handle must be of type ZX_OBJ_TYPE_VCPU and have ZX_RIGHT_EXECUTE.
zx_status_t zx_vcpu_kick(
zx_handle_t handle
);
當 zx_vcpu_kick
在 VCPU 句柄上呼叫時,對該句柄上目前執行的 zx_vcpu_enter
呼叫會傳回 ZX_ERR_CANCELED
。此外,如果 zx_vcpu_enter
在 zx_vcpu_kick
呼叫時未執行,下一次對 zx_vcpu_enter
的呼叫會立即傳回 ZX_ERR_CANCELED
。這可讓虛擬機器管理員呼叫 zx_vcpu_kick
,並確保 zx_vcpu_enter
會在下次傳回 ZX_ERR_CANCELED
。反之,這表示如果 zx_vcpu_enter
尚未傳回 ZX_ERR_CANCELED
,則無論 zx_vcpu_kick
呼叫幾次,都只會傳回一次。
ZX_ERR_CANCELED
是所選的狀態,用於傳回,這樣虛擬機器管理員就能輕鬆區分退出的原因。這樣一來,虛擬機器管理員就能使用該狀態,在不需在虛擬機器管理員中進行任何額外狀態管理的情況下,優雅地停止 VCPU。當它發現 zx_vcpu_enter
已傳回 ZX_ERR_CANCELED
時,即可關閉 VCPU 句柄,並釋放任何其他相關聯的資源。
此外,zx_vcpu_kick
的行為是停止 VCPU,而不是終止 VCPU。也就是說,虛擬機器管理員可能會在 zx_vcpu_enter
傳回 ZX_ERR_CANCELED
後,再次呼叫 zx_vcpu_enter
來繼續執行 VCPU。除了處理傳回值和略過任何封包處理作業之外,虛擬機器管理員不需要執行任何特殊作業,而且可以立即呼叫 zx_vcpu_enter
來繼續執行。
實作
在管理程序中,zx_vcpu_enter
是以 zx_port_wait
為模型。除了截止日期外,兩者幾乎使用相同的 API。這表示系統會等待訪客封包抵達,然後將封包傳回使用者空間。與 zx_thread_start
不同,此方法並非用來建立新的執行緒,而是用來轉換目前的執行緒。
不過,我們認為以符記為基礎的方法 (例如 zx_task_suspend
中的方法) 無法有效中斷 VCPU 的執行。符記式方法不符合 VCPU 執行模式,因為 VCPU 執行模式需要在使用者空間和核心之間持續來回切換。
相反地,我們建議 zx_vcpu_kick
只讓 zx_vcpu_enter
傳回至使用者空間,並附上錯誤代碼,指出該程式已中斷。在 Hypervisor 中,zx_vcpu_kick
的實作方式與 zx_vcpu_interrupt
非常相似。這項功能會:
- 設定狀態。對於
zx_vcpu_kick
,此狀態是用於指示 VCPU 應在退出訪客時傳回的原子布林值。您可以使用zx_object_get_info
搭配ZX_INFO_VCPU
主題和對應的zx_info_vcpu_t
類型,查詢這個變數。 - 檢查 VCPU 目前是否正在執行,如果是的話,就會 IPI 目前在 VCPU 上執行的實體 CPU。這會強制 VCPU 退出訪客,以便處理中斷,並允許 VCPU 處理要求以便返回。
原子布林值會追蹤是否已呼叫 zx_vcpu_kick
,以及 VCPU 應在沒有任何未完成的資訊可傳回至使用者空間時傳回 ZX_ERR_CANCELED
。也就是說,如果有未完成的使用者空間訪客封包,系統會在後續呼叫 zx_vcpu_enter
時傳回 ZX_ERR_CANCELED
之前,成功傳回該封包。
這個方法可讓 zx_vcpu_enter
的行為類似於遇到逾時的 zx_port_wait
。
由於 Fuchsia 存放區包含所有已知的輔助處理器使用者,因此實作作業會在單一 CL 中執行。這項異動將包括更新說明文件和系統呼叫的語言繫結,以及對輔助虛擬機器管理員和虛擬機器管理員的變更。
成效
除了會導致訪客退出執行作業之外,這不會對效能造成任何已知影響。由於這項功能的主要用途是優雅地終止執行 VCPU,因此不會對實際情況造成影響。
人體工學
設計一節討論了 zx_vcpu_enter
和 zx_vcpu_kick
的人體工學考量。
回溯相容性
Fuchsia 存放區內包含所有已知的輔助執行體使用者,因此可以同時導入 zx_vcpu_kick
並將 zx_vcpu_resume
重新命名為 zx_vcpu_enter
。
安全性考量
使用 zx_vcpu_kick
的虛擬機器管理員應進行稽核,以確保任何 zx_vcpu_enter
用途都會考量 ZX_ERR_CANCELED
的傳回狀態,且如果要恢復 VCPU 作業,則必須忽略傳回的 PortPacket
。如果不忽略 PortPacket
,則會對已歸零的無效資料運算,而 zx_vcpu_enter
傳回的任何錯誤狀態都是如此。
隱私權注意事項
這項提案不會影響隱私權。
測試
實作 CL 後,我們可以為虛擬機器管理器測試啟用 ASAN 機器人,並證明我們可以順利關機,而不會發生 ASAN 失敗。
說明文件
我們需要為 zx_vcpu_kick
系統呼叫新增其他文件,並擴充 zx_vcpu_enter
系統呼叫的文件,納入新的傳回狀態和 PortPacket
處理建議。
缺點、替代方案和未知事項
這項提案的缺點是引入額外的系統呼叫。我們最初建議重複使用 zx_task_kill
或 zx_handle_close
,但這兩者都有各自的缺點。
為了讓 zx_task_kill
專門用於處理 VCPU,我們必須將 VCPU 視為工作,因此讓所有與工作相關的系統呼叫都能與 VCPU 搭配運作。如果我們只讓 zx_task_kill
與 vCPU 搭配運作,而沒有其他與工作相關的系統呼叫,就會出現不一致的情況。
我們可以改為依賴 zx_handle_close
的語意,並將 on_zero_handles
處理常式新增至 VcpuDispatcher
。這樣一來,如果句柄數量降至零,我們就能終止 VCPU。不過,這有兩個立即的缺點:我們無法在 VCPU 停止後繼續執行,且我們會使 VCPU 句柄失效。無效化 VCPU 句柄特別有問題,因為這是一種本質上競爭激烈的作業。當句柄失效時,其他執行緒可能會在使用 VCPU 句柄的過程中,藉由插入和中斷的方式導致意外錯誤。
另一個做法是引入更通用的此系統呼叫版本,例如 zx_thread_cancel
,其中任何對特定執行緒的封鎖作業都會立即傳回 ZX_ERR_CANCELED
。這可讓我們將系統呼叫擴充至未來使用情境,這些情境使用與 vCPU 相似的模型。
既有技術與參考資料
Apple 的 Hypervisor Framework 中也有類似的作業:https://developer.apple.com/documentation/hypervisor/1441468-hv_vcpu_interrupt
以及 Linux 的 KVM (核心式虛擬機器):https://www.kernel.org/doc/html/latest/virt/kvm/vcpu-requests.html#vcpu-kicks