ARM 虛擬通用中斷控制器 v3 及更高版本 (VGICv3)¶
- 支援的裝置型別
KVM_DEV_TYPE_ARM_VGIC_V3 ARM 通用中斷控制器 v3.0
此 API 只能例項化一個 VGIC 例項。建立的 VGIC 將充當 VM 中斷控制器,要求模擬的使用者空間裝置將中斷注入到 VGIC,而不是直接注入到 CPU。無法在同一 VM 上同時建立 GICv3 和 GICv2。
建立訪客 GICv3 裝置也需要主機 GICv3。
- 組
- KVM_DEV_ARM_VGIC_GRP_ADDR
屬性
- KVM_VGIC_V3_ADDR_TYPE_DIST (讀寫, 64 位)
GICv3 分發器暫存器對映在訪客物理地址空間中的基地址。僅對 KVM_DEV_TYPE_ARM_VGIC_V3 有效。該地址需要 64KB 對齊,且區域覆蓋 64KB。
- KVM_VGIC_V3_ADDR_TYPE_REDIST (讀寫, 64 位)
GICv3 重分發器暫存器對映在訪客物理地址空間中的基地址。每個 VCPU 有兩個 64KB 頁,並且所有重分發器頁都是連續的。僅對 KVM_DEV_TYPE_ARM_VGIC_V3 有效。該地址需要 64KB 對齊。
- KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION (讀寫, 64 位)
kvm_device_attr.addr 指向的屬性資料是一個 __u64 值
bits: | 63 .... 52 | 51 .... 16 | 15 - 12 |11 - 0 values: | count | base | flags | index
index 編碼了唯一的重分發器區域索引
flags:保留供將來使用,當前為 0
base 欄位編碼了區域中第一個重分發器的訪客物理基地址的位 [51:16]。
count 編碼了區域中重分發器的數量。必須大於 0。
區域中的每個重分發器有兩個 64KB 頁,並且重分發器在區域內是連續佈局的。區域按照索引順序填充重分發器。所有區域計數字段的總和必須大於或等於 VCPU 的數量。重分發器區域必須按增量索引順序註冊,從索引 0 開始。
可以透過預設 attr 資料中的 index 欄位來讀取特定重分發器區域的特性。僅對 KVM_DEV_TYPE_ARM_VGIC_V3 有效。
混合使用 KVM_VGIC_V3_ADDR_TYPE_REDIST 和 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION 屬性的呼叫是無效的。
請注意,為了獲得可重現的結果(在儲存/恢復操作中,同一個 VCPU 與同一個重分發器相關聯),VCPU 建立順序、重分發器區域建立順序以及 VCPU 和區域建立的相應交錯順序必須保留。任何順序上的更改都可能導致不同的 vcpu_id/重分發器關聯,從而導致 VM 在恢復時無法執行。
錯誤
-E2BIG
地址超出可定址 IPA 範圍
-EINVAL
地址未正確對齊,重分發器區域計數/索引錯誤,混合使用重分發器區域屬性
-EEXIST
地址已配置
-ENOENT
嘗試讀取不存在的重分發器區域的特性
-ENXIO
該組或屬性對於此裝置而言未知/不支援,或者缺少硬體支援。
-EFAULT
attr->addr 的使用者指標無效。
- KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
屬性
kvm_device_attr 的 attr 欄位編碼了兩個值
bits: | 63 .... 32 | 31 .... 0 | values: | mpidr | offset |
所有分發器暫存器都是 (讀寫, 32 位),且 kvm_device_attr.addr 指向一個 __u32 值。必須透過分別訪問低位字和高位字來訪問 64 位暫存器。
對只讀暫存器的寫入操作將被核心忽略。
KVM_DEV_ARM_VGIC_GRP_DIST_REGS 訪問主分發器暫存器。KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 訪問由 mpidr 指定的 CPU 的重分發器。
偏移量是相對於 GICv3/4 規範中定義的“[重]分發器基地址”的。獲取或設定此類暫存器與在實際硬體上讀取或寫入暫存器具有相同的效果,以下暫存器除外:GICD_STATUSR、GICR_STATUSR、GICD_ISPENDR、GICR_ISPENDR0、GICD_ICPENDR 和 GICR_ICPENDR0。當透過此介面訪問這些暫存器時,它們的行為與架構定義的行為不同,以便軟體能夠全面檢視 VGIC 的內部狀態。
mpidr 欄位用於指定訪問哪個重分發器。對於分發器,mpidr 被忽略。
mpidr 編碼基於架構定義的 MPIDR 中的親和資訊,該欄位編碼如下
| 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 | | Aff3 | Aff2 | Aff1 | Aff0 |
請注意,分發器欄位不是分割槽的(banked),無論用於訪問暫存器的 mpidr 是什麼,它們都返回相同的值。
當 KVM 實現以訪客或使用者空間可以直接觀察到的方式更改時,GICD_IIDR.Revision 會更新。使用者空間應從 KVM 讀取 GICD_IIDR 並將讀取的值寫回,以確認其預期行為與 KVM 實現保持一致。使用者空間在設定任何其他暫存器之前應設定 GICD_IIDR,以確保預期行為。
GICD_STATUSR 和 GICR_STATUSR 暫存器在架構上定義為:清除位的寫入沒有效果,而設定位的寫入會清除該值。為了允許使用者空間自由設定這兩個暫存器的值,透過這兩個暫存器的暫存器偏移量設定屬性時,只需將非保留位設定為寫入的值。
對 GICD_ISPENDR 暫存器區域和 GICR_ISPENDR0 暫存器的訪問(讀寫)會獲取/設定中斷的鎖存掛起狀態的值。
這與訪客從 ISPENDR 讀取邊緣觸發中斷時返回的值相同,但對於電平觸發中斷可能不同。對於邊緣觸發中斷,一旦中斷變為掛起(無論是由於輸入線檢測到邊緣還是由於訪客寫入 ISPENDR),此狀態即被“鎖存”,並且僅當中斷被啟用或訪客寫入 ICPENDR 時才清除。電平觸發中斷可能處於掛起狀態,原因可能是裝置將電平輸入保持為高電平,或者由於訪客寫入 ISPENDR 暫存器。只有 ISPENDR 寫入會被鎖存;如果裝置降低線路電平,則除非訪客也寫入 ISPENDR,否則中斷將不再掛起;相反,如果線路電平仍保持高電平,則對 ICPENDR 的寫入或中斷的啟用不會清除掛起狀態。(這些規則在 GICv3 規範中 ICPENDR 和 ISPENDR 暫存器的描述中有記載。)對於電平觸發中斷,此處訪問的值是 ISPENDR 設定並由 ICPENDR 或中斷啟用清除的鎖存器的值,而訪客從 ISPENDR 讀取返回的值是鎖存器值與輸入線電平的邏輯或(OR)結果。
提供對鎖存狀態的原始訪問許可權給使用者空間,以便使用者空間可以儲存和恢復整個 GIC 內部狀態(該狀態由當前輸入線電平和鎖存狀態的組合定義,不能僅從線電平和 ISPENDR 暫存器的值推斷出來)。
對 GICD_ICPENDR 暫存器區域和 GICR_ICPENDR0 暫存器的訪問具有 RAZ/WI 語義,這意味著讀取總是返回 0,寫入總是被忽略。
錯誤
-ENXIO
尚不支援獲取或設定此暫存器
-EBUSY
一個或多個 VCPU 正在執行
- KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS
屬性
kvm_device_attr 的 attr 欄位編碼了兩個值
bits: | 63 .... 32 | 31 .... 16 | 15 .... 0 | values: | mpidr | RES | instr |
mpidr 欄位基於架構定義的 MPIDR 中的親和資訊編碼 CPU ID,該欄位編碼如下
| 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 | | Aff3 | Aff2 | Aff1 | Aff0 |
instr 欄位基於 A64 指令集編碼中定義的系統暫存器訪問欄位來編碼要訪問的系統暫存器(RES 表示這些位保留供將來使用,應為零)
| 15 ... 14 | 13 ... 11 | 10 ... 7 | 6 ... 3 | 2 ... 0 | | Op 0 | Op1 | CRn | CRm | Op2 |
透過此 API 訪問的所有系統暫存器都是 (讀寫, 64 位),且 kvm_device_attr.addr 指向一個 __u64 值。
KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 訪問由 mpidr 欄位指定的 CPU 的 CPU 介面暫存器。
CPU 介面暫存器訪問未在 AArch32 模式下實現。在 AArch32 模式下訪問時返回錯誤 -ENXIO。
錯誤
-ENXIO
尚不支援獲取或設定此暫存器
-EBUSY
VCPU 正在執行
-EINVAL
提供了無效的 mpidr 或暫存器值
- KVM_DEV_ARM_VGIC_GRP_NR_IRQS
屬性
一個描述此 GIC 例項中斷數量(SGI、PPI 和 SPI)的值,範圍從 64 到 1024,增量為 32。
kvm_device_attr.addr 指向一個 __u32 值。
錯誤
-EINVAL
設定的值超出預期範圍
-EBUSY
值已設定。
- KVM_DEV_ARM_VGIC_GRP_CTRL
屬性
- KVM_DEV_ARM_VGIC_CTRL_INIT
請求初始化 VGIC,kvm_device_attr.addr 中無額外引數。必須在所有 VCPU 建立後呼叫。
- KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
將所有 LPI 掛起位儲存到訪客 RAM 掛起表中。
掛起表中的第一個 KB 不受此操作影響。
錯誤
-ENXIO
在呼叫此屬性之前,VGIC 未按要求正確配置
-ENODEV
沒有線上 VCPU
-ENOMEM
分配 vgic 內部資料時記憶體不足
-EFAULT
無效的訪客 RAM 訪問
-EBUSY
一個或多個 VCPU 正在執行
- KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO
屬性
kvm_device_attr 的 attr 欄位編碼了以下值
bits: | 63 .... 32 | 31 .... 10 | 9 .... 0 | values: | mpidr | info | vINTID |
vINTID 指定報告哪個 IRQ 集合。
info 欄位指定使用者空間希望使用此介面獲取或設定的資訊。目前我們支援以下 info 值
- VGIC_LEVEL_INFO_LINE_LEVEL
獲取/設定一組 32 個連續編號中斷的 IRQ 線的輸入電平。
vINTID 必須是 32 的倍數。
kvm_device_attr.addr 指向一個 __u32 值,該值將包含一個位圖,其中設定的位表示中斷電平被置位。
位[n] 表示中斷 vINTID + n 的狀態。
SGI 以及任何 ID 高於支援中斷數量的中斷都將是 RAZ/WI。LPI 總是邊緣觸發的,因此此介面不支援。
PPIs 根據 mpidr 欄位指定為每個 VCPU 報告,而 SPIs 無論指定的 mpidr 是什麼都報告相同的值。
mpidr 欄位基於架構定義的 MPIDR 中的親和資訊編碼 CPU ID,該欄位編碼如下
| 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 | | Aff3 | Aff2 | Aff1 | Aff0 |
- 錯誤
-EINVAL
vINTID 不是 32 的倍數或 info 欄位不是 VGIC_LEVEL_INFO_LINE_LEVEL
- KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ
屬性
kvm_device_attr 的 attr 欄位編碼了以下值
位: | 31 .... 5 | 4 .... 0 | 值: | RES0 | vINTID |
vINTID 指定當 vGIC 必須生成維護中斷時,生成哪個中斷。這必須是一個 PPI。