RFC-0128:推出「zx_vcpu_kick」

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 系統呼叫介面進行的下列變更:

  1. 新增 zx_vcpu_kick
  2. zx_vcpu_resume 重新命名為 zx_vcpu_enter

其中 zx_vcpu_enterzx_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_enterzx_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 非常相似。這項功能會:

  1. 設定狀態。對於 zx_vcpu_kick,此狀態是用於指示 VCPU 應在退出訪客時傳回的原子布林值。您可以使用 zx_object_get_info 搭配 ZX_INFO_VCPU 主題和對應的 zx_info_vcpu_t 類型,查詢這個變數。
  2. 檢查 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_enterzx_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_killzx_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