PPC KVM 半虛擬化介面¶
PowerPC 上 KVM 的基本執行原理是:所有核心空間程式碼都在 PR=1(使用者空間)中執行。這樣我們就能捕獲所有特權指令並進行相應的模擬。
不幸的是,這同時也是它的缺點。有相當多的特權指令不必要地將我們返回到虛擬機器管理程式,即使它們可以以不同的方式處理。
這正是 PPC PV 介面所能幫助的地方。它將特權指令在虛擬機器管理程式的幫助下轉換為非特權指令。根據我的一些基準測試,這能將虛擬化成本降低約 50%。
該介面的程式碼可以在 arch/powerpc/kernel/kvm* 中找到
查詢是否存在¶
為了查明我們是否在 KVM 上執行,我們利用裝置樹。當 Linux 在 KVM 上執行時,存在一個 /hypervisor 節點。該節點包含一個相容屬性,其值為“linux,kvm”。
一旦您確定您正在支援 PV 的 KVM 下執行,您現在就可以使用下面描述的超級呼叫。
KVM 超級呼叫¶
在裝置樹的 /hypervisor 節點內,有一個名為“hypercall-instructions”的屬性。該屬性最多包含 4 個構成超級呼叫的操作碼。要呼叫一個超級呼叫,只需呼叫這些指令即可。
引數如下
暫存器
輸入
輸出
r0
易失性
r3
第 1 個引數
返回程式碼
r4
第 2 個引數
第 1 個輸出值
r5
第 3 個引數
第 2 個輸出值
r6
第 4 個引數
第 3 個輸出值
r7
第 5 個引數
第 4 個輸出值
r8
第 6 個引數
第 5 個輸出值
r9
第 7 個引數
第 6 個輸出值
r10
第 8 個引數
第 7 個輸出值
r11
超級呼叫號
第 8 個輸出值
r12
易失性
超級呼叫定義在通用程式碼中共享,因此 x86 和 powerpc 採用相同的超級呼叫號,但每個 KVM 超級呼叫還需要與 KVM 供應商程式碼進行或運算,該程式碼為 (42 << 16)。
返回程式碼可能如下
程式碼
含義
0
成功
12
超級呼叫未實現
<0
錯誤
魔術頁¶
為了實現虛擬機器管理程式和客戶機之間的通訊,有一個新的共享頁,其中包含部分對監管者可見的暫存器狀態。客戶機可以使用 KVM 超級呼叫 KVM_HC_PPC_MAP_MAGIC_PAGE 來對映此共享頁。
發出此超級呼叫後,客戶機總能將魔術頁對映到所需位置。第一個引數表示 MMU 啟用時的有效地址。第二個引數表示實際模式下的地址(如果適用於目標)。目前,我們總是將頁對映到 -4096。這樣我們就可以使用絕對載入和儲存功能來訪問它。以下指令讀取魔術頁的第一個欄位
ld rX, -4096(0)
該介面設計為可擴充套件,以便日後需要向魔術頁新增更多暫存器。如果您向魔術頁新增欄位,也請定義一個新的超級呼叫功能來指示宿主可以為您提供更多暫存器。只有當宿主支援這些額外功能時,才使用它們。
魔術頁佈局由 arch/powerpc/include/uapi/asm/kvm_para.h 中的 struct kvm_vcpu_arch_shared 描述。
魔術頁特性¶
當使用 KVM 超級呼叫 KVM_HC_PPC_MAP_MAGIC_PAGE 對映魔術頁時,會將第二個返回值傳遞給客戶機。該第二個返回值包含魔術頁中可用特性的點陣圖。
目前魔術頁提供以下增強功能
KVM_MAGIC_FEAT_SR
在魔術頁中對映 SR 暫存器讀/寫
KVM_MAGIC_FEAT_MAS0_TO_SPRG7
對映 MASn、ESR、PIR 和高 SPRG
對於魔術頁中的增強功能,請在使用前檢查該功能是否存在!
魔術頁標誌¶
除了指示宿主是否支援特定功能的特性之外,我們還有一個通道供客戶機告知宿主其是否支援某項功能。我們稱之為“標誌”。
標誌透過有效地址的低 12 位傳遞給宿主。
客戶機目前可以暴露以下標誌
MAGIC_PAGE_FLAG_NOT_MAPPED_NX 客戶機正確處理與魔術頁相關的 NX 位
MSR 位¶
MSR 包含需要虛擬機器管理程式干預的位以及不需要直接虛擬機器管理程式干預的位,因為它們只在進入客戶機時才被解釋,或者對虛擬機器管理程式的行為沒有任何影響。
以下位可在客戶機內安全設定
MSR_EE
MSR_RI
如果 MSR 中有任何其他位發生變化,請仍然使用 mtmsr(d)。
修補指令¶
在 32 位系統上,“ld”和“std”指令分別轉換為“lwz”和“stw”指令,並增加 4 的偏移量以適應大端序。
以下是 Linux 核心作為客戶機執行時執行的對映列表。實現這些對映中的任何一個都是可選的,因為指令陷阱也作用於共享頁。因此,呼叫特權指令仍然像以前一樣有效。
從 |
到 |
|---|---|
mfmsr rX |
ld rX, magic_page->msr |
mfsprg rX, 0 |
ld rX, magic_page->sprg0 |
mfsprg rX, 1 |
ld rX, magic_page->sprg1 |
mfsprg rX, 2 |
ld rX, magic_page->sprg2 |
mfsprg rX, 3 |
ld rX, magic_page->sprg3 |
mfsrr0 rX |
ld rX, magic_page->srr0 |
mfsrr1 rX |
ld rX, magic_page->srr1 |
mfdar rX |
ld rX, magic_page->dar |
mfdsisr rX |
lwz rX, magic_page->dsisr |
mtmsr rX |
std rX, magic_page->msr |
mtsprg 0, rX |
std rX, magic_page->sprg0 |
mtsprg 1, rX |
std rX, magic_page->sprg1 |
mtsprg 2, rX |
std rX, magic_page->sprg2 |
mtsprg 3, rX |
std rX, magic_page->sprg3 |
mtsrr0 rX |
std rX, magic_page->srr0 |
mtsrr1 rX |
std rX, magic_page->srr1 |
mtdar rX |
std rX, magic_page->dar |
mtdsisr rX |
stw rX, magic_page->dsisr |
tlbsync |
nop |
mtmsrd rX, 0 |
b <特殊 mtmsr 部分> |
mtmsr rX |
b <特殊 mtmsr 部分> |
mtmsrd rX, 1 |
b <特殊 mtmsrd 部分> |
[僅 Book3S] |
|
mtsrin rX, rY |
b <特殊 mtsrin 部分> |
[僅 BookE] |
|
wrteei [0|1] |
b <特殊 wrteei 部分> |
有些指令需要比載入或儲存指令更多的邏輯來確定發生了什麼。為了能夠修補這些指令,我們保留了一些 RAM,可以在其中即時翻譯指令。發生的情況如下:
將模擬程式碼複製到記憶體
修補該程式碼以適應被模擬的指令
修補該程式碼以返回到原始 pc + 4
修補原始指令以分支到新程式碼
這樣,我們可以注入任意數量的程式碼來替換單個指令。這允許我們在設定 EE=1 時檢查掛起的中斷,例如。
KVM on PowerPC 中的超級呼叫 ABI¶
KVM 超級呼叫 (ePAPR)
這些是符合 ePAPR 規範的超級呼叫實現(如上所述)。甚至通用超級呼叫也在此實現,例如 ePAPR 空閒超級呼叫。這些在所有目標上都可用。
PAPR 超級呼叫
PAPR 超級呼叫是執行伺服器 PowerPC PAPR 客戶機(QEMU 中的 -M pseries)所必需的。這些與 POWER 虛擬機器管理程式 pHyp 實現的超級呼叫相同。其中一些在核心中處理,另一些在使用者空間中處理。這僅在 book3s_64 上可用。
OSI 超級呼叫
Mac-on-Linux 是 KVM on PowerPC 的另一個使用者,它有自己的超級呼叫(遠在 KVM 之前)。這是為了保持相容性而支援的。所有這些超級呼叫都被轉發到使用者空間。這僅在 book3s_32 上有用,但也可用於 book3s_64。