KVM(基于内核的虚拟机)API 权威文档

1. 概述

KVM API 围绕不同类型的文件描述符和可以向这些文件描述符发出的 ioctl 展开。初始的 open(“/dev/kvm”) 获取 KVM 子系统的句柄;此句柄可用于发出系统 ioctl。在此句柄上执行 KVM_CREATE_VM ioctl 将创建一个 VM 文件描述符,该描述符可用于发出 VM ioctl。在 VM fd 上执行 KVM_CREATE_VCPU 或 KVM_CREATE_DEVICE ioctl 将创建一个虚拟 CPU 或设备,并返回一个指向新资源的文件描述符。

换句话说,KVM API 是一组 ioctl,它们被发出到不同类型的文件描述符,以控制虚拟机的各个方面。根据接受它们的文件描述符,ioctl 属于以下类别

  • 系统 ioctl:这些查询和设置影响整个 KVM 子系统的全局属性。此外,系统 ioctl 用于创建虚拟机。

  • VM ioctl:这些查询和设置影响整个虚拟机的属性,例如内存布局。此外,VM ioctl 用于创建虚拟 CPU (vCPU) 和设备。

    VM ioctl 必须从用于创建 VM 的同一进程(地址空间)发出。

  • vCPU ioctl:这些查询和设置控制单个虚拟 CPU 运行的属性。

    vCPU ioctl 应从用于创建 vCPU 的同一线程发出,异步 vCPU ioctl 在文档中标记为异步的情况除外。否则,切换线程后的第一个 ioctl 可能会受到性能影响。

  • 设备 ioctl:这些查询和设置控制单个设备运行的属性。

    设备 ioctl 必须从用于创建 VM 的同一进程(地址空间)发出。

虽然大多数 ioctl 都是特定于一种文件描述符,但在某些情况下,同一 ioctl 可以属于多个类别。

KVM API 随着时间的推移而增长。因此,KVM 定义了许多形式为 KVM_CAP_* 的常量,每个常量对应于一个或多个 ioctl 提供的一组功能。可以使用 KVM_CHECK_EXTENSION 检查这些“功能”的可用性。某些功能还需要在需要其功能的 VM 或 VCPU 上启用(请参阅 6. 可以在 vCPU 上启用的功能7. 可以在 VM 上启用的功能)。

2. 限制

通常,可以通过 fork() 和 unix 域套接字的 SCM_RIGHTS 工具在进程之间迁移文件描述符。KVM 明确不支持这些技巧。虽然它们不会对主机造成损害,但 API 不保证它们的实际行为。有关 KVM 支持的 ioctl 使用模型的详细信息,请参阅“概述”。

重要的是要注意,虽然 VM ioctl 只能从创建 VM 的进程发出,但 VM 的生命周期与其文件描述符相关联,而不是与其创建者(进程)相关联。换句话说,VM 及其资源,*包括关联的地址空间*,在释放对 VM 文件描述符的最后一个引用之前不会被释放。例如,如果在 ioctl(KVM_CREATE_VM) 之后发出 fork(),则在父进程(原始进程)及其子进程都释放了它们对 VM 文件描述符的引用之前,VM 不会被释放。

由于 VM 的资源在释放对其文件描述符的最后一个引用之前不会被释放,因此强烈建议不要通过 fork()、dup() 等方式创建对 VM 的额外引用,而没有仔细考虑,并且可能产生不希望的副作用,例如,当 VM 关闭时,VM 的进程分配的内存可能不会被释放/未记账。

3. 扩展

从 Linux 2.6.22 开始,KVM ABI 已稳定:不允许向后不兼容的更改。但是,存在一个扩展工具,允许查询和使用向后兼容的 API 扩展。

扩展机制不是基于 Linux 版本号。相反,KVM 定义了扩展标识符和一个工具来查询特定扩展标识符是否可用。如果是,则有一组 ioctl 可供应用程序使用。

4. API 描述

本节介绍可用于控制 KVM 客户机的 ioctl。对于每个 ioctl,都提供了以下信息以及描述

功能

哪个 KVM 扩展提供了此 ioctl。可以是“basic”,这意味着它将由任何支持 API 版本 12 的内核提供(请参阅 KVM_GET_API_VERSION),或者是一个可以使用 KVM_CHECK_EXTENSION 检查的 KVM_CAP_xyz 常量。

架构

哪些指令集架构提供了此 ioctl。x86 包括 i386 和 x86_64。

类型

系统、vm 或 vcpu。

参数

ioctl 接受哪些参数。

返回值

返回值。未详细说明常规错误号(EBADF、ENOMEM、EINVAL),但详细说明了具有特定含义的错误。

4.1 KVM_GET_API_VERSION

功能:

基本

架构:

全部

类型:

系统 ioctl

参数:

返回值:

常量 KVM_API_VERSION (=12)

这会将 API 版本标识为稳定的 KVM API。预计此数字不会更改。但是,Linux 2.6.20 和 2.6.21 报告了早期版本;这些版本未记录且不受支持。如果 KVM_GET_API_VERSION 返回的值不是 12,应用程序应拒绝运行。如果此检查通过,所有描述为“basic”的 ioctl 都可用。

4.2 KVM_CREATE_VM

功能:

基本

架构:

全部

类型:

系统 ioctl

参数:

机器类型标识符 (KVM_VM_*)

返回值:

可用于控制新虚拟机的 VM fd。

新 VM 没有虚拟 CPU 也没有内存。您可能想要使用 0 作为机器类型。

X86:

可以通过 KVM_CAP_VM_TYPES 查询支持的 X86 VM 类型。

S390:

为了在 S390 上创建用户控制的虚拟机,请检查 KVM_CAP_S390_UCONTROL 并使用标志 KVM_VM_S390_UCONTROL 作为特权用户 (CAP_SYS_ADMIN)。

MIPS:

要在 MIPS (VZ ASE) 上使用硬件辅助虚拟化,而不是默认的陷阱和模拟实现(它更改虚拟内存布局以适应用户模式),请检查 KVM_CAP_MIPS_VZ 并使用标志 KVM_VM_MIPS_VZ。

ARM64:

在 arm64 上,VM 的物理地址大小(IPA 大小限制)默认限制为 40 位。如果主机支持扩展 KVM_CAP_ARM_VM_IPA_SIZE,则可以配置该限制。如果支持,请使用 KVM_VM_TYPE_ARM_IPA_SIZE(IPA_Bits) 在机器类型标识符中设置大小,其中 IPA_Bits 是 VM 使用的任何物理地址的最大宽度。IPA_Bits 编码在机器类型标识符的位 [7-0] 中。

例如,要配置客户机以使用 48 位物理地址大小

vm_fd = ioctl(dev_fd, KVM_CREATE_VM, KVM_VM_TYPE_ARM_IPA_SIZE(48));

请求的大小 (IPA_Bits) 必须是

0

暗示默认大小,40 位(为了向后兼容)

N

暗示 N 位,其中 N 是一个正整数,使得 32 <= N <= Host_IPA_Limit

Host_IPA_Limit 是主机上 IPA_Bits 的最大可能值,并且取决于 CPU 功能和内核配置。可以使用运行时 KVM_CHECK_EXTENSION ioctl() 的 KVM_CAP_ARM_VM_IPA_SIZE 检索该限制。

如果主机不支持请求的 IPA 大小(无论是隐式还是显式),则 VM 的创建将失败。

请注意,配置 IPA 大小不会影响客户机 CPU 在 ID_AA64MMFR0_EL1[PARange] 中公开的功能。它只会影响由 stage2 级别(客户机物理地址到主机物理地址转换)转换的地址大小。

4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST

功能:

基本,KVM_GET_MSR_FEATURE_INDEX_LIST 的 KVM_CAP_GET_MSR_FEATURES

架构:

x86

类型:

系统 ioctl

参数:

struct kvm_msr_list (输入/输出)

返回值:

成功时为 0;出错时为 -1

错误

EFAULT

无法读取或写入 msr 索引列表

E2BIG

msr 索引列表太大,无法放入用户指定的数组中。

struct kvm_msr_list {
      __u32 nmsrs; /* number of msrs in entries */
      __u32 indices[0];
};

用户在 nmsrs 中填写索引数组的大小,作为回报,kvm 调整 nmsrs 以反映 msr 的实际数量,并在索引数组中填写它们的编号。

KVM_GET_MSR_INDEX_LIST 返回支持的客户机 msr。该列表因 KVM 版本和主机处理器而异,但在其他方面不会更改。

注意:如果 kvm 指示支持 MCE (KVM_CAP_MCE),则 MCE bank MSR 不会在 MSR 列表中返回,因为不同的 vCPU 可以具有不同数量的 bank,如通过 KVM_X86_SETUP_MCE ioctl 设置。

KVM_GET_MSR_FEATURE_INDEX_LIST 返回可以传递给 KVM_GET_MSRS 系统 ioctl 的 MSR 列表。这使用户空间可以探测通过 MSR 公开的主机功能和处理器特性(例如,VMX 功能)。此列表也因 kvm 版本和主机处理器而异,但在其他方面不会更改。

4.4 KVM_CHECK_EXTENSION

功能:

基本,vm ioctl 的 KVM_CAP_CHECK_EXTENSION_VM

架构:

全部

类型:

系统 ioctl,vm ioctl

参数:

扩展标识符 (KVM_CAP_*)

返回值:

如果不支持则为 0;如果支持则为 1(或某个其他正整数)

API 允许应用程序查询核心 KVM API 的扩展。用户空间传递一个扩展标识符(一个整数),并接收一个描述扩展可用性的整数。通常 0 表示否,1 表示是,但某些扩展可能会在整数返回值中报告其他信息。

根据它们的初始化,不同的 VM 可能具有不同的功能。因此,鼓励使用 vm ioctl 来查询功能(在 vm fd 上使用 KVM_CAP_CHECK_EXTENSION_VM 可用)

4.5 KVM_GET_VCPU_MMAP_SIZE

功能:

基本

架构:

全部

类型:

系统 ioctl

参数:

返回值:

vcpu mmap 区域的大小,以字节为单位

KVM_RUN ioctl(cf.)通过共享内存区域与用户空间通信。此 ioctl 返回该区域的大小。有关详细信息,请参阅 KVM_RUN 文档。

除了 KVM_RUN 通信区域的大小之外,还可以 mmap-ed VCPU 文件描述符的其他区域,包括

  • 如果 KVM_CAP_COALESCED_MMIO 可用,则为 KVM_COALESCED_MMIO_PAGE_OFFSET * PAGE_SIZE 处的页面;由于历史原因,此页面包含在 KVM_GET_VCPU_MMAP_SIZE 的结果中。KVM_CAP_COALESCED_MMIO 尚未记录。

  • 如果 KVM_CAP_DIRTY_LOG_RING 可用,则为 KVM_DIRTY_LOG_PAGE_OFFSET * PAGE_SIZE 处的多个页面。有关 KVM_CAP_DIRTY_LOG_RING 的更多信息,请参阅 7. 可以在 VM 上启用的功能

4.7 KVM_CREATE_VCPU

功能:

基本

架构:

全部

类型:

vm ioctl

参数:

vcpu id(x86 上的 apic id)

返回值:

成功时为 vcpu fd,出错时为 -1

此 API 将 vCPU 添加到虚拟机。最多可以添加 max_vcpus。vcpu id 是一个介于 [0, max_vcpu_id) 范围内的整数。

可以使用运行时 KVM_CHECK_EXTENSION ioctl() 的 KVM_CAP_NR_VCPUS 检索建议的 max_vcpus 值。可以使用运行时 KVM_CHECK_EXTENSION ioctl() 的 KVM_CAP_MAX_VCPUS 检索 max_vcpus 的最大可能值。

如果 KVM_CAP_NR_VCPUS 不存在,您应该假设 max_vcpus 最多为 4 个 CPU。如果 KVM_CAP_MAX_VCPUS 不存在,您应该假设 max_vcpus 与 KVM_CAP_NR_VCPUS 返回的值相同。

可以使用运行时 KVM_CHECK_EXTENSION ioctl() 的 KVM_CAP_MAX_VCPU_ID 检索 max_vcpu_id 的最大可能值。

如果 KVM_CAP_MAX_VCPU_ID 不存在,您应该假设 max_vcpu_id 与 KVM_CAP_MAX_VCPUS 返回的值相同。

在使用 book3s_hv 模式的 powerpc 上,vCPU 映射到一个或多个虚拟 CPU 核心中的虚拟线程。(这是因为硬件要求 CPU 核心中的所有硬件线程都位于同一分区中。)KVM_CAP_PPC_SMT 功能指示每个虚拟核心 (vcore) 的 vCPU 数量。vcore id 通过将 vCPU id 除以每个 vcore 的 vCPU 数量获得。给定 vcore 中的 vCPU 将始终位于彼此相同的物理核心中(尽管这可能不时地是不同的物理核心)。用户空间可以通过分配 vCPU id 来控制客户机的线程 (SMT) 模式。例如,如果用户空间想要单线程客户机 vCPU,它应使所有 vCPU id 都是每个 vcore 的 vCPU 数量的倍数。

对于已使用 S390 用户控制的虚拟机创建的虚拟 CPU,可以在页面偏移量 KVM_S390_SIE_PAGE_OFFSET 处对生成的 vCPU fd 进行内存映射,以便获得虚拟 CPU 硬件控制块的内存映射。

4.8 KVM_GET_DIRTY_LOG

功能:

基本

架构:

全部

类型:

vm ioctl

参数:

struct kvm_dirty_log(输入/输出)

返回值:

成功时为 0,出错时为 -1

/* for KVM_GET_DIRTY_LOG */
struct kvm_dirty_log {
      __u32 slot;
      __u32 padding;
      union {
              void __user *dirty_bitmap; /* one bit per page */
              __u64 padding;
      };
};

给定一个内存槽,返回一个位图,其中包含自上次调用此 ioctl 以来已修改的任何页面。位 0 是内存槽中的第一页。确保整个结构都已清除以避免填充问题。

如果 KVM_CAP_MULTI_ADDRESS_SPACE 可用,则槽字段的位 16-31 指定要为其返回脏位图的地址空间。有关槽字段用法的详细信息,请参阅 KVM_SET_USER_MEMORY_REGION。

在 ioctl 返回之前,将清除脏位图中的位,除非启用了 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2。有关更多信息,请参阅该功能的描述。

请注意,如果配置了 Xen shared_info 页面,则应始终假定它是脏的。KVM 不会明确地将其标记为脏。

4.10 KVM_RUN

功能:

基本

架构:

全部

类型:

vcpu ioctl

参数:

返回值:

成功时为 0,出错时为 -1

错误

EINTR

未屏蔽的信号正在挂起

ENOEXEC

vcpu 尚未初始化,或者客户机尝试从设备内存执行指令 (arm64)

ENOSYS

在没有 syndrome 信息且未启用 KVM_CAP_ARM_NISV_TO_USER 的情况下,数据中止在内存槽之外 (arm64)

EPERM

SVE 功能集已设置但未最终确定 (arm64)

此 ioctl 用于运行客户机虚拟 CPU。虽然没有显式参数,但有一个隐式参数块可以通过在偏移量 0 处 mmap() vcpu fd 来获得,其大小由 KVM_GET_VCPU_MMAP_SIZE 给出。该参数块的格式为“struct kvm_run”(参见下文)。

4.11 KVM_GET_REGS

功能:

基本

架构:

除了 arm64 之外的所有

类型:

vcpu ioctl

参数:

struct kvm_regs(输出)

返回值:

成功时为 0,出错时为 -1

从 vCPU 读取通用寄存器。

/* x86 */
struct kvm_regs {
      /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
      __u64 rax, rbx, rcx, rdx;
      __u64 rsi, rdi, rsp, rbp;
      __u64 r8,  r9,  r10, r11;
      __u64 r12, r13, r14, r15;
      __u64 rip, rflags;
};

/* mips */
struct kvm_regs {
      /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
      __u64 gpr[32];
      __u64 hi;
      __u64 lo;
      __u64 pc;
};

/* LoongArch */
struct kvm_regs {
      /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
      unsigned long gpr[32];
      unsigned long pc;
};

4.12 KVM_SET_REGS

功能:

基本

架构:

除了 arm64 之外的所有

类型:

vcpu ioctl

参数:

struct kvm_regs(输入)

返回值:

成功时为 0,出错时为 -1

将通用寄存器写入 vCPU。

有关数据结构,请参阅 KVM_GET_REGS。

4.13 KVM_GET_SREGS

功能:

基本

架构:

x86、ppc

类型:

vcpu ioctl

参数:

struct kvm_sregs(输出)

返回值:

成功时为 0,出错时为 -1

从 vCPU 读取特殊寄存器。

/* x86 */
struct kvm_sregs {
      struct kvm_segment cs, ds, es, fs, gs, ss;
      struct kvm_segment tr, ldt;
      struct kvm_dtable gdt, idt;
      __u64 cr0, cr2, cr3, cr4, cr8;
      __u64 efer;
      __u64 apic_base;
      __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
};

/* ppc -- see arch/powerpc/include/uapi/asm/kvm.h */

interrupt_bitmap 是挂起的外部中断的位图。最多可以设置一位。此中断已被 APIC 确认,但尚未注入到 CPU 核心中。

4.14 KVM_SET_SREGS

功能:

基本

架构:

x86、ppc

类型:

vcpu ioctl

参数:

struct kvm_sregs(输入)

返回值:

成功时为 0,出错时为 -1

将特殊寄存器写入 vCPU。有关数据结构,请参阅 KVM_GET_SREGS。

4.15 KVM_TRANSLATE

功能:

基本

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_translation(输入/输出)

返回值:

成功时为 0,出错时为 -1

根据 vCPU 当前的地址转换模式转换虚拟地址。

struct kvm_translation {
      /* in */
      __u64 linear_address;

      /* out */
      __u64 physical_address;
      __u8  valid;
      __u8  writeable;
      __u8  usermode;
      __u8  pad[5];
};

4.16 KVM_INTERRUPT

功能:

基本

架构:

x86、ppc、mips、riscv、loongarch

类型:

vcpu ioctl

参数:

struct kvm_interrupt(输入)

返回值:

成功时为 0,失败时为负数。

将硬件中断向量排队以进行注入。

/* for KVM_INTERRUPT */
struct kvm_interrupt {
      /* in */
      __u32 irq;
};

X86:

返回值:

0

成功时,

-EEXIST

如果已有一个中断排队

-EINVAL

irq 编号无效

-ENXIO

如果 PIC 在内核中

-EFAULT

如果指针无效

注意“irq”是中断向量,而不是中断引脚或线路。如果未使用内核内 PIC,则此 ioctl 非常有用。

PPC:

将外部中断排队以进行注入。此 ioctl 重载了 3 个不同的 irq 值

  1. KVM_INTERRUPT_SET

    一旦客户机准备好接收中断,这将注入一个边缘类型外部中断到客户机中。注入后,中断完成。

  2. KVM_INTERRUPT_UNSET

    这将取消设置任何挂起的中断。

    仅在使用 KVM_CAP_PPC_UNSET_IRQ 的情况下可用。

  3. KVM_INTERRUPT_SET_LEVEL

    这将注入一个级别类型的外部中断到客户机上下文中。中断保持挂起状态,直到触发具有 KVM_INTERRUPT_UNSET 的特定 ioctl。

    仅在使用 KVM_CAP_PPC_IRQ_LEVEL 的情况下可用。

请注意,“irq”的任何值(上述值除外)都无效,并且会导致意外行为。

这是一个异步 vcpu ioctl,可以从任何线程调用。

MIPS:

将外部中断排队以注入到虚拟 CPU 中。负中断编号将中断出队。

这是一个异步 vcpu ioctl,可以从任何线程调用。

RISC-V:

将外部中断排队以注入到虚拟 CPU 中。此 ioctl 重载了 2 个不同的 irq 值

  1. KVM_INTERRUPT_SET

    这为虚拟 CPU 设置外部中断,并且它将在准备好后接收该中断。

  2. KVM_INTERRUPT_UNSET

    这会清除虚拟 CPU 的挂起外部中断。

这是一个异步 vcpu ioctl,可以从任何线程调用。

LOONGARCH:

将外部中断排队以注入到虚拟 CPU 中。负中断编号将中断出队。

这是一个异步 vcpu ioctl,可以从任何线程调用。

4.18 KVM_GET_MSRS

功能:

基本 (vcpu),KVM_CAP_GET_MSR_FEATURES(系统)

架构:

x86

类型:

系统 ioctl,vcpu ioctl

参数:

struct kvm_msrs(输入/输出)

返回值:

成功返回的 msr 数量;出错时为 -1

当用作系统 ioctl 时:读取 VM 可用的基于 MSR 的功能的值。这类似于 KVM_GET_SUPPORTED_CPUID,但它返回 MSR 索引和值。可以使用系统 ioctl 中的 KVM_GET_MSR_FEATURE_INDEX_LIST 获取基于 MSR 的功能的列表。

当用作 vcpu ioctl 时:从 vcpu 读取特定于模型的寄存器。可以使用系统 ioctl 中的 KVM_GET_MSR_INDEX_LIST 获取支持的 msr 索引。

struct kvm_msrs {
      __u32 nmsrs; /* number of msrs in entries */
      __u32 pad;

      struct kvm_msr_entry entries[0];
};

struct kvm_msr_entry {
      __u32 index;
      __u32 reserved;
      __u64 data;
};

应用程序代码应设置“nmsrs”成员(指示条目数组的大小)和每个数组条目的“index”成员。kvm 将填写“data”成员。

4.19 KVM_SET_MSRS

功能:

基本

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_msrs(输入)

返回值:

成功设置的 msr 数量(见下文),出错时为 -1

将特定于模型的寄存器写入 vcpu。有关数据结构,请参阅 KVM_GET_MSRS。

应用程序代码应设置“nmsrs”成员(指示条目数组的大小)和每个数组条目的“index”和“data”成员。

它尝试逐个设置数组 entries[] 中的 MSR。如果设置 MSR 失败,例如,由于设置了保留位,或者 KVM 不支持/模拟该 MSR,等等,它将停止处理 MSR 列表,并返回已成功设置的 MSR 的数量。

4.20 KVM_SET_CPUID

功能:

基本

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_cpuid (输入)

返回值:

成功时为 0,出错时为 -1

定义 vcpu 对 cpuid 指令的响应。如果可用,应用程序应使用 KVM_SET_CPUID2 ioctl。

买者自负
  • 如果此 IOCTL 失败,KVM 不保证先前的有效 CPUID 配置(如果存在)未损坏。用户空间可以通过 KVM_GET_CPUID2 获取结果 CPUID 配置的副本。

  • 在 KVM_RUN 之后使用 KVM_SET_CPUID{,2},即在运行 guest 之后更改 guest vCPU 模型,可能会导致 guest 不稳定。

  • 使用异构 CPUID 配置(模 APIC ID、拓扑等)可能会导致 guest 不稳定。

struct kvm_cpuid_entry {
      __u32 function;
      __u32 eax;
      __u32 ebx;
      __u32 ecx;
      __u32 edx;
      __u32 padding;
};

/* for KVM_SET_CPUID */
struct kvm_cpuid {
      __u32 nent;
      __u32 padding;
      struct kvm_cpuid_entry entries[0];
};

4.21 KVM_SET_SIGNAL_MASK

功能:

基本

架构:

全部

类型:

vcpu ioctl

参数:

struct kvm_signal_mask (输入)

返回值:

成功时为 0,出错时为 -1

定义在 KVM_RUN 执行期间阻止哪些信号。此信号掩码暂时覆盖线程的信号掩码。接收到的任何未被阻止的信号(除了 SIGKILL 和 SIGSTOP,它们保留其传统行为)将导致 KVM_RUN 返回 -EINTR。

请注意,只有当信号未被原始信号掩码阻止时,才会传递该信号。

/* for KVM_SET_SIGNAL_MASK */
struct kvm_signal_mask {
      __u32 len;
      __u8  sigset[0];
};

4.22 KVM_GET_FPU

功能:

基本

架构:

x86, loongarch

类型:

vcpu ioctl

参数:

struct kvm_fpu (输出)

返回值:

成功时为 0,出错时为 -1

从 vcpu 读取浮点状态。

/* x86: for KVM_GET_FPU and KVM_SET_FPU */
struct kvm_fpu {
      __u8  fpr[8][16];
      __u16 fcw;
      __u16 fsw;
      __u8  ftwx;  /* in fxsave format */
      __u8  pad1;
      __u16 last_opcode;
      __u64 last_ip;
      __u64 last_dp;
      __u8  xmm[16][16];
      __u32 mxcsr;
      __u32 pad2;
};

/* LoongArch: for KVM_GET_FPU and KVM_SET_FPU */
struct kvm_fpu {
      __u32 fcsr;
      __u64 fcc;
      struct kvm_fpureg {
              __u64 val64[4];
      }fpr[32];
};

4.23 KVM_SET_FPU

功能:

基本

架构:

x86, loongarch

类型:

vcpu ioctl

参数:

struct kvm_fpu (输入)

返回值:

成功时为 0,出错时为 -1

将浮点状态写入 vcpu。

/* x86: for KVM_GET_FPU and KVM_SET_FPU */
struct kvm_fpu {
      __u8  fpr[8][16];
      __u16 fcw;
      __u16 fsw;
      __u8  ftwx;  /* in fxsave format */
      __u8  pad1;
      __u16 last_opcode;
      __u64 last_ip;
      __u64 last_dp;
      __u8  xmm[16][16];
      __u32 mxcsr;
      __u32 pad2;
};

/* LoongArch: for KVM_GET_FPU and KVM_SET_FPU */
struct kvm_fpu {
      __u32 fcsr;
      __u64 fcc;
      struct kvm_fpureg {
              __u64 val64[4];
      }fpr[32];
};

4.24 KVM_CREATE_IRQCHIP

功能:

KVM_CAP_IRQCHIP, KVM_CAP_S390_IRQCHIP (s390)

架构:

x86, arm64, s390

类型:

vm ioctl

参数:

返回值:

成功时为 0,出错时为 -1

在内核中创建一个中断控制器模型。在 x86 上,创建一个虚拟 ioapic,一个虚拟 PIC(两个 PIC,嵌套),并设置未来的 vcpu 以具有本地 APIC。GSI 0-15 的 IRQ 路由设置为 PIC 和 IOAPIC;GSI 16-23 仅转到 IOAPIC。在 arm64 上,创建一个 GICv2。任何其他 GIC 版本都需要使用 KVM_CREATE_DEVICE,它也支持创建 GICv2。对于 GICv2,首选使用 KVM_CREATE_DEVICE 而不是 KVM_CREATE_IRQCHIP。在 s390 上,创建一个虚拟的 irq 路由表。

请注意,在 s390 上,需要先启用 KVM_CAP_S390_IRQCHIP vm 功能,然后才能使用 KVM_CREATE_IRQCHIP。

4.25 KVM_IRQ_LINE

功能:

KVM_CAP_IRQCHIP

架构:

x86, arm64

类型:

vm ioctl

参数:

struct kvm_irq_level

返回值:

成功时为 0,出错时为 -1

设置 GSI 输入到内核中的中断控制器模型的级别。在某些架构上,需要先前使用 KVM_CREATE_IRQCHIP 创建中断控制器模型。请注意,边沿触发的中断需要将级别设置为 1,然后再设置为 0。

在真实的硬件上,中断引脚可以是低电平有效或高电平有效。这对于 struct kvm_irq_level 的 level 字段无关紧要:1 始终表示有效(断言),0 表示无效(解除断言)。

x86 允许操作系统为电平触发的中断编程中断极性(低电平有效/高电平有效),并且 KVM 过去考虑了极性。但是,由于处理低电平有效中断时的比特腐烂,上述约定现在在 x86 上也有效。这由 KVM_CAP_X86_IOAPIC_POLARITY_IGNORED 信号表示。除非存在此功能(或者除非它不使用内核 irqchip),否则用户空间不应将中断呈现给 guest 作为低电平有效。

arm64 可以在 CPU 级别或内核 irqchip (GIC) 级别发出中断信号,对于内核 irqchip,可以告诉 GIC 使用为特定 cpu 指定的 PPI。irq 字段的解释如下

bits:  |  31 ... 28  | 27 ... 24 | 23  ... 16 | 15 ... 0 |
field: | vcpu2_index | irq_type  | vcpu_index |  irq_id  |

irq_type 字段具有以下值

  • KVM_ARM_IRQ_TYPE_CPU

    内核外 GIC:irq_id 0 是 IRQ,irq_id 1 是 FIQ

  • KVM_ARM_IRQ_TYPE_SPI

    内核内 GIC:SPI,irq_id 在 32 到 1019 之间(包括)(vcpu_index 字段被忽略)

  • KVM_ARM_IRQ_TYPE_PPI

    内核内 GIC:PPI,irq_id 在 16 到 31 之间(包括)

(因此,irq_id 字段与 ARM GIC 规范中的 IRQ ID 非常吻合)

在这两种情况下,level 用于断言/解除断言线路。

当支持 KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 时,目标 vcpu 被标识为 (256 * vcpu2_index + vcpu_index)。否则,vcpu2_index 必须为零。

请注意,在 arm64 上,KVM_CAP_IRQCHIP 功能仅调节内核 irqchip 的中断注入。KVM_IRQ_LINE 始终可用于用户空间中断控制器。

struct kvm_irq_level {
      union {
              __u32 irq;     /* GSI */
              __s32 status;  /* not used for KVM_IRQ_LEVEL */
      };
      __u32 level;           /* 0 or 1 */
};

4.26 KVM_GET_IRQCHIP

功能:

KVM_CAP_IRQCHIP

架构:

x86

类型:

vm ioctl

参数:

struct kvm_irqchip (输入/输出)

返回值:

成功时为 0,出错时为 -1

将使用 KVM_CREATE_IRQCHIP 创建的内核中断控制器的状态读取到调用者提供的缓冲区中。

struct kvm_irqchip {
      __u32 chip_id;  /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */
      __u32 pad;
      union {
              char dummy[512];  /* reserving space */
              struct kvm_pic_state pic;
              struct kvm_ioapic_state ioapic;
      } chip;
};

4.27 KVM_SET_IRQCHIP

功能:

KVM_CAP_IRQCHIP

架构:

x86

类型:

vm ioctl

参数:

struct kvm_irqchip (输入)

返回值:

成功时为 0,出错时为 -1

从调用者提供的缓冲区设置使用 KVM_CREATE_IRQCHIP 创建的内核中断控制器的状态。

struct kvm_irqchip {
      __u32 chip_id;  /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */
      __u32 pad;
      union {
              char dummy[512];  /* reserving space */
              struct kvm_pic_state pic;
              struct kvm_ioapic_state ioapic;
      } chip;
};

4.28 KVM_XEN_HVM_CONFIG

功能:

KVM_CAP_XEN_HVM

架构:

x86

类型:

vm ioctl

参数:

struct kvm_xen_hvm_config (输入)

返回值:

成功时为 0,出错时为 -1

设置 Xen HVM guest 用来初始化其 hypercall 页面的 MSR,并提供用户空间中 hypercall blobs 的起始地址和大小。当 guest 写入 MSR 时,kvm 将一个 blob 页面(32 位或 64 位,取决于 vcpu 模式)复制到 guest 内存。

MSR 索引必须在范围 [0x40000000, 0x4fffffff] 中,即必须驻留在非官方保留给 hypervisor 使用的范围内。最小/最大值通过 KVM_XEN_MSR_MIN_INDEX 和 KVM_XEN_MSR_MAX_INDEX 枚举。

struct kvm_xen_hvm_config {
      __u32 flags;
      __u32 msr;
      __u64 blob_addr_32;
      __u64 blob_addr_64;
      __u8 blob_size_32;
      __u8 blob_size_64;
      __u8 pad2[30];
};

如果从 KVM_CAP_XEN_HVM 检查返回某些标志,则可以在此 ioctl 的标志字段中设置它们

KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL 标志请求 KVM 自动生成 hypercall 页面的内容;hypercall 将被拦截并通过 KVM_EXIT_XEN 传递给用户空间。在这种情况下,所有 blob 大小和地址字段必须为零。

KVM_XEN_HVM_CONFIG_EVTCHN_SEND 标志指示 KVM,用户空间将始终使用 KVM_XEN_HVM_EVTCHN_SEND ioctl 来传递事件通道中断,而不是直接操作 guest 的 shared_info 结构。反过来,这可能允许 KVM 启用某些功能,例如拦截 SCHEDOP_poll hypercall 以加速 guest 的 PV 自旋锁操作。即使用户空间不发送将始终这样做的指示,用户空间仍然可以使用 ioctl 来传递事件(如果已公布)。

目前,在 struct kvm_xen_hvm_config 中没有其他有效标志。

4.29 KVM_GET_CLOCK

功能:

KVM_CAP_ADJUST_CLOCK

架构:

x86

类型:

vm ioctl

参数:

struct kvm_clock_data (输出)

返回值:

成功时为 0,出错时为 -1

获取当前 guest 看到的 kvmclock 的当前时间戳。与 KVM_SET_CLOCK 结合使用,它用于确保迁移等场景的单调性。

当 KVM_CAP_ADJUST_CLOCK 传递给 KVM_CHECK_EXTENSION 时,它返回 KVM 可以在 struct kvm_clock_data 的 flag 成员中返回的位集合。

定义了以下标志

KVM_CLOCK_TSC_STABLE

如果设置,则返回的值是调用 KVM_GET_CLOCK 时所有 VCPU 看到的精确 kvmclock 值。如果清除,则返回的值仅为 CLOCK_MONOTONIC 加上一个常数偏移量;可以使用 KVM_SET_CLOCK 修改偏移量。KVM 将尝试使所有 VCPU 遵循此时钟,但每个 VCPU 读取的精确值可能会有所不同,因为主机 TSC 不稳定。

KVM_CLOCK_REALTIME

如果设置,则 kvm_clock_data 结构中的 realtime 字段填充了调用 KVM_GET_CLOCK 时主机实时时钟源的值。如果清除,则 realtime 字段不包含值。

KVM_CLOCK_HOST_TSC

如果设置,则 kvm_clock_data 结构中的 host_tsc 字段填充了调用 KVM_GET_CLOCK 时主机时间戳计数器 (TSC) 的值。如果清除,则 host_tsc 字段不包含值。

struct kvm_clock_data {
      __u64 clock;  /* kvmclock current value */
      __u32 flags;
      __u32 pad0;
      __u64 realtime;
      __u64 host_tsc;
      __u32 pad[4];
};

4.30 KVM_SET_CLOCK

功能:

KVM_CAP_ADJUST_CLOCK

架构:

x86

类型:

vm ioctl

参数:

struct kvm_clock_data (输入)

返回值:

成功时为 0,出错时为 -1

将 kvmclock 的当前时间戳设置为其参数中指定的值。与 KVM_GET_CLOCK 结合使用,它用于确保迁移等场景的单调性。

可以传递以下标志

KVM_CLOCK_REALTIME

如果设置,KVM 将比较 realtime 字段的值与调用 KVM_SET_CLOCK 时主机实时时钟源的值。经过的时间差将添加到将提供给 guest 的最终 kvmclock 值。

KVM_GET_CLOCK 返回的其他标志被接受但被忽略。

struct kvm_clock_data {
      __u64 clock;  /* kvmclock current value */
      __u32 flags;
      __u32 pad0;
      __u64 realtime;
      __u64 host_tsc;
      __u32 pad[4];
};

4.31 KVM_GET_VCPU_EVENTS

功能:

KVM_CAP_VCPU_EVENTS

由扩展:

KVM_CAP_INTR_SHADOW

架构:

x86, arm64

类型:

vcpu ioctl

参数:

struct kvm_vcpu_events (输出)

返回值:

成功时为 0,出错时为 -1

X86:

获取当前挂起的异常、中断和 NMI,以及 vcpu 的相关状态。

struct kvm_vcpu_events {
      struct {
              __u8 injected;
              __u8 nr;
              __u8 has_error_code;
              __u8 pending;
              __u32 error_code;
      } exception;
      struct {
              __u8 injected;
              __u8 nr;
              __u8 soft;
              __u8 shadow;
      } interrupt;
      struct {
              __u8 injected;
              __u8 pending;
              __u8 masked;
              __u8 pad;
      } nmi;
      __u32 sipi_vector;
      __u32 flags;
      struct {
              __u8 smm;
              __u8 pending;
              __u8 smm_inside_nmi;
              __u8 latched_init;
      } smi;
      __u8 reserved[27];
      __u8 exception_has_payload;
      __u64 exception_payload;
};

在 flags 字段中定义了以下位

  • 可以设置 KVM_VCPUEVENT_VALID_SHADOW 以指示 interrupt.shadow 包含有效状态。

  • 可以设置 KVM_VCPUEVENT_VALID_SMM 以指示 smi 包含有效状态。

  • 可以设置 KVM_VCPUEVENT_VALID_PAYLOAD 以指示 exception_has_payload、exception_payload 和 exception.pending 字段包含有效状态。只要启用 KVM_CAP_EXCEPTION_PAYLOAD,就会设置此位。

  • 可以设置 KVM_VCPUEVENT_VALID_TRIPLE_FAULT 以指示 triple_fault_pending 字段包含有效状态。只要启用 KVM_CAP_X86_TRIPLE_FAULT_EVENT,就会设置此位。

ARM64:

如果 guest 以真实设备会生成物理 SError 的方式访问由主机内核模拟的设备,KVM 可能会使虚拟 SError 对该 VCPU 挂起。此系统错误中断保持挂起状态,直到 guest 通过取消屏蔽 PSTATE.A 来处理异常。

运行 VCPU 可能会导致它处理挂起的 SError,或者进行导致 SError 变为挂起状态的访问。事件的描述仅在 VPCU 未运行时有效。

此 API 提供了一种读取和写入 guest 不可见的挂起 'event' 状态的方法。为了保存、恢复或迁移 VCPU,可以使用此 GET/SET API 读取然后写入表示状态的结构,以及其他 guest 可见的寄存器。无法“取消”已设置为挂起的 SError。

用户空间中模拟的设备也可能希望生成 SError。为此,用户空间可以填充事件结构。应首先读取当前状态,以确保没有挂起的 SError。如果存在挂起的 SError,则应遵循架构的“多个 SError 中断”规则。(DDI0587.a “ARM 可靠性、可用性和可维护性 (RAS) 规范”的 2.5.3)。

SError 异常始终具有 ESR 值。某些 CPU 能够指定虚拟 SError 的 ESR 值应是什么。这些系统将公布 KVM_CAP_ARM_INJECT_SERROR_ESR。在这种情况下,读取时 exception.has_esr 将始终具有非零值,并且使 SError 挂起的代理应在 exception.serror_esr 的低 24 位中指定 ISS 字段。如果系统支持 KVM_CAP_ARM_INJECT_SERROR_ESR,但用户空间将 exception.has_esr 设置为零的事件,KVM 将选择一个 ESR。

在不支持的系统上指定 exception.has_esr 将返回 -EINVAL。设置 exception.serror_esr 的低 24 位之外的任何内容将返回 -EINVAL。

无法读取回挂起的外部中止(通过 KVM_SET_VCPU_EVENTS 注入或其他方式),因为此类异常始终直接传递到虚拟 CPU)。

struct kvm_vcpu_events {
      struct {
              __u8 serror_pending;
              __u8 serror_has_esr;
              __u8 ext_dabt_pending;
              /* Align it to 8 bytes */
              __u8 pad[5];
              __u64 serror_esr;
      } exception;
      __u32 reserved[12];
};

4.32 KVM_SET_VCPU_EVENTS

功能:

KVM_CAP_VCPU_EVENTS

由扩展:

KVM_CAP_INTR_SHADOW

架构:

x86, arm64

类型:

vcpu ioctl

参数:

struct kvm_vcpu_events (输入)

返回值:

成功时为 0,出错时为 -1

X86:

设置挂起的异常、中断和 NMI,以及 vcpu 的相关状态。

有关数据结构,请参阅 KVM_GET_VCPU_EVENTS。

可以从更新中排除可能由运行 VCPU 异步修改的字段。这些字段是 nmi.pending、sipi_vector、smi.smm、smi.pending。保持 flags 字段中相应的位清除,以禁止覆盖当前的内核状态。这些位是

KVM_VCPUEVENT_VALID_NMI_PENDING

将 nmi.pending 传输到内核

KVM_VCPUEVENT_VALID_SIPI_VECTOR

传输 sipi_vector

KVM_VCPUEVENT_VALID_SMM

传输 smi 子结构。

如果 KVM_CAP_INTR_SHADOW 可用,则可以在 flags 字段中设置 KVM_VCPUEVENT_VALID_SHADOW,以指示 interrupt.shadow 包含有效状态,并且应写入 VCPU。

只有当 KVM_CAP_X86_SMM 可用时,才能设置 KVM_VCPUEVENT_VALID_SMM。

如果启用了 KVM_CAP_EXCEPTION_PAYLOAD,则可以在 flags 字段中设置 KVM_VCPUEVENT_VALID_PAYLOAD,以指示 exception_has_payload、exception_payload 和 exception.pending 字段包含有效状态,并且应写入 VCPU。

如果启用了 KVM_CAP_X86_TRIPLE_FAULT_EVENT,则可以在 flags 字段中设置 KVM_VCPUEVENT_VALID_TRIPLE_FAULT,以指示 triple_fault 字段包含有效状态,并且应写入 VCPU。

ARM64:

用户空间可能需要将几种类型的事件注入到 guest 中。

为此 VCPU 设置挂起的 SError 异常状态。无法“取消”已设置为挂起的 SError。

如果 guest 执行了用户空间无法处理的 I/O 内存访问,例如由于缺少指令综合征解码信息,或者由于在访问的 IPA 处没有映射设备,则用户空间可以要求内核使用 VCPU 上退出故障的地址来注入外部中止。在未进行 KVM_EXIT_MMIO 或 KVM_EXIT_ARM_NISV 的退出之后设置 ext_dabt_pending 是一种编程错误。只有当系统支持 KVM_CAP_ARM_INJECT_EXT_DABT 时,此功能才可用。这是一种帮助程序,用于提供用户空间如何跨不同的用户空间实现向 guest 报告上述情况的通用性。但是,用户空间仍然可以使用 KVM_SET_ONE_REG API 操作单个寄存器来模拟所有 Arm 异常。

有关数据结构,请参阅 KVM_GET_VCPU_EVENTS。

4.33 KVM_GET_DEBUGREGS

功能:

KVM_CAP_DEBUGREGS

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_debugregs (输出)

返回值:

成功时为 0,出错时为 -1

从 vcpu 读取调试寄存器。

struct kvm_debugregs {
      __u64 db[4];
      __u64 dr6;
      __u64 dr7;
      __u64 flags;
      __u64 reserved[9];
};

4.34 KVM_SET_DEBUGREGS

功能:

KVM_CAP_DEBUGREGS

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_debugregs (输入)

返回值:

成功时为 0,出错时为 -1

将调试寄存器写入 vcpu。

有关数据结构,请参阅 KVM_GET_DEBUGREGS。flags 字段尚未使用,必须在条目上清除。

4.35 KVM_SET_USER_MEMORY_REGION

功能:

KVM_CAP_USER_MEMORY

架构:

全部

类型:

vm ioctl

参数:

struct kvm_userspace_memory_region (输入)

返回值:

成功时为 0,出错时为 -1

struct kvm_userspace_memory_region {
      __u32 slot;
      __u32 flags;
      __u64 guest_phys_addr;
      __u64 memory_size; /* bytes */
      __u64 userspace_addr; /* start of the userspace allocated memory */
};

/* for kvm_userspace_memory_region::flags */
#define KVM_MEM_LOG_DIRTY_PAGES       (1UL << 0)
#define KVM_MEM_READONLY      (1UL << 1)

此 ioctl 允许用户创建、修改或删除 guest 物理内存槽。“slot” 的位 0-15 指定槽 ID,此值应小于每个 VM 支持的最大用户内存槽数。可以使用 KVM_CAP_NR_MEMSLOTS 查询允许的最大槽数。槽不得在 guest 物理地址空间中重叠。

如果 KVM_CAP_MULTI_ADDRESS_SPACE 可用,则 “slot” 的位 16-31 指定要修改的地址空间。它们必须小于 KVM_CHECK_EXTENSION 为 KVM_CAP_MULTI_ADDRESS_SPACE 功能返回的值。单独地址空间中的槽不相关;对重叠槽的限制仅适用于每个地址空间。

删除槽通过为 memory_size 传递零来完成。更改现有槽时,可以在 guest 物理内存空间中移动它,或者可以修改其标志,但不能调整其大小。

该区域的内存从 userspace_addr 字段表示的地址开始获取,该地址必须指向整个内存槽大小的用户可寻址内存。任何对象都可以支持此内存,包括匿名内存、普通文件和 hugetlbfs。

在支持某种形式的地址标记的架构上,userspace_addr 必须是未标记的地址。

建议 guest_phys_addr 和 userspace_addr 的低 21 位相同。这允许 guest 中的大页面由主机中的大页面支持。

flags 字段支持两个标志:KVM_MEM_LOG_DIRTY_PAGES 和 KVM_MEM_READONLY。可以设置前者以指示 KVM 跟踪槽中内存的写入。有关如何使用它,请参阅 KVM_GET_DIRTY_LOG ioctl。如果 KVM_CAP_READONLY_MEM 功能允许,可以设置后者以使新槽只读。在这种情况下,对此内存的写入将作为 KVM_EXIT_MMIO 退出发布到用户空间。

当 KVM_CAP_SYNC_MMU 功能可用时,内存区域支持中的更改会自动反映到 guest 中。例如,影响该区域的 mmap() 将立即可见。另一个示例是 madvise(MADV_DROP)。

对于 TDX guest,删除/移动内存区域会丢失 guest 内存内容。不支持只读区域。仅支持 as-id 0。

注意:在 arm64 上,页面表 walker 生成的写入(例如,为了更新访问和脏位)永远不会导致当槽具有 KVM_MEM_READONLY 标志时的 KVM_EXIT_MMIO 退出。这是因为 KVM 无法提供页面表 walker 将写入的数据,从而无法模拟访问。相反,在 guest 中注入中止(如果页面表更新的原因是加载或存储,则为数据中止,如果是指令提取,则为指令中止)。

S390:

如果 VM 设置了 KVM_VM_S390_UCONTROL 标志,则返回 -EINVAL 或 -EEXIST。如果在受保护的 VM 上调用,则返回 -EINVAL。

4.36 KVM_SET_TSS_ADDR

功能:

KVM_CAP_SET_TSS_ADDR

架构:

x86

类型:

vm ioctl

参数:

unsigned long tss_address (输入)

返回值:

成功时为 0,出错时为 -1

此 ioctl 定义 guest 物理地址空间中三页区域的物理地址。该区域必须在 guest 物理地址空间的前 4GB 中,并且不得与任何内存槽或任何 mmio 地址冲突。如果 guest 访问此内存区域,则可能会发生故障。

在基于 Intel 的主机上需要此 ioctl。由于虚拟化实现中的一个怪癖,基于 Intel 的硬件需要这样做(当它出现时,请参阅内部文档)。

4.37 KVM_ENABLE_CAP

功能:

KVM_CAP_ENABLE_CAP

架构:

mips, ppc, s390, x86, loongarch

类型:

vcpu ioctl

参数:

struct kvm_enable_cap (输入)

返回值:

成功时为 0;出错时为 -1

功能:

KVM_CAP_ENABLE_CAP_VM

架构:

全部

类型:

vm ioctl

参数:

struct kvm_enable_cap (输入)

返回值:

成功时为 0;出错时为 -1

注意

并非所有扩展都默认启用。使用此 ioctl,应用程序可以启用扩展,使其可用于 guest。

在不支持此 ioctl 的系统上,它始终失败。在支持它的系统上,它仅适用于支持启用的扩展。

要检查是否可以启用功能,应使用 KVM_CHECK_EXTENSION ioctl。

struct kvm_enable_cap {
     /* in */
     __u32 cap;

应该启用的功能。

__u32 flags;

指示未来增强功能的位字段。现在必须为 0。

__u64 args[4];

用于启用功能的参数。如果功能需要初始值才能正常运行,则这是放置它们的位置。

     __u8  pad[64];
};

vcpu ioctl 应用于 vcpu 特定的功能,vm ioctl 应用于 vm 范围的功能。

4.38 KVM_GET_MP_STATE

功能:

KVM_CAP_MP_STATE

架构:

x86, s390, arm64, riscv, loongarch

类型:

vcpu ioctl

参数:

struct kvm_mp_state (输出)

返回值:

成功时为 0;出错时为 -1

struct kvm_mp_state {
      __u32 mp_state;
};

返回 vcpu 的当前“多处理状态”(尽管在单处理器 guest 上也有效)。

可能的值是

KVM_MP_STATE_RUNNABLE

vcpu 当前正在运行 [x86,arm64,riscv,loongarch]

KVM_MP_STATE_UNINITIALIZED

vcpu 是尚未收到 INIT 信号的应用程序处理器 (AP) [x86]

KVM_MP_STATE_INIT_RECEIVED

vcpu 已收到 INIT 信号,现在已准备好进行 SIPI [x86]

KVM_MP_STATE_HALTED

vcpu 已执行 HLT 指令,正在等待中断 [x86]

KVM_MP_STATE_SIPI_RECEIVED

vcpu 刚刚收到 SIPI(可通过 KVM_GET_VCPU_EVENTS 访问的向量)[x86]

KVM_MP_STATE_STOPPED

vcpu 已停止 [s390,arm64,riscv]

KVM_MP_STATE_CHECK_STOP

vcpu 处于特殊错误状态 [s390]

KVM_MP_STATE_OPERATING

vcpu 正在运行(正在运行或已停止)[s390]

KVM_MP_STATE_LOAD

vcpu 处于特殊加载/启动状态 [s390]

KVM_MP_STATE_SUSPENDED

vcpu 处于挂起状态,正在等待唤醒事件 [arm64]

在 x86 上,只有在 KVM_CREATE_IRQCHIP 之后此 ioctl 才有用。如果没有内核 irqchip,则必须由用户空间在这些架构上维护多处理状态。

对于 arm64:

如果 vCPU 处于 KVM_MP_STATE_SUSPENDED 状态,KVM 将模拟 WFI 指令的架构执行。

如果识别出唤醒事件,KVM 将通过 KVM_SYSTEM_EVENT 退出返回到用户空间,其中事件类型为 KVM_SYSTEM_EVENT_WAKEUP。如果用户空间想要遵守唤醒,则必须将 vCPU 的 MP 状态设置为 KVM_MP_STATE_RUNNABLE。如果不是,KVM 将继续在后续调用 KVM_RUN 中等待唤醒事件。

警告

如果用户空间打算将 vCPU 保留在 SUSPENDED 状态,强烈建议用户空间采取行动来抑制唤醒事件(例如屏蔽中断)。否则,后续调用 KVM_RUN 将立即退出,并显示 KVM_SYSTEM_EVENT_WAKEUP 事件,并无意中浪费 CPU 周期。

此外,如果用户空间采取行动来抑制唤醒事件,强烈建议在再次使 vCPU 可运行时,也将其恢复到原始状态。例如,如果用户空间屏蔽了挂起的中断以抑制唤醒,则应在将控制权返回给 guest 之前取消屏蔽中断。

对于 riscv:

唯一有效的状态是 KVM_MP_STATE_STOPPED 和 KVM_MP_STATE_RUNNABLE,它们反映了 vcpu 是否暂停。

在 LoongArch 上,仅使用 KVM_MP_STATE_RUNNABLE 状态来反映 vcpu 是否可运行。

4.39 KVM_SET_MP_STATE

功能:

KVM_CAP_MP_STATE

架构:

x86, s390, arm64, riscv, loongarch

类型:

vcpu ioctl

参数:

struct kvm_mp_state (输入)

返回值:

成功时为 0;出错时为 -1

设置 vcpu 的当前“多处理状态”;有关参数,请参阅 KVM_GET_MP_STATE。

在 x86 上,只有在 KVM_CREATE_IRQCHIP 之后此 ioctl 才有用。如果没有内核 irqchip,则必须由用户空间在这些架构上维护多处理状态。

对于 arm64/riscv:

唯一有效的状态是 KVM_MP_STATE_STOPPED 和 KVM_MP_STATE_RUNNABLE,它们反映了 vcpu 是否应该暂停。

在 LoongArch 上,仅使用 KVM_MP_STATE_RUNNABLE 状态来反映 vcpu 是否可运行。

4.40 KVM_SET_IDENTITY_MAP_ADDR

功能:

KVM_CAP_SET_IDENTITY_MAP_ADDR

架构:

x86

类型:

vm ioctl

参数:

unsigned long identity (in)

返回值:

成功时为 0,出错时为 -1

此 ioctl 定义了客户机物理地址空间中一个页大小区域的物理地址。该区域必须位于客户机物理地址空间的前 4GB 内,并且不得与任何内存槽或任何 mmio 地址冲突。如果客户机访问此内存区域,可能会发生故障。

将地址设置为 0 将导致地址重置为其默认值 (0xfffbc000)。

在基于 Intel 的主机上需要此 ioctl。由于虚拟化实现中的一个怪癖,基于 Intel 的硬件需要这样做(当它出现时,请参阅内部文档)。

如果已创建任何 VCPU,则失败。

4.41 KVM_SET_BOOT_CPU_ID

功能:

KVM_CAP_SET_BOOT_CPU_ID

架构:

x86

类型:

vm ioctl

参数:

unsigned long vcpu_id

返回值:

成功时为 0,出错时为 -1

定义哪个 vcpu 是引导处理器 (BSP)。值与 KVM_CREATE_VCPU 中的 vcpu id 相同。如果未调用此 ioctl,则默认为 vcpu 0。必须在 vcpu 创建之前调用此 ioctl,否则将返回 EBUSY 错误。

4.42 KVM_GET_XSAVE

功能:

KVM_CAP_XSAVE

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_xsave (out)

返回值:

成功时为 0,出错时为 -1

struct kvm_xsave {
      __u32 region[1024];
      __u32 extra[0];
};

此 ioctl 会将当前 vcpu 的 xsave 结构复制到用户空间。

4.43 KVM_SET_XSAVE

功能:

KVM_CAP_XSAVE 和 KVM_CAP_XSAVE2

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_xsave (in)

返回值:

成功时为 0,出错时为 -1

struct kvm_xsave {
      __u32 region[1024];
      __u32 extra[0];
};

此 ioctl 会将用户空间的 xsave 结构复制到内核。它复制的字节数与在 vm 文件描述符上调用 KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) 返回的字节数一样多。KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) 返回的大小值将始终至少为 4096。目前,只有在使用 arch_prctl() 启用动态功能后,该值才会大于 4096,但将来可能会发生变化。

struct kvm_xsave 中状态保存区域的偏移量遵循主机上 CPUID 叶 0xD 的内容。

4.44 KVM_GET_XCRS

功能:

KVM_CAP_XCRS

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_xcrs (out)

返回值:

成功时为 0,出错时为 -1

struct kvm_xcr {
      __u32 xcr;
      __u32 reserved;
      __u64 value;
};

struct kvm_xcrs {
      __u32 nr_xcrs;
      __u32 flags;
      struct kvm_xcr xcrs[KVM_MAX_XCRS];
      __u64 padding[16];
};

此 ioctl 会将当前 vcpu 的 xcrs 复制到用户空间。

4.45 KVM_SET_XCRS

功能:

KVM_CAP_XCRS

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_xcrs (in)

返回值:

成功时为 0,出错时为 -1

struct kvm_xcr {
      __u32 xcr;
      __u32 reserved;
      __u64 value;
};

struct kvm_xcrs {
      __u32 nr_xcrs;
      __u32 flags;
      struct kvm_xcr xcrs[KVM_MAX_XCRS];
      __u64 padding[16];
};

此 ioctl 会将 vcpu 的 xcr 设置为用户空间指定的值。

4.46 KVM_GET_SUPPORTED_CPUID

功能:

KVM_CAP_EXT_CPUID

架构:

x86

类型:

系统 ioctl

参数:

struct kvm_cpuid2 (in/out)

返回值:

成功时为 0,出错时为 -1

struct kvm_cpuid2 {
      __u32 nent;
      __u32 padding;
      struct kvm_cpuid_entry2 entries[0];
};

#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX               BIT(0)
#define KVM_CPUID_FLAG_STATEFUL_FUNC          BIT(1) /* deprecated */
#define KVM_CPUID_FLAG_STATE_READ_NEXT                BIT(2) /* deprecated */

struct kvm_cpuid_entry2 {
      __u32 function;
      __u32 index;
      __u32 flags;
      __u32 eax;
      __u32 ebx;
      __u32 ecx;
      __u32 edx;
      __u32 padding[3];
};

此 ioctl 返回 x86 cpuid 功能,这些功能受硬件和 kvm 在其默认配置中支持。用户空间可以使用此 ioctl 返回的信息来构建与硬件、内核和用户空间功能一致的 cpuid 信息(对于 KVM_SET_CPUID2),并满足用户要求(例如,用户可能希望约束 cpuid 以模拟较旧的硬件,或者为了跨集群的功能一致性)。

动态启用的功能位需要在调用此 ioctl 之前使用 arch_prctl() 请求。未请求的功能位将从结果中排除。

请注意,某些功能(例如 KVM_CAP_X86_DISABLE_EXITS)可能会公开 kvm 在其默认配置中不支持的 cpuid 功能(例如 MONITOR)。如果用户空间启用此类功能,则它负责适当地修改此 ioctl 的结果。

用户空间通过传递一个 kvm_cpuid2 结构来调用 KVM_GET_SUPPORTED_CPUID,其中 'nent' 字段指示可变大小数组 'entries' 中的条目数。如果条目数太低而无法描述 cpu 功能,则返回错误 (E2BIG)。如果数量太高,则调整 'nent' 字段并返回错误 (ENOMEM)。如果数量恰好合适,则将 'nent' 字段调整为 'entries' 数组中有效条目的数量,然后填充该数组。

返回的条目是由 cpuid 指令返回的主机 cpuid,其中未知或不受支持的功能被屏蔽掉。某些功能(例如 x2apic)可能不存在于主机 cpu 中,但如果 kvm 可以有效地模拟它们,则由 kvm 公开。每个条目中的字段定义如下

function

用于获取条目的 eax 值

index

用于获取条目的 ecx 值(对于受 ecx 影响的条目)

flags

以下零个或多个的 OR

KVM_CPUID_FLAG_SIGNIFCANT_INDEX

如果索引字段有效

eax, ebx, ecx, edx

cpuid 指令为此 function/index 组合返回的值

x2APIC(CPUID 叶 1,ecx[21) 和 TSC 截止时间计时器(CPUID 叶 1,ecx[24])可能会返回 true,但它们依赖于 KVM_CREATE_IRQCHIP 来实现本地 APIC 的内核内模拟。TSC 截止时间计时器支持也通过以下方式报告

ioctl(KVM_CHECK_EXTENSION, KVM_CAP_TSC_DEADLINE_TIMER)

如果返回 true 并且您使用 KVM_CREATE_IRQCHIP,或者如果您在用户空间中模拟该功能,则可以为 KVM_SET_CPUID2 启用该功能。

在 KVM_SET_CPUID2 中启用 x2APIC 需要 KVM_CREATE_IRQCHIP,因为 KVM 不支持将 x2APIC MSR 访问转发到用户空间,即 KVM 不支持在用户空间中模拟 x2APIC。

4.47 KVM_PPC_GET_PVINFO

功能:

KVM_CAP_PPC_GET_PVINFO

架构:

ppc

类型:

vm ioctl

参数:

struct kvm_ppc_pvinfo (out)

返回值:

成功时为 0,出错时为 !0

struct kvm_ppc_pvinfo {
      __u32 flags;
      __u32 hcall[4];
      __u8  pad[108];
};

此 ioctl 获取需要使用设备树或其他方式从 vm 上下文传递到客户机的 PV 特定信息。

hcall 数组定义了构成超调用的 4 个指令。

如果在以后向该结构添加任何其他字段,则将在 flags 位图中设置该附加信息位的标志。

flags 位图定义为

/* the host supports the ePAPR idle hcall
#define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)

4.52 KVM_SET_GSI_ROUTING

功能:

KVM_CAP_IRQ_ROUTING

架构:

x86 s390 arm64

类型:

vm ioctl

参数:

struct kvm_irq_routing (in)

返回值:

成功时为 0,出错时为 -1

设置 GSI 路由表条目,覆盖任何先前设置的条目。

在 arm64 上,GSI 路由具有以下限制

  • GSI 路由不适用于 KVM_IRQ_LINE,仅适用于 KVM_IRQFD。

struct kvm_irq_routing {
      __u32 nr;
      __u32 flags;
      struct kvm_irq_routing_entry entries[0];
};

到目前为止,未指定任何标志,相应的字段必须设置为零。

struct kvm_irq_routing_entry {
      __u32 gsi;
      __u32 type;
      __u32 flags;
      __u32 pad;
      union {
              struct kvm_irq_routing_irqchip irqchip;
              struct kvm_irq_routing_msi msi;
              struct kvm_irq_routing_s390_adapter adapter;
              struct kvm_irq_routing_hv_sint hv_sint;
              struct kvm_irq_routing_xen_evtchn xen_evtchn;
              __u32 pad[8];
      } u;
};

/* gsi routing entry types */
#define KVM_IRQ_ROUTING_IRQCHIP 1
#define KVM_IRQ_ROUTING_MSI 2
#define KVM_IRQ_ROUTING_S390_ADAPTER 3
#define KVM_IRQ_ROUTING_HV_SINT 4
#define KVM_IRQ_ROUTING_XEN_EVTCHN 5

在 s390 上,在 ucontrol VM 上添加 KVM_IRQ_ROUTING_S390_ADAPTER 会因错误 -EINVAL 而被拒绝。

flags

  • KVM_MSI_VALID_DEVID:与 KVM_IRQ_ROUTING_MSI 路由条目类型一起使用,指定 devid 字段包含有效值。每个 VM 的 KVM_CAP_MSI_DEVID 功能会声明提供设备 ID 的要求。如果此功能不可用,则用户空间绝不应设置 KVM_MSI_VALID_DEVID 标志,因为 ioctl 可能会失败。

  • 否则为零

struct kvm_irq_routing_irqchip {
      __u32 irqchip;
      __u32 pin;
};

struct kvm_irq_routing_msi {
      __u32 address_lo;
      __u32 address_hi;
      __u32 data;
      union {
              __u32 pad;
              __u32 devid;
      };
};

如果设置了 KVM_MSI_VALID_DEVID,则 devid 包含写入 MSI 消息的设备的唯一设备标识符。对于 PCI,这通常是低 16 位中的 BDF 标识符。

在 x86 上,除非启用了 KVM_CAP_X2APIC_API 功能的 KVM_X2APIC_API_USE_32BIT_IDS 功能,否则 address_hi 将被忽略。如果启用了该功能,则 address_hi 的位 31-8 提供目标 id 的位 31-8。address_hi 的位 7-0 必须为零。

struct kvm_irq_routing_s390_adapter {
      __u64 ind_addr;
      __u64 summary_addr;
      __u64 ind_offset;
      __u32 summary_offset;
      __u32 adapter_id;
};

struct kvm_irq_routing_hv_sint {
      __u32 vcpu;
      __u32 sint;
};

struct kvm_irq_routing_xen_evtchn {
      __u32 port;
      __u32 vcpu;
      __u32 priority;
};

当 KVM_CAP_XEN_HVM 在其支持的功能指示中包含 KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL 位时,支持路由到 Xen 事件通道。尽管存在优先级字段,但仅支持值 KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL,这意味着通过 2 级事件通道传递。将来可能会添加 FIFO 事件通道支持。

4.55 KVM_SET_TSC_KHZ

功能:

KVM_CAP_TSC_CONTROL / KVM_CAP_VM_TSC_CONTROL

架构:

x86

类型:

vcpu ioctl / vm ioctl

参数:

virtual tsc_khz

返回值:

成功时为 0,出错时为 -1

指定虚拟机的 tsc 频率。频率的单位为 KHz。

如果声明了 KVM_CAP_VM_TSC_CONTROL 功能,则它也可以用作 vm ioctl 来设置后续创建的 vCPU 的初始 tsc 频率。

4.56 KVM_GET_TSC_KHZ

功能:

KVM_CAP_GET_TSC_KHZ / KVM_CAP_VM_TSC_CONTROL

架构:

x86

类型:

vcpu ioctl / vm ioctl

参数:

返回值:

成功时为 virtual tsc-khz,出错时为负值

返回客户机的 tsc 频率。返回值单位为 KHz。如果主机具有不稳定的 tsc,则此 ioctl 返回 -EIO 作为错误。

4.57 KVM_GET_LAPIC

功能:

KVM_CAP_IRQCHIP

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_lapic_state (out)

返回值:

成功时为 0,出错时为 -1

#define KVM_APIC_REG_SIZE 0x400
struct kvm_lapic_state {
      char regs[KVM_APIC_REG_SIZE];
};

读取本地 APIC 寄存器并将它们复制到输入参数中。数据格式和布局与架构手册中记录的相同。

如果启用了 KVM_CAP_X2APIC_API 的 KVM_X2APIC_API_USE_32BIT_IDS 功能,则 APIC_ID 寄存器的格式取决于其 VCPU 的 APIC 模式(由 MSR_IA32_APICBASE 报告)。x2APIC 将 APIC ID 存储在 APIC_ID 寄存器中(字节 32-35)。xAPIC 仅允许一个 8 位 APIC ID,该 ID 存储在 APIC 寄存器的位 31-24 中,或者等效地存储在 struct kvm_lapic_state 的 regs 字段的字节 35 中。然后必须在使用 KVM_SET_MSR 设置 MSR_IA32_APICBASE 后调用 KVM_GET_LAPIC。

如果禁用了 KVM_X2APIC_API_USE_32BIT_IDS 功能,则 struct kvm_lapic_state 始终使用 xAPIC 格式。

4.58 KVM_SET_LAPIC

功能:

KVM_CAP_IRQCHIP

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_lapic_state (in)

返回值:

成功时为 0,出错时为 -1

#define KVM_APIC_REG_SIZE 0x400
struct kvm_lapic_state {
      char regs[KVM_APIC_REG_SIZE];
};

将输入参数复制到本地 APIC 寄存器中。数据格式和布局与架构手册中记录的相同。

APIC ID 寄存器的格式(struct kvm_lapic_state 的 regs 字段的字节 32-35)取决于 KVM_CAP_X2APIC_API 功能的状态。请参阅 KVM_GET_LAPIC 中的注释。

4.59 KVM_IOEVENTFD

功能:

KVM_CAP_IOEVENTFD

架构:

全部

类型:

vm ioctl

参数:

struct kvm_ioeventfd (in)

返回值:

成功时为 0,出错时为 !0

此 ioctl 将 ioeventfd 附加或分离到客户机中的合法 pio/mmio 地址。在注册地址中进行客户机写入将发出提供的事件信号,而不是触发退出。

struct kvm_ioeventfd {
      __u64 datamatch;
      __u64 addr;        /* legal pio/mmio address */
      __u32 len;         /* 0, 1, 2, 4, or 8 bytes    */
      __s32 fd;
      __u32 flags;
      __u8  pad[36];
};

对于 s390 上的 virtio-ccw 设备的特殊情况,ioevent 与子通道/virtqueue 元组匹配。

定义了以下标志

#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
#define KVM_IOEVENTFD_FLAG_PIO       (1 << kvm_ioeventfd_flag_nr_pio)
#define KVM_IOEVENTFD_FLAG_DEASSIGN  (1 << kvm_ioeventfd_flag_nr_deassign)
#define KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY \
      (1 << kvm_ioeventfd_flag_nr_virtio_ccw_notify)

如果设置了 datamatch 标志,则只有在写入到注册地址的值等于 struct kvm_ioeventfd 中的 datamatch 时,才会发出事件信号。

对于 virtio-ccw 设备,addr 包含子通道 id,datamatch 包含 virtqueue 索引。

使用 KVM_CAP_IOEVENTFD_ANY_LENGTH,允许零长度 ioeventfd,内核将忽略客户机写入的长度,并且可能会获得更快的 vmexit。加速可能仅适用于特定架构,但 ioeventfd 无论如何都可以工作。

4.60 KVM_DIRTY_TLB

功能:

KVM_CAP_SW_TLB

架构:

ppc

类型:

vcpu ioctl

参数:

struct kvm_dirty_tlb (in)

返回值:

成功时为 0,出错时为 -1

struct kvm_dirty_tlb {
      __u64 bitmap;
      __u32 num_dirty;
};

每当用户空间更改共享 TLB 中的条目时,必须在对关联的 vcpu 调用 KVM_RUN 之前调用此函数。

“bitmap”字段是数组的用户空间地址。此数组由多个位组成,等于上次成功调用 KVM_ENABLE_CAP(KVM_CAP_SW_TLB) 确定的 TLB 条目总数,向上舍入到最接近的 64 的倍数。

每个位对应一个 TLB 条目,排序方式与共享 TLB 数组中相同。

该数组是小端序:位 0 是第一个字节的最低有效位,位 8 是第二个字节的最低有效位,依此类推。这避免了不同字大小的任何复杂情况。

“num_dirty”字段是 KVM 的性能提示,用于确定它是否应跳过处理位图并仅使所有内容无效。它必须设置为位图中设置的位数。

4.62 KVM_CREATE_SPAPR_TCE

功能:

KVM_CAP_SPAPR_TCE

架构:

powerpc

类型:

vm ioctl

参数:

struct kvm_create_spapr_tce (in)

返回值:

用于操作创建的 TCE 表的文件描述符

这将创建一个虚拟 TCE(转换控制条目)表,该表是 PAPR 样式的虚拟 I/O 的 IOMMU。它用于将虚拟 I/O 中使用的逻辑地址转换为客户机物理地址,并为 PAPR 虚拟 I/O 提供分散/收集功能。

/* for KVM_CAP_SPAPR_TCE */
struct kvm_create_spapr_tce {
      __u64 liobn;
      __u32 window_size;
};

liobn 字段给出了要为其创建 TCE 表的逻辑 IO 总线号。window_size 字段指定此 TCE 表将转换的 DMA 窗口的大小 - 该表将为 DMA 窗口的每 4kiB 包含一个 64 位 TCE 条目。

当客户机在已使用此 ioctl() 创建 TCE 表的 liobn 上发出 H_PUT_TCE hcall 时,内核将在真实模式下处理它,从而更新 TCE 表。其他 liobn 的 H_PUT_TCE 调用将导致 vm 退出,并且必须由用户空间处理。

返回值是一个文件描述符,可以将其传递给 mmap(2) 以将创建的 TCE 表映射到用户空间。这使用户空间可以读取由内核处理的 H_PUT_TCE 调用写入的条目,并且还使用户空间可以直接更新 TCE 表,这在某些情况下很有用。

4.64 KVM_NMI

功能:

KVM_CAP_USER_NMI

架构:

x86

类型:

vcpu ioctl

参数:

返回值:

成功时为 0,出错时为 -1

在线程的 vcpu 上对 NMI 进行排队。请注意,只有在未调用 KVM_CREATE_IRQCHIP 时,此定义才明确,因为这是虚拟 cpu 内核和虚拟本地 APIC 之间的接口。调用 KVM_CREATE_IRQCHIP 后,此接口完全在内核中模拟。

要使用此函数通过 KVM_CREATE_IRQCHIP 模拟 LINT1 输入,请使用以下算法

  • 暂停 vcpu

  • 读取本地 APIC 的状态 (KVM_GET_LAPIC)

  • 检查更改 LINT1 是否会对 NMI 进行排队(请参阅 LINT1 的 LVT 条目)

  • 如果是,则发出 KVM_NMI

  • 恢复 vcpu

某些客户机配置 LINT1 NMI 输入以导致崩溃,从而有助于调试。

4.65 KVM_S390_UCAS_MAP

功能:

KVM_CAP_S390_UCONTROL

架构:

s390

类型:

vcpu ioctl

参数:

struct kvm_s390_ucas_mapping (in)

返回值:

成功时为 0

该参数的定义如下

struct kvm_s390_ucas_mapping {
        __u64 user_addr;
        __u64 vcpu_addr;
        __u64 length;
};

此 ioctl 将“user_addr”处的内存(长度为“length”)映射到 vcpu 的地址空间,从“vcpu_addr”开始。所有参数都需要对齐 1 兆字节。

4.66 KVM_S390_UCAS_UNMAP

功能:

KVM_CAP_S390_UCONTROL

架构:

s390

类型:

vcpu ioctl

参数:

struct kvm_s390_ucas_mapping (in)

返回值:

成功时为 0

该参数的定义如下

struct kvm_s390_ucas_mapping {
        __u64 user_addr;
        __u64 vcpu_addr;
        __u64 length;
};

此 ioctl 取消映射 vcpu 地址空间中从“vcpu_addr”开始的内存(长度为“length”)。忽略字段“user_addr”。所有参数都需要对齐 1 兆字节。

4.67 KVM_S390_VCPU_FAULT

功能:

KVM_CAP_S390_UCONTROL

架构:

s390

类型:

vcpu ioctl

参数:

vcpu 绝对地址 (in)

返回值:

成功时为 0

此调用在虚拟 cpu 的地址空间(对于用户控制的虚拟机)或虚拟机的地址空间(对于常规虚拟机)上创建一个页表条目。这仅适用于小错误,因此建议预先通过用户页表访问主题内存页。这对于处理用户控制的虚拟机的有效性拦截非常有用,可以在调用 KVM_RUN ioctl 之前将虚拟 cpu 的 lowcore 页错误置于其中。

4.68 KVM_SET_ONE_REG

功能:

KVM_CAP_ONE_REG

架构:

全部

类型:

vcpu ioctl

参数:

struct kvm_one_reg (in)

返回值:

成功时为 0,失败时为负值

错误

ENOENT

没有这样的寄存器

EINVAL

无效的寄存器 ID,或者没有这样的寄存器,或者在 s390 上与受保护的虚拟化模式下的 VM 一起使用

EPERM

(arm64) 在 vcpu 完成之前不允许访问寄存器

EBUSY

(riscv) 在 vcpu 至少运行一次后不允许更改寄存器值

(这些错误代码仅供参考:不要依赖于在特定情况下返回特定错误代码。)

 struct kvm_one_reg {
      __u64 id;
      __u64 addr;
};

使用此 ioctl,可以将单个 vcpu 寄存器设置为用户空间定义的特定值,其中 id 指的是下面描述的寄存器标识符,addr 是指向具有相应大小的变量的指针。可以有与架构无关的寄存器和与架构相关的寄存器。每个寄存器都有自己的操作范围、自己的常量和宽度。为了跟踪已实现的寄存器,请在下面找到一个列表

Arch

Register

Width (bits)

PPC

KVM_REG_PPC_HIOR

64

PPC

KVM_REG_PPC_IAC1

64

PPC

KVM_REG_PPC_IAC2

64

PPC

KVM_REG_PPC_IAC3

64

PPC

KVM_REG_PPC_IAC4

64

PPC

KVM_REG_PPC_DAC1

64

PPC

KVM_REG_PPC_DAC2

64

PPC

KVM_REG_PPC_DABR

64

PPC

KVM_REG_PPC_DSCR

64

PPC

KVM_REG_PPC_PURR

64

PPC

KVM_REG_PPC_SPURR

64

PPC

KVM_REG_PPC_DAR

64

PPC

KVM_REG_PPC_DSISR

32

PPC

KVM_REG_PPC_AMR

64

PPC

KVM_REG_PPC_UAMOR

64

PPC

KVM_REG_PPC_MMCR0

64

PPC

KVM_REG_PPC_MMCR1

64

PPC

KVM_REG_PPC_MMCRA

64

PPC

KVM_REG_PPC_MMCR2

64

PPC

KVM_REG_PPC_MMCRS

64

PPC

KVM_REG_PPC_MMCR3

64

PPC

KVM_REG_PPC_SIAR

64

PPC

KVM_REG_PPC_SDAR

64

PPC

KVM_REG_PPC_SIER

64

PPC

KVM_REG_PPC_SIER2

64

PPC

KVM_REG_PPC_SIER3

64

PPC

KVM_REG_PPC_PMC1

32

PPC

KVM_REG_PPC_PMC2

32

PPC

KVM_REG_PPC_PMC3

32

PPC

KVM_REG_PPC_PMC4

32

PPC

KVM_REG_PPC_PMC5

32

PPC

KVM_REG_PPC_PMC6

32

PPC

KVM_REG_PPC_PMC7

32

PPC

KVM_REG_PPC_PMC8

32

PPC

KVM_REG_PPC_FPR0

64

...

PPC

KVM_REG_PPC_FPR31

64

PPC

KVM_REG_PPC_VR0

128

...

PPC

KVM_REG_PPC_VR31

128

PPC

KVM_REG_PPC_VSR0

128

...

PPC

KVM_REG_PPC_VSR31

128

PPC

KVM_REG_PPC_FPSCR

64

PPC

KVM_REG_PPC_VSCR

32

PPC

KVM_REG_PPC_VPA_ADDR

64

PPC

KVM_REG_PPC_VPA_SLB

128

PPC

KVM_REG_PPC_VPA_DTL

128

PPC

KVM_REG_PPC_EPCR

32

PPC

KVM_REG_PPC_EPR

32

PPC

KVM_REG_PPC_TCR

32

PPC

KVM_REG_PPC_TSR

32

PPC

KVM_REG_PPC_OR_TSR

32

PPC

KVM_REG_PPC_CLEAR_TSR

32

PPC

KVM_REG_PPC_MAS0

32

PPC

KVM_REG_PPC_MAS1

32

PPC

KVM_REG_PPC_MAS2

64

PPC

KVM_REG_PPC_MAS7_3

64

PPC

KVM_REG_PPC_MAS4

32

PPC

KVM_REG_PPC_MAS6

32

PPC

KVM_REG_PPC_MMUCFG

32

PPC

KVM_REG_PPC_TLB0CFG

32

PPC

KVM_REG_PPC_TLB1CFG

32

PPC

KVM_REG_PPC_TLB2CFG

32

PPC

KVM_REG_PPC_TLB3CFG

32

PPC

KVM_REG_PPC_TLB0PS

32

PPC

KVM_REG_PPC_TLB1PS

32

PPC

KVM_REG_PPC_TLB2PS

32

PPC

KVM_REG_PPC_TLB3PS

32

PPC

KVM_REG_PPC_EPTCFG

32

PPC

KVM_REG_PPC_ICP_STATE

64

PPC

KVM_REG_PPC_VP_STATE

128

PPC

KVM_REG_PPC_TB_OFFSET

64

PPC

KVM_REG_PPC_SPMC1

32

PPC

KVM_REG_PPC_SPMC2

32

PPC

KVM_REG_PPC_IAMR

64

PPC

KVM_REG_PPC_TFHAR

64

PPC

KVM_REG_PPC_TFIAR

64

PPC

KVM_REG_PPC_TEXASR

64

PPC

KVM_REG_PPC_FSCR

64

PPC

KVM_REG_PPC_PSPB

32

PPC

KVM_REG_PPC_EBBHR

64

PPC

KVM_REG_PPC_EBBRR

64

PPC

KVM_REG_PPC_BESCR

64

PPC

KVM_REG_PPC_TAR

64

PPC

KVM_REG_PPC_DPDES

64

PPC

KVM_REG_PPC_DAWR

64

PPC

KVM_REG_PPC_DAWRX

64

PPC

KVM_REG_PPC_CIABR

64

PPC

KVM_REG_PPC_IC

64

PPC

KVM_REG_PPC_VTB

64

PPC

KVM_REG_PPC_CSIGR

64

PPC

KVM_REG_PPC_TACR

64

PPC

KVM_REG_PPC_TCSCR

64

PPC

KVM_REG_PPC_PID

64

PPC

KVM_REG_PPC_ACOP

64

PPC

KVM_REG_PPC_VRSAVE

32

PPC

KVM_REG_PPC_LPCR

32

PPC

KVM_REG_PPC_LPCR_64

64

PPC

KVM_REG_PPC_PPR

64

PPC

KVM_REG_PPC_ARCH_COMPAT

32

PPC

KVM_REG_PPC_DABRX

32

PPC

KVM_REG_PPC_WORT

64

PPC

KVM_REG_PPC_SPRG9

64

PPC

KVM_REG_PPC_DBSR

32

PPC

KVM_REG_PPC_TIDR

64

PPC

KVM_REG_PPC_PSSCR

64

PPC

KVM_REG_PPC_DEC_EXPIRY

64

PPC

KVM_REG_PPC_PTCR

64

PPC

KVM_REG_PPC_HASHKEYR

64

PPC

KVM_REG_PPC_HASHPKEYR

64

PPC

KVM_REG_PPC_DAWR1

64

PPC

KVM_REG_PPC_DAWRX1

64

PPC

KVM_REG_PPC_DEXCR

64

PPC

KVM_REG_PPC_TM_GPR0

64

...

PPC

KVM_REG_PPC_TM_GPR31

64

PPC

KVM_REG_PPC_TM_VSR0

128

...

PPC

KVM_REG_PPC_TM_VSR63

128

PPC

KVM_REG_PPC_TM_CR

64

PPC

KVM_REG_PPC_TM_LR

64

PPC

KVM_REG_PPC_TM_CTR

64

PPC

KVM_REG_PPC_TM_FPSCR

64

PPC

KVM_REG_PPC_TM_AMR

64

PPC

KVM_REG_PPC_TM_PPR

64

PPC

KVM_REG_PPC_TM_VRSAVE

64

PPC

KVM_REG_PPC_TM_VSCR

32

PPC

KVM_REG_PPC_TM_DSCR

64

PPC

KVM_REG_PPC_TM_TAR

64

PPC

KVM_REG_PPC_TM_XER

64

MIPS

KVM_REG_MIPS_R0

64

...

MIPS

KVM_REG_MIPS_R31

64

MIPS

KVM_REG_MIPS_HI

64

MIPS

KVM_REG_MIPS_LO

64

MIPS

KVM_REG_MIPS_PC

64

MIPS

KVM_REG_MIPS_CP0_INDEX

32

MIPS

KVM_REG_MIPS_CP0_ENTRYLO0

64

MIPS

KVM_REG_MIPS_CP0_ENTRYLO1

64

MIPS

KVM_REG_MIPS_CP0_CONTEXT

64

MIPS

KVM_REG_MIPS_CP0_CONTEXTCONFIG

32

MIPS

KVM_REG_MIPS_CP0_USERLOCAL

64

MIPS

KVM_REG_MIPS_CP0_XCONTEXTCONFIG

64

MIPS

KVM_REG_MIPS_CP0_PAGEMASK

32

MIPS

KVM_REG_MIPS_CP0_PAGEGRAIN

32

MIPS

KVM_REG_MIPS_CP0_SEGCTL0

64

MIPS

KVM_REG_MIPS_CP0_SEGCTL1

64

MIPS

KVM_REG_MIPS_CP0_SEGCTL2

64

MIPS

KVM_REG_MIPS_CP0_PWBASE

64

MIPS

KVM_REG_MIPS_CP0_PWFIELD

64

MIPS

KVM_REG_MIPS_CP0_PWSIZE

64

MIPS

KVM_REG_MIPS_CP0_WIRED

32

MIPS

KVM_REG_MIPS_CP0_PWCTL

32

MIPS

KVM_REG_MIPS_CP0_HWRENA

32

MIPS

KVM_REG_MIPS_CP0_BADVADDR

64

MIPS

KVM_REG_MIPS_CP0_BADINSTR

32

MIPS

KVM_REG_MIPS_CP0_BADINSTRP

32

MIPS

KVM_REG_MIPS_CP0_COUNT

32

MIPS

KVM_REG_MIPS_CP0_ENTRYHI

64

MIPS

KVM_REG_MIPS_CP0_COMPARE

32

MIPS

KVM_REG_MIPS_CP0_STATUS

32

MIPS

KVM_REG_MIPS_CP0_INTCTL

32

MIPS

KVM_REG_MIPS_CP0_CAUSE

32

MIPS

KVM_REG_MIPS_CP0_EPC

64

MIPS

KVM_REG_MIPS_CP0_PRID

32

MIPS

KVM_REG_MIPS_CP0_EBASE

64

MIPS

KVM_REG_MIPS_CP0_CONFIG

32

MIPS

KVM_REG_MIPS_CP0_CONFIG1

32

MIPS

KVM_REG_MIPS_CP0_CONFIG2

32

MIPS

KVM_REG_MIPS_CP0_CONFIG3

32

MIPS

KVM_REG_MIPS_CP0_CONFIG4

32

MIPS

KVM_REG_MIPS_CP0_CONFIG5

32

MIPS

KVM_REG_MIPS_CP0_CONFIG7

32

MIPS

KVM_REG_MIPS_CP0_XCONTEXT

64

MIPS

KVM_REG_MIPS_CP0_ERROREPC

64

MIPS

KVM_REG_MIPS_CP0_KSCRATCH1

64

MIPS

KVM_REG_MIPS_CP0_KSCRATCH2

64

MIPS

KVM_REG_MIPS_CP0_KSCRATCH3

64

MIPS

KVM_REG_MIPS_CP0_KSCRATCH4

64

MIPS

KVM_REG_MIPS_CP0_KSCRATCH5

64

MIPS

KVM_REG_MIPS_CP0_KSCRATCH6

64

MIPS

KVM_REG_MIPS_CP0_MAAR(0..63)

64

MIPS

KVM_REG_MIPS_COUNT_CTL

64

MIPS

KVM_REG_MIPS_COUNT_RESUME

64

MIPS

KVM_REG_MIPS_COUNT_HZ

64

MIPS

KVM_REG_MIPS_FPR_32(0..31)

32

MIPS

KVM_REG_MIPS_FPR_64(0..31)

64

MIPS

KVM_REG_MIPS_VEC_128(0..31)

128

MIPS

KVM_REG_MIPS_FCR_IR

32

MIPS

KVM_REG_MIPS_FCR_CSR

32

MIPS

KVM_REG_MIPS_MSA_IR

32

MIPS

KVM_REG_MIPS_MSA_CSR

32

ARM registers are mapped using the lower 32 bits. The upper 16 of that is the register group type, or coprocessor number

ARM core registers have the following id bit patterns

0x4020 0000 0010 <index into the kvm_regs struct:16>

ARM 32-bit CP15 registers have the following id bit patterns

0x4020 0000 000F <zero:1> <crn:4> <crm:4> <opc1:4> <opc2:3>

ARM 64-bit CP15 registers have the following id bit patterns

0x4030 0000 000F <zero:1> <zero:4> <crm:4> <opc1:4> <zero:3>

ARM CCSIDR registers are demultiplexed by CSSELR value

0x4020 0000 0011 00 <csselr:8>

ARM 32-bit VFP control registers have the following id bit patterns

0x4020 0000 0012 1 <regno:12>

ARM 64-bit FP registers have the following id bit patterns

0x4030 0000 0012 0 <regno:12>

ARM firmware pseudo-registers have the following bit pattern

0x4030 0000 0014 <regno:16>

arm64 registers are mapped using the lower 32 bits. The upper 16 of that is the register group type, or coprocessor number

arm64 core/FP-SIMD registers have the following id bit patterns. Note that the size of the access is variable, as the kvm_regs structure contains elements ranging from 32 to 128 bits. The index is a 32bit value in the kvm_regs structure seen as a 32bit array

0x60x0 0000 0010 <index into the kvm_regs struct:16>

Specifically

Encoding

Register

Bits

kvm_regs member

0x6030 0000 0010 0000

X0

64

regs.regs[0]

0x6030 0000 0010 0002

X1

64

regs.regs[1]

...

0x6030 0000 0010 003c

X30

64

regs.regs[30]

0x6030 0000 0010 003e

SP

64

regs.sp

0x6030 0000 0010 0040

PC

64

regs.pc

0x6030 0000 0010 0042

PSTATE

64

regs.pstate

0x6030 0000 0010 0044

SP_EL1

64

sp_el1

0x6030 0000 0010 0046

ELR_EL1

64

elr_el1

0x6030 0000 0010 0048

SPSR_EL1

64

spsr[KVM_SPSR_EL1] (alias SPSR_SVC)

0x6030 0000 0010 004a

SPSR_ABT

64

spsr[KVM_SPSR_ABT]

0x6030 0000 0010 004c

SPSR_UND

64

spsr[KVM_SPSR_UND]

0x6030 0000 0010 004e

SPSR_IRQ

64

spsr[KVM_SPSR_IRQ]

0x6030 0000 0010 0050

SPSR_FIQ

64

spsr[KVM_SPSR_FIQ]

0x6040 0000 0010 0054

V0

128

fp_regs.vregs[0] [1]

0x6040 0000 0010 0058

V1

128

fp_regs.vregs[1] [1]

...

0x6040 0000 0010 00d0

V31

128

fp_regs.vregs[31] [1]

0x6020 0000 0010 00d4

FPSR

32

fp_regs.fpsr

0x6020 0000 0010 00d5

FPCR

32

fp_regs.fpcr

arm64 CCSIDR registers are demultiplexed by CSSELR value

0x6020 0000 0011 00 <csselr:8>

arm64 system registers have the following id bit patterns

0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3>

警告

Two system register IDs do not follow the specified pattern. These are KVM_REG_ARM_TIMER_CVAL and KVM_REG_ARM_TIMER_CNT, which map to system registers CNTV_CVAL_EL0 and CNTVCT_EL0 respectively. These two had their values accidentally swapped, which means TIMER_CVAL is derived from the register encoding for CNTVCT_EL0 and TIMER_CNT is derived from the register encoding for CNTV_CVAL_EL0. As this is API, it must remain this way.

arm64 firmware pseudo-registers have the following bit pattern

0x6030 0000 0014 <regno:16>

arm64 SVE registers have the following bit patterns

0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register

Access to register IDs where 2048 * slice >= 128 * max_vq will fail with ENOENT. max_vq is the vcpu’s maximum supported vector length in 128-bit quadwords: see [2] below.

These registers are only accessible on vcpus for which SVE is enabled. See KVM_ARM_VCPU_INIT for details.

In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not accessible until the vcpu’s SVE configuration has been finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE). See KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE for more information about this procedure.

KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector lengths supported by the vcpu to be discovered and configured by userspace. When transferred to or from user memory via KVM_GET_ONE_REG or KVM_SET_ONE_REG, the value of this register is of type __u64[KVM_ARM64_SVE_VLS_WORDS], and encodes the set of vector lengths as follows

__u64 vector_lengths[KVM_ARM64_SVE_VLS_WORDS];

if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
    ((vector_lengths[(vq - KVM_ARM64_SVE_VQ_MIN) / 64] >>
              ((vq - KVM_ARM64_SVE_VQ_MIN) % 64)) & 1))
      /* Vector length vq * 16 bytes supported */
else
      /* Vector length vq * 16 bytes not supported */

(See Scalable Vector Extension support for AArch64 Linux for an explanation of the “vq” nomenclature.)

KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT. KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that the host supports.

Userspace may subsequently modify it if desired until the vcpu’s SVE configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).

Apart from simply removing all vector lengths from the host set that exceed some value, support for arbitrarily chosen sets of vector lengths is hardware-dependent and may not be available. Attempting to configure an invalid set of vector lengths via KVM_SET_ONE_REG will fail with EINVAL.

After the vcpu’s SVE configuration is finalized, further attempts to write this register will fail with EPERM.

arm64 bitmap feature firmware pseudo-registers have the following bit pattern

0x6030 0000 0016 <regno:16>

The bitmap feature firmware registers exposes the hypercall services that are available for userspace to configure. The set bits corresponds to the services that are available for the guests to access. By default, KVM sets all the supported bits during VM initialization. The userspace can discover the available services via KVM_GET_ONE_REG, and write back the bitmap corresponding to the features that it wishes guests to see via KVM_SET_ONE_REG.

Note: These registers are immutable once any of the vCPUs of the VM has run at least once. A KVM_SET_ONE_REG in such a scenario will return a -EBUSY to userspace.

(See KVM/arm64-specific hypercalls exposed to guests for more details.)

MIPS registers are mapped using the lower 32 bits. The upper 16 of that is the register group type

MIPS core registers (see above) have the following id bit patterns

0x7030 0000 0000 <reg:16>

MIPS CP0 registers (see KVM_REG_MIPS_CP0_* above) have the following id bit patterns depending on whether they’re 32-bit or 64-bit registers

0x7020 0000 0001 00 <reg:5> <sel:3>   (32-bit)
0x7030 0000 0001 00 <reg:5> <sel:3>   (64-bit)

Note: KVM_REG_MIPS_CP0_ENTRYLO0 and KVM_REG_MIPS_CP0_ENTRYLO1 are the MIPS64 versions of the EntryLo registers regardless of the word size of the host hardware, host kernel, guest, and whether XPA is present in the guest, i.e. with the RI and XI bits (if they exist) in bits 63 and 62 respectively, and the PFNX field starting at bit 30.

MIPS MAARs (see KVM_REG_MIPS_CP0_MAAR(*) above) have the following id bit patterns

0x7030 0000 0001 01 <reg:8>

MIPS KVM control registers (see above) have the following id bit patterns

0x7030 0000 0002 <reg:16>

MIPS FPU registers (see KVM_REG_MIPS_FPR_{32,64}() above) have the following id bit patterns depending on the size of the register being accessed. They are always accessed according to the current guest FPU mode (Status.FR and Config5.FRE), i.e. as the guest would see them, and they become unpredictable if the guest FPU mode is changed. MIPS SIMD Architecture (MSA) vector registers (see KVM_REG_MIPS_VEC_128() above) have similar patterns as they overlap the FPU registers

0x7020 0000 0003 00 <0:3> <reg:5> (32-bit FPU registers)
0x7030 0000 0003 00 <0:3> <reg:5> (64-bit FPU registers)
0x7040 0000 0003 00 <0:3> <reg:5> (128-bit MSA vector registers)

MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the following id bit patterns

0x7020 0000 0003 01 <0:3> <reg:5>

MIPS MSA control registers (see KVM_REG_MIPS_MSA_{IR,CSR} above) have the following id bit patterns

0x7020 0000 0003 02 <0:3> <reg:5>

RISC-V registers are mapped using the lower 32 bits. The upper 8 bits of that is the register group type.

RISC-V config registers are meant for configuring a Guest VCPU and it has the following id bit patterns

0x8020 0000 01 <index into the kvm_riscv_config struct:24> (32bit Host)
0x8030 0000 01 <index into the kvm_riscv_config struct:24> (64bit Host)

Following are the RISC-V config registers

Encoding

Register

Description

0x80x0 0000 0100 0000

isa

ISA feature bitmap of Guest VCPU

The isa config register can be read anytime but can only be written before a Guest VCPU runs. It will have ISA feature bits matching underlying host set by default.

RISC-V core registers represent the general execution state of a Guest VCPU and it has the following id bit patterns

0x8020 0000 02 <index into the kvm_riscv_core struct:24> (32bit Host)
0x8030 0000 02 <index into the kvm_riscv_core struct:24> (64bit Host)

Following are the RISC-V core registers

Encoding

Register

Description

0x80x0 0000 0200 0000

regs.pc

Program counter

0x80x0 0000 0200 0001

regs.ra

Return address

0x80x0 0000 0200 0002

regs.sp

Stack pointer

0x80x0 0000 0200 0003

regs.gp

Global pointer

0x80x0 0000 0200 0004

regs.tp

Task pointer

0x80x0 0000 0200 0005

regs.t0

Caller saved register 0

0x80x0 0000 0200 0006

regs.t1

Caller saved register 1

0x80x0 0000 0200 0007

regs.t2

Caller saved register 2

0x80x0 0000 0200 0008

regs.s0

Callee saved register 0

0x80x0 0000 0200 0009

regs.s1

Callee saved register 1

0x80x0 0000 0200 000a

regs.a0

Function argument (or return value) 0

0x80x0 0000 0200 000b

regs.a1

Function argument (or return value) 1

0x80x0 0000 0200 000c

regs.a2

Function argument 2

0x80x0 0000 0200 000d

regs.a3

Function argument 3

0x80x0 0000 0200 000e

regs.a4

Function argument 4

0x80x0 0000 0200 000f

regs.a5

Function argument 5

0x80x0 0000 0200 0010

regs.a6

Function argument 6

0x80x0 0000 0200 0011

regs.a7

Function argument 7

0x80x0 0000 0200 0012

regs.s2

Callee saved register 2

0x80x0 0000 0200 0013

regs.s3

Callee saved register 3

0x80x0 0000 0200 0014

regs.s4

Callee saved register 4

0x80x0 0000 0200 0015

regs.s5

Callee saved register 5

0x80x0 0000 0200 0016

regs.s6

Callee saved register 6

0x80x0 0000 0200 0017

regs.s7

Callee saved register 7

0x80x0 0000 0200 0018

regs.s8

Callee saved register 8

0x80x0 0000 0200 0019

regs.s9

Callee saved register 9

0x80x0 0000 0200 001a

regs.s10

Callee saved register 10

0x80x0 0000 0200 001b

regs.s11

Callee saved register 11

0x80x0 0000 0200 001c

regs.t3

Caller saved register 3

0x80x0 0000 0200 001d

regs.t4

Caller saved register 4

0x80x0 0000 0200 001e

regs.t5

Caller saved register 5

0x80x0 0000 0200 001f

regs.t6

调用者保存了寄存器 6

0x80x0 0000 0200 0020

mode

权限模式 (1 = S 模式或 0 = U 模式)

RISC-V csr 寄存器代表 Guest VCPU 的监管者模式控制/状态寄存器,它具有以下 ID 位模式

0x8020 0000 03 <index into the kvm_riscv_csr struct:24> (32bit Host)
0x8030 0000 03 <index into the kvm_riscv_csr struct:24> (64bit Host)

以下是 RISC-V csr 寄存器

Encoding

Register

Description

0x80x0 0000 0300 0000

sstatus

监管者状态

0x80x0 0000 0300 0001

sie

监管者中断使能

0x80x0 0000 0300 0002

stvec

监管者陷阱向量基址

0x80x0 0000 0300 0003

sscratch

监管者暂存寄存器

0x80x0 0000 0300 0004

sepc

监管者异常程序计数器

0x80x0 0000 0300 0005

scause

监管者陷阱原因

0x80x0 0000 0300 0006

stval

监管者错误地址或指令

0x80x0 0000 0300 0007

sip

监管者中断挂起

0x80x0 0000 0300 0008

satp

监管者地址转换和保护

RISC-V 定时器寄存器代表 Guest VCPU 的定时器状态,它具有以下 ID 位模式

0x8030 0000 04 <index into the kvm_riscv_timer struct:24>

以下是 RISC-V 定时器寄存器

Encoding

Register

Description

0x8030 0000 0400 0000

frequency

时基频率(只读)

0x8030 0000 0400 0001

time

Guest 可见的时间值

0x8030 0000 0400 0002

compare

Guest 编程的时间比较值

0x8030 0000 0400 0003

state

时间比较状态 (1 = ON 或 0 = OFF)

RISC-V F 扩展寄存器代表 Guest VCPU 的单精度浮点状态,它具有以下 ID 位模式

0x8020 0000 05 <index into the __riscv_f_ext_state struct:24>

以下是 RISC-V F 扩展寄存器

Encoding

Register

Description

0x8020 0000 0500 0000

f[0]

浮点寄存器 0

...

0x8020 0000 0500 001f

f[31]

浮点寄存器 31

0x8020 0000 0500 0020

fcsr

浮点控制和状态寄存器

RISC-V D 扩展寄存器代表 Guest VCPU 的双精度浮点状态,它具有以下 ID 位模式

0x8020 0000 06 <index into the __riscv_d_ext_state struct:24> (fcsr)
0x8030 0000 06 <index into the __riscv_d_ext_state struct:24> (non-fcsr)

以下是 RISC-V D 扩展寄存器

Encoding

Register

Description

0x8030 0000 0600 0000

f[0]

浮点寄存器 0

...

0x8030 0000 0600 001f

f[31]

浮点寄存器 31

0x8020 0000 0600 0020

fcsr

浮点控制和状态寄存器

LoongArch 寄存器使用低 32 位进行映射。 其中的高 16 位是寄存器组类型。

LoongArch csr 寄存器用于控制 guest cpu 或获取 guest cpu 的状态,它们具有以下 ID 位模式

0x9030 0000 0001 00 <reg:5> <sel:3>   (64-bit)

LoongArch KVM 控制寄存器用于实现一些新定义的功能,例如设置 vcpu 计数器或重置 vcpu,它们具有以下 ID 位模式

0x9030 0000 0002 <reg:16>

4.69 KVM_GET_ONE_REG

功能:

KVM_CAP_ONE_REG

架构:

全部

类型:

vcpu ioctl

参数:

struct kvm_one_reg (输入和输出)

返回值:

成功时为 0,失败时为负值

错误包括

ENOENT

没有这样的寄存器

EINVAL

无效的寄存器 ID,或者没有这样的寄存器,或者在 s390 上与受保护的虚拟化模式下的 VM 一起使用

EPERM

(arm64) 在 vcpu 完成之前不允许访问寄存器

(这些错误代码仅供参考:不要依赖于在特定情况下返回特定错误代码。)

此 ioctl 允许接收 vcpu 中实现的单个寄存器的值。 要读取的寄存器由传入的 kvm_one_reg 结构的“id”字段指示。 成功后,可以在“addr”指向的内存位置找到寄存器值。

使用此接口可访问的寄存器列表与 4.68 中的列表相同。

4.70 KVM_KVMCLOCK_CTRL

功能:

KVM_CAP_KVMCLOCK_CTRL

架构:

任何实现 pvclocks 的 (目前仅限 x86)

类型:

vcpu ioctl

参数:

返回值:

成功时为 0,出错时为 -1

此 ioctl 设置一个 guest 可访问的标志,指示指定的 vCPU 已被主机用户空间暂停。

主机将在 pvclock 结构中设置一个标志,该标志从软锁死看门狗检查。该标志是 guest 和主机之间共享的 pvclock 结构的一部分,特别是 pvclock_vcpu_time_info 结构的 flags 字段的第二位。它将仅由主机设置,并仅由 guest 读取/清除。guest 检查和清除标志的操作必须是原子操作,因此必须使用 load-link/store-conditional 或等效项。guest 清除该标志有两种情况:当软锁死看门狗定时器重置自身或检测到软锁死时。可以在暂停 vcpu 之后的任何时间调用此 ioctl,但在恢复 vcpu 之前。

4.71 KVM_SIGNAL_MSI

功能:

KVM_CAP_SIGNAL_MSI

架构:

x86 arm64

类型:

vm ioctl

参数:

struct kvm_msi (输入)

返回值:

>0 表示传递成功,0 表示 guest 阻止了 MSI,-1 表示错误

直接注入 MSI 消息。 仅在使用处理 MSI 消息的内核 irqchip 时有效。

struct kvm_msi {
      __u32 address_lo;
      __u32 address_hi;
      __u32 data;
      __u32 flags;
      __u32 devid;
      __u8  pad[12];
};
flags

KVM_MSI_VALID_DEVID:devid 包含有效值。 每个 VM 的 KVM_CAP_MSI_DEVID 功能会声明提供设备 ID 的要求。 如果此功能不可用,则用户空间永远不应设置 KVM_MSI_VALID_DEVID 标志,因为 ioctl 可能会失败。

如果设置了 KVM_MSI_VALID_DEVID,则 devid 包含写入 MSI 消息的设备的唯一设备标识符。对于 PCI,这通常是低 16 位中的 BDF 标识符。

在 x86 上,除非启用了 KVM_CAP_X2APIC_API 功能的 KVM_X2APIC_API_USE_32BIT_IDS 功能,否则 address_hi 将被忽略。如果启用了该功能,则 address_hi 的位 31-8 提供目标 id 的位 31-8。address_hi 的位 7-0 必须为零。

4.71 KVM_CREATE_PIT2

功能:

KVM_CAP_PIT2

架构:

x86

类型:

vm ioctl

参数:

struct kvm_pit_config (输入)

返回值:

成功时为 0,出错时为 -1

为 i8254 PIT 创建一个内核设备模型。 仅在通过 KVM_CREATE_IRQCHIP 启用内核 irqchip 支持后,此调用才有效。 必须传递以下参数

struct kvm_pit_config {
      __u32 flags;
      __u32 pad[15];
};

有效的标志包括

#define KVM_PIT_SPEAKER_DUMMY     1 /* emulate speaker port stub */

PIT 定时器中断可能会使用每个 VM 的内核线程进行注入。 如果存在,此线程将具有以下模式的名称

kvm-pit/<owner-process-pid>

在运行具有较高优先级的 guest 时,可能需要相应地调整此线程的调度参数。

此 IOCTL 替换了已过时的 KVM_CREATE_PIT。

4.72 KVM_GET_PIT2

功能:

KVM_CAP_PIT_STATE2

架构:

x86

类型:

vm ioctl

参数:

struct kvm_pit_state2 (输出)

返回值:

成功时为 0,出错时为 -1

检索内核 PIT 模型的状态。 仅在 KVM_CREATE_PIT2 之后有效。 该状态在以下结构中返回

struct kvm_pit_state2 {
      struct kvm_pit_channel_state channels[3];
      __u32 flags;
      __u32 reserved[9];
};

有效的标志包括

/* disable PIT in HPET legacy mode */
#define KVM_PIT_FLAGS_HPET_LEGACY     0x00000001
/* speaker port data bit enabled */
#define KVM_PIT_FLAGS_SPEAKER_DATA_ON 0x00000002

此 IOCTL 替换了已过时的 KVM_GET_PIT。

4.73 KVM_SET_PIT2

功能:

KVM_CAP_PIT_STATE2

架构:

x86

类型:

vm ioctl

参数:

struct kvm_pit_state2 (输入)

返回值:

成功时为 0,出错时为 -1

设置内核 PIT 模型的状态。 仅在 KVM_CREATE_PIT2 之后有效。 有关 struct kvm_pit_state2 的详细信息,请参阅 KVM_GET_PIT2。

此 IOCTL 替换了已过时的 KVM_SET_PIT。

4.74 KVM_PPC_GET_SMMU_INFO

功能:

KVM_CAP_PPC_GET_SMMU_INFO

架构:

powerpc

类型:

vm ioctl

参数:

返回值:

成功时为 0,出错时为 -1

此操作会填充并返回一个结构,描述 KVM 支持的“服务器”类 MMU 仿真的功能。 用户空间可以反过来使用此结构来为 guest 操作系统生成适当的设备树属性。

该结构包含一些全局信息,后跟一个支持的段页面大小数组

struct kvm_ppc_smmu_info {
       __u64 flags;
       __u32 slb_size;
       __u32 pad;
       struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
};

支持的标志包括

  • KVM_PPC_PAGE_SIZES_REAL

    设置该标志后,guest 页面大小必须“适合”后备存储页面大小。 如果未设置,则可以使用列表中的任何页面大小,而不管它们如何由用户空间支持。

  • KVM_PPC_1T_SEGMENTS

    除了标准的 256M 段之外,模拟的 MMU 还支持 1T 段。

  • KVM_PPC_NO_HASH

    此标志指示 KVM 不支持 HPT guest,因此所有 guest 必须使用 radix MMU 模式。

“slb_size”字段指示支持多少个 SLB 条目

“sps”数组包含 8 个条目,指示段支持的基本页面大小(按递增顺序)。 每个条目定义如下

struct kvm_ppc_one_seg_page_size {
     __u32 page_shift;       /* Base page shift of segment (or 0) */
     __u32 slb_enc;          /* SLB encoding for BookS */
     struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
};

“page_shift”为 0 的条目未使用。 由于该数组按递增顺序组织,因此在遇到此类条目时可以停止查找。

“slb_enc”字段提供用于 SLB 中页面大小的编码。 这些位位于这样的位置,以便该值可以直接 OR 到 slbmte 指令的“vsid”参数中。

“enc”数组是一个列表,对于每个段基本页面大小,它都提供支持的实际页面大小列表(这些大小只能大于或等于基本页面大小),以及哈希 PTE 中相应的编码。 同样,该数组是 8 个条目,按大小递增排序,“0”移位的条目是空条目和终止符

struct kvm_ppc_one_page_size {
     __u32 page_shift;       /* Page shift (or 0) */
     __u32 pte_enc;          /* Encoding in the HPTE (>>12) */
};

“pte_enc”字段提供一个可以 OR 到哈希 PTE 的 RPN 字段中的值(即,需要将其左移 12 位才能将其 OR 到哈希 PTE 的第二个双字中)。

4.75 KVM_IRQFD

功能:

KVM_CAP_IRQFD

架构:

x86 s390 arm64

类型:

vm ioctl

参数:

struct kvm_irqfd (输入)

返回值:

成功时为 0,出错时为 -1

允许设置 eventfd 以直接触发 guest 中断。 kvm_irqfd.fd 指定用作 eventfd 的文件描述符,kvm_irqfd.gsi 指定由此事件切换的 irqchip 引脚。 当在 eventfd 上触发事件时,会使用指定的 gsi 引脚将中断注入到 guest 中。 使用 KVM_IRQFD_FLAG_DEASSIGN 标志移除 irqfd,同时指定 kvm_irqfd.fd 和 kvm_irqfd.gsi。

使用 KVM_CAP_IRQFD_RESAMPLE,KVM_IRQFD 支持取消断言和通知机制,从而允许模拟基于 irqfd 的电平触发中断。 设置 KVM_IRQFD_FLAG_RESAMPLE 后,用户必须在 kvm_irqfd.resamplefd 字段中传递一个额外的 eventfd。 在重采样模式下运行,通过 kvm_irq.fd 发布中断会在 irqchip 中断言指定的 gsi。 当重采样 irqchip 时(例如从 EOI),将取消断言 gsi,并通过 kvm_irqfd.resamplefd 通知用户。 用户有责任在使用它的设备仍然需要服务时重新排队中断。 请注意,关闭 resamplefd 不足以禁用 irqfd。 KVM_IRQFD_FLAG_RESAMPLE 仅在分配时是必需的,不需要使用 KVM_IRQFD_FLAG_DEASSIGN 指定。

在 arm64 上,在支持 gsi 路由的情况下,可能会发生以下情况

  • 如果没有任何路由条目与此 gsi 关联,则注入失败

  • 如果 gsi 与 irqchip 路由条目关联,则 irqchip.pin + 32 对应于注入的 SPI ID。

  • 如果 gsi 与 MSI 路由条目关联,则 MSI 消息和设备 ID 将转换为 LPI(支持仅限于内核仿真的 GICv3 ITS)。

4.76 KVM_PPC_ALLOCATE_HTAB

功能:

KVM_CAP_PPC_ALLOC_HTAB

架构:

powerpc

类型:

vm ioctl

参数:

指向包含哈希表顺序的 u32 的指针(输入/输出)

返回值:

成功时为 0,出错时为 -1

这会请求主机内核使用 PAPR 半虚拟化接口为 guest 分配 MMU 哈希表。 仅当内核配置为使用 Book 3S HV 样式的虚拟化时,此操作才会执行任何操作。 否则,该功能不存在,ioctl 返回 ENOTTY 错误。 此说明的其余部分假定为 Book 3S HV。

调用此 ioctl 时不得有任何 vcpu 正在运行; 如果有,它将不执行任何操作并返回 EBUSY 错误。

该参数是指向 32 位无符号整数变量的指针,该变量包含哈希表所需大小的顺序(以 2 为底的对数),该顺序必须介于 18 和 46 之间。从 ioctl 成功返回时,内核不会更改该值。

如果在请求任何 vcpu 运行时(使用 KVM_RUN ioctl)尚未分配任何哈希表,则主机内核将分配一个默认大小的哈希表 (16 MB)。

如果在已分配哈希表的情况下调用此 ioctl,且其顺序与现有哈希表的顺序不同,则会释放现有哈希表并分配一个新的哈希表。 如果在已分配的哈希表与指定的顺序相同的情况下调用此 ioctl,则内核将清除现有哈希表(将所有 HPTE 置零)。 在任一情况下,如果 guest 正在使用虚拟化实模式区域 (VRMA) 功能,则内核将在任何 vcpu 的下一个 KVM_RUN 上重新创建 VMRA HPTE。

4.77 KVM_S390_INTERRUPT

功能:

基本

架构:

s390

类型:

vm ioctl、vcpu ioctl

参数:

struct kvm_s390_interrupt (输入)

返回值:

成功时为 0,出错时为 -1

允许将中断注入到 guest 中。 中断可以是浮动的(vm ioctl)或每个 cpu 的(vcpu ioctl),具体取决于中断类型。

中断参数通过 kvm_s390_interrupt 传递

struct kvm_s390_interrupt {
      __u32 type;
      __u32 parm;
      __u64 parm64;
};

type 可以是以下之一

KVM_S390_SIGP_STOP (vcpu)
  • sigp 停止; parm 中的可选标志

KVM_S390_PROGRAM_INT (vcpu)
  • 程序检查; parm 中的代码

KVM_S390_SIGP_SET_PREFIX (vcpu)
  • sigp 设置前缀; parm 中的前缀地址

KVM_S390_RESTART (vcpu)
  • 重新启动

KVM_S390_INT_CLOCK_COMP (vcpu)
  • 时钟比较器中断

KVM_S390_INT_CPU_TIMER (vcpu)
  • CPU 定时器中断

KVM_S390_INT_VIRTIO (vm)
  • virtio 外部中断; parm 和 parm64 中的外部中断参数

KVM_S390_INT_SERVICE (vm)
  • sclp 外部中断; parm 中的 sclp 参数

KVM_S390_INT_EMERGENCY (vcpu)
  • sigp 紧急情况; parm 中的源 cpu

KVM_S390_INT_EXTERNAL_CALL (vcpu)
  • sigp 外部调用; parm 中的源 cpu

KVM_S390_INT_IO(ai,cssid,ssid,schid) (vm)
  • 用于指示 I/O 中断的复合值(ai - 适配器中断; cssid,ssid,schid - 子通道); parm(子通道)和 parm64(intparm,中断子类)中的 I/O 中断参数

KVM_S390_MCHK (vm, vcpu)
  • 机器检查中断; parm 中的 cr 14 位,parm64 中的机器检查中断代码(请注意,此 ioctl 不支持需要其他有效负载的机器检查)

这是一个异步 vcpu ioctl,可以从任何线程调用。

4.78 KVM_PPC_GET_HTAB_FD

功能:

KVM_CAP_PPC_HTAB_FD

架构:

powerpc

类型:

vm ioctl

参数:

指向 struct kvm_get_htab_fd 的指针(输入)

返回值:

成功时返回文件描述符号 (>= 0),错误时返回 -1

这将返回一个文件描述符,该文件描述符可用于读取 guest 的哈希页面表 (HPT) 中的条目,或写入条目以初始化 HPT。 仅当参数的标志字段中设置了 KVM_GET_HTAB_WRITE 位时,才能写入返回的 fd,并且仅当该位为清除状态时,才能读取该 fd。 参数结构如下所示

/* For KVM_PPC_GET_HTAB_FD */
struct kvm_get_htab_fd {
      __u64   flags;
      __u64   start_index;
      __u64   reserved[2];
};

/* Values for kvm_get_htab_fd.flags */
#define KVM_GET_HTAB_BOLTED_ONLY      ((__u64)0x1)
#define KVM_GET_HTAB_WRITE            ((__u64)0x2)

“start_index”字段给出了 HPT 中要开始读取的条目的索引。 写入时会忽略该字段。

fd 上的读取最初将提供有关所有“有趣的”HPT 条目的信息。 如果设置了 KVM_GET_HTAB_BOLTED_ONLY 位,则有趣的条目是设置了固定位的条目,否则为所有条目。 到达 HPT 结尾时,read() 将返回。 如果再次在 fd 上调用 read(),它将从 HPT 的开头再次开始,但只会返回自上次读取以来已更改的 HPT 条目。

读取或写入的数据结构是一个标头(8 个字节),后跟一系列有效的 HPT 条目(每个条目 16 个字节)。 标头指示有多少个有效的 HPT 条目,以及有多少个无效条目位于有效条目之后。 无效条目未在流中显式表示。 标头格式为

struct kvm_get_htab_header {
      __u32   index;
      __u16   n_valid;
      __u16   n_invalid;
};

写入 fd 会创建从标头中给出的索引开始的 HPT 条目; 首先,带有写入数据内容的“n_valid”有效条目,然后是“n_invalid”无效条目,使先前找到的任何有效条目无效。

4.79 KVM_CREATE_DEVICE

功能:

KVM_CAP_DEVICE_CTRL

架构:

全部

类型:

vm ioctl

参数:

struct kvm_create_device (输入/输出)

返回值:

成功时为 0,出错时为 -1

错误

ENODEV

设备类型未知或不受支持

EEXIST

设备已创建,并且无法多次实例化此类型的设备

其他错误条件可能由各个设备类型定义或具有其标准含义。

在内核中创建一个模拟设备。 fd 中返回的文件描述符可以与 KVM_SET/GET/HAS_DEVICE_ATTR 一起使用。

如果设置了 KVM_CREATE_DEVICE_TEST 标志,则仅测试设备类型是否受支持(不一定是在当前 vm 中是否可以创建)。

各个设备不应定义标志。 属性应该用于指定任何未由设备类型编号暗示的行为。

struct kvm_create_device {
      __u32   type;   /* in: KVM_DEV_TYPE_xxx */
      __u32   fd;     /* out: device handle */
      __u32   flags;  /* in: KVM_CREATE_DEVICE_xxx */
};

4.80 KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR

功能:

KVM_CAP_DEVICE_CTRL、KVM_CAP_VM_ATTRIBUTES(用于 vm 设备)、KVM_CAP_VCPU_ATTRIBUTES(用于 vcpu 设备)、KVM_CAP_SYS_ATTRIBUTES(用于系统 (/dev/kvm) 设备)(无设置)

架构:

x86, arm64, s390

类型:

device ioctl、vm ioctl、vcpu ioctl

参数:

struct kvm_device_attr

返回值:

成功时为 0,出错时为 -1

错误

ENXIO

此设备组或属性未知/不受支持,或者缺少硬件支持。

EPERM

当前无法以这种方式访问该属性(例如,只读属性,或仅当设备处于不同状态时才有意义的属性)

其他错误条件可能由各个设备类型定义。

获取/设置指定的设备配置和/或状态。 语义特定于设备。 请参阅“设备”目录中的各个设备文档。 与 ONE_REG 一样,传输的数据大小由特定属性定义。

struct kvm_device_attr {
      __u32   flags;          /* no flags currently defined */
      __u32   group;          /* device-defined */
      __u64   attr;           /* group-defined */
      __u64   addr;           /* userspace address of attr data */
};

4.81 KVM_HAS_DEVICE_ATTR

功能:

KVM_CAP_DEVICE_CTRL、KVM_CAP_VM_ATTRIBUTES(用于 vm 设备)、KVM_CAP_VCPU_ATTRIBUTES(用于 vcpu 设备)、KVM_CAP_SYS_ATTRIBUTES(用于系统 (/dev/kvm) 设备)

类型:

device ioctl、vm ioctl、vcpu ioctl

参数:

struct kvm_device_attr

返回值:

成功时为 0,出错时为 -1

错误

ENXIO

此设备组或属性未知/不受支持,或者缺少硬件支持。

测试设备是否支持特定属性。 成功返回表示已实现该属性。 它不一定表示可以在设备的当前状态下读取或写入该属性。 “addr”将被忽略。

4.82 KVM_ARM_VCPU_INIT

功能:

基本

架构:

arm64

类型:

vcpu ioctl

参数:

struct kvm_vcpu_init (输入)

返回值:

成功时为 0;出错时为 -1

错误

EINVAL

目标未知,或者功能组合无效。

ENOENT

指定的功能位未知。

这会告知 KVM 要向 guest 呈现的 CPU 类型,以及它应具有哪些可选功能。 这将导致 CPU 寄存器重置为其初始值。 如果未调用此方法,KVM_RUN 将为该 vcpu 返回 ENOEXEC。

初始值定义为
  • 处理器状态
    • AArch64:设置了 EL1h、D、A、I 和 F 位。 所有其他位均已清除。

    • AArch32:设置了 SVC、A、I 和 F 位。 所有其他位均已清除。

  • 通用寄存器,包括 PC 和 SP:设置为 0

  • FPSIMD/NEON 寄存器:设置为 0

  • SVE 寄存器:设置为 0

  • 系统寄存器:重置为其架构定义的 EL1(resp. SVC)或 EL2(在启用 EL2 的情况下)的暖重置值。

请注意,由于某些寄存器反映了机器拓扑,因此应在调用此 ioctl 之前创建所有 vcpu。

对于给定的 vcpu,用户空间可以多次调用此函数,包括在 vcpu 运行之后。 这会将 vcpu 重置为其初始状态。 初始调用之后的对此函数的所有调用都必须使用相同的目标和相同的功能标志集,否则将返回 EINVAL。

可能的功能

  • KVM_ARM_VCPU_POWER_OFF:以断电状态启动 CPU。 依赖于 KVM_CAP_ARM_PSCI。 如果未设置,则 CPU 将在调用 KVM_RUN 时通电并执行 guest 代码。

  • KVM_ARM_VCPU_EL1_32BIT:以 32 位模式启动 CPU。 依赖于 KVM_CAP_ARM_EL1_32BIT(仅限 arm64)。

  • KVM_ARM_VCPU_PSCI_0_2:为 CPU 模拟 PSCI v0.2(或与 v0.2 向后兼容的未来版本)。 依赖于 KVM_CAP_ARM_PSCI_0_2。

  • KVM_ARM_VCPU_PMU_V3:为 CPU 模拟 PMUv3。 依赖于 KVM_CAP_ARM_PMU_V3。

  • KVM_ARM_VCPU_PTRAUTH_ADDRESS:仅为 arm64 启用地址指针身份验证。 依赖于 KVM_CAP_ARM_PTRAUTH_ADDRESS。 如果同时存在 KVM_CAP_ARM_PTRAUTH_ADDRESS 和 KVM_CAP_ARM_PTRAUTH_GENERIC,则必须请求 KVM_ARM_VCPU_PTRAUTH_ADDRESS 和 KVM_ARM_VCPU_PTRAUTH_GENERIC,或者两者都不请求。

  • KVM_ARM_VCPU_PTRAUTH_GENERIC:仅为 arm64 启用通用指针身份验证。 依赖于 KVM_CAP_ARM_PTRAUTH_GENERIC。 如果同时存在 KVM_CAP_ARM_PTRAUTH_ADDRESS 和 KVM_CAP_ARM_PTRAUTH_GENERIC,则必须请求 KVM_ARM_VCPU_PTRAUTH_ADDRESS 和 KVM_ARM_VCPU_PTRAUTH_GENERIC,或者两者都不请求。

  • KVM_ARM_VCPU_SVE:为 CPU 启用 SVE(仅限 arm64)。 依赖于 KVM_CAP_ARM_SVE。 需要 KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE)

    • 在 KVM_ARM_VCPU_INIT 之后

      • 可以使用 KVM_GET_ONE_REG 读取 KVM_REG_ARM64_SVE_VLS:此伪寄存器的初始值指示此主机上 vcpu 可能的最佳矢量长度集。

    • 在 KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE) 之前

      • KVM_RUN 和 KVM_GET_REG_LIST 不可用;

      • KVM_GET_ONE_REG 和 KVM_SET_ONE_REG 不能用于访问可缩放的架构 SVE 寄存器 KVM_REG_ARM64_SVE_ZREG()、KVM_REG_ARM64_SVE_PREG() 或 KVM_REG_ARM64_SVE_FFR;

      • 可以选择使用 KVM_SET_ONE_REG 写入 KVM_REG_ARM64_SVE_VLS,以修改 vcpu 可用的矢量长度集。

    • 在 KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE) 之后

      • KVM_REG_ARM64_SVE_VLS 伪寄存器是不可变的,不能再使用 KVM_SET_ONE_REG 写入。

  • KVM_ARM_VCPU_HAS_EL2:启用嵌套虚拟化支持,从 EL2 而不是 EL1 启动客户机。依赖于 KVM_CAP_ARM_EL2。虚拟机在 HCR_EL2.E2H 为 RES1 (VHE) 的情况下运行,除非同时设置了 KVM_ARM_VCPU_HAS_EL2_E2H0。

  • KVM_ARM_VCPU_HAS_EL2_E2H0:将嵌套虚拟化支持限制为 HCR_EL2.E2H 为 RES0(非 VHE)。依赖于 KVM_CAP_ARM_EL2_E2H0。还必须设置 KVM_ARM_VCPU_HAS_EL2。

4.83 KVM_ARM_PREFERRED_TARGET

功能:

基本

架构:

arm64

类型:

vm ioctl

参数:

struct kvm_vcpu_init (输出)

返回值:

成功时为 0;出错时为 -1

错误

ENODEV

主机没有可用的首选目标

此调用向 KVM 查询主机上 KVM 可以模拟的首选 CPU 目标类型。

该 ioctl 返回 struct kvm_vcpu_init 实例,其中包含有关首选 CPU 目标类型及其建议功能的信息。如果首选目标建议设置这些功能,则返回的 kvm_vcpu_init->features 位图将设置功能位,但这不是强制性的。

此 ioctl 返回的信息可用于准备 struct kvm_vcpu_init 实例,以用于 KVM_ARM_VCPU_INIT ioctl,这将导致 VCPU 与底层主机匹配。

4.84 KVM_GET_REG_LIST

功能:

基本

架构:

arm64, mips, riscv

类型:

vcpu ioctl

参数:

struct kvm_reg_list (输入/输出)

返回值:

成功时为 0;出错时为 -1

错误

E2BIG

reg 索引列表太大,无法放入用户指定的数组中(所需的数字将写入 n 中)。

struct kvm_reg_list {
      __u64 n; /* number of registers in reg[] */
      __u64 reg[0];
};

此 ioctl 返回 KVM_GET_ONE_REG/KVM_SET_ONE_REG 调用支持的客户机寄存器。

请注意,由于历史原因,s390 不支持 KVM_GET_REG_LIST(读取:没人关心)。内核 4.x 及更新版本中的寄存器集是

  • KVM_REG_S390_TODPR

  • KVM_REG_S390_EPOCHDIFF

  • KVM_REG_S390_CPU_TIMER

  • KVM_REG_S390_CLOCK_COMP

  • KVM_REG_S390_PFTOKEN

  • KVM_REG_S390_PFCOMPARE

  • KVM_REG_S390_PFSELECT

  • KVM_REG_S390_PP

  • KVM_REG_S390_GBEA

4.85 KVM_ARM_SET_DEVICE_ADDR (已弃用)

功能:

KVM_CAP_ARM_SET_DEVICE_ADDR

架构:

arm64

类型:

vm ioctl

参数:

struct kvm_arm_device_address (输入)

返回值:

成功时为 0,出错时为 -1

错误

ENODEV

设备 ID 未知

ENXIO

当前系统不支持该设备

EEXIST

地址已设置

E2BIG

地址位于客户机物理地址空间之外

EBUSY

地址与其他设备范围重叠

struct kvm_arm_device_addr {
      __u64 id;
      __u64 addr;
};

在客户机的物理地址空间中指定一个设备地址,客户机可以在该地址访问模拟或直接公开的设备,主机内核需要了解这些设备。id 字段是特定于架构的特定设备的标识符。

arm64 将 id 字段分为两个部分,一个是设备 ID,另一个是特定于各个设备的地址类型 ID

bits:  | 63        ...       32 | 31    ...    16 | 15    ...    0 |
field: |        0x00000000      |     device id   |  addr type id  |

arm64 当前仅在使用内核 GIC 支持硬件 VGIC 功能时才需要这样做,使用 KVM_ARM_DEVICE_VGIC_V2 作为设备 ID。在为客户机映射 VGIC 虚拟 CPU 和分配器接口设置基地址时,必须在调用 KVM_CREATE_IRQCHIP 之后,但在任何 VCPU 上调用 KVM_RUN 之前调用 ioctl。对于任何基地址,调用此 ioctl 两次将返回 -EEXIST。

请注意,此 IOCTL 已弃用,应改用更灵活的 SET/GET_DEVICE_ATTR API。

4.86 KVM_PPC_RTAS_DEFINE_TOKEN

功能:

KVM_CAP_PPC_RTAS

架构:

ppc

类型:

vm ioctl

参数:

struct kvm_rtas_token_args

返回值:

成功时为 0,出错时为 -1

为 RTAS(运行时抽象服务)服务定义一个令牌值,以便允许在内核中处理它。参数结构提供服务的名称,该名称必须是具有内核端实现的服务名称。如果令牌值非零,则它将与该服务关联,并且客户机后续对指定该令牌的 RTAS 调用将由内核处理。如果令牌值为 0,则将忘记与该服务关联的任何令牌,并且客户机后续对该服务的 RTAS 调用将传递到用户空间进行处理。

4.87 KVM_SET_GUEST_DEBUG

功能:

KVM_CAP_SET_GUEST_DEBUG

架构:

x86, s390, ppc, arm64

类型:

vcpu ioctl

参数:

struct kvm_guest_debug (输入)

返回值:

成功时为 0;出错时为 -1

struct kvm_guest_debug {
     __u32 control;
     __u32 pad;
     struct kvm_guest_debug_arch arch;
};

设置特定于处理器的调试寄存器,并将 vcpu 配置为处理客户机调试事件。该结构有两个部分,第一部分是一个控制位字段,指示运行时要处理的调试事件类型。常见的控制位包括

  • KVM_GUESTDBG_ENABLE:启用客户机调试

  • KVM_GUESTDBG_SINGLESTEP:下一次运行应单步执行

控制字段的前 16 位是特定于架构的控制标志,可以包括以下内容

  • KVM_GUESTDBG_USE_SW_BP:使用软件断点 [x86, arm64]

  • KVM_GUESTDBG_USE_HW_BP:使用硬件断点 [x86, s390]

  • KVM_GUESTDBG_USE_HW:使用硬件调试事件 [arm64]

  • KVM_GUESTDBG_INJECT_DB:注入 DB 类型异常 [x86]

  • KVM_GUESTDBG_INJECT_BP:注入 BP 类型异常 [x86]

  • KVM_GUESTDBG_EXIT_PENDING:触发立即客户机退出 [s390]

  • KVM_GUESTDBG_BLOCKIRQ:避免注入中断/NMI/SMI [x86]

例如,KVM_GUESTDBG_USE_SW_BP 指示在内存中启用了软件断点,因此我们需要确保正确捕获断点异常,并且 KVM 运行循环在断点处退出,而不是运行到正常的客户机向量中。对于 KVM_GUESTDBG_USE_HW_BP,我们需要确保客户机 vCPU 的特定于架构的寄存器已更新为正确(提供)的值。

该结构的第二部分是特定于架构的,通常包含一组调试寄存器。

对于 arm64,调试寄存器的数量由实现定义,可以通过查询 KVM_CAP_GUEST_DEBUG_HW_BPS 和 KVM_CAP_GUEST_DEBUG_HW_WPS 功能来确定,这些功能返回一个正数,指示支持的寄存器数量。

对于 ppc,KVM_CAP_PPC_GUEST_DEBUG_SSTEP 功能指示是否支持单步调试事件 (KVM_GUESTDBG_SINGLESTEP)。

同样,在支持时,KVM_CAP_SET_GUEST_DEBUG2 功能指示控制字段中支持的 KVM_GUESTDBG_* 位。

当调试事件以原因 KVM_EXIT_DEBUG 退出主运行循环时,kvm_run 结构的 kvm_debug_exit_arch 部分包含特定于架构的调试信息。

4.88 KVM_GET_EMULATED_CPUID

功能:

KVM_CAP_EXT_EMUL_CPUID

架构:

x86

类型:

系统 ioctl

参数:

struct kvm_cpuid2 (in/out)

返回值:

成功时为 0,出错时为 -1

struct kvm_cpuid2 {
      __u32 nent;
      __u32 flags;
      struct kvm_cpuid_entry2 entries[0];
};

成员“flags”用于从用户空间传递标志。

#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX               BIT(0)
#define KVM_CPUID_FLAG_STATEFUL_FUNC          BIT(1) /* deprecated */
#define KVM_CPUID_FLAG_STATE_READ_NEXT                BIT(2) /* deprecated */

struct kvm_cpuid_entry2 {
      __u32 function;
      __u32 index;
      __u32 flags;
      __u32 eax;
      __u32 ebx;
      __u32 ecx;
      __u32 edx;
      __u32 padding[3];
};

此 ioctl 返回 kvm 模拟的 x86 cpuid 功能。用户空间可以使用此 ioctl 返回的信息来查询 kvm 模拟哪些功能,而不是本机存在哪些功能。

用户空间通过传递一个 kvm_cpuid2 结构来调用 KVM_GET_EMULATED_CPUID,其中“nent”字段指示可变大小数组“entries”中的条目数。如果条目数太低而无法描述 cpu 功能,则返回错误 (E2BIG)。如果数量过高,则调整“nent”字段并返回错误 (ENOMEM)。如果数量正好,则将“nent”字段调整为“entries”数组中有效条目的数量,然后填充该数组。

返回的条目是 kvm 模拟的各个功能的 CPUID 位集,如 CPUID 指令返回的那样,清除未知或不支持的功能位。

例如,像 x2apic 这样的功能可能不存在于主机 cpu 中,但在 KVM_GET_SUPPORTED_CPUID 中由 kvm 公开,因为它们可以被有效地模拟,因此不包括在此处。

每个条目中的字段定义如下

function

用于获取条目的 eax 值

index

用于获取条目的 ecx 值(对于受 ecx 影响的条目)

flags

以下零个或多个的 OR

KVM_CPUID_FLAG_SIGNIFCANT_INDEX

如果索引字段有效

eax, ebx, ecx, edx

cpuid 指令为此 function/index 组合返回的值

4.89 KVM_S390_MEM_OP

功能:

KVM_CAP_S390_MEM_OP, KVM_CAP_S390_PROTECTED, KVM_CAP_S390_MEM_OP_EXTENSION

架构:

s390

类型:

vm ioctl、vcpu ioctl

参数:

struct kvm_s390_mem_op (输入)

返回值:

= 0 表示成功,< 0 表示一般错误(例如 -EFAULT 或 -ENOMEM),如果访问导致此类异常,则为 16 位程序异常代码

从/向虚拟机的内存读取或写入数据。KVM_CAP_S390_MEM_OP_EXTENSION 功能指定支持哪些功能。

参数通过以下结构指定

struct kvm_s390_mem_op {
      __u64 gaddr;            /* the guest address */
      __u64 flags;            /* flags */
      __u32 size;             /* amount of bytes */
      __u32 op;               /* type of operation */
      __u64 buf;              /* buffer in userspace */
      union {
              struct {
                      __u8 ar;        /* the access register number */
                      __u8 key;       /* access key, ignored if flag unset */
                      __u8 pad1[6];   /* ignored */
                      __u64 old_addr; /* ignored if flag unset */
              };
              __u32 sida_offset; /* offset into the sida */
              __u8 reserved[32]; /* ignored */
      };
};

内存区域的起始地址必须在“gaddr”字段中指定,区域的长度必须在“size”字段中指定(不能为 0)。“size”的最大值可以通过检查 KVM_CAP_S390_MEM_OP 功能获得。“buf”是用户空间应用程序提供的缓冲区,读取访问时,读取的数据应写入其中;写入访问时,应写入的数据存储在该缓冲区中。“reserved”字段用于将来的扩展。保留和未使用的值将被忽略。添加成员的未来扩展必须引入新的标志。

操作类型在“op”字段中指定。修改其行为的标志可以在“flags”字段中设置。未定义的标志位必须设置为 0。

可能的操作包括
  • KVM_S390_MEMOP_LOGICAL_READ

  • KVM_S390_MEMOP_LOGICAL_WRITE

  • KVM_S390_MEMOP_ABSOLUTE_READ

  • KVM_S390_MEMOP_ABSOLUTE_WRITE

  • KVM_S390_MEMOP_SIDA_READ

  • KVM_S390_MEMOP_SIDA_WRITE

  • KVM_S390_MEMOP_ABSOLUTE_CMPXCHG

逻辑读取/写入:

访问逻辑内存,即,给定 VCPU 的状态,将给定的客户机地址转换为绝对地址,并将绝对地址用作访问的目标。“ar”指定要使用的访问寄存器号;有效范围是 0..15。逻辑访问仅允许用于 VCPU ioctl。逻辑访问仅允许用于非保护客户机。

支持的标志
  • KVM_S390_MEMOP_F_CHECK_ONLY

  • KVM_S390_MEMOP_F_INJECT_EXCEPTION

  • KVM_S390_MEMOP_F_SKEY_PROTECTION

可以设置 KVM_S390_MEMOP_F_CHECK_ONLY 标志来检查相应的内存访问是否会导致访问异常;但是,不会对目标内存中的数据执行实际访问。在这种情况下,“buf”未使用,可以为 NULL。

如果在访问期间发生访问异常(或在 KVM_S390_MEMOP_F_CHECK_ONLY 的情况下会发生),则 ioctl 返回一个正错误号,指示异常类型。如果设置了标志 KVM_S390_MEMOP_F_INJECT_EXCEPTION,则此异常也会直接在相应的 VCPU 上引发。对于保护异常,除非另有说明,否则注入的转换异常标识符 (TEID) 指示抑制。

如果设置了 KVM_S390_MEMOP_F_SKEY_PROTECTION 标志,则存储键保护也生效,如果给定“key”指定的访问键,禁止访问,则可能会导致异常;有效范围是 0..15。如果 KVM_CAP_S390_MEM_OP_EXTENSION > 0,则 KVM_S390_MEMOP_F_SKEY_PROTECTION 可用。由于访问的内存可能跨越多个页面,并且这些页面可能具有不同的存储键,因此有可能在修改内存后发生保护异常。在这种情况下,如果注入异常,则 TEID 不指示抑制。

绝对读取/写入:

访问绝对内存。此操作旨在与 KVM_S390_MEMOP_F_SKEY_PROTECTION 标志一起使用,以允许访问内存并执行存储键保护所需的检查作为一项操作(而不是用户空间获取存储键、执行检查,然后在之后访问内存,这可能会导致检查和访问之间存在延迟)。如果 KVM_CAP_S390_MEM_OP_EXTENSION 具有 KVM_S390_MEMOP_EXTENSION_CAP_BASE 位集,则 VM ioctl 允许绝对访问。当前,VCPU ioctl 不允许绝对访问。绝对访问仅允许用于非保护客户机。

支持的标志
  • KVM_S390_MEMOP_F_CHECK_ONLY

  • KVM_S390_MEMOP_F_SKEY_PROTECTION

与逻辑访问共享的标志的语义与逻辑访问的语义相同。

绝对 cmpxchg:

在绝对客户机内存上执行 cmpxchg。旨在与 KVM_S390_MEMOP_F_SKEY_PROTECTION 标志一起使用。访问仅在目标位置包含“old_addr”指向的值时才会发生,而不是进行无条件写入。这是作为长度由“size”参数指定的原子 cmpxchg 执行的。“size”必须是 2 的幂,最大为 16。如果由于目标值与旧值不匹配而未发生交换,则“old_addr”指向的值将替换为目标值。用户空间可以通过检查是否发生此替换来判断是否发生了交换。如果 KVM_CAP_S390_MEM_OP_EXTENSION 具有标志 KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG 集,则 VM ioctl 允许 cmpxchg op。

支持的标志
  • KVM_S390_MEMOP_F_SKEY_PROTECTION

SIDA 读取/写入:

访问安全指令数据区域,该区域包含受保护客户机指令模拟所需的内存操作数。如果 KVM_CAP_S390_PROTECTED 功能可用,则 SIDA 访问可用。SIDA 访问仅允许用于 VCPU ioctl。SIDA 访问仅允许用于受保护客户机。

不支持任何标志。

4.90 KVM_S390_GET_SKEYS

功能:

KVM_CAP_S390_SKEYS

架构:

s390

类型:

vm ioctl

参数:

struct kvm_s390_skeys

返回值:

成功时为 0,如果客户机未使用存储键,则为 KVM_S390_GET_SKEYS_NONE,出错时为负值

此 ioctl 用于获取 s390 架构上的客户机存储键值。该 ioctl 通过 kvm_s390_skeys 结构获取参数

struct kvm_s390_skeys {
      __u64 start_gfn;
      __u64 count;
      __u64 skeydata_addr;
      __u32 flags;
      __u32 reserved[9];
};

start_gfn 字段是您要获取其存储键的第一个客户机帧的编号。

count 字段是要获取其存储键的连续帧的数量(从 start_gfn 开始)。count 字段必须至少为 1,允许的最大值定义为 KVM_S390_SKEYS_MAX。超出此范围的值将导致 ioctl 返回 -EINVAL。

skeydata_addr 字段是指向一个足够大的缓冲区地址,该缓冲区可以容纳 count 字节。ioctl 将使用存储键数据填充此缓冲区。

4.91 KVM_S390_SET_SKEYS

功能:

KVM_CAP_S390_SKEYS

架构:

s390

类型:

vm ioctl

参数:

struct kvm_s390_skeys

返回值:

成功时为 0,出错时为负值

此 ioctl 用于设置 s390 架构上的客户机存储键值。该 ioctl 通过 kvm_s390_skeys 结构获取参数。有关结构定义,请参阅 KVM_S390_GET_SKEYS 部分。

start_gfn 字段是您要设置其存储键的第一个客户机帧的编号。

count 字段是要获取其存储键的连续帧的数量(从 start_gfn 开始)。count 字段必须至少为 1,允许的最大值定义为 KVM_S390_SKEYS_MAX。超出此范围的值将导致 ioctl 返回 -EINVAL。

skeydata_addr 字段是指向包含 count 字节存储键的缓冲区的地址。缓冲区中的每个字节都将设置为从 start_gfn 开始的单个帧的存储键,计数帧。

注意:如果在给定的数据中发现任何架构上无效的键值,则 ioctl 将返回 -EINVAL。

4.92 KVM_S390_IRQ

功能:

KVM_CAP_S390_INJECT_IRQ

架构:

s390

类型:

vcpu ioctl

参数:

struct kvm_s390_irq (输入)

返回值:

成功时为 0,出错时为 -1

错误

EINVAL

中断类型是无效类型,类型是 KVM_S390_SIGP_STOP,并且标志参数是无效值,类型是 KVM_S390_INT_EXTERNAL_CALL,并且代码大于 VCPU 的最大值

EBUSY

类型是 KVM_S390_SIGP_SET_PREFIX,并且 vcpu 未停止,类型是 KVM_S390_SIGP_STOP,并且已存在挂起的停止 irq,类型是 KVM_S390_INT_EXTERNAL_CALL,并且已存在挂起的外部调用中断

允许将中断注入到客户机。

使用 struct kvm_s390_irq 作为参数可以注入额外的有效负载,这是通过 KVM_S390_INTERRUPT 无法实现的。

中断参数通过 kvm_s390_irq 传递

struct kvm_s390_irq {
      __u64 type;
      union {
              struct kvm_s390_io_info io;
              struct kvm_s390_ext_info ext;
              struct kvm_s390_pgm_info pgm;
              struct kvm_s390_emerg_info emerg;
              struct kvm_s390_extcall_info extcall;
              struct kvm_s390_prefix_info prefix;
              struct kvm_s390_stop_info stop;
              struct kvm_s390_mchk_info mchk;
              char reserved[64];
      } u;
};

type 可以是以下之一

  • KVM_S390_SIGP_STOP - sigp 停止;.stop 中的参数

  • KVM_S390_PROGRAM_INT - 程序检查;.pgm 中的参数

  • KVM_S390_SIGP_SET_PREFIX - sigp 设置前缀;.prefix 中的参数

  • KVM_S390_RESTART - 重新启动;没有参数

  • KVM_S390_INT_CLOCK_COMP - 时钟比较器中断;没有参数

  • KVM_S390_INT_CPU_TIMER - CPU 计时器中断;没有参数

  • KVM_S390_INT_EMERGENCY - sigp 紧急情况;.emerg 中的参数

  • KVM_S390_INT_EXTERNAL_CALL - sigp 外部调用;.extcall 中的参数

  • KVM_S390_MCHK - 机器检查中断;.mchk 中的参数

这是一个异步 vcpu ioctl,可以从任何线程调用。

4.94 KVM_S390_GET_IRQ_STATE

功能:

KVM_CAP_S390_IRQ_STATE

架构:

s390

类型:

vcpu ioctl

参数:

struct kvm_s390_irq_state (输出)

返回值:

>= 复制到缓冲区中的字节数,如果缓冲区大小为 0,则为 -EINVAL,如果缓冲区大小太小而无法容纳所有挂起的中断,则为 -ENOBUFS,如果缓冲区地址无效,则为 -EFAULT

此 ioctl 允许用户空间在单个缓冲区中检索所有当前挂起的中断的完整状态。用例包括迁移和内省。参数结构包含用户空间缓冲区的地址及其长度

struct kvm_s390_irq_state {
      __u64 buf;
      __u32 flags;        /* will stay unused for compatibility reasons */
      __u32 len;
      __u32 reserved[4];  /* will stay unused for compatibility reasons */
};

用户空间传入上述结构,并且对于每个挂起的中断,都会将一个 struct kvm_s390_irq 复制到提供的缓冲区。

该结构包含一个 flags 字段和一个 reserved 字段,用于将来的扩展。由于内核从未检查 flags == 0,并且 QEMU 从未预先将 flags 和 reserved 清零,因此将来无法使用这些字段而不破坏兼容性。

如果返回 -ENOBUFS,则提供的缓冲区太小,用户空间可以使用更大的缓冲区重试。

4.95 KVM_S390_SET_IRQ_STATE

功能:

KVM_CAP_S390_IRQ_STATE

架构:

s390

类型:

vcpu ioctl

参数:

struct kvm_s390_irq_state (输入)

返回值:

成功时为 0,如果缓冲区地址无效,则为 -EFAULT,如果缓冲区长度无效(见下文),则为 -EINVAL,如果已存在挂起的中断,则为 -EBUSY,发生错误时实际注入中断。请参阅 KVM_S390_IRQ。

此 ioctl 允许用户空间设置当前为 vcpu 挂起的所有 cpu 本地中断的完整状态。它旨在用于在迁移后恢复中断状态。输入参数是一个用户空间缓冲区,其中包含一个 struct kvm_s390_irq_state

struct kvm_s390_irq_state {
      __u64 buf;
      __u32 flags;        /* will stay unused for compatibility reasons */
      __u32 len;
      __u32 reserved[4];  /* will stay unused for compatibility reasons */
};

flags 和 reserved 的限制同样适用。(请参阅 KVM_S390_GET_IRQ_STATE)

buf 引用的用户空间内存包含一个 struct kvm_s390_irq,用于每个要注入到客户机中的中断。如果由于某种原因无法注入其中一个中断,则 ioctl 将中止。

len 必须是 sizeof(struct kvm_s390_irq) 的倍数。它必须 > 0,并且不能超过 (max_vcpus + 32) * sizeof(struct kvm_s390_irq),这是可能挂起的 cpu 本地中断的最大数量。

4.96 KVM_SMI

功能:

KVM_CAP_X86_SMM

架构:

x86

类型:

vcpu ioctl

参数:

返回值:

成功时为 0,出错时为 -1

在线程的 vcpu 上排队一个 SMI。

4.97 KVM_X86_SET_MSR_FILTER

功能:

KVM_CAP_X86_MSR_FILTER

架构:

x86

类型:

vm ioctl

参数:

struct kvm_msr_filter

返回值:

成功时为 0,出错时 < 0

struct kvm_msr_filter_range {
#define KVM_MSR_FILTER_READ  (1 << 0)
#define KVM_MSR_FILTER_WRITE (1 << 1)
      __u32 flags;
      __u32 nmsrs; /* number of msrs in bitmap */
      __u32 base;  /* MSR index the bitmap starts at */
      __u8 *bitmap; /* a 1 bit allows the operations in flags, 0 denies */
};

#define KVM_MSR_FILTER_MAX_RANGES 16
struct kvm_msr_filter {
#define KVM_MSR_FILTER_DEFAULT_ALLOW (0 << 0)
#define KVM_MSR_FILTER_DEFAULT_DENY  (1 << 0)
      __u32 flags;
      struct kvm_msr_filter_range ranges[KVM_MSR_FILTER_MAX_RANGES];
};

struct kvm_msr_filter_range 的 flags 值

KVM_MSR_FILTER_READ

使用给定的位图过滤对 MSR 的读取访问。位图中的 0 指示应拒绝读取访问,而 1 指示无论默认过滤器操作如何,都应允许读取特定 MSR。

KVM_MSR_FILTER_WRITE

使用给定的位图过滤对 MSR 的写入访问。位图中的 0 指示应拒绝写入访问,而 1 指示无论默认过滤器操作如何,都应允许写入特定 MSR。

struct kvm_msr_filter 的 flags 值

KVM_MSR_FILTER_DEFAULT_ALLOW

如果没有任何过滤器范围与正在访问的 MSR 索引匹配,KVM 默认将允许访问所有 MSR。

KVM_MSR_FILTER_DEFAULT_DENY

如果没有任何过滤器范围与正在访问的 MSR 索引匹配,KVM 默认将拒绝访问所有 MSR。

此 ioctl 允许用户空间定义最多 16 个 MSR 范围的位图,以拒绝 KVM 通常允许的客户机 MSR 访问。如果 MSR 不在特定范围内,则应用“默认”过滤行为。每个位图范围涵盖 [base .. base+nmsrs) 中的 MSR。

如果用户空间拒绝 MSR 访问,则生成的 KVM 行为取决于是否启用了 KVM_CAP_X86_USER_SPACE_MSR 的 KVM_MSR_EXIT_REASON_FILTER。如果启用了 KVM_MSR_EXIT_REASON_FILTER,则 KVM 将在拒绝访问时退出到用户空间,即用户空间有效地拦截 MSR 访问。如果未启用 KVM_MSR_EXIT_REASON_FILTER,则 KVM 将在拒绝访问时将 #GP 注入到客户机中。请注意,如果在 VMX 转换期间模拟 MSR 加载/存储时拒绝 MSR 访问,则 KVM 将忽略 KVM_MSR_EXIT_REASON_FILTER。有关完整详细信息,请参阅以下警告。

如果用户空间允许 MSR 访问,则 KVM 将根据 vCPU 模型模拟和/或虚拟化访问。请注意,如果用户空间允许访问,KVM 仍然可能最终注入 #GP,例如,如果 KVM 不支持 MSR,或者遵循 MSR 的架构行为。

默认情况下,KVM 在没有 MSR 范围过滤器的情况下以 KVM_MSR_FILTER_DEFAULT_ALLOW 模式运行。

使用空范围集(所有 nmsrs == 0)调用此 ioctl 会禁用 MSR 过滤。在该模式下,KVM_MSR_FILTER_DEFAULT_DENY 无效并导致错误。

警告

作为指令执行的副作用的 MSR 访问(模拟或本机)未被过滤,因为硬件不遵守 RDMSR 和 WRMSR 之外的 MSR 位图,并且 KVM 在模拟指令时会模仿该行为,以避免与硬件产生不必要的差异。例如,RDPID 读取 MSR_TSC_AUX,SYSENTER 读取 SYSENTER MSR 等。

通过专用 VMCS 字段加载/存储的 MSR 不会作为 VM-Enter/VM-Exit 模拟的一部分进行过滤。

通过 VMX 的加载/存储列表加载/存储的 MSR _确实_作为 VM-Enter/VM-Exit 模拟的一部分进行过滤。如果在 VM-Enter 时拒绝 MSR 访问,则 KVM 会合成一个一致性检查 VM-Exit(EXIT_REASON_MSR_LOAD_FAIL)。如果在 VM-Exit 时拒绝 MSR 访问,则 KVM 会合成一个 VM-Abort。简而言之,KVM 扩展了 Intel 的架构 MSR 列表,这些 MSR 无法通过 VM-Enter/VM-Exit MSR 列表加载/保存。平台所有者有责任将其任何此类限制告知其最终用户。

x2APIC MSR 访问无法过滤(KVM 会静默忽略涵盖任何 x2APIC MSR 的过滤器)。

请注意,在 vCPU 运行时调用此 ioctl 本身就是竞争性的。但是,KVM 确实保证 vCPU 将看到先前的过滤器或新过滤器,例如,旧过滤器和新过滤器中具有相同设置的 MSR 将具有确定性行为。

同样,如果用户空间希望拦截拒绝的访问,则必须在激活任何过滤器之前启用 KVM_MSR_EXIT_REASON_FILTER,并保持启用状态,直到所有过滤器都被停用之后。否则可能会导致 KVM 注入 #GP 而不是退出到用户空间。

4.98 KVM_CREATE_SPAPR_TCE_64

功能:

KVM_CAP_SPAPR_TCE_64

架构:

powerpc

类型:

vm ioctl

参数:

struct kvm_create_spapr_tce_64 (输入)

返回值:

用于操作创建的 TCE 表的文件描述符

这是 KVM_CAP_SPAPR_TCE 的一个扩展,仅支持 32 位窗口,如 4.62 KVM_CREATE_SPAPR_TCE 中所述

此功能使用 ioctl 接口中的扩展结构。

/* for KVM_CAP_SPAPR_TCE_64 */
struct kvm_create_spapr_tce_64 {
      __u64 liobn;
      __u32 page_shift;
      __u32 flags;
      __u64 offset;   /* in pages */
      __u64 size;     /* in pages */
};

扩展的目的是支持一个具有可变页面大小的更大的 DMA 窗口。 KVM_CREATE_SPAPR_TCE_64 接收一个 64 位窗口大小、一个 IOMMU 页面移位以及相应 DMA 窗口的总线偏移量,@size 和 @offset 是 IOMMU 页面的数量。

目前未使用 @flags。

其余功能与 KVM_CREATE_SPAPR_TCE 相同。

4.99 KVM_REINJECT_CONTROL

功能:

KVM_CAP_REINJECT_CONTROL

架构:

x86

类型:

vm ioctl

参数:

struct kvm_reinject_control (输入)

返回值:

成功时返回 0,如果无法读取 struct kvm_reinject_control 则返回 -EFAULT,如果 KVM_CREATE_PIT 或 KVM_CREATE_PIT2 先前未成功则返回 -ENXIO。

i8254 (PIT) 有两种模式,重注入和非重注入。 默认值为重注入,其中 KVM 会将经过的 i8254 计时节拍排队,并监控来自 i8254 注入的向量的中断完成情况。 当没有来自 i8254 的挂起中断时,重注入模式会取消排队一个计时节拍并注入其中断。 非重注入模式会在计时节拍到达时立即注入中断。

struct kvm_reinject_control {
      __u8 pit_reinject;
      __u8 reserved[31];
};

建议使用 pit_reinject = 0(非重注入模式),除非运行使用 PIT 进行计时的旧操作系统(例如,Linux 2.4.x)。

4.100 KVM_PPC_CONFIGURE_V3_MMU

功能:

KVM_CAP_PPC_MMU_RADIX 或 KVM_CAP_PPC_MMU_HASH_V3

架构:

ppc

类型:

vm ioctl

参数:

struct kvm_ppc_mmuv3_cfg (输入)

返回值:

成功时返回 0,如果无法读取 struct kvm_ppc_mmuv3_cfg 则返回 -EFAULT,如果配置无效则返回 -EINVAL

此 ioctl 控制访客是否将使用基数树或 HPT(哈希页面表)转换,并设置指向访客进程表的指针。

struct kvm_ppc_mmuv3_cfg {
      __u64   flags;
      __u64   process_table;
};

可以在标志中设置两个位; KVM_PPC_MMUV3_RADIX 和 KVM_PPC_MMUV3_GTSE。 如果设置了 KVM_PPC_MMUV3_RADIX,则配置访客使用基数树转换;如果清除,则使用 HPT 转换。 如果设置了 KVM_PPC_MMUV3_GTSE 并且 KVM 允许,则配置访客能够使用全局 TLB 和 SLB 无效指令;如果清除,则访客可能无法使用这些指令。

process_table 字段指定访客进程表的地址和大小,该表位于访客空间中。 此字段的格式设置为分区表条目的第二个双字,如 Power ISA V3.00 Book III 第 5.7.6.1 节中所定义。

4.101 KVM_PPC_GET_RMMU_INFO

功能:

KVM_CAP_PPC_MMU_RADIX

架构:

ppc

类型:

vm ioctl

参数:

struct kvm_ppc_rmmu_info (输出)

返回值:

成功时返回 0,如果无法写入 struct kvm_ppc_rmmu_info 则返回 -EFAULT,如果无法返回任何有用的信息则返回 -EINVAL

此 ioctl 返回一个包含两个内容的结构:(a) 一个包含支持的基数树几何形状的列表,以及 (b) 一个将页面大小映射到要在 tlbie(TLB 无效条目)指令的“AP”(实际页面大小)字段中放置的列表。

struct kvm_ppc_rmmu_info {
      struct kvm_ppc_radix_geom {
              __u8    page_shift;
              __u8    level_bits[4];
              __u8    pad[3];
      }       geometries[8];
      __u32   ap_encodings[8];
};

geometries[] 字段最多为基数页面表提供 8 个支持的几何形状,以最小页面大小的以 2 为底的对数以及树的每个级别(从 PTE 级别到 PGD 级别)索引的位数来表示。 任何未使用的条目在 page_shift 字段中都将为 0。

ap_encodings 提供支持的页面大小及其 AP 字段编码,AP 值编码在前 3 位,页面大小的以 2 为底的对数编码在后 6 位。

4.102 KVM_PPC_RESIZE_HPT_PREPARE

功能:

KVM_CAP_SPAPR_RESIZE_HPT

架构:

powerpc

类型:

vm ioctl

参数:

struct kvm_ppc_resize_hpt (输入)

返回值:

成功完成时返回 0,如果正在准备新的 HPT 则返回 >0,该值是准备完成前的估计毫秒数,如果无法读取 struct kvm_reinject_control 则返回 -EFAULT,如果提供的移位或标志无效则返回 -EINVAL,如果无法分配新的 HPT 则返回 -ENOMEM

用于实现用于运行时调整访客的哈希页面表 (HPT) 大小的 PAPR 扩展。 具体而言,这会启动、停止或监控访客新的潜在 HPT 的准备工作,本质上是实现 H_RESIZE_HPT_PREPARE 超调用。

struct kvm_ppc_resize_hpt {
      __u64 flags;
      __u32 shift;
      __u32 pad;
};

如果在访客没有挂起的 HPT 时调用 shift > 0,则这会开始准备大小为 2^(shift) 字节的新挂起 HPT。 然后,它会返回一个正整数,其中包含准备完成前的估计毫秒数。

如果在调用时存在挂起的 HPT,其大小与参数中请求的大小不匹配,则会丢弃现有的挂起 HPT 并创建一个新的 HPT,如上所述。

如果在调用时存在所请求大小的挂起 HPT,则会

  • 如果挂起 HPT 的准备工作已经完成,则返回 0

  • 如果挂起 HPT 的准备工作失败,则返回错误代码,然后丢弃挂起 HPT。

  • 如果挂起 HPT 的准备工作仍在进行中,则返回准备完成前的估计毫秒数。

如果使用 shift == 0 调用,则会丢弃当前任何挂起的 HPT 并返回 0(即取消任何正在进行的准备工作)。

flags 保留用于将来扩展,目前在 flags 中设置任何位将导致 -EINVAL。

通常,这将使用相同的参数重复调用,直到它返回 <= 0。 第一次调用将启动准备工作,后续调用将监控准备工作,直到它完成或失败。

4.103 KVM_PPC_RESIZE_HPT_COMMIT

功能:

KVM_CAP_SPAPR_RESIZE_HPT

架构:

powerpc

类型:

vm ioctl

参数:

struct kvm_ppc_resize_hpt (输入)

返回值:

成功完成时返回 0,如果无法读取 struct kvm_reinject_control 则返回 -EFAULT,如果提供的移位或标志无效则返回 -EINVAL,如果不存在挂起的 HPT 或者挂起的 HPT 没有所请求的大小则返回 -ENXIO,如果挂起的 HPT 未完全准备好则返回 -EBUSY,如果在将现有 HPT 条目移动到新的 HPT 时发生哈希冲突则返回 -ENOSPC,在其他错误情况下返回 -EIO

用于实现用于运行时调整访客的哈希页面表 (HPT) 大小的 PAPR 扩展。 具体而言,这会请求将访客转移到使用新的 HPT,本质上是实现 H_RESIZE_HPT_COMMIT 超调用。

struct kvm_ppc_resize_hpt {
      __u64 flags;
      __u32 shift;
      __u32 pad;
};

只有在 KVM_PPC_RESIZE_HPT_PREPARE 使用相同参数返回 0 后才能调用此函数。 在其他情况下,KVM_PPC_RESIZE_HPT_COMMIT 将返回一个错误(通常为 -ENXIO 或 -EBUSY,但如果准备工作已启动但失败,则可能会出现其他错误)。

如果访客尚未将自身置于没有 vcpu 会进行 MMU 启用的内存访问的静默状态,这将对访客产生未定义的影响。

成功完成后,挂起的 HPT 将成为访客的活动 HPT,并且先前的 HPT 将被丢弃。

如果失败,访客仍将在其先前的 HPT 上运行。

4.104 KVM_X86_GET_MCE_CAP_SUPPORTED

功能:

KVM_CAP_MCE

架构:

x86

类型:

系统 ioctl

参数:

u64 mce_cap (输出)

返回值:

成功时为 0,出错时为 -1

返回支持的 MCE 功能。 u64 mce_cap 参数的格式与 MSR_IA32_MCG_CAP 寄存器相同。 支持的功能将设置相应的位。

4.105 KVM_X86_SETUP_MCE

功能:

KVM_CAP_MCE

架构:

x86

类型:

vcpu ioctl

参数:

u64 mcg_cap (输入)

返回值:

成功时返回 0,如果无法读取 u64 mcg_cap 则返回 -EFAULT,如果请求的 bank 数量无效则返回 -EINVAL,如果不支持请求的 MCE 功能则返回 -EINVAL。

初始化 MCE 支持以供使用。 u64 mcg_cap 参数的格式与 MSR_IA32_MCG_CAP 寄存器相同,并指定应启用哪些功能。 检查 KVM_CAP_MCE 时,可以检索支持的最大错误报告 bank 数量。 可以使用 KVM_X86_GET_MCE_CAP_SUPPORTED 检索支持的功能。

4.106 KVM_X86_SET_MCE

功能:

KVM_CAP_MCE

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_x86_mce (输入)

返回值:

成功时返回 0,如果无法读取 struct kvm_x86_mce 则返回 -EFAULT,如果 bank 编号无效则返回 -EINVAL,如果在状态字段中未设置 VAL 位则返回 -EINVAL。

将机器检查错误 (MCE) 注入到访客中。 输入参数为

struct kvm_x86_mce {
      __u64 status;
      __u64 addr;
      __u64 misc;
      __u64 mcg_status;
      __u8 bank;
      __u8 pad1[7];
      __u64 pad2[3];
};

如果报告的 MCE 是未更正的错误,则 KVM 会将其作为 MCE 异常注入到访客中。 如果访客 MCG_STATUS 寄存器报告 MCE 正在进行中,则 KVM 会导致 KVM_EXIT_SHUTDOWN vmexit。

否则,如果 MCE 是已更正的错误,则 KVM 只会将其存储在相应的 bank 中(前提是此 bank 没有保存先前报告的未更正的错误)。

4.107 KVM_S390_GET_CMMA_BITS

功能:

KVM_CAP_S390_CMMA_MIGRATION

架构:

s390

类型:

vm ioctl

参数:

struct kvm_s390_cmma_log (输入,输出)

返回值:

成功时返回 0,出错时返回负值

错误

ENOMEM

没有足够的内存来完成该任务

ENXIO

如果未启用 CMMA

EINVAL

如果未设置 KVM_S390_CMMA_PEEK 但未启用迁移模式

EINVAL

如果未设置 KVM_S390_CMMA_PEEK 但已禁用脏跟踪(因此自动禁用了迁移模式)

EFAULT

如果用户空间地址无效或者地址不存在页面表(例如,在使用巨页时)。

此 ioctl 用于获取 s390 架构上的 CMMA 位的取值。 它旨在用于两种情况

  • 在实时迁移期间保存 CMMA 值。 需要通过 KVM_REQ_START_MIGRATION VM 属性启用实时迁移。

  • 通过设置标志 KVM_S390_CMMA_PEEK 来非破坏性地查看 CMMA 值。

ioctl 通过 kvm_s390_cmma_log 结构获取参数。 所需的值被写入到缓冲区,该缓冲区的位置通过 kvm_s390_cmma_log 结构中的“values”成员指示。 输入结构中的值也会根据需要进行更新。

每个 CMMA 值占用一个字节。

struct kvm_s390_cmma_log {
      __u64 start_gfn;
      __u32 count;
      __u32 flags;
      union {
              __u64 remaining;
              __u64 mask;
      };
      __u64 values;
};

start_gfn 是要检索其 CMMA 值的第一个访客帧的编号

count 是缓冲区长度(以字节为单位)

values 指向将在其中写入结果的缓冲区。

如果 count 大于 KVM_S390_SKEYS_MAX,则将其视为 KVM_S390_SKEYS_MAX。 KVM_S390_SKEYS_MAX 被重新使用以与其他 ioctl 保持一致。

结果写入到由字段 values 指向的缓冲区中,并且输入参数的值按如下方式更新。

根据标志,执行不同的操作。 到目前为止,唯一支持的标志是 KVM_S390_CMMA_PEEK。

如果未设置 KVM_S390_CMMA_PEEK,则默认行为是:start_gfn 将指示 CMMA 位被置脏的第一个页帧。它不一定与作为输入传递的页帧相同,因为会跳过干净的页面。

count 将指示实际写入缓冲区中的字节数。它可能(并且非常经常会)小于输入值,因为缓冲区仅填充到找到 16 字节的干净值(然后不会复制到缓冲区中)。由于 CMMA 迁移块需要基地址和长度,总共 16 字节,因此如果之后存在一些脏数据,我们将返回一些干净的数据,只要干净数据的大小不超过标头的大小。这允许以增加与用户空间的往返次数为代价,最大限度地减少要保存或通过网络传输的数据量。下一次调用 ioctl 将跳过所有干净的值,从而可能节省超过我们找到的 16 字节。

如果设置了 KVM_S390_CMMA_PEEK:即使不在迁移模式下,也会读取现有的存储属性,并且不执行其他操作;

输出 start_gfn 将等于输入 start_gfn,

输出 count 将等于输入 count,除非已到达内存末尾。

在两种情况下:字段 “remaining” 将指示剩余的脏 CMMA 值的总数,或者如果设置了 KVM_S390_CMMA_PEEK 并且未启用迁移模式,则为 0。

mask 未使用。

values 指向用户空间缓冲区,结果将存储在该缓冲区中。

4.108 KVM_S390_SET_CMMA_BITS

功能:

KVM_CAP_S390_CMMA_MIGRATION

架构:

s390

类型:

vm ioctl

参数:

struct kvm_s390_cmma_log (输入)

返回值:

成功时返回 0,出错时返回负值

此 ioctl 用于设置 s390 架构上的 CMMA 位的值。它旨在在实时迁移期间用于恢复 CMMA 值,但对其使用没有限制。ioctl 通过 kvm_s390_cmma_values 结构体获取参数。每个 CMMA 值占用一个字节。

struct kvm_s390_cmma_log {
      __u64 start_gfn;
      __u32 count;
      __u32 flags;
      union {
              __u64 remaining;
              __u64 mask;
      };
      __u64 values;
};

start_gfn 指示起始客户机帧号,

count 指示缓冲区中要考虑的值的数量,

flags 未使用,必须为 0。

mask 指示要考虑哪些 PGSTE 位。

remaining 未使用。

values 指向用户空间中的缓冲区,用于存储这些值。

如果无法分配足够的内存来完成任务,则此 ioctl 可能会失败并返回 -ENOMEM;如果未启用 CMMA,则返回 -ENXIO;如果 count 字段太大(例如,大于 KVM_S390_CMMA_SIZE_MAX)或 flags 字段不为 0,则返回 -EINVAL;如果用户空间地址无效,如果写入了无效页面(例如,在内存末尾之后),或者如果地址不存在页表(例如,使用巨页时),则返回 -EFAULT。

4.109 KVM_PPC_GET_CPU_CHAR

功能:

KVM_CAP_PPC_GET_CPU_CHAR

架构:

powerpc

类型:

vm ioctl

参数:

struct kvm_ppc_cpu_char (输出)

返回值:

成功完成时返回 0,如果无法写入 struct kvm_ppc_cpu_char,则返回 -EFAULT

此 ioctl 向用户空间提供有关 CPU 某些特性的信息,这些特性与指令的推测执行以及由推测执行可能导致的信息泄露有关(请参阅 CVE-2017-5715、CVE-2017-5753 和 CVE-2017-5754)。该信息在 struct kvm_ppc_cpu_char 中返回,如下所示

struct kvm_ppc_cpu_char {
      __u64   character;              /* characteristics of the CPU */
      __u64   behaviour;              /* recommended software behaviour */
      __u64   character_mask;         /* valid bits in character */
      __u64   behaviour_mask;         /* valid bits in behaviour */
};

为了扩展性,character_mask 和 behaviour_mask 字段指示内核已填充 character 和 behaviour 的哪些位。如果未来扩展了定义的位集,则用户空间将能够判断它是否在知道新位的内核上运行。

character 字段描述了 CPU 的属性,这些属性可以帮助防止意外的信息泄露 - 具体来说,是否存在用于闪存无效 L1 数据缓存的指令(ori 30,30,0 或 mtspr SPRN_TRIG2,rN),L1 数据缓存是否设置为只能由创建它们的线程使用的模式,bcctr[l] 指令是否阻止推测,以及是否提供了推测屏障指令(ori 31,31,0)。

behaviour 字段描述了软件应采取的防止意外信息泄露的措施,因此描述了硬件容易受到哪些漏洞的影响;具体来说,是否应在从内核返回到用户模式时刷新 L1 数据缓存,以及是否应在数组边界检查和数组访问之间放置推测屏障。

这些字段使用与新的 H_GET_CPU_CHARACTERISTICS 超级调用相同的位定义。

4.110 KVM_MEMORY_ENCRYPT_OP

功能:

基本

架构:

x86

类型:

vm ioctl、vcpu ioctl

参数:

一个不透明的平台特定结构体 (输入/输出)

返回值:

成功时为 0;出错时为 -1

如果平台支持创建加密 VM,则可以使用此 ioctl 发出平台特定的内存加密命令来管理这些加密 VM。

目前,此 ioctl 用于在 AMD 处理器上发出安全加密虚拟化 (SEV) 命令,以及在 Intel 处理器上发出可信域扩展 (TDX) 命令。详细命令在安全加密虚拟化 (SEV)英特尔可信域扩展 (TDX)中定义。

4.111 KVM_MEMORY_ENCRYPT_REG_REGION

功能:

基本

架构:

x86

类型:

系统

参数:

struct kvm_enc_region (输入)

返回值:

成功时为 0;出错时为 -1

此 ioctl 可用于注册可能包含加密数据的客户机内存区域(例如,客户机 RAM、SMRAM 等)。

它在启用 SEV 的客户机中使用。启用加密后,客户机内存区域可能包含加密数据。SEV 内存加密引擎使用一种调整,以便位于不同位置的两个相同的明文页面将具有不同的密文。因此,交换或移动这些页面的密文将不会导致交换明文。因此,重新定位(或迁移)SEV 客户机的物理支持页面将需要一些额外的步骤。

注意:当前的 SEV 密钥管理规范不提供交换或迁移(移动)密文页面的命令。因此,目前我们固定使用 ioctl 注册的客户机内存区域。

4.112 KVM_MEMORY_ENCRYPT_UNREG_REGION

功能:

基本

架构:

x86

类型:

系统

参数:

struct kvm_enc_region (输入)

返回值:

成功时为 0;出错时为 -1

此 ioctl 可用于注销使用上述 KVM_MEMORY_ENCRYPT_REG_REGION ioctl 注册的客户机内存区域。

4.113 KVM_HYPERV_EVENTFD

功能:

KVM_CAP_HYPERV_EVENTFD

架构:

x86

类型:

vm ioctl

参数:

struct kvm_hyperv_eventfd (输入)

此 ioctl (取消)注册一个 eventfd,以通过 SIGNAL_EVENT 超级调用接收来自客户机的指定 Hyper-V 连接 id 的通知,而不会导致用户退出。具有非零事件标志编号(位 24-31)的 SIGNAL_EVENT 超级调用仍会触发 KVM_EXIT_HYPERV_HCALL 用户退出。

struct kvm_hyperv_eventfd {
      __u32 conn_id;
      __s32 fd;
      __u32 flags;
      __u32 padding[3];
};

conn_id 字段应适合 24 位

#define KVM_HYPERV_CONN_ID_MASK               0x00ffffff

flags 字段的可接受值为

#define KVM_HYPERV_EVENTFD_DEASSIGN   (1 << 0)
返回值:

成功时返回 0,如果 conn_id 或 flags 超出允许范围则返回 -EINVAL,如果取消分配时 conn_id 未注册则返回 -ENOENT,如果分配时 conn_id 已注册则返回 -EEXIST

4.114 KVM_GET_NESTED_STATE

功能:

KVM_CAP_NESTED_STATE

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_nested_state (输入/输出)

返回值:

成功时为 0,出错时为 -1

错误

E2BIG

总状态大小超过用户指定的 “size” 值;所需的大小将写入 size 中。

struct kvm_nested_state {
      __u16 flags;
      __u16 format;
      __u32 size;

      union {
              struct kvm_vmx_nested_state_hdr vmx;
              struct kvm_svm_nested_state_hdr svm;

              /* Pad the header to 128 bytes.  */
              __u8 pad[120];
      } hdr;

      union {
              struct kvm_vmx_nested_state_data vmx[0];
              struct kvm_svm_nested_state_data svm[0];
      } data;
};

#define KVM_STATE_NESTED_GUEST_MODE           0x00000001
#define KVM_STATE_NESTED_RUN_PENDING          0x00000002
#define KVM_STATE_NESTED_EVMCS                0x00000004

#define KVM_STATE_NESTED_FORMAT_VMX           0
#define KVM_STATE_NESTED_FORMAT_SVM           1

#define KVM_STATE_NESTED_VMX_VMCS_SIZE        0x1000

#define KVM_STATE_NESTED_VMX_SMM_GUEST_MODE   0x00000001
#define KVM_STATE_NESTED_VMX_SMM_VMXON        0x00000002

#define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE 0x00000001

struct kvm_vmx_nested_state_hdr {
      __u64 vmxon_pa;
      __u64 vmcs12_pa;

      struct {
              __u16 flags;
      } smm;

      __u32 flags;
      __u64 preemption_timer_deadline;
};

struct kvm_vmx_nested_state_data {
      __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
      __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
};

此 ioctl 将 vcpu 的嵌套虚拟化状态从内核复制到用户空间。

可以通过将 KVM_CAP_NESTED_STATE 传递给 KVM_CHECK_EXTENSION ioctl() 来检索状态的最大大小。

4.115 KVM_SET_NESTED_STATE

功能:

KVM_CAP_NESTED_STATE

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_nested_state (输入)

返回值:

成功时为 0,出错时为 -1

这会将 vcpu 的 kvm_nested_state 结构体从用户空间复制到内核。有关 struct kvm_nested_state 的定义,请参阅 KVM_GET_NESTED_STATE。

4.116 KVM_(UN)REGISTER_COALESCED_MMIO

功能:

KVM_CAP_COALESCED_MMIO(用于合并 mmio)KVM_CAP_COALESCED_PIO(用于合并 pio)

架构:

全部

类型:

vm ioctl

参数:

struct kvm_coalesced_mmio_zone

返回值:

成功时为 0,出错时 < 0

合并 I/O 是一种性能优化,它会延迟硬件寄存器写入模拟,从而避免用户空间退出。它通常用于减少模拟频繁访问的硬件寄存器的开销。

当硬件寄存器配置为合并 I/O 时,写入访问不会退出到用户空间,并且它们的值会记录在内核和用户空间之间共享的环形缓冲区中。

如果可以延迟对硬件寄存器的一个或多个写入访问,直到读取或写入同一设备上的另一个硬件寄存器,则使用合并 I/O。最后一次访问将导致 vmexit,用户空间将在模拟之前处理来自环形缓冲区的访问。这将避免在重复写入时退出到用户空间。

合并 pio 基于合并 mmio。合并 mmio 和 pio 之间几乎没有区别,除了合并 pio 记录对 I/O 端口的访问。

4.117 KVM_CLEAR_DIRTY_LOG

功能:

KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2

架构:

x86, arm64, mips

类型:

vm ioctl

参数:

struct kvm_clear_dirty_log (输入)

返回值:

成功时为 0,出错时为 -1

/* for KVM_CLEAR_DIRTY_LOG */
struct kvm_clear_dirty_log {
      __u32 slot;
      __u32 num_pages;
      __u64 first_page;
      union {
              void __user *dirty_bitmap; /* one bit per page */
              __u64 padding;
      };
};

ioctl 根据在 struct kvm_clear_dirty_log 的 dirty_bitmap 字段中传递的位图,清除内存槽中页面的脏状态。位图的位 0 对应于内存槽中的页面 “first_page”,num_pages 是输入位图的位数大小。first_page 必须是 64 的倍数;num_pages 也必须是 64 的倍数,除非 first_page + num_pages 是内存槽的大小。对于输入位图中设置的每个位,对应的页面在 KVM 的脏位图中标记为 “clean”,并且重新启用该页面的脏跟踪(例如,通过写保护,或通过清除页表条目中的脏位)。

如果 KVM_CAP_MULTI_ADDRESS_SPACE 可用,则 slot 字段的位 16-31 指定您要清除脏状态的地址空间。有关 slot 字段用法的详细信息,请参阅 KVM_SET_USER_MEMORY_REGION。

当启用 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 时,此 ioctl 最有用;有关更多信息,请参阅该功能的描述。但是,只要 KVM_CHECK_EXTENSION 确认 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 存在,它就可以始终使用。

4.118 KVM_GET_SUPPORTED_HV_CPUID

功能:

KVM_CAP_HYPERV_CPUID (vcpu), KVM_CAP_SYS_HYPERV_CPUID (系统)

架构:

x86

类型:

系统 ioctl,vcpu ioctl

参数:

struct kvm_cpuid2 (in/out)

返回值:

成功时为 0,出错时为 -1

struct kvm_cpuid2 {
      __u32 nent;
      __u32 padding;
      struct kvm_cpuid_entry2 entries[0];
};

struct kvm_cpuid_entry2 {
      __u32 function;
      __u32 index;
      __u32 flags;
      __u32 eax;
      __u32 ebx;
      __u32 ecx;
      __u32 edx;
      __u32 padding[3];
};

此 ioctl 返回与 KVM 中 Hyper-V 模拟相关的 x86 cpuid 功能叶子。用户空间可以使用此 ioctl 返回的信息来构造呈现给使用 Hyper-V 增强的客户机(例如 Windows 或 Hyper-V 客户机)的 cpuid 信息。

此 ioctl 返回的 CPUID 功能叶子由 Hyper-V 顶级功能规范 (TLFS) 定义。这些叶子无法通过 KVM_GET_SUPPORTED_CPUID ioctl 获得,因为其中一些叶子与 KVM 功能叶子 (0x40000000, 0x40000001) 相交。

目前,返回以下 CPUID 叶子

  • HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS

  • HYPERV_CPUID_INTERFACE

  • HYPERV_CPUID_VERSION

  • HYPERV_CPUID_FEATURES

  • HYPERV_CPUID_ENLIGHTMENT_INFO

  • HYPERV_CPUID_IMPLEMENT_LIMITS

  • HYPERV_CPUID_NESTED_FEATURES

  • HYPERV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS

  • HYPERV_CPUID_SYNDBG_INTERFACE

  • HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES

用户空间通过传递一个 kvm_cpuid2 结构体来调用 KVM_GET_SUPPORTED_HV_CPUID,其中 “nent” 字段指示变量大小数组 “entries” 中的条目数。如果条目数太少而无法描述所有 Hyper-V 功能叶子,则会返回错误 (E2BIG)。如果该数量大于或等于 Hyper-V 功能叶子的数量,则 “nent” 字段将调整为 “entries” 数组中有效条目的数量,然后填充该数组。

“struct kvm_cpuid_entry2” 中的 “index” 和 “flags” 字段当前已保留,用户空间不应期望在那里获得任何特定值。

请注意,vcpu 版本的 KVM_GET_SUPPORTED_HV_CPUID 目前已弃用。与无条件地公开所有支持的功能位的系统 ioctl 不同,vcpu 版本具有以下怪癖

  • 仅当先前在相应的 vCPU 上启用了 Enlightened VMCS 时,才会公开 HYPERV_CPUID_NESTED_FEATURES 叶子和 HV_X64_ENLIGHTENED_VMCS_RECOMMENDED 功能位(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)。

  • HV_STIMER_DIRECT_MODE_AVAILABLE 位仅在使用内核 LAPIC 时公开。(假定已调用 KVM_CREATE_IRQCHIP)。

4.119 KVM_ARM_VCPU_FINALIZE

架构:

arm64

类型:

vcpu ioctl

参数:

int feature (输入)

返回值:

成功时为 0,出错时为 -1

错误

EPERM

未启用该功能,需要配置,或已完成

EINVAL

功能未知或不存在

feature 的可识别值

arm64

KVM_ARM_VCPU_SVE(需要 KVM_CAP_ARM_SVE)

完成指定 vcpu 功能的配置。

必须已经初始化 vcpu,并通过在 features[] 中设置适当的标志,通过成功的KVM_ARM_VCPU_INIT调用来启用受影响的功能。

对于受影响的 vcpu 功能,这是在使用 vcpu 之前必须执行的强制性步骤。

在 KVM_ARM_VCPU_INIT 和 KVM_ARM_VCPU_FINALIZE 之间,可以使用 KVM_SET_ONE_REG 等 ioctl 来配置该功能。应该执行的确切配置以及如何执行该配置取决于具体功能。

依赖于特定功能已完成的其他调用,例如 KVM_RUN、KVM_GET_REG_LIST、KVM_GET_ONE_REG 和 KVM_SET_ONE_REG,除非该功能已通过 KVM_ARM_VCPU_FINALIZE 调用完成,否则将失败并返回 -EPERM。

有关需要使用此 ioctl 完成的 vcpu 功能的详细信息,请参阅 KVM_ARM_VCPU_INIT。

4.120 KVM_SET_PMU_EVENT_FILTER

功能:

KVM_CAP_PMU_EVENT_FILTER

架构:

x86

类型:

vm ioctl

参数:

struct kvm_pmu_event_filter (输入)

返回值:

成功时为 0,出错时为 -1

错误

EFAULT

无法访问 args[0]

EINVAL

args[0] 包含过滤器或过滤器事件中的无效数据

E2BIG

nevents 太大

EBUSY

没有足够的内存来分配过滤器

struct kvm_pmu_event_filter {
      __u32 action;
      __u32 nevents;
      __u32 fixed_counter_bitmap;
      __u32 flags;
      __u32 pad[4];
      __u64 events[0];
};

此 ioctl 通过限制允许哪些事件选择和单元掩码组合来限制客户机可以编程的 PMU 事件集。

该参数包含将允许或拒绝的过滤器事件列表。

过滤器事件仅控制通用计数器;固定用途计数器由 fixed_counter_bitmap 控制。

“flags” 的有效值

``0``

要使用此模式,请清除 “flags” 字段。

在此模式下,每个事件将包含一个事件选择 + 单元掩码。

当客户机尝试编程 PMU 时,会将客户机的事件选择 + 单元掩码与过滤器事件进行比较,以确定客户机是否应具有访问权限。

KVM_PMU_EVENT_FLAG_MASKED_EVENTS:功能:KVM_CAP_PMU_EVENT_MASKED_EVENTS

在此模式下,每个过滤器事件将包含一个事件选择、掩码、匹配和排除值。要编码掩码事件,请使用

KVM_PMU_ENCODE_MASKED_ENTRY()

编码的事件将遵循此布局

Bits   Description
----   -----------
7:0    event select (low bits)
15:8   umask match
31:16  unused
35:32  event select (high bits)
36:54  unused
55     exclude bit
63:56  umask mask

当客户机尝试编程 PMU 时,将按照以下步骤确定客户机是否应具有访问权限

  1. 将客户机的事件选择与过滤器事件进行匹配。

  2. 如果找到匹配项,则将客户机的单元掩码与包含的过滤器事件的掩码和匹配值进行匹配。即 (unit mask & mask) == match && !exclude。

  3. 如果找到匹配项,则将客户机的单元掩码与排除的过滤器事件的掩码和匹配值进行匹配。即 (unit mask & mask) == match && exclude。

    1. 如果找到包含的匹配项并且未找到排除的匹配项,则过滤该事件。

    2. 对于其他所有内容,不要过滤该事件。

    1. 如果该事件被过滤并且是允许列表,则允许客户机编程该事件。

    2. 如果该事件被过滤并且是拒绝列表,则不允许客户机编程该事件。

当设置新的 pmu 事件过滤器时,如果在 Intel 上调用时设置了任何未使用的字段或设置了事件选择中的任何高位 (35:32),则会返回 -EINVAL。

“action” 的有效值

#define KVM_PMU_EVENT_ALLOW 0
#define KVM_PMU_EVENT_DENY 1

通过此 API,KVM 用户空间还可以通过配置 “action” 和 “fixed_counter_bitmap” 字段来控制 VM 固定计数器(如果有)的行为。

具体来说,KVM 在确定是否允许客户机 FixCtr[i] 计数其预定义的固定事件时,遵循以下伪代码

FixCtr[i]_is_allowed = (action == ALLOW) && (bitmap & BIT(i)) ||
  (action == DENY) && !(bitmap & BIT(i));
FixCtr[i]_is_denied = !FixCtr[i]_is_allowed;

KVM 始终使用 fixed_counter_bitmap,用户空间有责任确保正确设置 fixed_counter_bitmap,例如,如果用户空间想要定义一个仅影响通用计数器的过滤器。

请注意,“events” 字段也适用于固定计数器的硬编码 event_select 和 unit_mask 值。如果两者之间存在矛盾,“fixed_counter_bitmap” 的优先级高于 “events”。

4.121 KVM_PPC_SVM_OFF

功能:

基本

架构:

powerpc

类型:

vm ioctl

参数:

返回值:

成功完成时返回 0,

错误

EINVAL

如果 ultravisor 未能终止安全客户机

ENOMEM

如果 hypervisor 未能为客户机分配新的基数页表

此 ioctl 用于关闭客户机的安全模式或将客户机从安全模式转换为正常模式。这在重置客户机时调用。如果为正常客户机调用,则此操作无效。

此 ioctl 发出 ultravisor 调用以终止安全客户机,取消固定 VPA 页面,并释放 hypervisor 用于跟踪安全页面的所有设备页面。

4.122 KVM_S390_NORMAL_RESET

功能:

KVM_CAP_S390_VCPU_RESETS

架构:

s390

类型:

vcpu ioctl

参数:

返回值:

0

此 ioctl 根据 POP(操作原理)中的 cpu 重置定义重置 VCPU 寄存器和控制结构。

4.123 KVM_S390_INITIAL_RESET

功能:

基本

架构:

s390

类型:

vcpu ioctl

参数:

返回值:

0

此 ioctl 根据 POP 中的初始 cpu 重置定义重置 VCPU 寄存器和控制结构。但是,cpu 不会进入 ESA 模式。此重置是正常重置的超集。

4.124 KVM_S390_CLEAR_RESET

功能:

KVM_CAP_S390_VCPU_RESETS

架构:

s390

类型:

vcpu ioctl

参数:

返回值:

0

此 ioctl 根据 POP 中的清除 cpu 重置定义重置 VCPU 寄存器和控制结构。但是,cpu 不会进入 ESA 模式。此重置是初始重置的超集。

4.125 KVM_S390_PV_COMMAND

功能:

KVM_CAP_S390_PROTECTED

架构:

s390

类型:

vm ioctl

参数:

struct kvm_pv_cmd

返回值:

成功时为 0,出错时 < 0

struct kvm_pv_cmd {
      __u32 cmd;      /* Command to be executed */
      __u16 rc;       /* Ultravisor return code */
      __u16 rrc;      /* Ultravisor return reason code */
      __u64 data;     /* Data or address */
      __u32 flags;    /* flags for future extensions. Must be 0 for now */
      __u32 reserved[3];
};

Ultravisor 返回代码 如果已执行 Ultravisor 调用以实现该命令预期的结果,则内核会提供 Ultravisor 返回(原因)代码。因此,它们独立于 IOCTL 返回代码。如果 KVM 更改 rc,其值将始终大于 0,因此建议在发出 PV 命令之前将其设置为 0,以便能够检测到 rc 的更改。

cmd 值

KVM_PV_ENABLE

分配内存并向 Ultravisor 注册 VM,从而将内存捐赠给 Ultravisor,这将使 KVM 无法访问该内存。所有现有的 CPU 都转换为受保护的 CPU。在此命令成功后,通过热插拔添加的任何 CPU 在创建期间也会变为受保护的 CPU。

错误

EINTR

未屏蔽的信号正在挂起

KVM_PV_DISABLE

从 Ultravisor 取消注册 VM,并回收已捐赠给 Ultravisor 的内存,使其再次可供内核使用。所有已注册的 VCPU 都转换回非受保护的 VCPU。如果先前已使用 KVM_PV_ASYNC_CLEANUP_PREPARE 准备了受保护的 VM 以进行异步拆卸,并且随后未使用 KVM_PV_ASYNC_CLEANUP_PERFORM 拆卸,则它将在此调用中与当前受保护的 VM 一起拆卸。

KVM_PV_VM_SET_SEC_PARMS

将 VM 内存中的镜像头传递给 Ultravisor,以准备镜像解包和验证。

KVM_PV_VM_UNPACK

解包(保护和解密)加密的启动镜像的页面。

KVM_PV_VM_VERIFY

验证解包镜像的完整性。只有在此成功后,才允许 KVM 启动受保护的 VCPU。

KVM_PV_INFO
功能:

KVM_CAP_S390_PROTECTED_DUMP

提供一个 API,该 API 通过子命令向用户空间提供与 Ultravisor 相关的数据。len_max 是用户空间缓冲区的大小,len_written 是 KVM 指示实际写入该缓冲区的字节数。如果在将来添加了更多响应字段,则可以使用 len_written 来确定有效字段。

enum pv_cmd_info_id {
   KVM_PV_INFO_VM,
   KVM_PV_INFO_DUMP,
};

struct kvm_s390_pv_info_header {
   __u32 id;
   __u32 len_max;
   __u32 len_written;
   __u32 reserved;
};

struct kvm_s390_pv_info {
   struct kvm_s390_pv_info_header header;
   struct kvm_s390_pv_info_dump dump;
   struct kvm_s390_pv_info_vm vm;
};

子命令

KVM_PV_INFO_VM

此子命令提供 PV 主机的基本 Ultravisor 信息。这些值也可能作为 sysfs 固件 UV 查询接口中的文件导出,但它们在此 API 中更易于程序使用。

installed calls 和 feature_indication 成员提供已安装的 UV 调用和 UV 的其他功能指示。

max_* 成员提供有关最大 PV vcpu、PV 客户机和 PV 客户机内存大小的信息。

struct kvm_s390_pv_info_vm {
  __u64 inst_calls_list[4];
  __u64 max_cpus;
  __u64 max_guests;
  __u64 max_guest_addr;
  __u64 feature_indication;
};
KVM_PV_INFO_DUMP

此子命令提供与转储 PV 客户机相关的信息。

struct kvm_s390_pv_info_dump {
  __u64 dump_cpu_buffer_len;
  __u64 dump_config_mem_buffer_per_1m;
  __u64 dump_config_finalize_len;
};
KVM_PV_DUMP
功能:

KVM_CAP_S390_PROTECTED_DUMP

提供一个 API,该 API 提供有助于转储受保护 VM 的调用。

struct kvm_s390_pv_dmp {
  __u64 subcmd;
  __u64 buff_addr;
  __u64 buff_len;
  __u64 gaddr;              /* For dump storage state */
};

子命令

KVM_PV_DUMP_INIT

初始化受保护 VM 的转储过程。如果此调用不成功,则所有其他子命令将失败并返回 -EINVAL。如果尚未完成转储过程,则此子命令将返回 -EINVAL。

并非所有 PV vm 都可以转储,所有者需要在 SE 标头中设置 dump allowed PCF 位 34 以允许转储。

KVM_PV_DUMP_CONFIG_STOR_STATE

存储以绝对客户机地址 (gaddr) 指定的 1MB 块开始的 buff_len 字节的调整组件值。buff_len 需要与 conf_dump_storage_state_len 对齐,并且至少 >= 转储 uv_info 数据提供的 conf_dump_storage_state_len 值。即使返回错误 rc,也可能会写入 buff_user。例如,如果在写入第一页数据后遇到故障。

KVM_PV_DUMP_COMPLETE

如果子命令成功,则完成转储过程,并允许再次调用 KVM_PV_DUMP_INIT。

成功后,conf_dump_finalize_len 字节的完成数据将存储到 buff_addr。完成数据包含密钥派生种子、IV、调整 nonce 和加密密钥,以及以后解密转储所需的所有身份验证标记。

KVM_PV_ASYNC_CLEANUP_PREPARE
功能:

KVM_CAP_S390_PROTECTED_ASYNC_DISABLE

准备当前受保护的 VM 以进行异步拆卸。当前受保护的 VM 使用的大多数资源将被留出用于后续的异步拆卸。然后,当前受保护的 VM 将立即恢复执行,作为非受保护的 VM。任何时候最多只能有一个受保护的 VM 准备进行异步拆卸。如果先前已准备好拆卸受保护的 VM,但未随后调用 KVM_PV_ASYNC_CLEANUP_PERFORM,则此调用将失败。在这种情况下,用户空间进程应发出正常的 KVM_PV_DISABLE。使用此调用留出的资源将需要使用后续的 KVM_PV_ASYNC_CLEANUP_PERFORM 或 KVM_PV_DISABLE 调用进行清理,否则它们将在 KVM 终止时进行清理。只要清理开始,就可以再次调用 KVM_PV_ASYNC_CLEANUP_PREPARE,即在 KVM_PV_ASYNC_CLEANUP_PERFORM 完成之前。

KVM_PV_ASYNC_CLEANUP_PERFORM
功能:

KVM_CAP_S390_PROTECTED_ASYNC_DISABLE

拆卸先前已使用 KVM_PV_ASYNC_CLEANUP_PREPARE 准备拆卸的受保护的 VM。在此命令执行期间,将释放已留出的资源。理想情况下,此 PV 命令应由用户空间从单独的线程发出。如果收到致命信号(或该进程自然终止),该命令将立即终止而不完成,并且正常的 KVM 关闭过程将负责清理所有剩余的受保护的 VM,包括其拆卸被进程终止中断的 VM。

4.126 KVM_XEN_HVM_SET_ATTR

功能:

KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO

架构:

x86

类型:

vm ioctl

参数:

struct kvm_xen_hvm_attr

返回值:

成功时为 0,出错时 < 0

struct kvm_xen_hvm_attr {
      __u16 type;
      __u16 pad[3];
      union {
              __u8 long_mode;
              __u8 vector;
              __u8 runstate_update_flag;
              union {
                      __u64 gfn;
                      __u64 hva;
              } shared_info;
              struct {
                      __u32 send_port;
                      __u32 type; /* EVTCHNSTAT_ipi / EVTCHNSTAT_interdomain */
                      __u32 flags;
                      union {
                              struct {
                                      __u32 port;
                                      __u32 vcpu;
                                      __u32 priority;
                              } port;
                              struct {
                                      __u32 port; /* Zero for eventfd */
                                      __s32 fd;
                              } eventfd;
                              __u32 padding[4];
                      } deliver;
              } evtchn;
              __u32 xen_version;
              __u64 pad[8];
      } u;
};

类型值

KVM_XEN_ATTR_TYPE_LONG_MODE

设置 VM 的 ABI 模式为 32 位或 64 位(长模式)。 这决定了暴露给 VM 的 shared_info 页面的布局。

KVM_XEN_ATTR_TYPE_SHARED_INFO

设置 Xen shared_info 页面所在的客户机物理帧编号。请注意,虽然 Xen 将前 32 个 vCPU 的 vcpu_info 放置在 shared_info 页面中,但 KVM 不会自动执行此操作,而是要求显式使用 KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO 或 KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA,即使给定 vCPU 的 vcpu_info 位于 shared_info 页面的“默认”位置。 这是因为 KVM 可能不知道用作 vcpu_info[] 数组索引的 Xen CPU id,因此可能知道正确的默认位置。

请注意,KVM 可能会不断写入 shared_info 页面;它包含用于向 Xen 客户机传递中断的事件通道位图,以及其他内容。 它不受脏跟踪机制的约束——KVM 不会显式地将页面标记为脏,每次向客户机传递事件通道中断! 因此,如果任何 vCPU 正在运行或任何事件通道中断可以路由到客户机,则用户空间应始终假设指定的 GFN 是脏的。

将 gfn 设置为 KVM_XEN_INVALID_GFN 将禁用 shared_info 页面。

KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA

如果 Xen 功能中也设置了 KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA 标志,则可以使用此属性设置 shared_info 页面所在的用户空间地址,该地址将始终固定在 VMM 中,而不管它映射在客户机物理地址空间的什么位置。 此属性应优先于 KVM_XEN_ATTR_TYPE_SHARED_INFO 使用,因为它避免了在客户机物理地址空间中重新映射页面时,不必要地使内部缓存失效。

将 hva 设置为零将禁用 shared_info 页面。

KVM_XEN_ATTR_TYPE_UPCALL_VECTOR

设置用于传递 Xen 事件通道 upcall 的异常向量。 这是由 hypervisor 直接注入的 HVM 范围向量(不是通过本地 APIC),通常由客户机通过 HVM_PARAM_CALLBACK_IRQ 配置。 可以通过将其设置为零来再次禁用它(例如,对于客户机 SHUTDOWN_soft_reset)。

KVM_XEN_ATTR_TYPE_EVTCHN

当 KVM_CAP_XEN_HVM ioctl 指示支持 KVM_XEN_HVM_CONFIG_EVTCHN_SEND 功能时,此属性可用。 它配置一个出站端口号,用于拦截来自客户机的 EVTCHNOP_send 请求。 给定的发送端口号可以被定向回客户机上指定的 vCPU(通过 APIC ID)/端口/优先级,或者触发 eventfd 上的事件。 vCPU 和优先级可以通过在后续调用中设置 KVM_XEN_EVTCHN_UPDATE 来更改,但对于给定的发送端口,其他字段不能更改。 通过在 flags 字段中使用 KVM_XEN_EVTCHN_DEASSIGN 来删除端口映射。 在 flags 字段中传递 KVM_XEN_EVTCHN_RESET 会删除所有出站事件通道的拦截。 flags 字段的值是互斥的,不能作为位掩码组合。

KVM_XEN_ATTR_TYPE_XEN_VERSION

当 KVM_CAP_XEN_HVM ioctl 指示支持 KVM_XEN_HVM_CONFIG_EVTCHN_SEND 功能时,此属性可用。 它配置在客户机调用 XENVER_version 调用时返回给客户机的 32 位版本代码; 通常 (XEN_MAJOR << 16 | XEN_MINOR)。 PV Xen 客户机通常会将其用作虚拟 hypercall 以触发事件通道传递,因此在内核中响应而无需退出到用户空间是有益的。

KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG

当 KVM_CAP_XEN_HVM ioctl 指示支持 KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG 时,此属性可用。 它启用 XEN_RUNSTATE_UPDATE 标志,该标志允许客户机 vCPU 安全地读取其他 vCPU 的 vcpu_runstate_info。 Xen 客户机通过 HYPERVISOR_vm_assist hypercall 的 VMASST_TYPE_runstate_update_flag 启用此功能。

4.127 KVM_XEN_HVM_GET_ATTR

功能:

KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO

架构:

x86

类型:

vm ioctl

参数:

struct kvm_xen_hvm_attr

返回值:

成功时为 0,出错时 < 0

允许读取 Xen VM 属性。 对于结构和类型,请参见上面的 KVM_XEN_HVM_SET_ATTR。 KVM_XEN_ATTR_TYPE_EVTCHN 属性无法读取。

4.128 KVM_XEN_VCPU_SET_ATTR

功能:

KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_xen_vcpu_attr

返回值:

成功时为 0,出错时 < 0

struct kvm_xen_vcpu_attr {
      __u16 type;
      __u16 pad[3];
      union {
              __u64 gpa;
              __u64 pad[4];
              struct {
                      __u64 state;
                      __u64 state_entry_time;
                      __u64 time_running;
                      __u64 time_runnable;
                      __u64 time_blocked;
                      __u64 time_offline;
              } runstate;
              __u32 vcpu_id;
              struct {
                      __u32 port;
                      __u32 priority;
                      __u64 expires_ns;
              } timer;
              __u8 vector;
      } u;
};

类型值

KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO

设置给定 vCPU 的 vcpu_info 的客户机物理地址。 与 VM 的 shared_info 页面一样,如果启用了事件通道中断传递,则可以在任何时间弄脏相应的页面,因此用户空间应始终假设该页面是脏的,而无需依赖脏日志记录。 将 gpa 设置为 KVM_XEN_INVALID_GPA 将禁用 vcpu_info。

KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO_HVA

如果 Xen 功能中也设置了 KVM_XEN_HVM_CONFIG_SHARED_INFO_HVA 标志,则可以使用此属性设置给定 vCPU 的 vcpu_info 的用户空间地址。 它应该只在 vcpu_info 位于 shared_info 页面的“默认”位置时使用。 在这种情况下,可以安全地假设用户空间地址不会更改,因为 shared_info 页面是客户机内存的覆盖,并且无论它映射在客户机物理地址空间的什么位置,都保持在固定的主机地址,因此如果修改了客户机内存布局,可以避免不必要地使内部缓存失效。 如果 vcpu_info 不位于“默认”位置,则不能保证它保持在相同的主机地址,因此需要上述缓存失效。

KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO

设置给定 vCPU 的附加 pvclock 结构的客户机物理地址。 这通常用于客户机 vsyscall 支持。 将 gpa 设置为 KVM_XEN_INVALID_GPA 将禁用该结构。

KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR

设置给定 vCPU 的 vcpu_runstate_info 的客户机物理地址。 这是 Xen 客户机如何跟踪 CPU 状态(如窃取时间)的方式。 将 gpa 设置为 KVM_XEN_INVALID_GPA 将禁用运行状态区域。

KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT

从结构的 .u.runstate.state 成员设置给定 vCPU 的运行状态 (RUNSTATE_running/_runnable/_blocked/_offline)。 KVM 自动计算运行和可运行时间,但阻塞和离线状态仅显式输入。

KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA

从结构的 .u.runstate 成员设置 vCPU 运行状态数据的所有字段,包括当前运行状态。 state_entry_time 必须等于其他四个时间的总和。

KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST

此操作 *添加* 结构的 .u.runstate 成员的内容到给定 vCPU 的运行状态数据的相应成员,从而允许原子调整运行状态时间。 对 state_entry_time 的调整必须等于对其他四个时间的调整之和。 state 字段必须设置为 -1,或者设置为有效的运行状态值(RUNSTATE_running、RUNSTATE_runnable、RUNSTATE_blocked 或 RUNSTATE_offline),以设置调整后的 state_entry_time 的当前计算状态。

KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID

当 KVM_CAP_XEN_HVM ioctl 指示支持 KVM_XEN_HVM_CONFIG_EVTCHN_SEND 功能时,此属性可用。 它设置给定 vCPU 的 Xen vCPU ID,以允许 KVM 拦截与计时器相关的 VCPU 操作。

KVM_XEN_VCPU_ATTR_TYPE_TIMER

当 KVM_CAP_XEN_HVM ioctl 指示支持 KVM_XEN_HVM_CONFIG_EVTCHN_SEND 功能时,此属性可用。 它设置 vCPU 的 VIRQ_TIMER 的事件通道端口/优先级,以及允许保存/恢复挂起的计时器。 将计时器端口设置为零会禁用内核对单发计时器的处理。

KVM_XEN_VCPU_ATTR_TYPE_UPCALL_VECTOR

当 KVM_CAP_XEN_HVM ioctl 指示支持 KVM_XEN_HVM_CONFIG_EVTCHN_SEND 功能时,此属性可用。 它设置每个 vCPU 的本地 APIC upcall 向量,该向量由 Xen 客户机使用 HVMOP_set_evtchn_upcall_vector hypercall 配置。 这通常由 Windows 客户机使用,并且与使用 HVM_PARAM_CALLBACK_IRQ 配置的 HVM 范围 upcall 向量不同。 通过将向量设置为零来禁用它。

4.129 KVM_XEN_VCPU_GET_ATTR

功能:

KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_xen_vcpu_attr

返回值:

成功时为 0,出错时 < 0

允许读取 Xen vCPU 属性。 对于结构和类型,请参见上面的 KVM_XEN_VCPU_SET_ATTR。

KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 类型不能与 KVM_XEN_VCPU_GET_ATTR ioctl 一起使用。

4.130 KVM_ARM_MTE_COPY_TAGS

功能:

KVM_CAP_ARM_MTE

架构:

arm64

类型:

vm ioctl

参数:

struct kvm_arm_copy_mte_tags

返回值:

复制的字节数,出错时 < 0(参数不正确时为 -EINVAL,无法访问内存时为 -EFAULT)。

struct kvm_arm_copy_mte_tags {
      __u64 guest_ipa;
      __u64 length;
      void __user *addr;
      __u64 flags;
      __u64 reserved[2];
};

将内存标记扩展 (MTE) 标记复制到/从客户机标记内存复制。 guest_ipalength 字段必须是 PAGE_SIZE 对齐的。 length 不能大于 2^31 - PAGE_SIZE 字节。 addr 字段必须指向将从中复制标记或复制到其中的缓冲区。

flags 指定复制的方向,可以是 KVM_ARM_TAGS_TO_GUESTKVM_ARM_TAGS_FROM_GUEST

存储标记的缓冲区的大小是 (length / 16) 字节(MTE 中的粒度为 16 字节长)。 每个字节包含单个标记值。 这与 PTRACE_PEEKMTETAGSPTRACE_POKEMTETAGS 的格式匹配。

如果在复制任何数据之前发生错误,则返回负错误代码。 如果在发生错误之前已复制一些标记,则返回成功复制的字节数。 如果调用成功完成,则返回 length

4.131 KVM_GET_SREGS2

功能:

KVM_CAP_SREGS2

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_sregs2 (out)

返回值:

成功时为 0,出错时为 -1

从 vcpu 读取特殊寄存器。 此 ioctl(如果支持)替换 KVM_GET_SREGS。

struct kvm_sregs2 {
        /* out (KVM_GET_SREGS2) / in (KVM_SET_SREGS2) */
        struct kvm_segment cs, ds, es, fs, gs, ss;
        struct kvm_segment tr, ldt;
        struct kvm_dtable gdt, idt;
        __u64 cr0, cr2, cr3, cr4, cr8;
        __u64 efer;
        __u64 apic_base;
        __u64 flags;
        __u64 pdptrs[4];
};

kvm_sregs2 的 flags 值

KVM_SREGS2_FLAGS_PDPTRS_VALID

指示该结构包含有效的 PDPTR 值。

4.132 KVM_SET_SREGS2

功能:

KVM_CAP_SREGS2

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_sregs2 (in)

返回值:

成功时为 0,出错时为 -1

将特殊寄存器写入 vcpu。 有关数据结构,请参见 KVM_GET_SREGS2。 此 ioctl(如果支持)替换 KVM_SET_SREGS。

4.133 KVM_GET_STATS_FD

功能:

KVM_CAP_STATS_BINARY_FD

架构:

全部

类型:

vm ioctl、vcpu ioctl

参数:

返回值:

成功时为统计信息文件描述符,出错时 < 0

错误

ENOMEM

如果由于缺少内存而无法创建 fd

EMFILE

如果打开的文件数超过限制

返回的文件描述符可用于以二进制格式读取 VM/vCPU 统计信息数据。 文件描述符中的数据由以下方式组织的四个块组成

标头

id 字符串

描述符

统计信息数据

除了从偏移量 0 开始的标头之外,请注意不能保证这四个块是相邻的或以上述顺序排列; id、描述符和数据块的偏移量在标头中找到。 但是,所有四个块都与文件中的 64 位偏移量对齐,并且它们不重叠。

除了数据块之外,所有块都是不可变的。 用户空间可以在检索文件描述符后仅读取它们一次,然后使用 preadlseek 重复读取统计信息。

所有数据均采用系统字节序。

标头的格式如下

struct kvm_stats_header {
        __u32 flags;
        __u32 name_size;
        __u32 num_desc;
        __u32 id_offset;
        __u32 desc_offset;
        __u32 data_offset;
};

flags 字段目前未使用。 它始终读取为 0。

name_size 字段是统计信息名称字符串的大小(以字节为单位)(包括尾随“0”),该字符串包含在“id 字符串”块中,并附加到每个描述符的末尾。

num_desc 字段是描述符块中包含的描述符的数量。(数据块中的实际值数量可能更大,因为每个描述符可能包含多个值)。

id_offset 字段是 id 字符串从文件描述符指示的文件开始处的偏移量。 它是 8 的倍数。

desc_offset 字段是描述符块从文件描述符指示的文件开始处的偏移量。 它是 8 的倍数。

data_offset 字段是统计信息数据块从文件描述符指示的文件开始处的偏移量。 它是 8 的倍数。

id 字符串块包含一个字符串,该字符串标识在其上调用 KVM_GET_STATS_FD 的文件描述符。 该块的大小(包括尾随 '\0')由标头中的 name_size 字段指示。

描述符块仅需要在文件描述符的生存期内读取一次,该文件描述符包含一系列 struct kvm_stats_desc,每个描述符后跟一个大小为 name_size 的字符串。

#define KVM_STATS_TYPE_SHIFT            0
#define KVM_STATS_TYPE_MASK             (0xF << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_CUMULATIVE       (0x0 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_INSTANT          (0x1 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_PEAK             (0x2 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_LINEAR_HIST      (0x3 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_LOG_HIST         (0x4 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_MAX              KVM_STATS_TYPE_LOG_HIST

#define KVM_STATS_UNIT_SHIFT            4
#define KVM_STATS_UNIT_MASK             (0xF << KVM_STATS_UNIT_SHIFT)
#define KVM_STATS_UNIT_NONE             (0x0 << KVM_STATS_UNIT_SHIFT)
#define KVM_STATS_UNIT_BYTES            (0x1 << KVM_STATS_UNIT_SHIFT)
#define KVM_STATS_UNIT_SECONDS          (0x2 << KVM_STATS_UNIT_SHIFT)
#define KVM_STATS_UNIT_CYCLES           (0x3 << KVM_STATS_UNIT_SHIFT)
#define KVM_STATS_UNIT_BOOLEAN          (0x4 << KVM_STATS_UNIT_SHIFT)
#define KVM_STATS_UNIT_MAX              KVM_STATS_UNIT_BOOLEAN

#define KVM_STATS_BASE_SHIFT            8
#define KVM_STATS_BASE_MASK             (0xF << KVM_STATS_BASE_SHIFT)
#define KVM_STATS_BASE_POW10            (0x0 << KVM_STATS_BASE_SHIFT)
#define KVM_STATS_BASE_POW2             (0x1 << KVM_STATS_BASE_SHIFT)
#define KVM_STATS_BASE_MAX              KVM_STATS_BASE_POW2

struct kvm_stats_desc {
        __u32 flags;
        __s16 exponent;
        __u16 size;
        __u32 offset;
        __u32 bucket_size;
        char name[];
};

flags 字段包含此描述符描述的统计信息数据的类型和单位。 它的字节序是 CPU 原生的。 支持以下标志

flags 的位 0-3 编码类型

  • KVM_STATS_TYPE_CUMULATIVE 统计信息报告累积计数。 数据的值只能增加。 KVM 中使用的大多数计数器都是这种类型。 此类型的相应 size 字段始终为 1。 所有累积统计信息数据都是读/写的。

  • KVM_STATS_TYPE_INSTANT 统计信息报告瞬时值。 它的值可以增加或减少。 此类型通常用作某些资源的度量,例如脏页的数量、大页的数量等。所有瞬时统计信息都是只读的。 此类型的相应 size 字段始终为 1。

  • KVM_STATS_TYPE_PEAK 统计信息数据报告峰值,例如哈希表桶中的最大项数、最长的等待时间等等。 数据的值只能增加。 此类型的相应 size 字段始终为 1。

  • KVM_STATS_TYPE_LINEAR_HIST 统计信息报告为线性直方图。 桶的数量由 size 字段指定。 桶的大小由 hist_param 字段指定。 第 N 个桶的范围(1 <= N < size)是 [hist_param``*(N-1), ``hist_param``*N), while the range of the last bucket is [``hist_param``*(``size-1), +INF)。 (+INF 表示正无穷大值。)

  • KVM_STATS_TYPE_LOG_HIST 统计信息报告为对数直方图。 桶的数量由 size 字段指定。 第一个桶的范围是 [0, 1),而最后一个桶的范围是 [pow(2, size-2), +INF)。 否则,第 N 个桶(1 < N < size)覆盖 [pow(2, N-2), pow(2, N-1))。

flags 的位 4-7 编码单位

  • KVM_STATS_UNIT_NONE 统计信息数据的值没有单位。 这通常意味着该值是事件的简单计数器。

  • KVM_STATS_UNIT_BYTES 它指示统计信息数据用于测量内存大小,单位为字节、KiByte、MiByte、GiByte 等。 数据的单位由描述符中的 exponent 字段确定。

  • KVM_STATS_UNIT_SECONDS 它指示统计信息数据用于测量时间或延迟。

  • KVM_STATS_UNIT_CYCLES 它指示统计信息数据用于测量 CPU 时钟周期。

  • KVM_STATS_UNIT_BOOLEAN 它指示统计信息将始终为 0 或 1。 “峰值”类型的布尔统计信息永远不会从 1 返回到 0。 布尔统计信息可以是线性直方图(具有两个桶),但不能是对数直方图。

请注意,对于直方图,单位适用于桶范围,而桶值指示有多少个样本落入桶的范围内。

flags 的位 8-11 与 exponent 一起编码单位的比例

  • KVM_STATS_BASE_POW10 比例基于 10 的幂。 它用于测量时间和 CPU 时钟周期。 例如,exponent 为 -9 可以与 KVM_STATS_UNIT_SECONDS 一起使用,以表示单位是纳秒。

  • KVM_STATS_BASE_POW2 比例基于 2 的幂。 它用于测量内存大小。 例如,exponent 为 20 可以与 KVM_STATS_UNIT_BYTES 一起使用,以表示单位是 MiB。

size 字段是此统计信息数据的值的数量。 对于大多数简单统计信息,它的值通常为 1。 1 表示它包含一个无符号 64 位数据。

offset 字段是从数据块的开始到相应统计信息数据的开始的偏移量。

bucket_size 字段用作直方图统计信息数据的参数。 它仅由线性直方图统计信息数据使用,指定桶的大小,单位由 flags 的位 4-11 以及 exponent 表示。

name 字段是统计信息数据的名称字符串。 名称字符串从 struct kvm_stats_desc 的末尾开始。 最大长度(包括尾随 '\0')由标头中的 name_size 指示。

统计信息数据块包含一个 64 位值的数组,其顺序与描述符块中的描述符相同。

4.134 KVM_GET_XSAVE2

功能:

KVM_CAP_XSAVE2

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_xsave (out)

返回值:

成功时为 0,出错时为 -1

struct kvm_xsave {
      __u32 region[1024];
      __u32 extra[0];
};

此 ioctl 会将当前 vcpu 的 xsave 结构复制到用户空间。 它复制 KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) 在 vm 文件描述符上调用时返回的字节数。 KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) 返回的大小值将始终至少为 4096。 目前,只有当使用 arch_prctl() 启用了动态功能时,它才会大于 4096,但这可能会在将来发生变化。

struct kvm_xsave 中状态保存区域的偏移量遵循主机上 CPUID 叶 0xD 的内容。

4.135 KVM_XEN_HVM_EVTCHN_SEND

功能:

KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_EVTCHN_SEND

架构:

x86

类型:

vm ioctl

参数:

struct kvm_irq_routing_xen_evtchn

返回值:

成功时为 0,出错时 < 0

struct kvm_irq_routing_xen_evtchn {
     __u32 port;
     __u32 vcpu;
     __u32 priority;
};

此 ioctl 将事件通道中断直接注入到客户机 vCPU。

4.136 KVM_S390_PV_CPU_COMMAND

功能:

KVM_CAP_S390_PROTECTED_DUMP

架构:

s390

类型:

vcpu ioctl

参数:

返回值:

成功时为 0,出错时 < 0

此 ioctl 与 KVM_S390_PV_COMMAND 非常相似,但处理 vcpu 的请求。 它重复使用 kvm_s390_pv_dmp 结构,因此也共享命令 id。

command

KVM_PV_DUMP

提供一个 API,该 API 提供有助于转储受保护的 VM 的 vcpu 的调用。

subcommand

KVM_PV_DUMP_CPU

提供加密的转储数据,例如寄存器值。 返回的数据的长度由 uv_info.guest_cpu_stor_len 提供。

4.137 KVM_S390_ZPCI_OP

功能:

KVM_CAP_S390_ZPCI_OP

架构:

s390

类型:

vm ioctl

参数:

struct kvm_s390_zpci_op (in)

返回值:

成功时为 0,出错时 <0

用于管理 zPCI 设备的硬件辅助虚拟化功能。

参数通过以下结构指定

struct kvm_s390_zpci_op {
      /* in */
      __u32 fh;               /* target device */
      __u8  op;               /* operation to perform */
      __u8  pad[3];
      union {
              /* for KVM_S390_ZPCIOP_REG_AEN */
              struct {
                      __u64 ibv;      /* Guest addr of interrupt bit vector */
                      __u64 sb;       /* Guest addr of summary bit */
                      __u32 flags;
                      __u32 noi;      /* Number of interrupts */
                      __u8 isc;       /* Guest interrupt subclass */
                      __u8 sbo;       /* Offset of guest summary bit vector */
                      __u16 pad;
              } reg_aen;
              __u64 reserved[8];
      } u;
};

操作的类型在“op”字段中指定。 KVM_S390_ZPCIOP_REG_AEN 用于为适配器事件通知解释注册 VM,这将允许固件将适配器事件直接传递到 VM,KVM 提供备份传递机制; KVM_S390_ZPCIOP_DEREG_AEN 用于随后禁用适配器事件通知的解释。

目标 zPCI 功能也必须通过“fh”字段指定。 对于 KVM_S390_ZPCIOP_REG_AEN 操作,必须通过“reg_aen”结构提供其他信息以建立固件传递。

“pad”和“reserved”字段可用于未来的扩展,用户空间应将其设置为 0。

4.138 KVM_ARM_SET_COUNTER_OFFSET

功能:

KVM_CAP_COUNTER_OFFSET

架构:

arm64

类型:

vm ioctl

参数:

struct kvm_arm_counter_offset (in)

返回值:

成功时为 0,出错时 < 0

此功能指示用户空间能够使用 KVM_ARM_SET_CNT_OFFSET ioctl 和以下数据结构将单个 VM 范围的偏移量应用于客户机查看的虚拟计数器和物理计数器

struct kvm_arm_counter_offset {
        __u64 counter_offset;
        __u64 reserved;
};

该偏移量描述了从虚拟和物理计数器视图中减去的计数器周期数(类似于 CNTVOFF_EL2 和 CNTPOFF_EL2 系统寄存器的效果,但仅是全局的)。 该偏移量始终适用于此 VM 的所有 vcpu(已创建或在此 ioctl 之后创建)。

用户空间有责任根据客户机计数器的先前值来计算偏移量。

“reserved”字段的任何非 0 值都可能导致返回错误 (-EINVAL)。 如果并发发出任何 vcpu ioctl,此 ioctl 也会返回 -EBUSY。

请注意,使用此 ioctl 会导致 KVM 忽略后续用户空间使用 SET_ONE_REG 接口写入 CNTVCT_EL0 和 CNTPCT_EL0 寄存器的操作。 不会返回任何错误,但不会应用生成的偏移量。

4.139 KVM_ARM_GET_REG_WRITABLE_MASKS

功能:

KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES

架构:

arm64

类型:

vm ioctl

参数:

struct reg_mask_range (in/out)

返回值:

成功时为 0,出错时 < 0

#define KVM_ARM_FEATURE_ID_RANGE        0
#define KVM_ARM_FEATURE_ID_RANGE_SIZE   (3 * 8 * 8)

struct reg_mask_range {
        __u64 addr;             /* Pointer to mask array */
        __u32 range;            /* Requested range */
        __u32 reserved[13];
};

此 ioctl 将所选寄存器范围的可写掩码复制到用户空间。

addr 字段是指向 KVM 将可写掩码复制到的目标数组的指针。

range 字段表示请求的寄存器范围。对于 KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES 功能,KVM_CHECK_EXTENSION 返回支持的范围,表示为一组标志。每个标志的位索引表示 range 字段的可能值。所有其他值都保留供将来使用,KVM 可能会返回错误。

reserved[13] 数组保留供将来使用,应为 0,否则 KVM 可能会返回错误。

KVM_ARM_FEATURE_ID_RANGE (0)

Feature ID 范围定义为 AArch64 系统寄存器空间,其中 op0==3,op1=={0, 1, 3},CRn==0,CRm=={0-7},op2=={0-7}。

addr 指向的返回的掩码数组由宏 ARM64_FEATURE_ID_RANGE_IDX(op0, op1, crn, crm, op2) 索引,允许用户空间知道对于由 op0, op1, crn, crm, op2 描述的系统寄存器,哪些字段可以更改。KVM 拒绝 ID 寄存器值,这些值描述了系统支持的功能的超集。

4.140 KVM_SET_USER_MEMORY_REGION2

功能:

KVM_CAP_USER_MEMORY2

架构:

全部

类型:

vm ioctl

参数:

struct kvm_userspace_memory_region2 (in)

返回值:

成功时为 0,出错时为 -1

KVM_SET_USER_MEMORY_REGION2 是 KVM_SET_USER_MEMORY_REGION 的扩展,允许将 guest_memfd 内存映射到 guest 中。所有与 KVM_SET_USER_MEMORY_REGION 共享的字段都相同。用户空间可以在标志中设置 KVM_MEM_GUEST_MEMFD,以使 KVM 将内存区域绑定到给定的 guest_memfd 范围 [guest_memfd_offset, guest_memfd_offset + memory_size]。目标 guest_memfd 必须指向通过当前 VM 上的 KVM_CREATE_GUEST_MEMFD 创建的文件,并且目标范围不能绑定到任何其他内存区域。所有标准边界检查都适用(使用常识)。

struct kvm_userspace_memory_region2 {
      __u32 slot;
      __u32 flags;
      __u64 guest_phys_addr;
      __u64 memory_size; /* bytes */
      __u64 userspace_addr; /* start of the userspace allocated memory */
      __u64 guest_memfd_offset;
      __u32 guest_memfd;
      __u32 pad1;
      __u64 pad2[14];
};

KVM_MEM_GUEST_MEMFD 区域_必须_具有有效的 guest_memfd(私有内存)和 userspace_addr(共享内存)。但是,userspace_addr 的 “有效” 仅表示地址本身必须是合法的用户空间地址。在 KVM_SET_USER_MEMORY_REGION2 时,userspace_addr 的后备映射不需要有效/填充,例如,共享内存可以按需延迟映射/分配。

将 gfn 映射到 guest 中时,KVM 基于 gfn 的 KVM_MEMORY_ATTRIBUTE_PRIVATE 状态选择共享或私有,即使用 userspace_addr 或 guest_memfd。在 VM 创建时,所有内存都是共享的,即所有 gfn 的 PRIVATE 属性都是 ‘0’。用户空间可以通过根据需要切换 KVM_MEMORY_ATTRIBUTE_PRIVATE(通过 KVM_SET_MEMORY_ATTRIBUTES)来控制内存是共享的还是私有的。

S390:

如果 VM 设置了 KVM_VM_S390_UCONTROL 标志,则返回 -EINVAL。如果在受保护的 VM 上调用,则返回 -EINVAL。

4.141 KVM_SET_MEMORY_ATTRIBUTES

功能:

KVM_CAP_MEMORY_ATTRIBUTES

架构:

x86

类型:

vm ioctl

参数:

struct kvm_memory_attributes (in)

返回值:

成功时为 0,出错时 <0

KVM_SET_MEMORY_ATTRIBUTES 允许用户空间为一系列客户机物理内存设置内存属性。

struct kvm_memory_attributes {
      __u64 address;
      __u64 size;
      __u64 attributes;
      __u64 flags;
};

#define KVM_MEMORY_ATTRIBUTE_PRIVATE           (1ULL << 3)

地址和大小必须按页对齐。支持的属性可以通过 KVM_CAP_MEMORY_ATTRIBUTES 上的 ioctl(KVM_CHECK_EXTENSION) 检索。如果在 VM 上执行,KVM_CAP_MEMORY_ATTRIBUTES 精确地返回该 VM 支持的属性。如果在系统范围内执行,KVM_CAP_MEMORY_ATTRIBUTES 返回 KVM 支持的所有属性。目前定义的唯一属性是 KVM_MEMORY_ATTRIBUTE_PRIVATE,它将关联的 gfn 标记为客户机私有内存。

请注意,没有 “get” API。用户空间负责根据需要显式跟踪 gfn/页的状态。

“flags” 字段保留供将来扩展使用,必须为 “0”。

4.142 KVM_CREATE_GUEST_MEMFD

功能:

KVM_CAP_GUEST_MEMFD

架构:

类型:

vm ioctl

参数:

struct kvm_create_guest_memfd(in)

返回值:

成功时返回文件描述符,出错时返回 <0

KVM_CREATE_GUEST_MEMFD 创建一个匿名文件并返回指向它的文件描述符。guest_memfd 文件大致类似于通过 memfd_create() 创建的文件,例如,guest_memfd 文件驻留在 RAM 中,具有易失性存储,并且在最后一个引用被删除时自动释放。与 “常规” memfd_create() 文件不同,guest_memfd 文件绑定到其拥有的虚拟机(见下文),不能由用户空间映射、读取或写入,并且无法调整大小(guest_memfd 文件确实支持 PUNCH_HOLE)。

struct kvm_create_guest_memfd {
      __u64 size;
      __u64 flags;
      __u64 reserved[6];
};

从概念上讲,支持 guest_memfd 文件的 inode 表示物理内存,即作为事物耦合到虚拟机,而不是耦合到 “struct kvm”。该文件本身绑定到 “struct kvm”,是该实例对底层内存的视图,例如,有效地提供了客户机地址到主机内存的转换。这允许用于使用多个 KVM 结构来管理单个虚拟机的使用场景,例如,在执行虚拟机的 intrahost 迁移时。

KVM 目前仅支持通过 KVM_SET_USER_MEMORY_REGION2 映射 guest_memfd,更具体地说,是通过 “struct kvm_userspace_memory_region2” 中的 guest_memfd 和 guest_memfd_offset 字段,其中 guest_memfd_offset 是进入 guest_memfd 实例的偏移量。对于给定的 guest_memfd 文件,每个页面最多可以有一个映射,即不允许将多个内存区域绑定到单个 guest_memfd 范围(任意数量的内存区域可以绑定到单个 guest_memfd 文件,但绑定的范围不得重叠)。

有关更多详细信息,请参见 KVM_SET_USER_MEMORY_REGION2。

4.143 KVM_PRE_FAULT_MEMORY

功能:

KVM_CAP_PRE_FAULT_MEMORY

架构:

类型:

vcpu ioctl

参数:

struct kvm_pre_fault_memory (in/out)

返回值:

如果至少处理了一个页面,则为 0,如果出错,则为 < 0

错误

EINVAL

指定的 gpasize 无效(例如,未按页面对齐,导致溢出,或者大小为零)。

ENOENT

指定的 gpa 超出了定义的内存插槽。

EINTR

未屏蔽的信号正在挂起,并且未处理任何页面。

EFAULT

参数地址无效。

EOPNOTSUPP

虚拟机监控程序不支持为 GPA 映射内存,和/或对于当前的 vCPU 状态/模式不支持。

EIO

意外的错误情况(也会导致 WARN)

struct kvm_pre_fault_memory {
      /* in/out */
      __u64 gpa;
      __u64 size;
      /* in */
      __u64 flags;
      __u64 padding[5];
};

KVM_PRE_FAULT_MEMORY 填充 KVM 的第 2 阶段页表,用于映射当前 vCPU 状态的内存。KVM 映射内存的方式与 vCPU 生成第 2 阶段读取页面错误的方式相同,例如,根据需要进行内存错误,但不会破坏 CoW。但是,KVM 不会将任何新创建的第 2 阶段 PTE 标记为已访问。

对于机密 VM 类型,如果在客户机 “最终确定”/测量之前有一个私有客户机内存的初始设置,则只有在完成所有必要的设置以将客户机置于 “最终确定” 状态之后,才能发出此 ioctl,以便可以可靠地确保上述语义。

在某些情况下,多个 vCPU 可能共享页表。在这种情况下,可以并行调用 ioctl。

当 ioctl 返回时,输入值会更新为指向剩余范围。如果在返回时 size > 0,则调用方可以使用相同的 struct kvm_map_memory 参数再次发出 ioctl。

阴影页表无法支持此 ioctl,因为它们由虚拟地址或嵌套的客户机物理地址索引。当客户机使用阴影页表时(例如,因为它运行具有嵌套页表的嵌套客户机),调用此 ioctl 将失败,并显示 EOPNOTSUPP,即使 KVM_CHECK_EXTENSION 报告该功能存在。

flags 目前必须为零。

5. kvm_run 结构

应用程序代码通过 mmap() 一个 vcpu fd 来获取指向 kvm_run 结构的指针。从那时起,应用程序代码可以通过在调用 KVM_RUN ioctl 之前更改 kvm_run 中的字段来控制执行,并通过查找结构成员来获取有关 KVM_RUN 返回原因的信息。

struct kvm_run {
      /* in */
      __u8 request_interrupt_window;

请求 KVM_RUN 在可以向 guest 中注入外部中断时返回。与 KVM_INTERRUPT 结合使用时很有用。

__u8 immediate_exit;

此字段在 KVM_RUN 启动时轮询一次;如果非零,KVM_RUN 会立即退出,返回 -EINTR。在使用信号将 VCPU “踢” 出 KVM_RUN 的常见情况下,可以使用此字段来避免使用可伸缩性较差的 KVM_SET_SIGNAL_MASK。用户空间可以设置一个信号处理程序,将 run->immediate_exit 设置为非零值,而不是在 KVM_RUN 之外阻止信号。

如果 KVM_CAP_IMMEDIATE_EXIT 不可用,则忽略此字段。

__u8 padding1[6];

/* out */
__u32 exit_reason;

当 KVM_RUN 成功返回(返回值 0)时,它会通知应用程序代码 KVM_RUN 返回的原因。此字段的允许值在下面详细说明。

__u8 ready_for_interrupt_injection;

如果已指定 request_interrupt_window,则此字段指示现在可以使用 KVM_INTERRUPT 注入中断。

__u8 if_flag;

当前中断标志的值。仅当未使用内核内本地 APIC 时才有效。

__u16 flags;

更多特定于体系结构的标志,详细说明了可能影响设备行为的 VCPU 状态。当前定义的标志

/* x86, set if the VCPU is in system management mode */
#define KVM_RUN_X86_SMM          (1 << 0)
/* x86, set if bus lock detected in VM */
#define KVM_RUN_X86_BUS_LOCK     (1 << 1)
/* x86, set if the VCPU is executing a nested (L2) guest */
#define KVM_RUN_X86_GUEST_MODE   (1 << 2)

/* arm64, set for KVM_EXIT_DEBUG */
#define KVM_DEBUG_ARCH_HSR_HIGH_VALID  (1 << 0)
/* in (pre_kvm_run), out (post_kvm_run) */
__u64 cr8;

cr8 寄存器的值。仅当未使用内核内本地 APIC 时才有效。既是输入又是输出。

__u64 apic_base;

APIC BASE msr 的值。仅当未使用内核内本地 APIC 时才有效。既是输入又是输出。

union {
        /* KVM_EXIT_UNKNOWN */
        struct {
                __u64 hardware_exit_reason;
        } hw;

如果 exit_reason 为 KVM_EXIT_UNKNOWN,则 vcpu 由于未知原因退出。有关更多特定于体系结构的信息,请参见 hardware_exit_reason。

/* KVM_EXIT_FAIL_ENTRY */
struct {
        __u64 hardware_entry_failure_reason;
        __u32 cpu; /* if KVM_LAST_CPU */
} fail_entry;

如果 exit_reason 为 KVM_EXIT_FAIL_ENTRY,则由于未知原因无法运行 vcpu。有关更多特定于体系结构的信息,请参见 hardware_entry_failure_reason。

/* KVM_EXIT_EXCEPTION */
struct {
        __u32 exception;
        __u32 error_code;
} ex;

未使用。

              /* KVM_EXIT_IO */
              struct {
#define KVM_EXIT_IO_IN  0
#define KVM_EXIT_IO_OUT 1
                      __u8 direction;
                      __u8 size; /* bytes */
                      __u16 port;
                      __u32 count;
                      __u64 data_offset; /* relative to kvm_run start */
              } io;

如果 exit_reason 为 KVM_EXIT_IO,则 vcpu 执行了端口 I/O 指令,而该指令无法由 kvm 满足。data_offset 描述了数据所在的位置(KVM_EXIT_IO_OUT)或 kvm 希望应用程序代码放置数据以用于下一个 KVM_RUN 调用的位置(KVM_EXIT_IO_IN)。数据格式是一个压缩数组。

/* KVM_EXIT_DEBUG */
struct {
        struct kvm_debug_exit_arch arch;
} debug;

如果 exit_reason 为 KVM_EXIT_DEBUG,则 vcpu 正在处理调试事件,并为此返回特定于体系结构的信息。

/* KVM_EXIT_MMIO */
struct {
        __u64 phys_addr;
        __u8  data[8];
        __u32 len;
        __u8  is_write;
} mmio;

如果 exit_reason 为 KVM_EXIT_MMIO,则 vcpu 执行了内存映射 I/O 指令,而该指令无法由 kvm 满足。如果 ‘is_write’ 为 true,则 ‘data’ 成员包含写入的数据,否则应由应用程序代码填充。

‘data’ 成员在其前 ‘len’ 个字节中包含该值,就像 VCPU 直接对字节数组执行适当宽度的加载或存储一样。

注意

对于 KVM_EXIT_IO、KVM_EXIT_MMIO、KVM_EXIT_OSI、KVM_EXIT_PAPR、KVM_EXIT_XEN、KVM_EXIT_EPR、KVM_EXIT_HYPERCALL、KVM_EXIT_TDX、KVM_EXIT_X86_RDMSR 和 KVM_EXIT_X86_WRMSR,只有在用户空间通过 KVM_RUN 重新进入内核后,相应的操作才会完成(并且客户机状态保持一致)。内核端将首先完成未完成的操作,然后检查挂起的信号。

操作的挂起状态不会保存在对用户空间可见的状态中,因此用户空间应确保在执行实时迁移之前完成操作。用户空间可以使用未屏蔽的信号挂起或将 immediate_exit 字段设置为完成挂起的操作,而无需允许执行任何其他指令来重新进入客户机。

/* KVM_EXIT_HYPERCALL */
struct {
        __u64 nr;
        __u64 args[6];
        __u64 ret;
        __u64 flags;
} hypercall;

强烈建议用户空间使用 KVM_EXIT_IO (x86) 或 KVM_EXIT_MMIO(除 s390 之外的所有体系结构)来实现需要客户机与主机用户空间交互的功能。

注意

KVM_EXIT_IO 比 KVM_EXIT_MMIO 快得多。

对于 arm64:

可以根据 SMCCC 过滤器的配置启用 SMCCC 退出。有关更多详细信息,请参见 通用 vm 接口 KVM_ARM_SMCCC_FILTER

nr 包含客户机的 SMCCC 调用的函数 ID。用户空间应使用 KVM_GET_ONE_REG ioctl 从 vCPU 的 GPR 中检索调用参数。

flags 的定义
  • KVM_HYPERCALL_EXIT_SMC:指示客户机使用 SMC 通路来启动 SMCCC 调用。如果此位为 0,则客户机使用 HVC 通路进行 SMCCC 调用。

  • KVM_HYPERCALL_EXIT_16BIT:指示客户机使用 16 位指令来启动 SMCCC 调用。如果此位为 0,则客户机使用 32 位指令。AArch64 客户机始终将此位设置为 0。

在退出点,PC 指向紧跟在陷阱指令之后的指令。

/* KVM_EXIT_TPR_ACCESS */
struct {
        __u64 rip;
        __u32 is_write;
        __u32 pad;
} tpr_access;

要记录(KVM_TPR_ACCESS_REPORTING)。

/* KVM_EXIT_S390_SIEIC */
struct {
        __u8 icptcode;
        __u64 mask; /* psw upper half */
        __u64 addr; /* psw lower half */
        __u16 ipa;
        __u32 ipb;
} s390_sieic;

s390 特定。

              /* KVM_EXIT_S390_RESET */
#define KVM_S390_RESET_POR       1
#define KVM_S390_RESET_CLEAR     2
#define KVM_S390_RESET_SUBSYSTEM 4
#define KVM_S390_RESET_CPU_INIT  8
#define KVM_S390_RESET_IPL       16
              __u64 s390_reset_flags;

s390 特定。

/* KVM_EXIT_S390_UCONTROL */
struct {
        __u64 trans_exc_code;
        __u32 pgm_code;
} s390_ucontrol;

s390 特定。用户控制的虚拟机 (KVM_VM_S390_UNCONTROL) 的主机页表上发生了页面错误,内核无法解决。程序代码和转换异常代码(放置在 cpu 的低核心中)在此处以 z 体系结构操作原则手册中动态地址转换 (DAT) 章节中的定义呈现。

/* KVM_EXIT_DCR */
struct {
        __u32 dcrn;
        __u32 data;
        __u8  is_write;
} dcr;

已弃用 - 曾用于 440 KVM。

/* KVM_EXIT_OSI */
struct {
        __u64 gprs[32];
} osi;

MOL 使用一个特殊的管理程序调用接口,它称之为 ‘OSI’。要启用它,我们会捕获管理程序调用并退出,并使用包含所有客户机 gpr 的此退出结构。

如果 exit_reason 为 KVM_EXIT_OSI,则 vcpu 触发了此类管理程序调用。用户空间现在可以处理管理程序调用,并在完成后根据需要修改 gpr。在客户机条目中,所有客户机 GPR 都将被此结构中的值替换。

/* KVM_EXIT_PAPR_HCALL */
struct {
        __u64 nr;
        __u64 ret;
        __u64 args[9];
} papr_hcall;

这在 64 位 PowerPC 上使用,用于模拟 pSeries 分区,例如,在 qemu 中使用 ‘pseries’ 机器类型。当客户机使用 ‘sc 1’ 指令进行管理程序调用时,会发生这种情况。‘nr’ 字段包含管理程序调用号(来自客户机 R3),‘args’ 包含参数(来自客户机 R4 - R12)。用户空间应将返回代码放入 ‘ret’ 中,并将任何额外的返回值放入 args[] 中。可能的管理程序调用在 Power Architecture Platform Requirements (PAPR) 文档中定义,该文档可从 www.power.org 获得(需要免费的开发人员注册才能访问)。

/* KVM_EXIT_S390_TSCH */
struct {
        __u16 subchannel_id;
        __u16 subchannel_nr;
        __u32 io_int_parm;
        __u32 io_int_word;
        __u32 ipb;
        __u8 dequeued;
} s390_tsch;

s390 特定。当 KVM_CAP_S390_CSS_SUPPORT 已启用且 TEST SUBCHANNEL 被拦截时,会发生此退出。如果已取消排队,则目标子通道的挂起 I/O 中断已取消排队,并且 subchannel_id、subchannel_nr、io_int_parm 和 io_int_word 包含该中断的参数。ipb 是指令参数解码所必需的。

/* KVM_EXIT_EPR */
struct {
        __u32 epr;
} epr;

在 FSL BookE PowerPC 芯片上,中断控制器具有到核心的快速补丁中断确认路径。当核心成功传递中断时,它会自动使用中断向量号填充 EPR 寄存器,并确认中断控制器内部的中断。

如果中断控制器位于用户空间中,我们需要通过它执行中断确认周期,以使用此退出提取下一个要传递的中断向量。

只要 KVM_CAP_PPC_EPR 都已启用并且刚刚将外部中断传递到客户机中,就会触发它。用户空间应将确认的中断向量放入 ‘epr’ 字段中。

              /* KVM_EXIT_SYSTEM_EVENT */
              struct {
#define KVM_SYSTEM_EVENT_SHUTDOWN       1
#define KVM_SYSTEM_EVENT_RESET          2
#define KVM_SYSTEM_EVENT_CRASH          3
#define KVM_SYSTEM_EVENT_WAKEUP         4
#define KVM_SYSTEM_EVENT_SUSPEND        5
#define KVM_SYSTEM_EVENT_SEV_TERM       6
#define KVM_SYSTEM_EVENT_TDX_FATAL      7
                      __u32 type;
                      __u32 ndata;
                      __u64 data[16];
              } system_event;

如果 exit_reason 为 KVM_EXIT_SYSTEM_EVENT,则 vcpu 使用某些特定于体系结构的机制(管理程序调用或某些特殊指令)触发了系统级事件。对于 ARM64,这是使用来自 vcpu 的基于 HVC 指令的 PSCI 调用触发的。

‘type’ 字段描述系统级事件类型。‘type’ 的有效值为

  • KVM_SYSTEM_EVENT_SHUTDOWN -- 客户机已请求关闭 VM。用户空间没有义务遵守此请求,如果它确实遵守此请求,则不需要同步销毁 VM(即,它可以在最终发生关闭之前再次调用 KVM_RUN)。

  • KVM_SYSTEM_EVENT_RESET -- 客户机已请求重置 VM。与 SHUTDOWN 一样,用户空间可以选择忽略该请求,或者计划在将来发生重置,并且可以再次调用 KVM_RUN。

  • KVM_SYSTEM_EVENT_CRASH -- 客户机发生崩溃,客户机已请求崩溃情况维护。用户空间可以选择忽略该请求,或者收集 VM 内存核心转储和/或重置/关闭 VM。

  • KVM_SYSTEM_EVENT_SEV_TERM -- AMD SEV 客户机请求终止。客户机的 GHCB 的客户机物理地址存储在 data[0] 中。

  • KVM_SYSTEM_EVENT_TDX_FATAL -- TDX 客户机报告了一个致命错误状态。KVM 不进行任何解析或转换,它只是将 16 个通用寄存器转储到用户空间,并按指令编码中 x86-64 通用寄存器的 4 位索引的升序排列,如 Intel SDM 中定义的那样。

  • KVM_SYSTEM_EVENT_WAKEUP -- 退出的 vCPU 处于挂起状态,并且 KVM 识别到一个唤醒事件。用户空间可以通过将退出的 vCPU 标记为可运行来遵守此事件,或者拒绝它并再次调用 KVM_RUN。

  • KVM_SYSTEM_EVENT_SUSPEND -- 客户机已请求挂起 VM。

如果存在 KVM_CAP_SYSTEM_EVENT_DATA,则 ‘data’ 字段可以包含特定于体系结构的系统级事件信息。只有数据数组的第一个 ndata 项(可能为零)有效。

  • 对于 arm64,如果客户机根据 PSCI 规范的 v1.1 发出了 SYSTEM_RESET2 调用,则 data[0] 设置为 KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2。

  • 对于 arm64,如果客户机根据 PSCI 规范的 v1.3 发出了 SYSTEM_OFF2 调用,则 data[0] 设置为 KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2。

  • 对于 RISC-V,data[0] 设置为 sbi_system_reset 调用的第二个参数的值。

以前的 Linux 版本在此结构中定义了一个 flags 成员。该字段现在别名为 data[0]。用户空间可以假定只有当 ndata 大于 0 时才会写入它。

对于 arm/arm64:

使用 KVM_CAP_ARM_SYSTEM_SUSPEND VM 功能启用 KVM_SYSTEM_EVENT_SUSPEND 退出。如果客户机调用 PSCI SYSTEM_SUSPEND 函数,KVM 将使用此事件类型退出到用户空间。

用户空间完全有责任根据 ARM DEN0022D.b 5.19 “SYSTEM_SUSPEND” 实现 PSCI SYSTEM_SUSPEND 调用。KVM 在退出到用户空间之前不会更改 vCPU 的状态,因此调用参数会保留在 vCPU 寄存器中。

用户空间_必须_采取行动来处理此类退出。它必须

  • 遵守客户机挂起 VM 的请求。用户空间可以通过将调用 vCPU 的状态设置为 KVM_MP_STATE_SUSPENDED 来请求内核内模拟挂起。当恢复调用 vCPU 时,用户空间必须根据传递给 PSCI 函数的参数配置 vCPU 的状态。有关函数参数的详细信息,请参见 ARM DEN0022D.b 5.19.1 “预期用途”。

  • 拒绝客户机挂起 VM 的请求。有关可能的返回值,请参见 ARM DEN0022D.b 5.19.2 “调用者职责”。

当启用 PSCI v1.3 时,将启用使用 PSCI SYSTEM_OFF2 调用的休眠。如果客户机调用 PSCI SYSTEM_OFF2 函数,KVM 将使用 KVM_SYSTEM_EVENT_SHUTDOWN 事件类型退出到用户空间,并且 data[0] 设置为 KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2。SYSTEM_OFF2 函数唯一支持的休眠类型是 HIBERNATE_OFF。

/* KVM_EXIT_IOAPIC_EOI */
struct {
        __u8 vector;
} eoi;

指示 VCPU 的内核内本地 APIC 收到了级别触发的 IOAPIC 中断的 EOI。仅当 IOAPIC 在用户空间中实现时(即,启用 KVM_CAP_SPLIT_IRQCHIP),才会触发此退出;用户空间 IOAPIC 应处理 EOI,并在中断仍被断言时重新触发中断。Vector 是收到 EOI 的 LAPIC 中断向量。

              struct kvm_hyperv_exit {
#define KVM_EXIT_HYPERV_SYNIC          1
#define KVM_EXIT_HYPERV_HCALL          2
#define KVM_EXIT_HYPERV_SYNDBG         3
                      __u32 type;
                      __u32 pad1;
                      union {
                              struct {
                                      __u32 msr;
                                      __u32 pad2;
                                      __u64 control;
                                      __u64 evt_page;
                                      __u64 msg_page;
                              } synic;
                              struct {
                                      __u64 input;
                                      __u64 result;
                                      __u64 params[2];
                              } hcall;
                              struct {
                                      __u32 msr;
                                      __u32 pad2;
                                      __u64 control;
                                      __u64 status;
                                      __u64 send_page;
                                      __u64 recv_page;
                                      __u64 pending_page;
                              } syndbg;
                      } u;
              };
              /* KVM_EXIT_HYPERV */
              struct kvm_hyperv_exit hyperv;

指示 VCPU 退出到用户空间以处理与 Hyper-V 仿真相关的一些任务。

‘type’ 的有效值为

  • KVM_EXIT_HYPERV_SYNIC -- 同步通知用户空间有关

Hyper-V SynIC 状态更改。通知用于重新映射 SynIC 事件/消息页面,以及在用户空间中启用/禁用 SynIC 消息/事件处理。

  • KVM_EXIT_HYPERV_SYNDBG -- 同步通知用户空间有关

Hyper-V Synthetic 调试器状态更改。通知用于更新 pending_page 位置,或发送控制命令(发送位于 send_page 中的缓冲区或接收到 recv_page 的缓冲区)。

/* KVM_EXIT_ARM_NISV */
struct {
        __u64 esr_iss;
        __u64 fault_ipa;
} arm_nisv;

用于 arm64 系统。如果客户机访问了不在 memslot 中的内存,KVM 通常会返回到用户空间并要求它代表其进行 MMIO 仿真。但是,对于某些类型的指令,不提供指令解码(方向,内存访问的长度),并且从 VM 中提取和解码指令过于复杂,无法驻留在内核中。

从历史上看,当发生这种情况时,KVM 会打印警告并终止 VM。KVM 假定如果客户机访问了非 memslot 内存,则它正在尝试执行 I/O,而这无法仿真,并且警告消息也相应地措辞。但是,更常见的情况是,客户机错误导致在客户机内存区域之外进行访问,如果访问未落在 I/O 窗口中,则应导致更有意义的警告消息和客户机中的外部中止。

用户空间实现可以查询 KVM_CAP_ARM_NISV_TO_USER,并在 VM 创建时启用此功能。完成此操作后,这些类型的错误将返回到用户空间,并显示 KVM_EXIT_ARM_NISV,其中 esr_iss 字段中包含来自 ESR_EL2 的有效位,fault_ipa 字段中包含错误的 IPA。用户空间可以修复访问(如果它实际上是 I/O 访问,方法是从客户机内存中解码指令(如果非常勇敢)并继续执行客户机),或者它可以决定挂起、转储或重新启动客户机。

请注意,KVM 不会像对 KVM_EXIT_MMIO 所做的那样跳过错误指令,但是如果用户空间决定解码和仿真指令,则用户空间必须仿真对处理状态的任何更改。

此功能不适用于受保护的 VM,因为用户空间无法访问执行仿真所需的状态。相反,会直接在客户机中注入数据中止异常。请注意,如果在受保护的 VM 上下文之外查询,将会报告 KVM_CAP_ARM_NISV_TO_USER,但如果在受保护的 VM 文件描述符上查询,则不会公开该功能。

/* KVM_EXIT_X86_RDMSR / KVM_EXIT_X86_WRMSR */
struct {
        __u8 error; /* user -> kernel */
        __u8 pad[7];
        __u32 reason; /* kernel -> user */
        __u32 index; /* kernel -> user */
        __u64 data; /* kernel <-> user */
} msr;

用于 x86 系统。启用 VM 功能 KVM_CAP_X86_USER_SPACE_MSR 后,对将调用 #GP 的 MSR 的访问(由 KVM 内核代码)可能会改为触发读取的 KVM_EXIT_X86_RDMSR 退出和写入的 KVM_EXIT_X86_WRMSR 退出。

“reason” 字段指定 MSR 拦截发生的原因。仅当在 ENABLE_CAP 期间请求特定原因时,用户空间才会收到 MSR 退出。当前有效的退出原因是

KVM_MSR_EXIT_REASON_UNKNOWN

访问 KVM 未知的 MSR

KVM_MSR_EXIT_REASON_INVAL

访问无效 MSR 或保留位

KVM_MSR_EXIT_REASON_FILTER

访问被 KVM_X86_SET_MSR_FILTER 阻止

对于 KVM_EXIT_X86_RDMSR,“index” 字段告诉用户空间客户机要读取哪个 MSR。要通过成功的读取来响应此请求,用户空间将相应的数据写入 “data” 字段,并且必须继续客户机执行以确保读取的数据传输到客户机寄存器状态中。

如果 RDMSR 请求不成功,则用户空间通过在 “error” 字段中放置 “1” 来指示。当再次执行 VCPU 时,这将在客户机中注入 #GP。

对于 KVM_EXIT_X86_WRMSR,“index” 字段告诉用户空间客户机要写入哪个 MSR。完成对该事件的处理后,用户空间必须继续 vCPU 执行。如果 MSR 写入不成功,则用户空间也会将 “error” 字段设置为 “1”。

有关与 MSR 筛选交互的详细信息,请参见 KVM_X86_SET_MSR_FILTER。

              struct kvm_xen_exit {
#define KVM_EXIT_XEN_HCALL          1
                      __u32 type;
                      union {
                              struct {
                                      __u32 longmode;
                                      __u32 cpl;
                                      __u64 input;
                                      __u64 result;
                                      __u64 params[6];
                              } hcall;
                      } u;
              };
              /* KVM_EXIT_XEN */
              struct kvm_hyperv_exit xen;

指示 VCPU 退出到用户空间以处理与 Xen 仿真相关的一些任务。

‘type’ 的有效值为

  • KVM_EXIT_XEN_HCALL -- 同步通知用户空间有关 Xen 管理程序调用。用户空间应将管理程序调用结果放入相应的字段中,然后再调用 KVM_RUN。

/* KVM_EXIT_RISCV_SBI */
struct {
        unsigned long extension_id;
        unsigned long function_id;
        unsigned long args[6];
        unsigned long ret[2];
} riscv_sbi;

如果退出原因是 KVM_EXIT_RISCV_SBI,则表示 VCPU 完成了一个 SBI 调用,该调用未由 KVM RISC-V 内核模块处理。SBI 调用的详细信息在 kvm_run 结构的 ‘riscv_sbi’ 成员中可用。‘riscv_sbi’ 的 ‘extension_id’ 字段表示 SBI 扩展 ID,而 ‘function_id’ 字段表示给定 SBI 扩展的函数 ID。‘riscv_sbi’ 的 ‘args’ 数组字段表示 SBI 调用的参数,而 ‘ret’ 数组字段表示返回值。用户空间应在恢复 VCPU 之前更新 SBI 调用的返回值。有关 RISC-V SBI 规范的更多详细信息,请参见 https://github.com/riscv/riscv-sbi-doc

              /* KVM_EXIT_MEMORY_FAULT */
              struct {
#define KVM_MEMORY_EXIT_FLAG_PRIVATE  (1ULL << 3)
                      __u64 flags;
                      __u64 gpa;
                      __u64 size;
              } memory_fault;

KVM_EXIT_MEMORY_FAULT 指示 vCPU 遇到 KVM 无法解决的内存错误。‘gpa’ 和 ‘size’(以字节为单位)描述了错误的客户机物理地址范围 [gpa, gpa + size)。‘flags’ 字段描述了可能相关的错误访问属性

  • KVM_MEMORY_EXIT_FLAG_PRIVATE - 设置后,指示内存错误发生在私有内存访问上。清除后,指示错误发生在共享访问上。

注意!在所有 KVM 退出原因中,KVM_EXIT_MEMORY_FAULT 是独一无二的,因为它伴随的返回代码为 ‘-1’,而不是 ‘0’!当 KVM 以 KVM_EXIT_MEMORY_FAULT 退出时,errno 将始终设置为 EFAULT 或 EHWPOISON,对于所有其他错误编号,用户空间应假定 kvm_run.exit_reason 已过时/未定义。

  /* KVM_EXIT_NOTIFY */
  struct {
#define KVM_NOTIFY_CONTEXT_INVALID    (1 << 0)
    __u32 flags;
  } notify;

用于 x86 系统。当启用 VM 功能 KVM_CAP_X86_NOTIFY_VMEXIT 时,如果在 VM 非根模式下指定的时间内未发生任何事件窗口,则会生成 VM 退出。一旦启用该功能时设置了 KVM_X86_NOTIFY_VMEXIT_USER,它将退出到用户空间,退出原因为 KVM_EXIT_NOTIFY,以便进一步处理。“flags”字段包含更详细的信息。

“flags”的有效值为

  • KVM_NOTIFY_CONTEXT_INVALID -- VM 上下文已损坏,在 VMCS 中无效。如果恢复目标 VM,可能会导致未知结果。

/* KVM_EXIT_TDX */
struct {
        __u64 flags;
        __u64 nr;
        union {
                struct {
                        u64 ret;
                        u64 data[5];
                } unknown;
                struct {
                        u64 ret;
                        u64 gpa;
                        u64 size;
                } get_quote;
                struct {
                        u64 ret;
                        u64 leaf;
                        u64 r11, r12, r13, r14;
                } get_tdvmcall_info;
        };
} tdx;

处理来自 guest 的 TDVMCALL。 KVM 根据 Guest-Hypervisor Communication Interface (GHCI) 规范转发选择的 TDVMCALL;KVM 以最小的更改将这些请求桥接到用户空间 VMM,将输入放置在联合中,并在重新进入时将其复制回 guest。

Flags 当前始终为零,而 nr 包含来自寄存器 R11 的 TDVMCALL 编号。联合的其余字段提供 TDVMCALL 的输入和输出。目前定义了以下 nr

  • TDVMCALL_GET_QUOTE:guest 已请求生成 TD-Quote

由托管在主机上的 TD-Quoting Enclave 服务签名。参数和返回值位于联合的 get_quote 字段中。gpa 字段和 size 指定共享内存缓冲区的 guest 物理地址(不设置共享位)和大小,TDX guest 在该缓冲区中传递 TD 报告。ret 字段表示 GetQuote 请求的返回值。当请求已成功排队时,TDX guest 可以轮询共享内存区域中的状态字段,以检查 Quote 生成是否已完成。完成后,生成的 Quote 将通过同一缓冲区返回。

  • TDVMCALL_GET_TD_VM_CALL_INFO:guest 已请求支持

TDVMCALL 的状态。给定叶的输出值应放置在联合的 get_tdvmcall_info 字段的 r11r14 字段中。

KVM 可能会在未来添加对更多值的支持,这可能会导致用户空间退出,即使没有调用 KVM_ENABLE_CAP 或类似函数。在这种情况下,它将进入并带有已有效的输出字段;在常见情况下,联合的 unknown.ret 字段将为 TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED。如果用户空间不希望支持 TDVMCALL,则无需执行任何操作。

        /* Fix the size of the union. */
        char padding[256];
};

/*
 * shared registers between kvm and userspace.
 * kvm_valid_regs specifies the register classes set by the host
 * kvm_dirty_regs specified the register classes dirtied by userspace
 * struct kvm_sync_regs is architecture specific, as well as the
 * bits for kvm_valid_regs and kvm_dirty_regs
 */
__u64 kvm_valid_regs;
__u64 kvm_dirty_regs;
union {
        struct kvm_sync_regs regs;
        char padding[SYNC_REGS_SIZE_BYTES];
} s;

如果定义了 KVM_CAP_SYNC_REGS,这些字段允许用户空间访问某些 guest 寄存器,而无需调用 SET/GET_*REGS。因此,如果用户空间必须处理退出,我们可以避免一些系统调用开销。用户空间可以通过检查 kvm_valid_regs 的特定位来查询结构的有效性。这些位是特定于体系结构的,通常定义寄存器组的有效性。(例如,通用寄存器的一个位)

请注意,内核允许将 kvm_run 结构用作某些寄存器类型的主要存储。因此,即使未设置 kvm_dirty_regs 中的相应位,内核也可以使用 kvm_run 中的值。

6. 可以在 vCPU 上启用的功能

有一些功能在启用时会改变虚拟 CPU 或虚拟机的行为。要启用它们,请参阅 4.37 KVM_ENABLE_CAP

以下是功能列表以及启用它们时它们对 vCPU 或虚拟机的影响。

以下信息与描述一起提供

架构

哪些指令集架构提供了此 ioctl。x86 包括 i386 和 x86_64。

目标

这是否是每个 vcpu 或每个 vm 的功能。

参数

该功能接受哪些参数。

返回值

返回值。未详细说明常规错误号(EBADF、ENOMEM、EINVAL),但详细说明了具有特定含义的错误。

6.1 KVM_CAP_PPC_OSI

架构:

ppc

目标:

vcpu

参数:

返回值:

成功时为 0;出错时为 -1

此功能允许拦截 OSI 超级调用,否则这些调用将被视为要注入到 guest 中的普通系统调用。OSI 超级调用由 Mac-on-Linux 发明,用于在 guest 和主机之间建立标准化的通信机制。

启用此功能后,可能会发生 KVM_EXIT_OSI。

6.2 KVM_CAP_PPC_PAPR

架构:

ppc

目标:

vcpu

参数:

返回值:

成功时为 0;出错时为 -1

此功能允许拦截 PAPR 超级调用。PAPR 超级调用使用超级调用指令“sc 1”完成。

它还将 guest 权限级别设置为“supervisor”模式。通常,guest 在具有一些缺失功能的“hypervisor”权限模式下运行。

除了上述之外,它还更改了 SDR1 的语义。在此模式下,SDR1 的 HTAB 地址部分包含 HVA 而不是 GPA,因为 PAPR 将 HTAB 对 guest 隐藏。

启用此功能后,可能会发生 KVM_EXIT_PAPR_HCALL。

6.3 KVM_CAP_SW_TLB

架构:

ppc

目标:

vcpu

参数:

args[0] 是 struct kvm_config_tlb 的地址

返回值:

成功时为 0;出错时为 -1

struct kvm_config_tlb {
      __u64 params;
      __u64 array;
      __u32 mmu_type;
      __u32 array_len;
};

配置虚拟 CPU 的 TLB 数组,在用户空间和 KVM 之间建立共享内存区域。“params”和“array”字段是 mmu 类型特定数据结构的用户空间地址。“array_len”字段是一种安全机制,应设置为用户空间为数组保留的内存大小(以字节为单位)。它必须至少是由“mmu_type”和“params”指定的大小。

当 KVM_RUN 处于活动状态时,共享区域受 KVM 控制。其内容未定义,用户空间对其进行的任何修改都会导致有界未定义的行为。

从 KVM_RUN 返回时,共享区域将反映 guest 的 TLB 的当前状态。如果用户空间进行任何更改,它必须调用 KVM_DIRTY_TLB 来告诉 KVM 哪些条目已更改,然后再在此 vcpu 上再次调用 KVM_RUN。

对于 mmu 类型 KVM_MMU_FSL_BOOKE_NOHV 和 KVM_MMU_FSL_BOOKE_HV

  • “params”字段的类型为“struct kvm_book3e_206_tlb_params”。

  • “array”字段指向类型为“struct kvm_book3e_206_tlb_entry”的数组。

  • 该数组由第一个 TLB 中的所有条目组成,后跟第二个 TLB 中的所有条目。

  • 在 TLB 中,条目首先按递增的集合编号排序。在一个集合中,条目按方式排序(递增 ESEL)。

  • 用于确定 TLB0 中集合编号的哈希值为:(MAS2 >> 12) & (num_sets - 1),其中“num_sets”是 tlb_sizes[] 值除以 tlb_ways[] 值。

  • 即使硬件忽略 TLB0 的此值,mas1 的 tsize 字段也应在 TLB0 上设置为 4K。

6.4 KVM_CAP_S390_CSS_SUPPORT

架构:

s390

目标:

vcpu

参数:

返回值:

成功时为 0;出错时为 -1

此功能允许支持处理通道 I/O 指令。

TEST PENDING INTERRUPTION 和 TEST SUBCHANNEL 的中断部分在内核中处理,而其他 I/O 指令传递给用户空间。

启用此功能后,将在 TEST SUBCHANNEL 拦截时发生 KVM_EXIT_S390_TSCH。

请注意,即使此功能是按 vcpu 启用的,整个虚拟机也会受到影响。

6.5 KVM_CAP_PPC_EPR

架构:

ppc

目标:

vcpu

参数:

args[0] 定义代理工具是否处于活动状态

返回值:

成功时为 0;出错时为 -1

此功能启用或禁用通过外部代理工具传递中断。

启用后 (args[0] != 0),每次 guest 收到传递的外部中断时,它都会自动退出到用户空间,并带有 KVM_EXIT_EPR 退出以接收最顶层中断向量。

禁用后 (args[0] == 0),行为就像不支持此工具一样。

启用此功能后,可能会发生 KVM_EXIT_EPR。

6.6 KVM_CAP_IRQ_MPIC

架构:

ppc

参数:

args[0] 是 MPIC 设备 fd;args[1] 是此 vcpu 的 MPIC CPU 编号

此功能将 vcpu 连接到内核中的 MPIC 设备。

6.7 KVM_CAP_IRQ_XICS

架构:

ppc

目标:

vcpu

参数:

args[0] 是 XICS 设备 fd;args[1] 是此 vcpu 的 XICS CPU 编号(服务器 ID)

此功能将 vcpu 连接到内核中的 XICS 设备。

6.8 KVM_CAP_S390_IRQCHIP

架构:

s390

目标:

vm

参数:

此功能为 s390 启用内核中的 irqchip。有关详细信息,请参阅“4.24 KVM_CREATE_IRQCHIP”。

6.9 KVM_CAP_MIPS_FPU

架构:

mips

目标:

vcpu

参数:

args[0] 保留供将来使用(应为 0)。

此功能允许 guest 使用主机浮点单元。它允许将 Config1.FP 位设置为启用 guest 中的 FPU。完成此操作后,可以访问 KVM_REG_MIPS_FPR_*KVM_REG_MIPS_FCR_* 寄存器(取决于当前的 guest FPU 寄存器模式),并且可以通过 KVM API 以及从 guest 访问 Status.FR、Config5.FRE 位,具体取决于 FPU 是否支持它们。

6.10 KVM_CAP_MIPS_MSA

架构:

mips

目标:

vcpu

参数:

args[0] 保留供将来使用(应为 0)。

此功能允许 guest 使用 MIPS SIMD 架构 (MSA)。它允许将 Config3.MSAP 位设置为启用 guest 对 MSA 的使用。完成此操作后,可以访问 KVM_REG_MIPS_VEC_*KVM_REG_MIPS_MSA_* 寄存器,并且可以通过 KVM API 以及从 guest 访问 Config5.MSAEn 位。

6.74 KVM_CAP_SYNC_REGS

架构:

s390, x86

目标:

s390:始终启用,x86:vcpu

参数:

返回值:

x86:KVM_CHECK_EXTENSION 返回一个位数组,指示支持哪些寄存器集(位字段在 arch/x86/include/uapi/asm/kvm.h 中定义)。

如上面 5. kvm_run 结构 部分中 kvm_sync_regs 结构信息中所述,KVM_CAP_SYNC_REGS“允许用户空间访问某些 guest 寄存器,而无需调用 SET/GET_*REGS”。这通过消除用于设置和/或获取寄存器值的重复 ioctl 调用来减少开销。当用户空间进行同步 guest 状态修改时,例如在用户空间中模拟和/或拦截指令时,这尤其重要。

有关 s390 的具体信息,请参阅源代码。

对于 x86

  • 要复制到 kvm_run 的寄存器集可由用户空间选择(而不是为每次退出复制所有集)。

  • 除了 regs 和 sregs 之外,还提供 vcpu_events。

对于 x86,struct kvm_run 的“kvm_valid_regs”字段被重载为用作用户空间设置的输入位数组字段,以指示要在下次退出时复制出的特定寄存器集。

为了指示用户空间何时修改了应复制到 vCPU 中的值,必须设置所有架构位数组字段“kvm_dirty_regs”。这使用与“kvm_valid_regs”字段相同的位标志来完成。如果未设置 dirty 位,则即使已修改寄存器集值,也不会将其复制到 vCPU 中。

位数组中未使用的位字段必须设置为零。

struct kvm_sync_regs {
      struct kvm_regs regs;
      struct kvm_sregs sregs;
      struct kvm_vcpu_events events;
};

6.75 KVM_CAP_PPC_IRQ_XIVE

架构:

ppc

目标:

vcpu

参数:

args[0] 是 XIVE 设备 fd;args[1] 是此 vcpu 的 XIVE CPU 编号(服务器 ID)

此功能将 vcpu 连接到内核中的 XIVE 设备。

6.76 KVM_CAP_HYPERV_SYNIC

架构:

x86

目标:

vcpu

此功能(如果 KVM_CHECK_EXTENSION 指示它可用)表示内核具有 Hyper-V Synthetic 中断控制器 (SynIC) 的实现。Hyper-V SynIC 用于支持基于 Windows Hyper-V 的 guest 准虚拟化驱动程序 (VMBus)。

为了使用 SynIC,必须通过在 vcpu fd 上通过 KVM_ENABLE_CAP ioctl 设置此功能来激活它。请注意,即使 CPU 支持 APIC 硬件虚拟化,这也将禁用 APIC 硬件虚拟化,因为它与 SynIC 自动 EOI 行为不兼容。

6.77 KVM_CAP_HYPERV_SYNIC2

架构:

x86

目标:

vcpu

此功能启用较新版本的 Hyper-V Synthetic 中断控制器 (SynIC)。与 KVM_CAP_HYPERV_SYNIC 的唯一区别在于,当通过写入相应的 MSR 来启用 SynIC 消息和事件标志页面时,KVM 不会清除它们。

6.78 KVM_CAP_HYPERV_DIRECT_TLBFLUSH

架构:

x86

目标:

vcpu

此功能指示在 Hyper-V hypervisor 之上运行的 KVM 为其 guest 启用了直接 TLB 刷新,这意味着 TLB 刷新超级调用由第 0 级 hypervisor (Hyper-V) 处理,绕过 KVM。由于 Hyper-V 和 KVM 之间 hypercall 参数的 ABI 不同,启用此功能实际上禁用了 KVM 对所有 hypercall 的处理(因为某些 KVM hypercall 可能会被 Hyper-V 错误地视为 TLB 刷新 hypercall),因此用户空间应禁用 CPUID 中的 KVM 标识,并且仅公开 Hyper-V 标识。在这种情况下,guest 认为它在 Hyper-V 上运行,并且仅使用 Hyper-V hypercall。

6.79 KVM_CAP_HYPERV_ENFORCE_CPUID

架构:

x86

目标:

vcpu

启用后,KVM 将根据 Hyper-V CPUID 功能叶中的位禁用提供给 guest 的模拟 Hyper-V 功能。否则,当在 HYPERV_CPUID_INTERFACE (0x40000001) 叶中设置 Hyper-V 标识时,将无条件地提供所有当前已实现的 Hyper-V 功能。

6.80 KVM_CAP_ENFORCE_PV_FEATURE_CPUID

架构:

x86

目标:

vcpu

启用后,KVM 将根据 KVM_CPUID_FEATURES CPUID 叶 (0x40000001) 中的位禁用提供给 guest 的准虚拟化功能。否则,guest 可能会使用准虚拟化功能,而不管实际通过 CPUID 叶公开了什么。

7. 可以在 VM 上启用的功能

有一些功能在启用时会改变虚拟机的行为。要启用它们,请参阅 4.37 KVM_ENABLE_CAP 部分。以下是功能列表以及启用它们时它们对 VM 的影响。

以下信息与描述一起提供

架构

哪些指令集架构提供了此 ioctl。x86 包括 i386 和 x86_64。

参数

该功能接受哪些参数。

返回值

返回值。未详细说明常规错误号(EBADF、ENOMEM、EINVAL),但详细说明了具有特定含义的错误。

7.1 KVM_CAP_PPC_ENABLE_HCALL

架构:

ppc

参数:

args[0] 是 sPAPR hcall 编号;args[1] 是 0 禁用,1 启用内核处理

此功能控制内核是否处理单个 sPAPR 超级调用 (hcall)。启用或禁用 hcall 的内核处理在 VM 中有效。创建时,会为内核处理启用一组初始 hcall,其中包括在该功能实现之前实现的内核处理程序的那些 hcall。如果禁用,内核将不会尝试处理 hcall,而总是退出到用户空间来处理它。请注意,启用一组相关 hcall 中的一些并禁用另一些可能没有意义,但 KVM 不会阻止用户空间这样做。

如果指定的 hcall 编号不是具有内核实现的编号,则 KVM_ENABLE_CAP ioctl 将失败并显示 EINVAL 错误。

7.2 KVM_CAP_S390_USER_SIGP

架构:

s390

参数:

此功能控制哪些 SIGP 命令将完全在用户空间中处理。启用此功能后,所有快速命令都将在内核中完全处理

  • SENSE

  • SENSE RUNNING

  • EXTERNAL CALL

  • EMERGENCY SIGNAL

  • CONDITIONAL EMERGENCY SIGNAL

所有其他命令都将在用户空间中完全处理。

只有特权操作异常才会在内核中检查(甚至在拦截之前的硬件中检查)。如果未启用此功能,则使用旧的 SIGP 命令处理方式(部分在内核和用户空间中)。

7.3 KVM_CAP_S390_VECTOR_REGISTERS

架构:

s390

参数:

返回值:

成功时为 0,出错时为负值

允许使用 z13 处理器引入的向量寄存器,并提供主机和用户空间之间的同步。如果机器不支持向量,将返回 -EINVAL。

7.4 KVM_CAP_S390_USER_STSI

架构:

s390

参数:

此功能允许 STSI 指令的后处理程序。在内核中进行初始处理后,KVM 会退出到用户空间,并显示 KVM_EXIT_S390_STSI,以允许用户空间插入更多数据。

在退出到用户空间之前,kvm 处理程序应填写 vcpu->run 的 s390_stsi 字段

struct {
      __u64 addr;
      __u8 ar;
      __u8 reserved;
      __u8 fc;
      __u8 sel1;
      __u16 sel2;
} s390_stsi;

@addr - guest address of STSI SYSIB
@fc   - function code
@sel1 - selector 1
@sel2 - selector 2
@ar   - access register number

KVM 处理程序应退出到用户空间,并显示 rc = -EREMOTE。

7.5 KVM_CAP_SPLIT_IRQCHIP

架构:

x86

参数:

args[0] - 为用户空间 IOAPIC 保留的路由数

返回值:

成功时为 0,出错时为 -1

为内核中的每个处理器创建一个本地 apic。如果用户空间 VMM 希望模拟 IOAPIC 和 PIC(以及 PIT,即使必须单独启用它),则可以使用此功能代替 KVM_CREATE_IRQCHIP。

此功能还启用内核中中断请求的路由;当 KVM_CAP_SPLIT_IRQCHIP 仅在 IRQ 路由表中使用 KVM_IRQ_ROUTING_MSI 类型的路由时。前 args[0] 个 MSI 路由保留用于 IOAPIC 引脚。每当 LAPIC 接收到这些路由的 EOI 时,将向用户空间报告 KVM_EXIT_IOAPIC_EOI vmexit。

如果已创建 VCPU,或者 irqchip 已经在内核中(即,已经调用了 KVM_CREATE_IRQCHIP),则失败。

7.6 KVM_CAP_S390_RI

架构:

s390

参数:

允许使用 zEC12 处理器引入的运行时检测。如果机器不支持运行时检测,将返回 -EINVAL。如果已经创建了 VCPU,将返回 -EBUSY。

7.7 KVM_CAP_X2APIC_API

架构:

x86

参数:

args[0] - 应启用的功能

返回值:

成功时为 0,当 args[0] 包含无效功能时为 -EINVAL

args[0] 中的有效功能标志为

#define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)

启用 KVM_X2APIC_API_USE_32BIT_IDS 会更改 KVM_SET_GSI_ROUTING、KVM_SIGNAL_MSI、KVM_SET_LAPIC 和 KVM_GET_LAPIC 的行为,允许使用 32 位 APIC ID。请参阅它们各自部分中的 KVM_CAP_X2APIC_API。

必须启用 KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK 才能使 x2APIC 在逻辑模式下或使用超过 255 个 VCPU 的情况下工作。否则,KVM 会将 0xff 视为广播,即使在 x2APIC 模式下,为了支持没有中断重映射的物理 x2APIC。这在逻辑模式下是不希望的,因为 0xff 表示集群 0 中的 CPU 0-7。

7.8 KVM_CAP_S390_USER_INSTR0

架构:

s390

参数:

启用此功能后,所有非法指令 0x0000(2 字节)都将被拦截并转发到用户空间。用户空间可以使用此机制,例如实现 2 字节软件断点。内核不会为这些指令注入操作异常,用户空间必须注意这一点。

即使已经创建并正在运行 VCPU,也可以动态启用此功能。

7.9 KVM_CAP_S390_GS

架构:

s390

参数:

返回值:

成功时为 0;如果机器不支持受保护的存储,则为 -EINVAL;如果已经创建了 VCPU,则为 -EBUSY。

允许为 KVM guest 使用受保护的存储。

7.10 KVM_CAP_S390_AIS

架构:

s390

参数:

允许使用适配器中断抑制。:返回值:成功时为 0;如果已经创建了 VCPU,则为 -EBUSY。

7.11 KVM_CAP_PPC_SMT

架构:

ppc

参数:

vsmt_mode, flags

在 VM 上启用此功能为用户空间提供了一种设置所需的虚拟 SMT 模式(即每个虚拟内核的虚拟 CPU 数量)的方法。虚拟 SMT 模式 vsmt_mode 必须是 1 到 8 之间的 2 的幂。在 POWER8 上,vsmt_mode 也不能大于主机的每个子内核的线程数。当前标志必须为 0。成功调用以启用此功能将在随后查询 VM 的 KVM_CAP_PPC_SMT 功能时返回 vsmt_mode。此功能仅受 HV KVM 支持,并且只能在创建任何 VCPU 之前设置。KVM_CAP_PPC_SMT_POSSIBLE 功能指示哪些虚拟 SMT 模式可用。

7.12 KVM_CAP_PPC_FWNMI

架构:

ppc

参数:

借助此功能,guest 地址空间中的机器检查异常将导致 KVM 以 NMI 退出原因退出 guest。这使 QEMU 能够构建错误日志并分支到 guest 内核注册的机器检查处理例程。如果没有此功能,KVM 将分支到 guest 的 0x200 中断向量。

7.13 KVM_CAP_X86_DISABLE_EXITS

架构:

x86

参数:

args[0] 定义禁用哪些退出

返回值:

成功时为 0,当 args[0] 包含无效退出或已经创建了任何 vCPU 时为 -EINVAL

args[0] 中的有效位为

#define KVM_X86_DISABLE_EXITS_MWAIT            (1 << 0)
#define KVM_X86_DISABLE_EXITS_HLT              (1 << 1)
#define KVM_X86_DISABLE_EXITS_PAUSE            (1 << 2)
#define KVM_X86_DISABLE_EXITS_CSTATE           (1 << 3)

在 VM 上启用此功能为用户空间提供了一种不再拦截某些指令以提高某些工作负载中的延迟的方法,建议在 vCPU 与专用物理 CPU 关联时使用。将来可以添加更多位;用户空间可以简单地将 KVM_CHECK_EXTENSION 结果传递给 KVM_ENABLE_CAP 以禁用所有此类 vmexit。

如果禁用 HLT 退出,请勿启用 KVM_FEATURE_PV_UNHALT。

7.14 KVM_CAP_S390_HPAGE_1M

架构:

s390

参数:

返回值:

成功时为 0,如果未设置 hpage 模块参数或启用了 cmma,或者 VM 设置了 KVM_VM_S390_UCONTROL 标志,则为 -EINVAL

借助此功能,可以为 VM 启用 KVM 对通过 hugetlbfs 的 1m 页面进行内存后备的支持。启用此功能后,不能再启用 cmma,并且 pfmfi 和存储密钥解释将被禁用。如果已经启用了 cmma 或 hpage 模块参数未设置为 1,则返回 -EINVAL。

虽然通常可以在没有此功能的情况下创建由巨页支持的 VM,但 VM 将无法运行。

7.15 KVM_CAP_MSR_PLATFORM_INFO

架构:

x86

参数:

args[0] 是否应启用该功能

借助此功能,guest 可以读取 MSR_PLATFORM_INFO MSR。否则,当 guest 尝试访问时,将引发 #GP。当前,此功能不启用 guest 对此 MSR 的写入权限。

7.16 KVM_CAP_PPC_NESTED_HV

架构:

ppc

参数:

返回值:

成功时为 0,当实现不支持嵌套 HV 虚拟化时为 -EINVAL。

POWER9 及更高系统上的 HV-KVM 允许“嵌套 HV”虚拟化,这为 guest VM 提供了一种运行可以使用 CPU 的 supervisor 模式(特权非 hypervisor 状态)运行的 guest 的方法。在 VM 上启用此功能取决于 CPU 是否具有必要的功能,以及是否使用 kvm-hv 模块参数启用了该工具。

7.17 KVM_CAP_EXCEPTION_PAYLOAD

架构:

x86

参数:

args[0] 是否应启用该功能

启用此功能后,当 L1 截获 L2 中发生的 #PF 异常时,CR2 不会在模拟的 VM-exit 之前被修改。同样,对于仅 kvm-intel,当 L1 截获 L2 中发生的 #DB 异常时,DR6 不会在模拟的 VM-exit 之前被修改。因此,当 KVM_GET_VCPU_EVENTS 报告 L2 有待处理的 #PF(或 #DB)异常时,exception.has_payload 将被设置,并且故障地址(或新的 DR6 位*)将在 exception_payload 字段中报告。同样,当用户空间使用 KVM_SET_VCPU_EVENTS 将 #PF(或 #DB)注入到 L2 中时,它应该设置 exception.has_payload 并将故障地址 - 或新的 DR6 位[3] - 放入 exception_payload 字段中。

此功能还启用 struct kvm_vcpu_events 中的 exception.pending,这允许用户空间区分待处理异常和注入异常。

7.18 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2

架构:

x86, arm64, mips

参数:

args[0] 是否应启用该功能

有效的标志包括

#define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE   (1 << 0)
#define KVM_DIRTY_LOG_INITIALLY_SET           (1 << 1)

当设置 KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE 时,KVM_GET_DIRTY_LOG 不会自动清除并写保护所有作为脏页返回的页面。相反,用户空间将不得不使用 KVM_CLEAR_DIRTY_LOG 单独执行此操作。

以稍微复杂的操作为代价,这提供了更好的可伸缩性和响应性,原因有两个。首先,KVM_CLEAR_DIRTY_LOG ioctl 可以在 64 页的粒度上运行,而不需要同步完整的 memslot;这确保了 KVM 不会长时间占用自旋锁。其次,在调用 KVM_GET_DIRTY_LOG 和用户空间实际使用页面中的数据之间可能会经过大量时间。页面可能在此期间被修改,这对访客和用户空间都是低效的:访客将因写保护故障而遭受更高的惩罚,而用户空间可能会看到脏页的错误报告。手动重新保护有助于减少这段时间,从而提高访客性能并减少脏日志误报的数量。

当设置 KVM_DIRTY_LOG_INITIALLY_SET 时,脏位图的所有位将在创建时初始化为 1。 这也提高了性能,因为可以在第一次调用 KVM_CLEAR_DIRTY_LOG 时以小块逐步启用脏日志记录。 KVM_DIRTY_LOG_INITIALLY_SET 依赖于 KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE(目前也仅在 x86 和 arm64 上可用)。

KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 之前以名称 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 提供,但该实现存在错误,使得难以或不可能正确使用它。 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 的可用性表明这些错误已修复。 用户空间不应尝试使用 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT。

7.19 KVM_CAP_PPC_SECURE_GUEST

架构:

ppc

此功能表明 KVM 正在具有超管理程序固件的主机上运行,因此可以支持安全访客。 在这样的系统上,访客可以要求超管理程序使其成为安全访客,即其内存对主机不可访问,除非明确请求与主机共享的页面。 当访客请求成为安全访客时,超管理程序会通知 KVM,KVM 有机会否决该转换。

如果存在,则可以为 VM 启用此功能,这意味着 KVM 将允许转换为安全访客模式。 否则,KVM 将否决该转换。

7.20 KVM_CAP_HALT_POLL

架构:

全部

目标:

VM

参数:

args[0] 是以纳秒为单位的最大轮询时间

返回值:

成功时为 0;出错时为 -1

KVM_CAP_HALT_POLL 覆盖 kvm.halt_poll_ns 模块参数,以设置目标 VM 中所有 vCPU 的最大暂停轮询时间。 可以随时调用此功能任意次数,以动态更改最大暂停轮询时间。

有关暂停轮询的更多信息,请参阅 KVM 暂停轮询系统

7.21 KVM_CAP_X86_USER_SPACE_MSR

架构:

x86

目标:

VM

参数:

args[0] 包含要报告的 KVM_MSR_EXIT_REASON_* 事件的掩码

返回值:

成功时为 0;出错时为 -1

如果拒绝访问 MSR,则此功能允许用户空间拦截 RDMSR 和 WRMSR 指令。 默认情况下,KVM 会在拒绝访问时注入 #GP。

当访客请求读取或写入 MSR 时,KVM 可能不会实现所有与相应系统相关的 MSR。 它也不会按 CPU 类型进行区分。

为了允许对 MSR 处理进行更细粒度的控制,用户空间可以启用此功能。 启用后,匹配 args[0] 中指定的掩码并且会在访客内部触发 #GP 的 MSR 访问将改为触发 KVM_EXIT_X86_RDMSR 和 KVM_EXIT_X86_WRMSR 退出通知。 然后,用户空间可以实现特定于模型的 MSR 处理和/或用户通知,以通知用户 KVM 未模拟/虚拟化 MSR。

有效的掩码标志为

KVM_MSR_EXIT_REASON_UNKNOWN

拦截对未知(对于 KVM)MSR 的访问

KVM_MSR_EXIT_REASON_INVAL

拦截根据 vCPU 模型和/或模式在架构上无效的访问

KVM_MSR_EXIT_REASON_FILTER

拦截用户空间通过 KVM_X86_SET_MSR_FILTER 拒绝的访问

7.22 KVM_CAP_X86_BUS_LOCK_EXIT

架构:

x86

目标:

VM

参数:

args[0] 定义了在访客中检测到总线锁时使用的策略

返回值:

成功时为 0,当 args[0] 包含无效位时为 -EINVAL

args[0] 中的有效位为

#define KVM_BUS_LOCK_DETECTION_OFF      (1 << 0)
#define KVM_BUS_LOCK_DETECTION_EXIT     (1 << 1)

在 VM 上启用此功能为用户空间提供了一种选择策略来处理访客中检测到的总线锁的方法。 用户空间可以从 KVM_CHECK_EXTENSION 的结果中获取支持的模式,并通过 KVM_ENABLE_CAP 定义它。 支持的模式是互斥的。

此功能允许用户空间强制 VM 在访客中检测到的总线锁上退出,无论主机是否启用了拆分锁检测(这将触发 KVM 拦截的 #AC 异常)。 此功能旨在缓解恶意/有缺陷的访客可以利用总线锁来降低整个系统性能的攻击。

如果设置了 KVM_BUS_LOCK_DETECTION_OFF,则 KVM 不会强制访客总线锁退出 VM,但如果启用,主机内核的拆分锁 #AC 检测仍然适用。

如果设置了 KVM_BUS_LOCK_DETECTION_EXIT,则 KVM 会启用一个 CPU 功能,该功能确保访客中的总线锁会触发 VM 退出,并且 KVM 会退出到用户空间以处理所有此类 VM 退出,例如,允许用户空间限制违规访客和/或应用一些其他基于策略的缓解措施。 退出到用户空间时,KVM 会在 vcpu-run->flags 中设置 KVM_RUN_X86_BUS_LOCK,并有条件地将 exit_reason 设置为 KVM_EXIT_X86_BUS_LOCK。

由于底层硬件实现的差异,退出时 vCPU 的 RIP 在 Intel 和 AMD 之间存在差异。 在 Intel 主机上,RIP 指向下一条指令,即退出类似于陷阱。 在 AMD 主机上,RIP 指向违规指令,即退出类似于故障。

注意! 检测到的总线锁可能与其他退出到用户空间的情况同时发生,即如果用户空间想要对所有检测到的总线锁采取措施,则无论主要退出原因如何,都应检查 KVM_RUN_X86_BUS_LOCK。

7.23 KVM_CAP_PPC_DAWR1

架构:

ppc

参数:

返回值:

成功时为 0,当 CPU 不支持第二个 DAWR 时为 -EINVAL

此功能可用于检查/启用 POWER10 处理器提供的第二个 DAWR 功能。

7.24 KVM_CAP_VM_COPY_ENC_CONTEXT_FROM

架构:

x86 SEV 已启用

类型:

vm

参数:

args[0] 是源 vm 的 fd

返回值:

成功时为 0;出错时为 ENOTTY

此功能使用户空间能够将加密上下文从 fd 指示的 vm 复制到调用此功能的 vm。

这旨在支持由主机调度的客户机内工作负载。 这允许客户机内工作负载维护其自己的 NPT,并防止两个 vm 通过中断等意外地相互覆盖(单独的 APIC/MSR/等)。

7.25 KVM_CAP_SGX_ATTRIBUTE

架构:

x86

目标:

VM

参数:

args[0] 是 securityfs 中 SGX 属性文件的文件句柄

返回值:

成功时为 0,如果文件句柄无效或 KVM 不支持请求的属性,则为 -EINVAL。

KVM_CAP_SGX_ATTRIBUTE 使用户空间 VMM 能够授予 VM 访问一个或多个特权 enclave 属性的权限。 args[0] 必须保存一个有效 SGX 属性文件的文件句柄,该文件对应于 KVM 支持/限制的属性(目前仅 PROVISIONKEY)。

SGX 子系统限制对 enclave 属性子集的访问,以便为未受损的内核提供额外的安全性,例如,PROVISIONKEY 的使用受到限制,以阻止恶意软件使用 PROVISIONKEY 获取稳定的系统指纹。 为了防止用户空间通过在 VM 中运行 enclave 来规避此类限制,KVM 默认情况下会阻止对特权属性的访问。

有关更多详细信息,请参阅 软件保护扩展 (SGX)

7.27 KVM_CAP_EXIT_ON_EMULATION_FAILURE

架构:

x86

参数:

args[0] 是否应启用该功能

启用此功能后,模拟失败将导致退出到用户空间并显示 KVM_INTERNAL_ERROR(除非调用模拟器来处理 VMware 后门指令)。 此外,KVM 现在将为任何因模拟失败而导致退出到用户空间的操作提供最多 15 个指令字节。 当这些退出到用户空间发生时,请使用 emulation_failure 结构而不是内部结构。 它们都具有相同的布局,但 emulation_failure 结构与内容更匹配。 它还显式定义了“flags”字段,该字段用于描述结构中有效的字段(即:如果在“flags”字段中设置了 KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES,则“insn_size”和“insn_bytes”都具有有效数据)。

7.28 KVM_CAP_ARM_MTE

架构:

arm64

参数:

此功能指示 KVM(和硬件)支持向访客公开内存标记扩展 (MTE)。 必须先由 VMM 启用,然后才能创建任何 VCPU,以允许访客访问。 请注意,MTE 仅适用于以 AArch64 模式运行的访客,并且启用此功能将导致创建 AArch32 VCPU 的尝试失败。

启用后,访客可以访问与分配给访客的任何内存关联的标记。 KVM 将确保在主机的交换或休眠期间维护标记;但是,如果 VM 被迁移,VMM 需要手动保存/恢复标记(如适用)。

启用此功能后,memslot 中的所有内存都必须映射为 MAP_ANONYMOUS 或使用基于 RAM 的文件映射(tmpfsmemfd),尝试使用无效 mmap 创建 memslot 将导致返回 -EINVAL。

启用后,VMM 可以使用 KVM_ARM_MTE_COPY_TAGS ioctl 来执行标记与访客之间的批量复制。

7.29 KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM

架构:

x86 SEV 已启用

类型:

vm

参数:

args[0] 是源 vm 的 fd

返回值:

成功时为 0

此功能使用户空间能够将加密上下文从 fd 指示的 VM 迁移到调用此功能的 VM。

这旨在支持用户空间 VMM 之间的 VM 的主机内迁移,无需中断访客即可升级 VMM 进程。

7.31 KVM_CAP_DISABLE_QUIRKS2

参数:

args[0] - 要禁用的 KVM 缺陷集

架构:

x86

类型:

vm

如果启用此功能,将导致 KVM 禁用某些行为缺陷。

调用此功能的 KVM_CHECK_EXTENSION 会返回一个可以在 KVM 中禁用的缺陷的位掩码。

此功能的 KVM_ENABLE_CAP 的参数是要禁用的缺陷的位掩码,并且必须是 KVM_CHECK_EXTENSION 返回的位掩码的子集。

cap.args[0] 中的有效位为

KVM_X86_QUIRK_LINT0_REENABLED

默认情况下,LVT LINT0 寄存器的重置值为 0x700 (APIC_MODE_EXTINT)。 禁用此缺陷后,重置值为 0x10000 (APIC_LVT_MASKED)。

KVM_X86_QUIRK_CD_NW_CLEARED

默认情况下,KVM 会清除 AMD CPU 上的 CR0.CD 和 CR0.NW,以解决以 CR0.CD(即缓存处于“无填充”模式)永久运行的有缺陷的访客固件。

禁用此缺陷后,KVM 不会更改 CR0.CD 和 CR0.NW 的值。

KVM_X86_QUIRK_LAPIC_MMIO_HOLE

默认情况下,即使配置为 x2APIC 模式,MMIO LAPIC 接口也可用。 禁用此缺陷后,如果 LAPIC 处于 x2APIC 模式,KVM 将禁用 MMIO LAPIC 接口。

KVM_X86_QUIRK_OUT_7E_INC_RIP

默认情况下,KVM 会在退出到用户空间之前将 %rip 预先递增到端口 0x7e 的 OUT 指令。 禁用此缺陷后,KVM 不会在退出到用户空间之前预先递增 %rip。

KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT

禁用此缺陷后,如果设置了 IA32_MISC_ENABLE[位 18] (MWAIT),KVM 会设置 CPUID.01H:ECX[位 3] (MONITOR/MWAIT)。 此外,禁用此缺陷后,如果清除了 IA32_MISC_ENABLE[位 18],KVM 会清除 CPUID.01H:ECX[位 3]。

KVM_X86_QUIRK_FIX_HYPERCALL_INSN

默认情况下,KVM 会重写访客 VMMCALL/VMCALL 指令,以匹配系统的供应商管理程序调用指令。 禁用此缺陷后,KVM 将不再重写无效的访客管理程序调用指令。 执行不正确的管理程序调用指令将在访客内部生成 #UD。

KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS

默认情况下,无论根据访客 CPUID 是否支持 MONITOR/MWAIT,KVM 都会将 MONITOR/MWAIT(如果被拦截)模拟为 NOP。 禁用此缺陷且未设置 KVM_X86_DISABLE_EXITS_MWAIT(MONITOR/MWAIT 被拦截)时,如果根据访客 CPUID 不支持 MONITOR/MWAIT,KVM 将在 MONITOR/MWAIT 上注入 #UD。 请注意,如果禁用了 KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT,KVM 将在写入 MISC_ENABLE 时修改访客 CPUID 中的 MONITOR/MWAIT 支持。

KVM_X86_QUIRK_SLOT_ZAP_ALL

默认情况下,对于 KVM_X86_DEFAULT_VM VM,当删除或移动 memslot 时,KVM 会使所有 memslot 和地址空间中的所有 SPTE 失效。 禁用此缺陷(或 VM 类型不是 KVM_X86_DEFAULT_VM)时,KVM 仅确保无法访问已删除或移动的 memslot 的后备内存,即 KVM _可以_ 仅使与 memslot 相关的 SPTE 失效。

KVM_X86_QUIRK_STUFF_FEATURE_MSRS

默认情况下,在 vCPU 创建时,KVM 会将 vCPU 的 MSR_IA32_PERF_CAPABILITIES (0x345)、MSR_IA32_ARCH_CAPABILITIES (0x10a)、MSR_PLATFORM_INFO (0xce) 和所有 VMX MSR (0x480..0x492) 设置为 KVM 支持的最大功能。 KVM 还会将 MSR_IA32_UCODE_REV (0x8b) 设置为任意值(Intel 与 AMD 的值不同)。 最后,当设置访客 CPUID(由用户空间设置)时,KVM 会修改选定的 VMX MSR 字段,以强制访客 CPUID 与 L2 的有效 ISA 之间的一致性。 禁用此缺陷后,KVM 会将 vCPU 的 MSR 值清零(有两个例外,请参见下文),即像对待 CPUID 叶一样对待功能 MSR,并使用户空间完全控制 vCPU 模型定义。 此缺陷不会影响 VMX MSR CR0/CR4_FIXED1 (0x487 和 0x489),因为 KVM 现在不允许用户空间设置它们(出于安全目的,KVM 会根据访客 CPUID 设置它们)。

KVM_X86_QUIRK_IGNORE_GUEST_PAT

默认情况下,在 Intel 平台上,KVM 会忽略访客 PAT,并强制 EPT 中的有效内存类型为 WB。 该缺陷在无法安全地遵守访客 PAT 的 Intel 平台上不可用(即,在没有 CPU 自侦听的情况下,KVM 始终忽略访客 PAT 并强制有效内存类型为 WB)。 它在 AMD 平台上或在 Intel 上,当 VM 分配了非一致 DMA 设备时也会被忽略; 在这种情况下,KVM 始终遵守访客 PAT。 需要该缺陷来避免在某些 Intel Xeon 平台(例如 ICX、SPR)上的速度减慢,在这些平台上支持自侦听功能,但 UC 的速度太慢,会导致某些使用 UC 而不是 WC 映射视频 RAM 的旧访客出现问题。 如果用户空间知道不存在此类访客软件,例如,如果它不公开 bochs 图形设备(已知该设备具有有缺陷的驱动程序),则可以禁用该缺陷以遵守访客 PAT。

7.32 KVM_CAP_MAX_VCPU_ID

架构:

x86

目标:

VM

参数:

args[0] - 为当前 VM 设置的最大 APIC ID 值

返回值:

成功时为 0,如果 args[0] 超出 KVM 中支持的 KVM_MAX_VCPU_IDS,或者如果已设置,则为 -EINVAL。

此功能允许用户空间在创建 vCPU 之前指定为当前 VM 会话分配的最大可能 APIC ID,从而为按 APIC ID 索引的数据结构节省内存。 用户空间能够从指定的 CPU 拓扑计算 APIC ID 值的限制。

该值只能在 KVM_ENABLE_CAP 设置为非零值或创建 vCPU 之前更改。 创建第一个 vCPU 后,如果该值设置为零或者未调用 KVM_ENABLE_CAP,KVM 将使用 KVM_CHECK_EXTENSION(KVM_CAP_MAX_VCPU_ID) 的返回值作为最大 APIC ID。

7.33 KVM_CAP_X86_NOTIFY_VMEXIT

架构:

x86

目标:

VM

参数:

args[0] 是通知窗口的值以及一些标志

返回值:

成功时为 0,如果 args[0] 包含无效标志或不支持通知 VM 退出,则为 -EINVAL。

args[0] 的位 63:32 用于通知窗口。 args[0] 的位 31:0 用于某些标志。 有效位为

#define KVM_X86_NOTIFY_VMEXIT_ENABLED    (1 << 0)
#define KVM_X86_NOTIFY_VMEXIT_USER       (1 << 1)

此功能允许用户空间在 VM 创建期间按 VM 范围配置通知 VM 退出开启/关闭。 默认情况下禁用通知 VM 退出。 当用户空间在 args[0] 中设置 KVM_X86_NOTIFY_VMEXIT_ENABLED 位时,VMM 将启用此功能,并提供通知窗口,如果在指定的的时间(通知窗口)内在 VM 非根模式下未发生任何事件窗口,则会生成 VM 退出。

如果在 args[0] 中设置了 KVM_X86_NOTIFY_VMEXIT_USER,则在发生通知 VM 退出时,KVM 将退出到用户空间以进行处理。

此功能旨在缓解恶意 VM 可能导致 CPU 卡住(由于事件窗口未打开)并使 CPU 对主机或其他 VM 不可用的威胁。

7.35 KVM_CAP_X86_APIC_BUS_CYCLES_NS

架构:

x86

目标:

VM

参数:

args[0] 是所需的 APIC 总线时钟频率,以纳秒为单位

返回值:

成功时为 0,如果 args[0] 包含频率的无效值,或者已创建任何 vCPU,则为 -EINVAL,如果尚未使用 KVM_CREATE_IRQCHIP 创建虚拟本地 APIC,则为 -ENXIO。

此功能设置 VM 的 APIC 总线时钟频率,KVM 的内核内虚拟 APIC 在模拟 APIC 计时器时使用该频率。 KVM 的默认值可以通过 KVM_CHECK_EXTENSION 检索。

注意:如果向访客公开了非零 CPUID 0x15,用户空间负责正确配置 CPUID 0x15,即核心晶体时钟频率。

7.36 KVM_CAP_DIRTY_LOG_RING/KVM_CAP_DIRTY_LOG_RING_ACQ_REL

架构:

x86, arm64

类型:

vm

参数:

args[0] - 脏日志环的大小

KVM 能够使用 mmapped 到用户空间的环形缓冲区跟踪脏内存; 每个 vcpu 都有一个脏环。

脏环以 struct kvm_dirty_gfn 数组的形式提供给用户空间。 每个脏条目的定义如下

struct kvm_dirty_gfn {
        __u32 flags;
        __u32 slot; /* as_id | slot_id */
        __u64 offset;
};

为标志字段定义了以下值,以定义条目的当前状态

#define KVM_DIRTY_GFN_F_DIRTY           BIT(0)
#define KVM_DIRTY_GFN_F_RESET           BIT(1)
#define KVM_DIRTY_GFN_F_MASK            0x3

用户空间应在 KVM_CREATE_VM ioctl 之后立即调用 KVM_ENABLE_CAP ioctl,以启用新访客的此功能并设置环的大小。 仅允许在创建任何 vCPU 之前启用该功能,并且环的大小必须是 2 的幂。 环形缓冲区越大,环越不太可能满,并且 VM 不会被强制退出到用户空间。 最佳大小取决于工作负载,但建议至少为 64 KiB(4096 个条目)。

与脏页位图一样,该缓冲区跟踪对所有用户内存区域的写入,这些区域在 KVM_SET_USER_MEMORY_REGION 中设置了 KVM_MEM_LOG_DIRTY_PAGES 标志。 一旦使用设置的标志注册了内存区域,用户空间就可以开始从环形缓冲区中收集脏页。

环形缓冲区中的条目可以是未使用(标志位 00)、脏(标志位 01)或已收集(标志位 1X)。 条目的状态机如下

     dirtied         harvested        reset
00 -----------> 01 -------------> 1X -------+
 ^                                          |
 |                                          |
 +------------------------------------------+

要收集脏页,用户空间访问 mmapped 环形缓冲区以读取脏 GFN。 如果标志设置了 DIRTY 位(在此阶段必须清除 RESET 位),则表示此 GFN 是脏 GFN。 用户空间应收集此 GFN 并将标志从状态 01b 标记为 1Xb(位 0 将被 KVM 忽略,但必须设置位 1 以表明已收集此 GFN 并正在等待重置),然后继续下一个 GFN。 用户空间应继续执行此操作,直到 GFN 的标志清除 DIRTY 位,这表示它已收集所有可用的脏 GFN。

请注意,在弱排序架构上,用户空间对环形缓冲区的访问(更具体地说,是对“flags”字段的访问)必须是有序的,在可用时使用 load-acquire/store-release 访问器,或任何其他将确保此排序的内存屏障。

用户空间不必一次收集所有脏 GFN。 但是,它必须按顺序收集脏 GFN,即用户空间程序不能跳过一个脏 GFN 来收集下一个脏 GFN。

在处理环形缓冲区中的一个或多个条目后,用户空间调用 VM ioctl KVM_RESET_DIRTY_RINGS 以通知内核,以便内核将重新保护那些收集的 GFN。 因此,ioctl 必须在读取脏页的内容之前调用。

脏环可能会满。 发生这种情况时,vcpu 的 KVM_RUN 将返回,退出原因为 KVM_EXIT_DIRTY_LOG_FULL。

脏环接口与 KVM_GET_DIRTY_LOG 接口的主要区别在于,从用户空间读取脏环时,内核仍然可能尚未将处理器的脏页缓冲区刷新到内核缓冲区中(使用脏位图,刷新由 KVM_GET_DIRTY_LOG ioctl 完成)。 为此,需要使用信号将 vcpu 从 KVM_RUN 中踢出。 生成的 vmexit 确保所有脏 GFN 都已刷新到脏环中。

注意:KVM_CAP_DIRTY_LOG_RING_ACQ_REL 是弱排序架构应公开的唯一功能,以便指示用户空间在读取条目的状态并将其从 DIRTY 更改为 HARVESTED 时施加的额外内存排序要求。 具有类似 TSO 排序的架构(例如 x86)允许向用户空间公开 KVM_CAP_DIRTY_LOG_RING 和 KVM_CAP_DIRTY_LOG_RING_ACQ_REL。

启用脏环后,用户空间需要检测 KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 的功能,以查看环形结构是否可以由每个插槽的位图支持。 如果宣传了此功能,则表示该架构可以在没有 vcpu/环上下文的情况下弄脏访客页面,因此某些脏信息仍将维护在位图结构中。 如果尚未启用 KVM_CAP_DIRTY_LOG_RING_ACQ_REL 的功能,或者已存在任何 memslot,则无法启用 KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP。

请注意,此处的位图只是环形结构的备份。 仅当只有非常少量的内存在 vcpu/环上下文之外被弄脏时,使用环和位图组合才有益。 否则,需要考虑独立的每个插槽的位图机制。

要收集备份位图中的脏位,用户空间可以使用相同的 KVM_GET_DIRTY_LOG ioctl。 只要所有脏位的生成都在一次传递中完成,就不需要 KVM_CLEAR_DIRTY_LOG。 收集脏位图应该是 VMM 在考虑状态为完整之前所做的最后一件事。 VMM 需要确保脏状态是最终状态,并避免丢失在位图收集之后排序的另一个 ioctl 中的脏页。

注意:使用备份位图的多个示例:(1) 通过 KVM 设备“kvm-arm-vgic-its”上的命令 KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_SAVE_TABLES} 保存 vgic/its 表。 (2) 通过 KVM 设备“kvm-arm-vgic-its”上的命令 KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_RESTORE_TABLES} 恢复 vgic/its 表。 恢复 VGICv3 LPI 待处理状态。 (3) 通过 KVM 设备“kvm-arm-vgic-v3”上的 KVM_DEV_ARM_VGIC_{GRP_CTRL, SAVE_PENDING_TABLES} 命令保存 vgic3 待处理表。

7.37 KVM_CAP_PMU_CAPABILITY

架构:

x86

类型:

vm

参数:

arg[0] 是 PMU 虚拟化功能的位掩码。

返回值:

成功时为 0,当 arg[0] 包含无效位时为 -EINVAL

此功能会更改 KVM 中的 PMU 虚拟化。

调用此功能的 KVM_CHECK_EXTENSION 会返回一个 PMU 虚拟化能力位掩码,该位掩码可以在虚拟机上进行调整。

KVM_ENABLE_CAP 的参数也是一个位掩码,用于选择要应用于虚拟机的特定 PMU 虚拟化能力。 只有在创建 VCPU 之前才能在虚拟机上调用此方法。

目前,KVM_PMU_CAP_DISABLE 是唯一的能力。设置此能力将禁用该虚拟机的 PMU 虚拟化。用户模式应调整 CPUID 叶 0xA 以反映 PMU 已被禁用。

7.38 KVM_CAP_VM_DISABLE_NX_HUGE_PAGES

架构:

x86

类型:

vm

参数:

arg[0] 必须为 0。

返回值:

成功时返回 0,如果用户空间进程没有 CAP_SYS_BOOT 则返回 -EPERM,如果 args[0] 不为 0 或已创建任何 vCPU 则返回 -EINVAL。

此功能禁用 iTLB MULTIHIT 的 NX 大页缓解措施。

如果未设置 nx_huge_pages 模块参数,则该功能无效。

只能在创建任何 vCPU 之前设置此功能。

7.39 KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE

架构:

arm64

类型:

vm

参数:

arg[0] 是新的分割块大小。

返回值:

成功时返回 0,如果已创建任何 memslot 则返回 -EINVAL。

此功能设置 Eager Page Splitting 中使用的块大小。

当客户机内存由大页支持时,Eager Page Splitting 可提高脏日志记录(用于实时迁移)的性能。 它通过在启用脏日志记录(对于内存区域使用 KVM_MEM_LOG_DIRTY_PAGES 标志)或使用 KVM_CLEAR_DIRTY_LOG 时,主动地分割大页,从而避免在故障时分割大页(成 PAGE_SIZE 大小的页)。

块大小指定一次要分解的页数,并为每个块使用单个分配。 块大小越大,需要提前分配的页数就越多。

块大小需要是有效的块大小。 可接受的块大小列表在 KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 中以 64 位位图的形式公开(每位描述一个块大小)。 默认值为 0,以禁用 eager page splitting。

7.40 KVM_CAP_EXIT_HYPERCALL

架构:

x86

类型:

vm

如果启用此功能,KVM 将以 KVM_EXIT_HYPERCALL 退出原因退出到用户空间,以处理某些系统调用。

调用此功能的 KVM_CHECK_EXTENSION 将返回一个位掩码,该位掩码表示可以配置为退出到用户空间的系统调用。 目前,唯一的此类系统调用是 KVM_HC_MAP_GPA_RANGE。

KVM_ENABLE_CAP 的参数也是一个位掩码,并且必须是 KVM_CHECK_EXTENSION 结果的子集。 KVM 将把与其位位于参数中的系统调用转发到用户空间,并为其他系统调用返回 ENOSYS。

7.41 KVM_CAP_ARM_SYSTEM_SUSPEND

架构:

arm64

类型:

vm

启用后,KVM 将以类型为 KVM_SYSTEM_EVENT_SUSPEND 的 KVM_EXIT_SYSTEM_EVENT 退出到用户空间,以处理客户机挂起请求。

7.37 KVM_CAP_ARM_WRITABLE_IMP_ID_REGS

架构:

arm64

目标:

VM

参数:

返回值:

成功时返回 0,如果在启用此功能之前已创建 vCPU 则返回 -EINVAL。

此功能更改了标识 Arm 架构 PE 实现的寄存器的行为:MIDR_EL1、REVIDR_EL1 和 AIDR_EL1。 默认情况下,这些寄存器对用户空间可见,但被视为不变。

启用此功能后,KVM 允许用户空间在第一次 KVM_RUN 之前更改上述寄存器。 这些寄存器是 VM 范围的,这意味着在给定 VM 中的所有 vCPU 上呈现相同的值集。

7.43 KVM_CAP_RISCV_MP_STATE_RESET

架构:

riscv

类型:

VM

参数:

返回值:

成功时返回 0,如果 arg[0] 不为零则返回 -EINVAL

启用此功能后,KVM 会在通过 IOCTL 设置 MP_STATE_INIT_RECEIVED 时重置 VCPU。 原始 MP_STATE 将被保留。

8. 其他功能。

本节列出了提供有关 KVM 实现的其他功能的信息的功能。

8.1 KVM_CAP_PPC_HWRNG

架构:

ppc

如果 KVM_CHECK_EXTENSION 指示此功能可用,则表示内核具有由硬件随机数生成器支持的 H_RANDOM 系统调用的实现。 如果存在,则可以使用 KVM_CAP_PPC_ENABLE_HCALL 功能为客户机启用内核 H_RANDOM 处理程序。

8.3 KVM_CAP_PPC_MMU_RADIX

架构:

ppc

如果 KVM_CHECK_EXTENSION 指示此功能可用,则表示内核可以支持使用 Power ISA V3.00 中定义的 radix MMU(在 POWER9 处理器中实现)的客户机。

8.4 KVM_CAP_PPC_MMU_HASH_V3

架构:

ppc

如果 KVM_CHECK_EXTENSION 指示此功能可用,则表示内核可以支持使用 Power ISA V3.00 中定义的哈希页表 MMU(在 POWER9 处理器中实现)的客户机,包括内存中的段表。

8.5 KVM_CAP_MIPS_VZ

架构:

mips

如果主 kvm 句柄上的 KVM_CHECK_EXTENSION 指示此功能可用,则表示硬件的完整硬件辅助虚拟化功能可通过 KVM 使用。 必须将适当的 KVM_VM_MIPS_* 类型传递给 KVM_CREATE_VM,以创建一个利用它的 VM。

如果 kvm VM 句柄上的 KVM_CHECK_EXTENSION 指示此功能可用,则表示 VM 正在使用硬件的完整硬件辅助虚拟化功能。 这在创建具有 KVM_VM_MIPS_DEFAULT 的 VM 之后检查非常有用。

KVM_CHECK_EXTENSION 返回的值应与已知值进行比较(请参见下文)。 所有其他值都保留。 这是为了允许其他可能与 MIPS VZ ASE 不兼容的硬件辅助虚拟化实现的可能性。

0

陷阱 & 模拟实现用于在用户模式下运行客户机代码。 重新排列客户机虚拟内存段,以使客户机适应用户模式地址空间。

1

正在使用 MIPS VZ ASE,提供完整的硬件辅助虚拟化,包括标准客户机虚拟内存段。

8.7 KVM_CAP_MIPS_64BIT

架构:

mips

此功能指示客户机支持的架构类型,即支持的寄存器和地址宽度。

当通过 kvm VM 句柄上的 KVM_CHECK_EXTENSION 检查此功能时返回的值大致对应于 CP0_Config.AT 寄存器字段,应专门针对已知值进行检查(请参见下文)。 所有其他值都保留。

0

MIPS32 或 microMIPS32。 寄存器和地址的宽度均为 32 位。 只能运行 32 位客户机代码。

1

MIPS64 或 microMIPS64,只能访问 32 位兼容性段。 寄存器的宽度为 64 位,但地址的宽度为 32 位。 64 位客户机代码可以运行,但无法访问 MIPS64 内存段。 也可以运行 32 位客户机代码。

2

MIPS64 或 microMIPS64,可以访问所有地址段。 寄存器和地址的宽度均为 64 位。 可以运行 64 位或 32 位客户机代码。

8.9 KVM_CAP_ARM_USER_IRQ

架构:

arm64

如果 KVM_CHECK_EXTENSION 指示此功能可用,则表示如果用户空间创建一个没有内核中断控制器的 VM,它将收到对内核仿真设备的输出级别的更改通知,这些设备可以生成呈现给 VM 的虚拟中断。 对于此类 VM,每次返回到用户空间时,内核都会更新 vcpu 的 run->s.regs.device_irq_level 字段,以表示设备的实际输出级别。

每当 kvm 检测到设备输出级别的更改时,kvm 保证在运行 VM 之前至少返回到用户空间一次。 此退出可以是 KVM_EXIT_INTR 或任何其他退出事件,例如 KVM_EXIT_MMIO。 这样,用户空间始终可以采样设备输出级别并重新计算用户空间中断控制器的状态。 用户空间应始终在每次 kvm 退出时检查 run->s.regs.device_irq_level 的状态。 run->s.regs.device_irq_level 中的值可以表示级别和边沿触发的中断信号,具体取决于设备。 对于每个边沿信号,边沿触发的中断信号将以 run->s.regs.device_irq_level 中的位仅设置一次的方式退出到用户空间。

字段 run->s.regs.device_irq_level 可用,与 run->kvm_valid_regs 或 run->kvm_dirty_regs 位无关。

如果支持 KVM_CAP_ARM_USER_IRQ,则 KVM_CHECK_EXTENSION ioctl 返回一个大于 0 的数字,指示此功能的已实现版本,从而指示 run->s.regs.device_irq_level 中的哪些位可以发出信号值。

当前为 device_irq_level 位图定义了以下位

KVM_CAP_ARM_USER_IRQ >= 1:

  KVM_ARM_DEV_EL1_VTIMER -  EL1 virtual timer
  KVM_ARM_DEV_EL1_PTIMER -  EL1 physical timer
  KVM_ARM_DEV_PMU        -  ARM PMU overflow interrupt signal

kvm 的未来版本可能会实现其他事件。 这些事件将通过从 KVM_CHECK_EXTENSION 返回更高的数字来指示,并且将在上面列出。

8.10 KVM_CAP_PPC_SMT_POSSIBLE

架构:

ppc

查询此功能会返回一个位图,指示可以使用 KVM_CAP_PPC_SMT 设置的可能的虚拟 SMT 模式。 如果设置了位 N(从右开始计数),则 2^N 的虚拟 SMT 模式可用。

8.12 KVM_CAP_HYPERV_VP_INDEX

架构:

x86

此功能指示用户空间可以加载 HV_X64_MSR_VP_INDEX msr。 其值用于表示 SynIC 中断的目标 vcpu。 为了兼容性,KVM 将此 msr 初始化为 KVM 的内部 vcpu 索引。 当此功能不存在时,用户空间仍然可以查询此 msr 的值。

8.13 KVM_CAP_S390_AIS_MIGRATION

架构:

s390

此功能指示 flic 设备是否能够通过 KVM_DEV_FLIC_AISM_ALL 属性获取/设置 AIS 状态以进行迁移,并允许在不必创建 flic 设备的情况下发现此功能。

8.14 KVM_CAP_S390_PSW

架构:

s390

此功能指示 PSW 通过 kvm_run 结构公开。

8.15 KVM_CAP_S390_GMAP

架构:

s390

此功能指示用作客户机映射的用户空间内存可以位于用户内存地址空间的任何位置,只要内存插槽与段(1MB)边界对齐并调整大小即可。

8.16 KVM_CAP_S390_COW

架构:

s390

此功能指示用作客户机映射的用户空间内存可以使用写时复制语义以及通过只读页表跟踪脏页。

8.17 KVM_CAP_S390_BPB

架构:

s390

此功能指示 kvm 将实现用于处理分支预测阻塞的重置、迁移和嵌套 KVM 的接口。 如果没有此功能,则不应向客户机提供 stfle facility 82。

8.18 KVM_CAP_HYPERV_TLBFLUSH

架构:

x86

此功能指示 KVM 支持半虚拟化的 Hyper-V TLB Flush 系统调用:HvFlushVirtualAddressSpace、HvFlushVirtualAddressSpaceEx、HvFlushVirtualAddressList、HvFlushVirtualAddressListEx。

8.19 KVM_CAP_ARM_INJECT_SERROR_ESR

架构:

arm64

此功能指示用户空间可以指定(通过 KVM_SET_VCPU_EVENTS ioctl)当客户机发生虚拟 SError 中断异常时报告给客户机的综合征值。 如果 KVM 公布此功能,则用户空间只能指定 ESR 综合征的 ISS 字段。 ESR 的其他部分(例如 EC)由 CPU 在发生异常时生成。 如果此虚拟 SError 使用 AArch64 进入 EL1,则此值将在 ESR_ELx 的 ISS 字段中报告。

有关更多详细信息,请参见 KVM_CAP_VCPU_EVENTS。

8.20 KVM_CAP_HYPERV_SEND_IPI

架构:

x86

此功能指示 KVM 支持半虚拟化的 Hyper-V IPI 发送系统调用:HvCallSendSyntheticClusterIpi、HvCallSendSyntheticClusterIpiEx。

8.22 KVM_CAP_S390_VCPU_RESETS

架构:

s390

此功能指示 KVM_S390_NORMAL_RESET 和 KVM_S390_CLEAR_RESET ioctl 可用。

8.23 KVM_CAP_S390_PROTECTED

架构:

s390

此功能指示 Ultravisor 已初始化,因此 KVM 可以启动受保护的 VM。 此功能控制 KVM_S390_PV_COMMAND ioctl 和 KVM_MP_STATE_LOAD MP_STATE。 当状态更改无效时,KVM_SET_MP_STATE 可能会针对受保护的客户机失败。

8.24 KVM_CAP_STEAL_TIME

架构:

arm64, x86

此功能指示 KVM 支持窃取时间核算。 当支持窃取时间核算时,可以使用特定于架构的接口启用它。 此功能和特定于架构的接口必须一致,即,如果一个说该功能受支持,则另一个也应如此,反之亦然。 对于 arm64,请参见 通用 vcpu 接口 “KVM_ARM_VCPU_PVTIME_CTRL”。 对于 x86,请参见 KVM 特定的 MSR “MSR_KVM_STEAL_TIME”。

8.25 KVM_CAP_S390_DIAG318

架构:

s390

此功能使客户机能够设置有关其控制程序的信息(即客户机内核类型和版本)。 该信息在系统/固件服务事件期间非常有用,提供了有关在计算机上运行的客户机环境的附加数据。

该信息与 DIAGNOSE 0x318 指令相关联,该指令设置一个 8 字节的值,该值由一个字节的控制程序名称代码 (CPNC) 和一个 7 字节的控制程序版本代码 (CPVC) 组成。 CPNC 确定控制程序在什么环境中运行(例如 Linux、z/VM...),CPVC 用于特定于 OS 的信息(例如 Linux 版本、Linux 发行版...)

如果此功能可用,则 CPNC 和 CPVC 可以通过同步寄存器机制(KVM_SYNC_DIAG318)在 KVM 和用户空间之间同步。

8.26 KVM_CAP_X86_USER_SPACE_MSR

架构:

x86

此功能指示 KVM 支持将 MSR 读取和写入偏转到用户空间。 可以在 VM 级别启用它。 如果启用,通常会通过 KVM 将 #GP 触发到客户机中的 MSR 访问将通过 KVM_EXIT_X86_RDMSR 和 KVM_EXIT_X86_WRMSR 退出通知反弹到用户空间。

8.27 KVM_CAP_X86_MSR_FILTER

架构:

x86

此功能指示 KVM 支持拒绝访问用户定义的 MSR。 在公开此功能后,KVM 会导出新的 VM ioctl KVM_X86_SET_MSR_FILTER,用户空间可以调用它来指定 KVM 应拒绝访问的 MSR 范围的位图。

与 KVM_CAP_X86_USER_SPACE_MSR 结合使用,这允许用户空间捕获和模拟 KVM 范围之外的 MSR,并限制对 KVM 的 MSR 仿真代码的攻击面。

8.30 KVM_CAP_XEN_HVM

架构:

x86

此功能指示 Xen 支持用于托管 Xen PVHVM 客户机的功能。 有效标志为

#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR              (1 << 0)
#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL            (1 << 1)
#define KVM_XEN_HVM_CONFIG_SHARED_INFO                (1 << 2)
#define KVM_XEN_HVM_CONFIG_RUNSTATE                   (1 << 3)
#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL              (1 << 4)
#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND                (1 << 5)
#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG       (1 << 6)
#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE       (1 << 7)

KVM_XEN_HVM_CONFIG_HYPERCALL_MSR 标志指示 KVM_XEN_HVM_CONFIG ioctl 可用,用于客户机设置其系统调用页。

如果还设置了 KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,则可以在不提供系统调用页内容的情况下,在 KVM_XEN_HVM_CONFIG 的标志中提供相同的标志,以请求 KVM 自动生成系统调用页内容,并启用使用 KVM_EXIT_XEN 拦截客户机系统调用。

KVM_XEN_HVM_CONFIG_SHARED_INFO 标志指示 KVM_XEN_HVM_SET_ATTR、KVM_XEN_HVM_GET_ATTR、KVM_XEN_VCPU_SET_ATTR 和 KVM_XEN_VCPU_GET_ATTR ioctl 的可用性,以及当设置了 vcpu 的 vcpu_info 的 evtchn_upcall_pending 字段时,事件通道回调的异常向量的传递。

KVM_XEN_HVM_CONFIG_RUNSTATE 标志指示 KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST 等运行状态相关功能受 KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctl 支持。

KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL 标志指示支持类型为 KVM_IRQ_ROUTING_XEN_EVTCHN 的 IRQ 路由条目,并且优先级字段设置为指示 2 级事件通道传递。

KVM_XEN_HVM_CONFIG_EVTCHN_SEND 标志指示 KVM 支持使用 KVM_XEN_HVM_EVTCHN_SEND ioctl 将事件通道事件直接注入到客户机中。 它还指示支持与事件通道传递、计时器和 XENVER_version 拦截相关的 KVM_XEN_ATTR_TYPE_EVTCHN/XEN_VERSION HVM 属性和 KVM_XEN_VCPU_ATTR_TYPE_VCPU_ID/TIMER/UPCALL_VECTOR vCPU 属性。

KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG 标志指示 KVM 支持 KVM_XEN_SET_ATTR 和 KVM_XEN_GET_ATTR ioctl 中的 KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 属性。 这控制 KVM 是否将在更新运行状态信息期间,在客户机内存映射的 vcpu_runstate_info 中设置 XEN_RUNSTATE_UPDATE 标志。 请注意,支持上述 RUNSTATE 功能但不支持 RUNSTATE_UPDATE_FLAG 功能的 KVM 版本在更新客户机结构时将始终设置 XEN_RUNSTATE_UPDATE 标志,这可能违反直觉。 当公布此标志时,KVM 的行为将更正确,除非专门启用(通过客户机进行系统调用,从而使 VMM 能够启用 KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG 属性),否则不会使用 XEN_RUNSTATE_UPDATE 标志。

KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE 标志指示 KVM 支持清除 Xen pvclock 源中的 PVCLOCK_TSC_STABLE_BIT 标志。 这将在 KVM_CAP_XEN_HVM ioctl 设置 KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE 标志时完成。

8.31 KVM_CAP_SPAPR_MULTITCE

架构:

ppc

类型:

vm

此功能表示内核能够处理系统调用 H_PUT_TCE_INDIRECT 和 H_STUFF_TCE,而无需将它们传递到用户空间。 这显著加速了 PPC KVM 客户机的 DMA 操作。 用户空间应预期,如果用户空间先前在 KVM 中注册了 LIOBN(通过 KVM_CREATE_SPAPR_TCE 或类似调用),则其对这些系统调用的处理程序将不会被调用。

为了在客户机中启用 H_PUT_TCE_INDIRECT 和 H_STUFF_TCE 的使用,用户空间可能必须为客户机公布它。 例如,如果在“ibm,hypertas-functions”设备树属性中存在“hcall-multi-tce”,则 IBM pSeries (sPAPR) 客户机将开始使用它们。

上述系统调用可能在基于内核快速路径中成功处理,也可能未成功处理。 如果内核无法处理它们,它们将被传递到用户空间。 因此,尽管有内核加速,用户空间仍然必须对这些系统调用进行实现。

此功能始终启用。

8.32 KVM_CAP_PTP_KVM

架构:

arm64

此功能指示主机中支持 KVM 虚拟 PTP 服务。 VMM 可以检查迁移时服务是否对客户机可用。

8.37 KVM_CAP_S390_PROTECTED_DUMP

架构:

s390

类型:

vm

此功能指示 KVM 和 Ultravisor 支持转储 PV 客户机。 KVM_PV_DUMP 命令可用于 KVM_S390_PV_COMMAND ioctl,并且 KVM_PV_INFO 命令提供与转储相关的 UV 数据。 此外,vcpu ioctl KVM_S390_PV_CPU_COMMAND 可用,并且支持 KVM_PV_DUMP_CPU 子命令。

8.39 KVM_CAP_S390_CPU_TOPOLOGY

架构:

s390

类型:

vm

此功能指示 KVM 将提供 S390 CPU 拓扑设施,该设施包括对功能代码 2 的 PTF 指令的解释以及拦截和转发功能代码为 0 或 1 的 PTF 指令和 STSI(15,1,x) 指令到用户空间虚拟机监控程序。

如果没有此功能,则不应向客户机指示 stfle facility 11 CPU 拓扑设施。

当此功能存在时,KVM 在 vm fd 上提供新的属性组 KVM_S390_VM_CPU_TOPOLOGY。 此新属性允许通过 kvm_device_attr 结构获取、设置或清除 SCA 的修改后的更改拓扑报告 (MTCR) 位。

当获取修改后的更改拓扑报告值时,attr->addr 必须指向将在其中存储或检索该值的字节。

8.41 KVM_CAP_VM_TYPES

架构:

x86

类型:

系统 ioctl

此功能返回支持的 VM 类型的位图。 位 @n 的 1 设置表示支持值为 @n 的 VM 类型。 @n 的可能值为

#define KVM_X86_DEFAULT_VM    0
#define KVM_X86_SW_PROTECTED_VM       1
#define KVM_X86_SEV_VM        2
#define KVM_X86_SEV_ES_VM     3

注意,KVM_X86_SW_PROTECTED_VM 当前仅用于开发和测试。 不要将 KVM_X86_SW_PROTECTED_VM 用于“真实” VM,尤其不要在生产中使用。 软件保护的 VM 的行为和有效 ABI 不稳定。

8.42 KVM_CAP_PPC_RPT_INVALIDATE

架构:

ppc

此功能指示内核能够处理 H_RPT_INVALIDATE hcall。

为了在客户机中启用 H_RPT_INVALIDATE 的使用,用户空间可能必须为客户机公布它。 例如,如果在“ibm,hypertas-functions”设备树属性中存在“hcall-rpt-invalidate”,则 IBM pSeries (sPAPR) 客户机将开始使用它。

对于 POWER9 等支持 radix MMU 的平台上的虚拟机监控程序,此功能已启用。

8.43 KVM_CAP_PPC_AIL_MODE_3

架构:

ppc

此功能指示内核支持“中断时的地址转换模式”(也称为“备用中断位置”)资源的模式 3 设置,该资源由 H_SET_MODE 系统调用控制。

此功能允许客户机内核使用更高性能的模式来处理中断和系统调用。

8.44 KVM_CAP_MEMORY_FAULT_INFO

架构:

x86

此功能的出现表明,如果 KVM 无法解决客户机页面错误 VM-Exit,例如,如果存在有效的 memslot 但对应的宿主机虚拟地址没有支持的 VMA,则 KVM_RUN 将填充 kvm_run.memory_fault。

仅当 KVM_RUN 返回错误,errno=EFAULT 或 errno=EHWPOISON 并且 kvm_run.exit_reason 设置为 KVM_EXIT_MEMORY_FAULT 时,kvm_run.memory_fault 中的信息才有效。

注意:鼓励尝试解决内存错误的 Userspace 保护自己免于重复收到相同的错误/带注释的错误,以便他们可以重试 KVM_RUN。

有关更多信息,请参见 KVM_EXIT_MEMORY_FAULT。

8.45 KVM_CAP_X86_GUEST_MODE

架构:

x86

此功能的出现表明 KVM_RUN 将更新 kvm_run.flags 中的 KVM_RUN_X86_GUEST_MODE 位,以指示 vCPU 在退出时是否正在执行嵌套的客户机代码。

KVM 将退出时的 L1 或 L2 客户机的寄存器状态退出,具体取决于退出时执行的寄存器状态。 用户空间必须注意区分这些情况。

9. 已知的 KVM API 问题

在某些情况下,KVM 的 API 存在一些不一致或常见的陷阱,用户空间需要注意。本节详细介绍其中一些问题。

它们中的大多数是架构特定的,因此本节按架构划分。

9.1. x86

KVM_GET_SUPPORTED_CPUID 问题

通常,KVM_GET_SUPPORTED_CPUID 的设计使得可以直接获取其结果并将其传递给 KVM_SET_CPUID2。本节记录了一些需要注意的情况。

本地 APIC 功能

CPU[EAX=1]:ECX[21] (X2APIC) 由 KVM_GET_SUPPORTED_CPUID 报告,但只有在使用 KVM_CREATE_IRQCHIPKVM_ENABLE_CAP(KVM_CAP_IRQCHIP_SPLIT) 启用内核中本地 APIC 的模拟时才能启用。

对于 KVM_FEATURE_PV_UNHALT 半虚拟化功能也是如此。

在旧版本的 Linux 上,CPU[EAX=1]:ECX[24] (TSC_DEADLINE) 不由 KVM_GET_SUPPORTED_CPUID 报告,但如果存在 KVM_CAP_TSC_DEADLINE_TIMER 并且内核已启用内核中本地 APIC 的模拟,则可以启用它。 在较新版本上,KVM_GET_SUPPORTED_CPUID 确实报告该位可用。

CPU 拓扑

一些 CPUID 值包含主机 CPU 的拓扑信息:Intel 系统的 0x0b 和 0x1f,AMD 系统的 0x8000001e。 不同版本的 KVM 为此信息返回不同的值,用户空间不应依赖它。 目前,它们返回全零。

如果用户空间希望设置客户机拓扑,则应注意这三个叶子的值对于每个 CPU 而言都不同。 特别是,APIC ID 在 0x0b 和 0x1f 的所有子叶的 EDX 中找到,在 0x8000001e 的 EAX 中找到; 后者还在 EBX 和 ECX 的位 7:0 中分别编码核心 ID 和节点 ID。

过时的 ioctl 和 capabilities

KVM_CAP_DISABLE_QUIRKS 不允许用户空间知道实际可用的 quirks。 如果可用,请改用 KVM_CHECK_EXTENSION(KVM_CAP_DISABLE_QUIRKS2)

KVM_GET_*/KVM_SET_* ioctl 的排序

待定