Hypercall 操作码 (hcalls)

概述

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

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

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

在 PPC64 架构上,运行在 PAPR Hypervisor 之上的客户内核称为pSeries 客户机。 pseries 客户机在 Supervisor 模式 (HV=0) 下运行,并且每当它需要执行 Hypervisor 特权操作 [3] 或 Hypervisor 管理的其他服务时,都必须发出 Hypercall 到 Hypervisor。

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

HCALL ABI

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

在 Hypervisor 服务了“HVCS”指令后控制返回给客户机之后,hcall 的返回值可在 *r3* 中获得,任何输出值都会在寄存器 *r4-r12* 中返回。 同样,就像输入参数的情况一样,存储在内存缓冲区中的任何输出值都将为大端字节序。

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

寄存器约定

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

寄存器范围

易失 (Y/N)

目的

r0

Y

可选用途

r1

N

堆栈指针

r2

N

TOC

r3

Y

hcall 操作码/返回值

r4-r10

Y

输入和输出值

r11

Y

可选用途/环境指针

r12

Y

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

r13

N

线程指针

r14-r31

N

局部变量

LR

Y

链接寄存器

CTR

Y

循环计数器

XER

Y

定点异常寄存器。

CR0-1

Y

条件寄存器字段。

CR2-4

N

条件寄存器字段。

CR5-7

Y

条件寄存器字段。

其他

N

DRC & DRC 索引

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

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

HCALL 返回值

在服务了 hcall 之后,Hypervisor 在 *r3* 中设置返回值,指示 hcall 成功或失败。 如果失败,错误代码指示错误的原因。 这些代码在架构特定的头文件 [4] 中定义和记录。

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

为了进行此类 hcall,客户机需要为初始调用设置 *continue-token == 0*,并为每个后续 hcall 使用 Hypervisor 返回的 *continue-token* 值,直到 Hypervisor 返回非 *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
输出:None
返回值: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-Index,在客户物理地址空间内的 targetLogicalMemoryAddress 处将连续的 SCM 块范围 (startingScmBlockIndex, startingScmBlockIndex+numScmBlocksToBind) 映射到客户机。 如果 targetLogicalMemoryAddress == 0xFFFFFFFF_FFFFFFFF,则 Hypervisor 会为客户机分配一个目标地址。 如果客户机具有指向要绑定的 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-Index,从客户物理地址空间取消映射从 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-Index 和 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
输出:None
返回值:H_Success, H_Parameter, H_P2, H_P3, H_In_Use, H_Busy,
H_LongBusyOrder1mSec, H_LongBusyOrder10mSec

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

H_SCM_HEALTH

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

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

健康状况位图标志

定义

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
输出:None
返回值: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 的参数列表中传递给 Hypervisor,直到完全服务该 hcall,此时 Hypervisor 返回 H_SUCCESS 或其他错误。

H_HTM

输入:flags, target, operation (op), op-param1, op-param2, op-param3
输出:dumphtmbufferdata
返回值:H_Success,H_Busy,H_LongBusyOrder,H_Partial,H_Parameter, H_P2,H_P3,H_P4,H_P5,H_P6,H_State,H_Not_Available,H_Authority

H_HTM 支持硬件跟踪宏 (HTM) 功能及其数据的设置、配置、控制和转储。 HTM 缓冲区存储诸如核心指令、核心 LLAT 和嵌套之类的函数的跟踪数据。

参考文献