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 mode,HV=0)下,每当它需要执行 hypervisor 特权操作 [3] 或请求由 hypervisor 管理的其他服务时,必须向 hypervisor 发出 hypercall。
因此,Hypercall (hcall) 本质上是 pseries 客户机请求 hypervisor 代表客户机执行特权操作的请求。客户机带着必要的输入操作数发出该请求。hypervisor 在执行完该特权操作后,会将状态码和输出操作数返回给客户机。
HCALL ABI¶
pseries 客户机与 PAPR hypervisor 之间 hcall 的 ABI 规范在参考文献 [2] 的 14.5.3 节中有介绍。切换到 Hypervisor 上下文是通过 HVCS 指令完成的,该指令要求在 r3 中设置 hcall 的操作码,并在寄存器 r4-r12 中提供 hcall 的所有输入参数。如果必须通过内存缓冲区传递值,则存储在该缓冲区中的数据应为大端(Big-endian)字节序。
一旦 hypervisor 处理完 ‘HVCS’ 指令并将控制权交还给客户机,hcall 的返回值就可以在 r3 中获取,任何输出值都在寄存器 r4-r12 中返回。与输入参数的情况类似,存储在内存缓冲区中的任何输出值也将是大端字节序。
PowerPC 架构代码提供了名为 plpar_hcall_xxx 的便捷包装函数,这些函数定义在架构特定的头文件 [4] 中,用于从作为 pseries 客户机运行的 Linux 内核中发出 hcall。
寄存器约定¶
任何 hcall 都应遵循“64-Bit ELF V2 ABI Specification: Power Architecture”[5] 第 2.2.1.1 节中所述的相同寄存器约定。下表总结了这些约定:
寄存器范围 |
易失性 (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)。当向 LPAR 分配 DR 时,PHYP 会创建一个名为动态资源连接器 (DRC) 的数据结构来管理 LPAR 访问。LPAR 通过一个称为 DRC-Index 的不透明 32 位数字引用 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
给定 NVDIMM 的 DRC 索引,在其指定的偏移量处从与其关联的元数据区域读取 N 个字节,并将其复制到提供的缓冲区中。元数据区域存储配置信息,例如标签信息、坏块等。元数据区域位于 NVDIMM 存储区域的带外,因此提供了单独的访问语义。
H_SCM_WRITE_METADATA
给定 NVDIMM 的 DRC 索引,将来自所提供缓冲区的 N 个字节写入与其关联的元数据区域中的指定偏移量处。
H_SCM_BIND_MEM
给定 NVDIMM 的 DRC-Index,将连续的 SCM 块范围 (startingScmBlockIndex, startingScmBlockIndex+numScmBlocksToBind) 映射到客户机物理地址空间内的 targetLogicalMemoryAddress 处。如果 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
给定 DRC-Index 和 SCM 块索引,返回 SCM 块所映射到的客户机物理地址。
H_SCM_QUERY_LOGICAL_MEM_BINDING
给定客户机物理地址,返回映射到该地址的 DRC 索引和 SCM 块。
H_SCM_UNBIND_ALL
根据目标范围,从 LPAR 内存中取消映射属于所有 NVDIMM 的所有 SCM 块,或者取消映射由其 drcIndex 标识的单个 NVDIMM 所属的所有 SCM 块。
H_SCM_HEALTH
给定 DRC 索引,返回关于 PMEM 设备的预测性故障和整体健康状况的信息。健康位图中置位的位指示 PMEM 设备的一个或多个状态(如下表所述),健康位有效位图指示健康位图中的哪些位是有效的。这些位以相反的位顺序报告,例如,值 0xC400000000000000 表示第 0、1 和 5 位有效。
健康位图标志 (Health Bitmap Flags)
位 |
定义 |
|---|---|
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
给定 DRC 索引,收集 NVDIMM 的性能统计信息并将其复制到 resultBuffer 中。
H_SCM_FLUSH
给定 DRC 索引,将数据刷新到后端 NVDIMM 设备。
当刷新耗时较长且需要多次发出 hcall 才能完全处理完毕时,该 hcall 返回 H_BUSY。输出中的 continue-token 需要传递给 hypervisor 的后续 hcall 的参数列表中,直到 hcall 完全处理完毕,此时 hypervisor 将返回 H_SUCCESS 或其他错误。
H_HTM
H_HTM 支持硬件跟踪宏 (HTM) 功能及其数据的设置、配置、控制和转储。HTM 缓冲区存储用于核心指令、核心 LLAT 和嵌套等功能的跟踪数据。
H_PKS_GEN_KEY
H_PKS_GEN_KEY 用于让 hypervisor 生成一个新的随机密钥。该密钥作为对象存储在 Power LPAR 平台密钥库中,带有提供的对象标签。设置了包装密钥策略后,该密钥仅对 hypervisor 可见,而密钥的标签对用户仍然可见。仅支持生成大小为 32 字节的包装密钥。
H_PKS_WRAP_OBJECT
H_PKS_WRAP_OBJECT 用于使用存储在 Power LPAR 平台密钥库中的包装密钥来包装对象,并将包装后的对象返回给调用方。调用方提供一个设置了“包装密钥”策略的包装密钥的标签,该密钥必须先前已通过 H_PKS_GEN_KEY 创建。然后使用包装密钥和附加元数据对所提供的对象进行加密,并将结果返回给调用方。
H_PKS_UNWRAP_OBJECT
H_PKS_UNWRAP_OBJECT 用于解包先前已用 H_PKS_WRAP_OBJECT 包装的对象。