Linux 核心虛擬化

最後更新: 2024-10-12 06:57:35 +0800 +0800
tags: Kernel | Kvm | Linux
原文以英文撰寫。您正在閱讀AI翻譯版本。

KVM 透過 /dev/kvm 暴露 Linux 硬體虛擬化。KVM 提供核心執行機制,而 QEMU 等虛擬機器監視器則建構並操作完整的客體機器。

職責分工 #

KVM 會在可能時使用 Intel VT-x、AMD-V、Arm 虛擬化擴充功能或相應的主機功能,直接執行客體指令。核心程式碼管理 vCPU 狀態、第二階段記憶體轉譯、中斷傳遞、計時器,以及客體與主機執行之間的轉換。KVM 刻意不提供完整的韌體與裝置模型。

QEMU 提供該機器模型:韌體介面、PCI 拓撲、儲存與網路控制器、顯示與輸入裝置、映像後端、遷移,以及透過 QMP 進行的管理。使用 -accel kvm 時,QEMU 將加速 CPU 執行委派給 KVM;沒有加速器時,則可使用 TCG 指令轉譯器。QEMU 支援的選項仍取決於機器與架構。

客體記憶體與記憶體槽 #

QEMU 首先保留由匿名記憶體、memfd、檔案或 huge page 支援的主機虛擬記憶體。接著使用 KVM_SET_USER_MEMORY_REGION 向 VM 檔案描述元註冊該位址空間的部分區域。每個區域描述:

  • 槽編號與旗標;
  • 客體實體基底與大小;以及
  • 支援該槽的使用者空間虛擬位址。

將槽的大小設為零會移除它。槽描述的是對映,而不是配置客體 RAM,因此在 KVM 使用支援對映期間,使用者空間必須保留該對映。選用的髒頁記錄會記錄寫入,以協調遷移與快照。

客體記憶體參照可能涉及兩次轉譯。客體頁表將客體虛擬位址轉譯為客體實體位址;KVM 與 MMU 硬體接著將該位址轉譯為與已註冊使用者空間對映相對應的主機實體頁面。Intel 稱硬體第二階段為 EPT,AMD 稱為 NPT。KVM 會處理遺失或無效的第二階段對映,並在存取目標為一般 RAM 時,不離開到 QEMU 就能安裝新對映。存取模擬 MMIO 範圍則會導致離開,或執行核心內的裝置操作。

NUMA 放置、透明或明確 huge page、交換與記憶體超額配置會影響延遲,但不會改變客體可見的位址模型。裝置指派會增加 DMA 對映;因此 VFIO 依賴 IOMMU 與隔離邊界,不暴露不相關的主機裝置或記憶體。

/dev/kvm 生命週期 #

穩定的 KVM 使用者空間 ABI 依檔案描述元型別組織:

  1. 開啟 /dev/kvm,接著要求 KVM_GET_API_VERSION 回傳 KVM_API_VERSION(目前為 12)。使用 KVM_CHECK_EXTENSION 查詢選用行為,而不是比較核心版本。
  2. 在系統描述元上發出 KVM_CREATE_VM。回傳的 VM 描述元一開始沒有 RAM 與 vCPU。
  3. 註冊記憶體槽,並在需要時建立該架構的中斷控制器與其他核心內裝置。
  4. 在 VM 描述元上發出 KVM_CREATE_VCPU。使用 KVM_GET_VCPU_MMAP_SIZE,接著對映 vCPU 描述元共用的 struct kvm_run 區域。
  5. 設定 CPU 模型與初始暫存器狀態,然後從 vCPU 的主機執行緒執行 KVM_RUN。

VM 與裝置 ioctl 必須遵循 KVM API 記載的程序與執行緒限制。VM 的生命週期取決於其檔案描述元的參照,而不是建立它的程序生命週期;因此,透過 fork 繼承或透過 dup 建立的意外參照可能保留 VM 資源。

虛擬 CPU、離開與中斷 #

每個 vCPU 都有 KVM 描述元,通常也有對應的 QEMU 執行緒。KVM_RUN 進入客體模式,並在使用者空間必須行動、訊號中斷主機執行緒或發生離開條件時返回。QEMU 檢查 kvm_run.exit_reason,處理連接埠 I/O、MMIO、關機或偵錯事件等離開,然後再次呼叫 KVM_RUN。KVM 能完全在核心中虛擬化的指令不需要使用者空間離開。

中斷可以透過模擬的使用者空間控制器或核心內 irqchip 進入。KVM_IRQ_LINE、MSI 路由與 irqfd 將裝置事件連接到客體中斷;ioeventfd 讓選定的客體 MMIO 或 PIO 寫入通知 eventfd,而不必往返主要模擬迴圈。當客體 CPU 可以接受待處理中斷時,KVM 會注入該中斷。

Virtio 與減少離開 #

陷阱與模擬裝置會重現硬體暫存器介面,但每個由使用者空間處理的存取都會跨越 KVM 邊界。Virtio 改為定義半虛擬化裝置與共用 virtqueue:客體將描述元放在記憶體中,批次處理工作後再通知主機。QEMU、核心內的 vhost 後端或 vhost-user 程序都可以服務該佇列。批次處理、中斷抑制與 irqfd/ioeventfd 會減少離開;裝置直通則可以從資料路徑移除軟體裝置模型,但代價是更嚴格的 IOMMU 與遷移限制。

隔離與作業可觀測性 #

對 /dev/kvm 的存取控制誰能建立 KVM VM,但 QEMU 程序也會處理客體控制的裝置輸入與主機檔案。以專用身分執行不受信任的客體,並使用 cgroups、命名空間、seccomp 以及 SELinux 或 AppArmor 限制 QEMU。減少模擬裝置,更新核心、QEMU 與客體韌體,並將 VFIO IOMMU 群組與共用記憶體後端視為明確的信任邊界。CPU 側通道也可能需要超執行緒(SMT)與超出記憶體隔離的排程政策。

基本主機檢查如下:

sh
test -r /dev/kvm && test -w /dev/kvm
ls -l /dev/kvm
lscpu | grep -i virtualization

QMP 與 libvirt 等管理層會回報客體狀態、vCPU 時間、區塊 I/O 與遷移進度。在主機層級,perf kvm stat 摘要成本高昂的 KVM 離開,追蹤檔案系統下的 KVM tracepoint 暴露進入、離開、MMIO 與中斷事件,而 /proc/PID/task 會識別 QEMU vCPU 執行緒。Debugfs 與 tracefs 需要提升權限,且在核心未以相關選項建置時可能無法使用。

權威介面是 KVM API 與 QEMU 系統模擬文件。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)