Hypercall 操作码 (hcalls)

概述

64 位 Power Book3S 平台上的虚拟化基于 PAPR 规范 [1],该规范描述了客户操作系统的运行时环境以及它应如何与虚拟机监控程序进行特权操作交互。目前有两个符合 PAPR 的虚拟机监控程序

  • IBM PowerVM (PHYP):IBM 的专有虚拟机监控程序,支持 AIX、IBM-i 和 Linux 作为受支持的客户机(称为逻辑分区或 LPAR)。它支持完整的 PAPR 规范。

  • Qemu/KVM:支持在 PPC64 Linux 主机上运行的 PPC64 Linux 客户机。虽然它只实现了 PAPR 规范的一个子集,称为 LoPAPR [2]

在 PPC64 架构上,运行在 PAPR 虚拟机监控程序之上的客户机内核称为 *pSeries 客户机*。pSeries 客户机在管理模式 (HV=0) 下运行,并且每当需要执行虚拟机监控程序特权操作时 [3] 或需要虚拟机监控程序管理的其他服务时,必须向虚拟机监控程序发出 hypercall。

因此,Hypercall (hcall) 本质上是 pSeries 客户机请求虚拟机监控程序代表客户机执行特权操作。客户机发出带有必要输入操作数的请求。虚拟机监控程序在执行特权操作后,将状态码和输出操作数返回给客户机。

HCALL ABI

pSeries 客户机和 PAPR 虚拟机监控程序之间 hcall 的 ABI 规范在参考 [2] 的第 14.5.3 节中进行了介绍。通过 HVCS 指令完成切换到虚拟机监控程序上下文,该指令期望 hcall 的操作码设置在 *r3* 中,并且 hcall 的任何输入参数都提供在寄存器 *r4-r12* 中。如果值必须通过内存缓冲区传递,则存储在该缓冲区中的数据应为大端字节顺序。

一旦控制权在虚拟机监控程序服务了 'HVCS' 指令后返回到客户机,hcall 的返回值在 *r3* 中可用,并且任何输出值都返回在寄存器 *r4-r12* 中。与输入参数一样,存储在内存缓冲区中的任何输出值都将为大端字节顺序。

Powerpc 架构代码提供了方便的包装器,名为 plpar_hcall_xxx,在架构特定的头文件 [4] 中定义,用于从作为 pSeries 客户机运行的 Linux 内核发出 hcall。

寄存器约定

任何 hcall 都应遵循与“64 位 ELF V2 ABI 规范:Power Architecture”[5] 的第 2.2.1.1 节中描述的相同的寄存器约定。下表总结了这些约定

寄存器范围

易失性(是/否)

目的

r0

可选使用

r1

堆栈指针

r2

TOC

r3

hcall 操作码/返回值

r4-r10

输入和输出值

r11

可选使用/环境指针

r12

可选使用/全局入口点的函数入口地址

r13

线程指针

r14-r31

局部变量

LR

链接寄存器

CTR

循环计数器

XER

定点异常寄存器。

CR0-1

条件寄存器字段。

CR2-4

条件寄存器字段。

CR5-7

条件寄存器字段。

其他

DRC 和 DRC 索引

DR1                                  Guest
+--+        +------------+         +---------+
|  | <----> |            |         |  User   |
+--+  DRC1  |            |   DRC   |  Space  |
            |    PAPR    |  Index  +---------+
DR2         | Hypervisor |         |         |
+--+        |            | <-----> |  Kernel |
|  | <----> |            |  Hcall  |         |
+--+  DRC2  +------------+         +---------+

PAPR 虚拟机监控程序将诸如 PCI 设备、NVDIMM 等可供 LPAR 使用的共享硬件资源称为动态资源 (DR)。当将 DR 分配给 LPAR 时,PHYP 会创建一个名为动态资源连接器 (DRC) 的数据结构来管理 LPAR 访问。LPAR 通过一个名为 DRC-Index 的不透明 32 位数字引用 DRC。DRC 索引值通过设备树提供给 LPAR,它作为与 DR 关联的设备树节点中的属性存在。

HCALL 返回值

在服务 hcall 之后,虚拟机监控程序会在 *r3* 中设置返回值,指示 hcall 是否成功。如果失败,错误代码会指示错误的原因。这些代码在架构特定的头文件 [4] 中定义和记录。

在某些情况下,hcall 可能会花费很长时间,并且需要多次发出才能完全服务。这些 hcall 通常会接受其参数列表中的不透明值 *continue-token*,并且返回值 *H_CONTINUE* 表示虚拟机监控程序尚未完成 hcall 的服务。

要发出此类 hcall,客户机需要为初始调用设置 *continue-token == 0*,并为每个后续 hcall 使用虚拟机监控程序返回的 *continue-token* 值,直到虚拟机监控程序返回非 *H_CONTINUE* 的返回值。

HCALL 操作码

以下是 PHYP 支持的部分 HCALL 列表。有关相应的操作码值,请查看架构特定的头文件 [4]

H_SCM_READ_METADATA

输入:*drcIndex、offset、buffer-address、numBytesToRead*
输出:*numBytesRead*
返回值:*H_Success、H_Parameter、H_P2、H_P3、H_Hardware*

给定 NVDIMM 的 DRC 索引,从与其关联的元数据区域读取 N 字节,在指定的偏移量处并将其复制到提供的缓冲区。元数据区域存储配置信息,例如标签信息、坏块等。元数据区域位于 NVDIMM 存储区域的带外,因此提供了单独的访问语义。

H_SCM_WRITE_METADATA

输入:*drcIndex、offset、data、numBytesToWrite*
输出:*无*
返回值:*H_Success、H_Parameter、H_P2、H_P4、H_Hardware*

给定 NVDIMM 的 DRC 索引,将 N 字节写入与其关联的元数据区域,在指定的偏移量处并从提供的缓冲区写入。

H_SCM_BIND_MEM

输入:*drcIndex、startingScmBlockIndex、numScmBlocksToBind、*
targetLogicalMemoryAddress、continue-token
输出:*continue-token、targetLogicalMemoryAddress、numScmBlocksToBound*
返回值:*H_Success、H_Parameter、H_P2、H_P3、H_P4、H_Overlap、*
H_Too_Big、H_P5、H_Busy

给定 NVDIMM 的 DRC 索引,将连续的 SCM 块范围 *(startingScmBlockIndex、startingScmBlockIndex+numScmBlocksToBind)* 映射到客户机在客户机物理地址空间内的 *targetLogicalMemoryAddress* 处。如果 *targetLogicalMemoryAddress == 0xFFFFFFFF_FFFFFFFF*,则虚拟机监控程序会将目标地址分配给客户机。如果客户机具有到正在绑定的 SCM 块的活动 PTE 条目,则 HCALL 可能会失败。

H_SCM_UNBIND_MEM | 输入:drcIndex、startingScmLogicalMemoryAddress、numScmBlocksToUnbind | 输出:numScmBlocksUnbound | 返回值:*H_Success、H_Parameter、H_P2、H_P3、H_In_Use、H_Overlap、* | *H_Busy、H_LongBusyOrder1mSec、H_LongBusyOrder10mSec*

给定 NVDimm 的 DRC 索引,从客户机物理地址空间中取消映射从 *startingScmLogicalMemoryAddress* 开始的 *numScmBlocksToUnbind* 个 SCM 块。如果客户机具有到正在取消绑定的 SCM 块的活动 PTE 条目,则 HCALL 可能会失败。

H_SCM_QUERY_BLOCK_MEM_BINDING

输入:*drcIndex、scmBlockIndex*
输出:*Guest-Physical-Address*
返回值:*H_Success、H_Parameter、H_P2、H_NotFound*

给定 DRC 索引和 SCM 块索引,返回 SCM 块映射到的客户机物理地址。

H_SCM_QUERY_LOGICAL_MEM_BINDING

输入:*Guest-Physical-Address*
输出:*drcIndex、scmBlockIndex*
返回值:*H_Success、H_Parameter、H_P2、H_NotFound*

给定客户机物理地址,返回哪个 DRC 索引和 SCM 块映射到该地址。

H_SCM_UNBIND_ALL

输入:*scmTargetScope、drcIndex*
输出:*无*
返回值:*H_Success、H_Parameter、H_P2、H_P3、H_In_Use、H_Busy、*
H_LongBusyOrder1mSec、H_LongBusyOrder10mSec

根据目标范围,取消映射属于所有 NVDIMM 或属于由其 drcIndex 标识的单个 NVDIMM 的所有 SCM 块,从 LPAR 内存中取消映射。

H_SCM_HEALTH

输入:drcIndex
输出:health-bitmap (r4), health-bit-valid-bitmap (r5)
返回值:H_Success, H_Parameter, H_Hardware

给定一个 DRC 索引,返回关于 PMEM 设备预测故障和整体健康状况的信息。 health-bitmap 中置位的位表示 PMEM 设备的一个或多个状态(如下表所述),health-bit-valid-bitmap 指示 health-bitmap 中哪些位是有效的。这些位以反向位顺序报告,例如,值 0xC400000000000000 表示位 0、1 和 5 有效。

Health Bitmap 标志

定义

00

PMEM 设备无法持久化内存内容。如果系统断电,则不会保存任何内容。

01

PMEM 设备未能持久化内存内容。要么在断电时未成功保存内容,要么在开机时未正确恢复内容。

02

PMEM 设备内容从之前的 IPL 持久化。上次启动的数据已成功恢复。

03

PMEM 设备内容未从之前的 IPL 持久化。没有要从上次启动恢复的数据。

04

PMEM 设备剩余内存寿命非常低

05

由于故障,PMEM 设备将在下次 IPL 时被隔离

06

由于当前平台健康状况,PMEM 设备内容无法持久化。硬件故障可能会阻止数据的保存或恢复。

07

PMEM 设备在某些情况下无法持久化内存内容

08

PMEM 设备已加密

09

PMEM 设备已成功完成请求的擦除或安全擦除过程。

10:63

保留 / 未使用

H_SCM_PERFORMANCE_STATS

输入:drcIndex, resultBuffer Addr
输出:无
返回值:H_Success, H_Parameter, H_Unsupported, H_Hardware, H_Authority, H_Privilege

给定一个 DRC 索引,收集 NVDIMM 的性能统计信息并将其复制到 resultBuffer。

H_SCM_FLUSH

输入:drcIndex, continue-token
输出:continue-token
返回值:H_SUCCESS, H_Parameter, H_P2, H_BUSY

给定一个 DRC 索引,将数据刷新到后端 NVDIMM 设备。

当刷新花费的时间较长时,hcall 返回 H_BUSY,并且需要多次发出 hcall 才能完全服务。来自输出的 continue-token 将传递给后续 hcall 的参数列表,直到 hcall 完全被服务,此时 hypervisor 将返回 H_SUCCESS 或其他错误。

参考资料