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 中的结构体 kvm_vcpu_arch_shared 描述。

魔术页功能

当使用 KVM 超调用 KVM_HC_PPC_MAP_MAGIC_PAGE 映射魔术页时,会将第二个返回值传递给客户机。此第二个返回值包含魔术页内可用功能的位图。

当前可以使用以下对魔术页的增强功能

KVM_MAGIC_FEAT_SR

在魔术页中映射 SR 寄存器 r/w

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,可以在其中实时转换指令。发生的情况如下:

  1. 将模拟代码复制到内存

  2. 修补该代码以适合模拟的指令

  3. 修补该代码以返回到原始 pc + 4

  4. 修补原始指令以跳转到新代码

这样,我们可以注入任意数量的代码来替代单个指令。例如,这使我们能够在设置 EE=1 时检查挂起的终端。

PowerPC 上 KVM 中的超调用 ABI

  1. KVM 超调用 (ePAPR)

这些是符合 ePAPR 的超调用实现(如上所述)。即使是通用的超调用也会在此处实现,例如 ePAPR 空闲 hcall。这些在所有目标上都可用。

  1. PAPR 超调用

运行服务器 PowerPC PAPR 客户机(QEMU 中的 -M pseries)需要 PAPR 超调用。这些是 pHyp(POWER 虚拟机管理程序)实现的相同超调用。其中一些在内核中处理,一些在用户空间中处理。这仅在 book3s_64 上可用。

  1. OSI 超调用

Mac-on-Linux 是 PowerPC 上 KVM 的另一个用户,它有自己的超调用(早在 KVM 之前)。支持此功能是为了保持兼容性。所有这些超调用都会转发到用户空间。这仅在 book3s_32 上有用,但也可以与 book3s_64 一起使用。