权威 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:这些查询和设置控制单个设备操作的属性。

    设备 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。可以是“基本”,这意味着任何支持 API 版本 12 的内核都将提供该 ioctl(请参阅 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,应用程序应拒绝运行。如果此检查通过,则所有描述为“基本”的 ioctl 都将可用。

4.2 KVM_CREATE_VM

功能:

基本

架构:

全部

类型:

系统 ioctl

参数:

机器类型标识符 (KVM_VM_*)

返回:

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

新的 VM 没有虚拟 CPU 并且没有内存。您可能希望使用 0 作为机器类型。

X86:

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

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] 中公开的功能。它只会影响第 2 级(访客物理地址到主机物理地址转换)转换的地址大小。

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

参数:

结构体 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 库 MSR 不会返回在 MSR 列表中,因为不同的 vCPU 可以具有不同数量的库,通过 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 ioctl 查询功能(在 vm fd 上使用 KVM_CAP_CHECK_EXTENSION_VM 可用)。

4.5 KVM_GET_VCPU_MMAP_SIZE

功能:

基本

架构:

全部

类型:

系统 ioctl

参数:

返回:

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

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

除了 KVM_RUN 通信区域的大小外,VCPU 文件描述符的其他区域也可以进行 mmap 映射,包括:

  • 如果 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 的更多信息,请参阅 8.29 KVM_CAP_DIRTY_LOG_RING/KVM_CAP_DIRTY_LOG_RING_ACQ_REL

4.7 KVM_CREATE_VCPU

功能:

基本

架构:

全部

类型:

vm ioctl

参数:

vcpu id(x86 上的 apic id)

返回:

成功时返回 vcpu fd,错误时返回 -1

此 API 向虚拟机添加一个 vcpu。添加的 vcpu 不得超过 max_vcpus。vcpu id 是 [0, max_vcpu_id) 范围内的整数。

建议的 max_vcpus 值可以使用 KVM_CHECK_EXTENSION ioctl() 在运行时通过 KVM_CAP_NR_VCPUS 获取。max_vcpus 的最大可能值可以使用 KVM_CHECK_EXTENSION ioctl() 在运行时通过 KVM_CAP_MAX_VCPUS 获取。

如果 KVM_CAP_NR_VCPUS 不存在,则应假定 max_vcpus 最大为 4 个 cpu。如果 KVM_CAP_MAX_VCPUS 不存在,则应假定 max_vcpus 与 KVM_CAP_NR_VCPUS 返回的值相同。

max_vcpu_id 的最大可能值可以使用 KVM_CHECK_EXTENSION ioctl() 在运行时通过 KVM_CAP_MAX_VCPU_ID 获取。

如果 KVM_CAP_MAX_VCPU_ID 不存在,则应假定 max_vcpu_id 与 KVM_CAP_MAX_VCPUS 返回的值相同。

在 powerpc 上使用 book3s_hv 模式时,vcpus 会映射到一个或多个虚拟 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,可以将生成的 vcpu fd 在页面偏移量 KVM_S390_SIE_PAGE_OFFSET 处进行内存映射,以便获取虚拟 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 可用,则 slot 字段的位 16-31 指定要为其返回脏位图的地址空间。有关 slot 字段的用法的详细信息,请参阅 KVM_SET_USER_MEMORY_REGION。

除非启用 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2,否则脏位图中的位将在 ioctl 返回之前被清除。有关更多信息,请参阅功能说明。

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

4.10 KVM_RUN

功能:

基本

架构:

全部

类型:

vcpu ioctl

参数:

返回:

成功时返回 0,错误时返回 -1

错误

EINTR

未屏蔽的信号挂起

ENOEXEC

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

ENOSYS

在没有综合征信息的 memslot 之外进行数据中止,并且未启用 KVM_CAP_ARM_NISV_TO_USER(arm64)

EPERM

SVE 功能集已启用但未最终确定(arm64)

此 ioctl 用于运行访客虚拟 cpu。虽然没有显式参数,但有一个隐式参数块,可以通过将 vcpu fd 在偏移量 0 处进行 mmap() 映射来获得,其大小由 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 索引和值。基于 msr 的功能列表可以使用系统 ioctl 中的 KVM_GET_MSR_FEATURE_INDEX_LIST 获取。

当用作 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’ 成员(指示 entries 数组的大小)和每个数组条目的 ‘index’ 成员。kvm 将填写 ‘data’ 成员。

4.19 KVM_SET_MSRS

功能:

基本

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_msrs(输入)

返回:

成功设置的 msr 数量(见下文),错误时返回 -1

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

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

它尝试逐个设置数组 entries[] 中的 MSR。如果设置 MSR 失败,例如,由于设置了保留位,MSR 不受 KVM 支持/模拟等,它会停止处理 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},即在运行访客后更改访客 vCPU 模型,可能会导致访客不稳定。

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

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),否则用户空间不应将中断呈现给客户机作为低电平有效。

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 客户机用于初始化其 hypercall 页面的 MSR,并提供用户空间中 hypercall blob 的起始地址和大小。当客户机写入 MSR 时,kvm 会将 blob 的一页(32 位或 64 位,具体取决于 vcpu 模式)复制到客户机内存。

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 的 flags 字段中设置它们

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 来传递事件通道中断,而不是直接操作客户机的 shared_info 结构。反过来,这可能允许 KVM 启用诸如拦截 SCHEDOP_poll hypercall 以加速客户机的 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

获取当前客户机看到的 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 时主机实时时钟源的值进行比较。经过时间差会添加到将提供给客户机的最终 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:

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

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

此 API 提供了一种读取和写入客户机不可见的挂起“事件”状态的方法。要保存、还原或迁移 VCPU,可以使用此 GET/SET API 读取然后写入表示状态的结构,以及其他客户机可见的寄存器。无法“取消”已挂起的 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:

用户空间可能需要向客户机注入几种类型的事件。

为此 VCPU 设置挂起的 SError 异常状态。一旦 Serror 变为挂起状态,就无法“取消”它。

如果客户机访问了用户空间无法处理的 I/O 内存(例如,因为缺少指令综合征解码信息,或者因为在访问的 IPA 上没有映射设备),则用户空间可以请求内核使用 VCPU 上退出错误的地址注入外部中止。如果在退出时不是 KVM_EXIT_MMIO 或 KVM_EXIT_ARM_NISV,则设置 ext_dabt_pending 是一个编程错误。仅当系统支持 KVM_CAP_ARM_INJECT_EXT_DABT 时,此功能才可用。这是一个辅助功能,提供了用户空间在上述情况下向客户机报告访问的通用方式,适用于不同的用户空间实现。尽管如此,用户空间仍然可以通过使用 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 允许用户创建、修改或删除客户机物理内存槽。“slot”的 0-15 位指定槽 ID,此值应小于每个 VM 支持的最大用户内存槽数。可以使用 KVM_CAP_NR_MEMSLOTS 查询允许的最大槽数。槽在客户机物理地址空间中可能不会重叠。

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

删除槽的方法是将 memory_size 设置为零。更改现有槽时,它可以在客户机物理内存空间中移动,或者其标志可以修改,但不能调整大小。

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

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

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

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 功能可用时,内存区域后备的更改会自动反映到客户机中。例如,影响该区域的 mmap() 将立即可见。另一个示例是 madvise(MADV_DROP)。

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

S390:

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

4.36 KVM_SET_TSS_ADDR

功能:

KVM_CAP_SET_TSS_ADDR

架构:

x86

类型:

vm ioctl

参数:

unsigned long tss_address (输入)

返回:

成功时返回 0,错误时返回 -1

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

基于英特尔的主机上需要此 ioctl。由于虚拟化实现中的一个怪癖,英特尔硬件上需要此功能(请参阅内部文档,当它出现时)。

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,应用程序可以启用扩展,使其可供客户机使用。

在不支持此 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 当前的“多处理状态”(尽管在单处理器客户机上也是有效的)。

可能的值为

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 上,此 ioctl 仅在 KVM_CREATE_IRQCHIP 之后有用。如果没有内核 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 再次变为 RUNNABLE 时,它也会将 vCPU 恢复到其原始状态。例如,如果用户空间屏蔽了一个挂起的中断以抑制唤醒,则应在将控制权返回给客户机之前取消屏蔽该中断。

对于 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 上,此 ioctl 仅在 KVM_CREATE_IRQCHIP 之后有用。如果没有内核 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 (输入)

返回:

成功时返回 0,错误时返回 -1

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

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

基于英特尔的主机上需要此 ioctl。由于虚拟化实现中的一个怪癖,英特尔硬件上需要此功能(请参阅内部文档,当它出现时)。

如果已创建任何 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 (输出)

返回:

成功时返回 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 (输入)

返回:

成功时返回 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 (输出)

返回:

成功时返回 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 (输入)

返回:

成功时返回 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 (输入/输出)

返回:

成功时返回 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)可能会公开 cpuid 功能(例如 MONITOR),而这些功能在 kvm 的默认配置中不受支持。如果用户空间启用了此类功能,则它有责任适当地修改此 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

零个或多个以下值的或运算

KVM_CPUID_FLAG_SIGNIFCANT_INDEX

如果 index 字段有效

eax, ebx, ecx, edx

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

TSC 截止时间定时器功能(CPUID 叶 1,ecx[24])始终返回为 false,因为该功能依赖于 KVM_CREATE_IRQCHIP 来支持本地 APIC。相反,它通过以下方式报告

ioctl(KVM_CHECK_EXTENSION, KVM_CAP_TSC_DEADLINE_TIMER)

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

4.47 KVM_PPC_GET_PVINFO

功能:

KVM_CAP_PPC_GET_PVINFO

架构:

ppc

类型:

vm ioctl

参数:

struct kvm_ppc_pvinfo (输出)

返回:

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

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

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

hcall 数组定义了构成 hypercall 的 4 条指令。

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

标志位图定义为

/* 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 (输入)

返回:

成功时返回 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

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 事件通道。尽管存在 priority 字段,但仅支持值 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

参数:

虚拟 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

参数:

返回:

成功时为虚拟 tsc-khz,错误时为负值

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

4.57 KVM_GET_LAPIC

功能:

KVM_CAP_IRQCHIP

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_lapic_state (输出)

返回:

成功时返回 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 (输入)

返回:

成功时返回 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 (输入)

返回:

成功时为 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 (输入)

返回:

成功时返回 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 (输入)

返回:

用于操作创建的 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 输入配置为导致 panic,从而有助于调试。

4.65 KVM_S390_UCAS_MAP

功能:

KVM_CAP_S390_UCONTROL

架构:

s390

类型:

vcpu ioctl

参数:

struct kvm_s390_ucas_mapping (输入)

返回:

成功时为 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 (输入)

返回:

成功时为 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 绝对地址(输入)

返回:

成功时为 0

此调用在虚拟 CPU 的地址空间(对于用户控制的虚拟机)或虚拟机的地址空间(对于常规虚拟机)上创建一个页表项。这仅适用于次要故障,因此建议预先通过用户页表访问目标内存页。这对于处理用户控制虚拟机的有效性拦截非常有用,可以在调用 KVM_RUN ioctl 之前将虚拟 CPU 的低核页置入故障。

4.68 KVM_SET_ONE_REG

功能:

KVM_CAP_ONE_REG

架构:

全部

类型:

vcpu ioctl

参数:

struct kvm_one_reg (输入)

返回:

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

错误

ENOENT

没有这样的寄存器

EINVAL

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

EPERM

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

EBUSY

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

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

 struct kvm_one_reg {
      __u64 id;
      __u64 addr;
};

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

架构

寄存器

宽度(位)

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 寄存器使用低 32 位进行映射。高 16 位是寄存器组类型,或协处理器号

ARM 核心寄存器具有以下 id 位模式

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

ARM 32 位 CP15 寄存器具有以下 id 位模式

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

ARM 64 位 CP15 寄存器具有以下 id 位模式

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

ARM CCSIDR 寄存器通过 CSSELR 值进行多路分解

0x4020 0000 0011 00 <csselr:8>

ARM 32 位 VFP 控制寄存器具有以下 id 位模式

0x4020 0000 0012 1 <regno:12>

ARM 64 位 FP 寄存器具有以下 id 位模式

0x4030 0000 0012 0 <regno:12>

ARM 固件伪寄存器具有以下位模式

0x4030 0000 0014 <regno:16>

arm64 寄存器使用低 32 位进行映射。高 16 位是寄存器组类型,或协处理器号

arm64 核心/FP-SIMD 寄存器具有以下 id 位模式。请注意,访问的大小是可变的,因为 kvm_regs 结构包含从 32 位到 128 位的元素。索引是 kvm_regs 结构中的 32 位值,被视为 32 位数组

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

具体来说

编码

寄存器

kvm_regs 成员

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](别名 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 寄存器通过 CSSELR 值进行多路分解

0x6020 0000 0011 00 <csselr:8>

arm64 系统寄存器具有以下 id 位模式

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

警告

两个系统寄存器 ID 不遵循指定的模式。它们是 KVM_REG_ARM_TIMER_CVAL 和 KVM_REG_ARM_TIMER_CNT,分别映射到系统寄存器 CNTV_CVAL_EL0 和 CNTVCT_EL0。这两个的值被意外地交换了,这意味着 TIMER_CVAL 来自 CNTVCT_EL0 的寄存器编码,而 TIMER_CNT 来自 CNTV_CVAL_EL0 的寄存器编码。由于这是 API,因此必须保持这种方式。

arm64 固件伪寄存器具有以下位模式

0x6030 0000 0014 <regno:16>

arm64 SVE 寄存器具有以下位模式

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

如果 2048 * 切片 >= 128 * max_vq,则对寄存器 ID 的访问将失败,并显示 ENOENT。 max_vq 是 vcpu 支持的最大向量长度,以 128 位四字为单位:请参见下面的 [2]

这些寄存器仅在启用了 SVE 的 vcpu 上可访问。有关详细信息,请参阅 KVM_ARM_VCPU_INIT。

此外,除了 KVM_REG_ARM64_SVE_VLS 之外,在通过 KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE) 完成 vcpu 的 SVE 配置之前,这些寄存器都不可访问。有关此过程的更多信息,请参阅 KVM_ARM_VCPU_INIT 和 KVM_ARM_VCPU_FINALIZE。

KVM_REG_ARM64_SVE_VLS 是一个伪寄存器,允许用户空间发现和配置 vcpu 支持的向量长度集。当通过 KVM_GET_ONE_REG 或 KVM_SET_ONE_REG 传输到或从用户内存传输时,此寄存器的值类型为 __u64[KVM_ARM64_SVE_VLS_WORDS],并按以下方式编码向量长度集

__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 */

(有关 “vq” 命名法的解释,请参见 AArch64 Linux 的可伸缩向量扩展支持。)

KVM_REG_ARM64_SVE_VLS 只有在 KVM_ARM_VCPU_INIT 之后才能访问。 KVM_ARM_VCPU_INIT 将其初始化为宿主机支持的最佳向量长度集合。

如果需要,用户空间可以随后修改它,直到使用 KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE) 最终确定 vcpu 的 SVE 配置。

除了简单地从宿主机集合中移除所有超过某个值的向量长度之外,对任意选择的向量长度集合的支持取决于硬件,并且可能不可用。尝试通过 KVM_SET_ONE_REG 配置无效的向量长度集合将会失败,并返回 EINVAL。

在最终确定 vcpu 的 SVE 配置后,进一步尝试写入此寄存器将会失败,并返回 EPERM。

arm64 位图特性固件伪寄存器具有以下位模式

0x6030 0000 0016 <regno:16>

位图特性固件寄存器公开了用户空间可用于配置的超调用服务。设置的位对应于可供客户机访问的服务。默认情况下,KVM 在 VM 初始化期间设置所有支持的位。用户空间可以通过 KVM_GET_ONE_REG 发现可用的服务,并通过 KVM_SET_ONE_REG 写回与希望客户机看到的功能对应的位图。

注意:一旦 VM 的任何 vCPU 至少运行过一次,这些寄存器就不可更改。在这种情况下,KVM_SET_ONE_REG 将会向用户空间返回 -EBUSY。

(有关更多详细信息,请参阅 暴露给客户机的 KVM/arm64 特定超调用。)

MIPS 寄存器使用低 32 位进行映射。高 16 位是寄存器组类型

MIPS 核心寄存器(见上文)具有以下 ID 位模式

0x7030 0000 0000 <reg:16>

MIPS CP0 寄存器(见上面的 KVM_REG_MIPS_CP0_*)根据它们是 32 位还是 64 位寄存器具有以下 ID 位模式

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

注意:KVM_REG_MIPS_CP0_ENTRYLO0 和 KVM_REG_MIPS_CP0_ENTRYLO1 是 EntryLo 寄存器的 MIPS64 版本,无论宿主机硬件、宿主机内核、客户机的字长如何,以及客户机中是否存在 XPA,即 RI 和 XI 位(如果存在)分别位于位 63 和 62,PFNX 字段从位 30 开始。

MIPS MAAR(见上面的 KVM_REG_MIPS_CP0_MAAR(*))具有以下 ID 位模式

0x7030 0000 0001 01 <reg:8>

MIPS KVM 控制寄存器(见上文)具有以下 ID 位模式

0x7030 0000 0002 <reg:16>

MIPS FPU 寄存器(见上面的 KVM_REG_MIPS_FPR_{32,64}())根据访问的寄存器的大小具有以下 ID 位模式。它们始终根据当前客户机 FPU 模式(Status.FR 和 Config5.FRE)进行访问,即按照客户机看到的方式进行访问,如果客户机 FPU 模式发生更改,则它们将变得不可预测。MIPS SIMD 架构 (MSA) 向量寄存器(见上面的 KVM_REG_MIPS_VEC_128())具有相似的模式,因为它们与 FPU 寄存器重叠

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 控制寄存器(见上面的 KVM_REG_MIPS_FCR_{IR,CSR})具有以下 ID 位模式

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

MIPS MSA 控制寄存器(见上面的 KVM_REG_MIPS_MSA_{IR,CSR})具有以下 ID 位模式

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

RISC-V 寄存器使用低 32 位进行映射。高 8 位是寄存器组类型。

RISC-V 配置寄存器用于配置客户机 VCPU,它具有以下 ID 位模式

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)

以下是 RISC-V 配置寄存器

编码

寄存器

描述

0x80x0 0000 0100 0000

isa

客户机 VCPU 的 ISA 特性位图

isa 配置寄存器可以随时读取,但只能在客户机 VCPU 运行之前写入。默认情况下,它将具有与底层宿主机集合匹配的 ISA 特性位。

RISC-V 核心寄存器表示客户机 VCPU 的通用执行状态,它具有以下 ID 位模式

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)

以下是 RISC-V 核心寄存器

编码

寄存器

描述

0x80x0 0000 0200 0000

regs.pc

程序计数器

0x80x0 0000 0200 0001

regs.ra

返回地址

0x80x0 0000 0200 0002

regs.sp

堆栈指针

0x80x0 0000 0200 0003

regs.gp

全局指针

0x80x0 0000 0200 0004

regs.tp

任务指针

0x80x0 0000 0200 0005

regs.t0

调用者保存的寄存器 0

0x80x0 0000 0200 0006

regs.t1

调用者保存的寄存器 1

0x80x0 0000 0200 0007

regs.t2

调用者保存的寄存器 2

0x80x0 0000 0200 0008

regs.s0

被调用者保存的寄存器 0

0x80x0 0000 0200 0009

regs.s1

被调用者保存的寄存器 1

0x80x0 0000 0200 000a

regs.a0

函数参数(或返回值)0

0x80x0 0000 0200 000b

regs.a1

函数参数(或返回值)1

0x80x0 0000 0200 000c

regs.a2

函数参数 2

0x80x0 0000 0200 000d

regs.a3

函数参数 3

0x80x0 0000 0200 000e

regs.a4

函数参数 4

0x80x0 0000 0200 000f

regs.a5

函数参数 5

0x80x0 0000 0200 0010

regs.a6

函数参数 6

0x80x0 0000 0200 0011

regs.a7

函数参数 7

0x80x0 0000 0200 0012

regs.s2

被调用者保存的寄存器 2

0x80x0 0000 0200 0013

regs.s3

被调用者保存的寄存器 3

0x80x0 0000 0200 0014

regs.s4

被调用者保存的寄存器 4

0x80x0 0000 0200 0015

regs.s5

被调用者保存的寄存器 5

0x80x0 0000 0200 0016

regs.s6

被调用者保存的寄存器 6

0x80x0 0000 0200 0017

regs.s7

被调用者保存的寄存器 7

0x80x0 0000 0200 0018

regs.s8

被调用者保存的寄存器 8

0x80x0 0000 0200 0019

regs.s9

被调用者保存的寄存器 9

0x80x0 0000 0200 001a

regs.s10

被调用者保存的寄存器 10

0x80x0 0000 0200 001b

regs.s11

被调用者保存的寄存器 11

0x80x0 0000 0200 001c

regs.t3

调用者保存的寄存器 3

0x80x0 0000 0200 001d

regs.t4

调用者保存的寄存器 4

0x80x0 0000 0200 001e

regs.t5

调用者保存的寄存器 5

0x80x0 0000 0200 001f

regs.t6

调用者保存的寄存器 6

0x80x0 0000 0200 0020

mode

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

RISC-V csr 寄存器表示客户机 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 寄存器

编码

寄存器

描述

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 定时器寄存器表示客户机 VCPU 的定时器状态,它具有以下 ID 位模式

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

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

编码

寄存器

描述

0x8030 0000 0400 0000

frequency

时基频率(只读)

0x8030 0000 0400 0001

time

对客户机可见的时间值

0x8030 0000 0400 0002

compare

客户机编程的时间比较值

0x8030 0000 0400 0003

state

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

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

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

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

编码

寄存器

描述

0x8020 0000 0500 0000

f[0]

浮点寄存器 0

...

0x8020 0000 0500 001f

f[31]

浮点寄存器 31

0x8020 0000 0500 0020

fcsr

浮点控制和状态寄存器

RISC-V D 扩展寄存器表示客户机 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 扩展寄存器

编码

寄存器

描述

0x8030 0000 0600 0000

f[0]

浮点寄存器 0

...

0x8030 0000 0600 001f

f[31]

浮点寄存器 31

0x8020 0000 0600 0020

fcsr

浮点控制和状态寄存器

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

LoongArch csr 寄存器用于控制客户机 CPU 或获取客户机 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 上受保护虚拟化模式下的虚拟机中使用

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 设置一个可供客户机访问的标志,指示指定的 vCPU 已被宿主机用户空间暂停。

宿主机将在 pvclock 结构中设置一个标志,该标志由软锁死看门狗检查。该标志是客户机和宿主机之间共享的 pvclock 结构的一部分,具体来说是 pvclock_vcpu_time_info 结构的 flags 字段的第二位。它将完全由宿主机设置,并完全由客户机读取/清除。客户机检查和清除标志的操作必须是原子操作,因此必须使用加载链接/存储条件或等效操作。有两种情况客户机将清除该标志:当软锁死看门狗定时器自行重置时或检测到软锁死时。此 ioctl 可以在暂停 vcpu 之后但在恢复 vcpu 之前随时调用。

4.71 KVM_SIGNAL_MSI

功能:

KVM_CAP_SIGNAL_MSI

架构:

x86 arm64

类型:

vm ioctl

参数:

struct kvm_msi (输入)

返回:

>0 表示已传递,0 表示客户机阻止了 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 定时器中断可能会使用每个虚拟机的内核线程进行注入。如果存在,此线程将具有以下模式的名称:

kvm-pit/<owner-process-pid>

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

此 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 仿真的功能。用户空间可以反过来使用它来为客户机操作系统生成适当的设备树属性。

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

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

    设置此标志后,客户机页大小必须“适合”后备存储页大小。如果未设置,则可以使用列表中的任何页大小,而不管它们在用户空间中是如何备份的。

  • KVM_PPC_1T_SEGMENTS

    除了标准的 256M 段外,仿真的 MMU 还支持 1T 段。

  • KVM_PPC_NO_HASH

    此标志指示 KVM 不支持 HPT 客户机,因此所有客户机都必须使用基数 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 以直接触发客户机中断。kvm_irqfd.fd 指定用作 eventfd 的文件描述符,kvm_irqfd.gsi 指定此事件切换的 irqchip 引脚。当 eventfd 上触发事件时,将使用指定的 gsi 引脚将中断注入到客户机中。使用 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 半虚拟化接口为客户机分配 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 置零)。在任何一种情况下,如果客户机正在使用虚拟化的实模式区域 (VRMA) 功能,则内核将在任何 vcpu 的下一个 KVM_RUN 上重新创建 VMRA HPTE。

4.77 KVM_S390_INTERRUPT

功能:

基本

架构:

s390

类型:

vm ioctl,vcpu ioctl

参数:

struct kvm_s390_interrupt (输入)

返回:

成功时返回 0,错误时返回 -1

允许将中断注入到客户机。根据中断类型,中断可以是浮动的 (vm ioctl) 或每个 CPU (vcpu ioctl)。

中断参数通过 kvm_s390_interrupt 传递

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

类型可以是以下之一

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 中的 I/O 中断参数(子通道)和 parm64(intparm,中断子类)

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

这会返回一个文件描述符,该文件描述符可以用来读取客户机哈希页表 (HPT) 中的条目,或写入条目以初始化 HPT。只有在参数的标志字段中设置了 KVM_GET_HTAB_WRITE 位时,才能写入返回的 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 标志,则仅测试是否支持设备类型(不一定测试是否可以在当前虚拟机中创建它)。

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

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,vcpu 设备的 KVM_CAP_VCPU_ATTRIBUTES,系统 (/dev/kvm) 设备的 KVM_CAP_SYS_ATTRIBUTES(无设置)

架构:

x86, arm64, s390

类型:

设备 ioctl,虚拟机 ioctl,vcpu ioctl

参数:

struct kvm_device_attr

返回:

成功时返回 0,错误时返回 -1

错误

ENXIO

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

EPERM

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

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

获取/设置指定的设备配置和/或状态。语义是设备特定的。请参阅“devices”目录中的各个设备文档。与 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,vcpu 设备的 KVM_CAP_VCPU_ATTRIBUTES,系统 (/dev/kvm) 设备的 KVM_CAP_SYS_ATTRIBUTES

类型:

设备 ioctl,虚拟机 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 向客户机呈现哪种类型的 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(或 SVC)进行热重置时的值

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

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

可能的功能

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

  • 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 写入。

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 返回的信息可用于为 KVM_ARM_VCPU_INIT ioctl 准备 struct kvm_vcpu_init 实例,这将导致 VCPU 与底层主机匹配。

4.84 KVM_GET_REG_LIST

功能:

基本

架构:

arm64、mips、riscv

类型:

vcpu ioctl

参数:

struct kvm_reg_list (输入/输出)

返回:

成功时返回 0;错误时返回 -1

错误

E2BIG

寄存器索引列表太大,无法容纳用户指定的数组(所需数量将写入 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 目前仅在对硬件 VGIC 功能使用内核内 GIC 支持时才需要此功能,使用 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 (输入/输出)

返回:

成功时返回 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 在 KVM_GET_SUPPORTED_CPUID 中公开,因此不包括在此处。

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

function

用于获取条目的 eax 值

index

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

flags

零个或多个以下值的或运算

KVM_CPUID_FLAG_SIGNIFCANT_INDEX

如果 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 位程序异常代码

从 VM 的内存中读取或向其中写入数据。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)。可以通过检查 KVM_CAP_S390_MEM_OP 功能来获取“size”的最大值。“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”指向的值时发生,而不是执行无条件写入。这是作为原子 cmpxchg 执行的,其长度由“size”参数指定。“size” 必须是 2 的幂,直到 16(含 16)。如果由于目标值与旧值不匹配而未发生交换,则“old_addr”指向的值将被目标值替换。用户空间可以通过检查是否发生了此替换来判断是否发生了交换。如果 KVM_CAP_S390_MEM_OP_EXTENSION 设置了标志 KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG,则允许执行 cmpxchg 操作。

支持的标志
  • 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 开始,持续 count 帧。

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

4.92 KVM_S390_IRQ

功能:

KVM_CAP_S390_INJECT_IRQ

架构:

s390

类型:

vcpu ioctl

参数:

struct kvm_s390_irq (in)

返回:

成功时返回 0,错误时返回 -1

错误

EINVAL

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

EBUSY

类型为 KVM_S390_SIGP_SET_PREFIX 且 vcpu 未停止,类型为 KVM_S390_SIGP_STOP 且已存在挂起的停止中断,类型为 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;
};

类型可以是以下之一

  • 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 (out)

返回:

>= 复制到缓冲区中的字节数,如果缓冲区大小为 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 复制到提供的缓冲区。

该结构包含一个标志和一个保留字段,用于将来的扩展。由于内核从未检查标志 == 0,并且 QEMU 从未预先清零标志和保留字段,因此将来不能在不破坏兼容性的情况下使用这些字段。

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

4.95 KVM_S390_SET_IRQ_STATE

功能:

KVM_CAP_S390_IRQ_STATE

架构:

s390

类型:

vcpu ioctl

参数:

struct kvm_s390_irq_state (in)

返回:

成功时为 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 */
};

标志和保留字段的限制也适用。(请参见 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 的标志值

KVM_MSR_FILTER_READ

使用给定的位图过滤对 MSR 的读取访问。位图中的 0 表示应拒绝读取访问,而 1 表示应允许读取特定 MSR,而不管默认的筛选操作如何。

KVM_MSR_FILTER_WRITE

使用给定的位图过滤对 MSR 的写入访问。位图中的 0 表示应拒绝写入访问,而 1 表示应允许写入特定 MSR,而不管默认的筛选操作如何。

struct kvm_msr_filter 的标志值

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,第三卷 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,如果提供的 shift 或标志无效则返回 -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,如果提供的 shift 或标志无效则返回 -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。为了与其他 ioctl 保持一致,重新使用 KVM_S390_SKEYS_MAX。

结果写入到字段 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

类型:

虚拟机

参数:

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

返回:

成功时返回 0;错误时返回 -1

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

目前,此 ioctl 用于在 AMD 处理器上发出安全加密虚拟化 (SEV) 命令。SEV 命令在安全加密虚拟化 (SEV)中定义。

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根据在结构体 kvm_clear_dirty_log 的 dirty_bitmap 字段中传递的位图,清除内存槽中页面的脏状态。位图的第 0 位对应于内存槽中的“first_page”页面,num_pages 是输入位图的位大小。first_page 必须是 64 的倍数;除非 first_page + num_pages 是内存槽的大小,否则 num_pages 也必须是 64 的倍数。对于输入位图中设置的每个位,相应的页面在 KVM 的脏位图中被标记为“干净”,并且该页面的脏跟踪被重新启用(例如,通过写保护,或通过清除页表条目中的脏位)。

如果 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 (输入/输出)

返回:

成功时返回 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’ 字段当前是保留的,用户空间不应期望在那里获得任何特定值。

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

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

  • 只有在内核 LAPIC 中才会公开 HV_STIMER_DIRECT_MODE_AVAILABLE 位。(假定已调用 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. 如果找到匹配项,请将客户机的单元掩码与包含的过滤器事件的掩码和匹配值进行匹配。即 (单元掩码 & 掩码) == 匹配 && !排除。

  3. 如果找到匹配项,请将客户机的单元掩码与排除的过滤器事件的掩码和匹配值进行匹配。即 (单元掩码 & 掩码) == 匹配 && 排除。

    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

如果超管理器未能终止安全客户机

ENOMEM

如果虚拟机监控程序未能为客户机分配新的基数页表

此 ioctl 用于关闭客户机的安全模式或将客户机从安全模式转换为正常模式。在客户机重置时调用此方法。如果为正常客户机调用,则此方法无效。

此 ioctl 发出超管理器调用以终止安全客户机,取消固定 VPA 页面并释放虚拟机监控程序用于跟踪安全页面的所有设备页面。

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];
};

超管理器返回代码 如果执行了超管理器调用以实现命令预期的结果,则内核会提供超管理器返回(原因)代码。因此,它们独立于 IOCTL 返回代码。如果 KVM 更改 rc,则其值将始终大于 0,因此建议在发出 PV 命令之前将其设置为 0,以便能够检测 rc 的更改。

cmd 值

KVM_PV_ENABLE

分配内存并将 VM 注册到超管理器,从而将内存捐赠给超管理器,这将使 KVM 无法访问该内存。所有现有的 CPU 都将转换为受保护的 CPU。在此命令成功后,任何通过热插拔添加的 CPU 也将在创建过程中变为受保护的 CPU。

错误

EINTR

未屏蔽的信号挂起

KVM_PV_DISABLE

从超管理器取消注册 VM,并回收已捐赠给超管理器的内存,使其再次可供内核使用。所有已注册的 VCPU 都将转换回非受保护的 VCPU。如果先前受保护的 VM 已通过 KVM_PV_ASYNC_CLEANUP_PREPARE 准备好进行异步拆卸,但随后未通过 KVM_PV_ASYNC_CLEANUP_PERFORM 拆卸,则将在本次调用中与当前受保护的 VM 一起拆卸。

KVM_PV_VM_SET_SEC_PARMS

将 VM 内存中的映像标头传递到超管理器,以准备映像解包和验证。

KVM_PV_VM_UNPACK

解包(保护和解密)加密的启动映像的页面。

KVM_PV_VM_VERIFY

验证解包映像的完整性。仅当此操作成功时,才允许 KVM 启动受保护的 VCPU。

KVM_PV_INFO
功能:

KVM_CAP_S390_PROTECTED_DUMP

提供一个 API,该 API 通过子命令向用户空间提供与超管理器相关的数据。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 主机提供基本的超管理器信息。这些值也可能作为 sysfs 固件 UV 查询接口中的文件导出,但在此 API 中更易于程序使用。

已安装的调用和 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

准备当前的受保护虚拟机以进行异步拆卸。当前受保护虚拟机使用的大部分资源将被保留以供后续异步拆卸。然后,当前受保护的虚拟机将立即恢复执行,作为非受保护的虚拟机。在任何时候,最多可以有一个受保护的虚拟机为异步拆卸做好准备。如果已经准备好一个受保护的虚拟机进行拆卸,而没有随后调用 KVM_PV_ASYNC_CLEANUP_PERFORM,则此调用将失败。在这种情况下,用户空间进程应发出正常的 KVM_PV_DISABLE。使用此调用保留的资源需要通过随后调用 KVM_PV_ASYNC_CLEANUP_PERFORM 或 KVM_PV_DISABLE 来清理,否则将在 KVM 终止时清理。一旦清理开始,即在 KVM_PV_ASYNC_CLEANUP_PERFORM 完成之前,可以再次调用 KVM_PV_ASYNC_CLEANUP_PREPARE。

KVM_PV_ASYNC_CLEANUP_PERFORM
功能:

KVM_CAP_S390_PROTECTED_ASYNC_DISABLE

拆卸先前使用 KVM_PV_ASYNC_CLEANUP_PREPARE 准备拆卸的受保护虚拟机。在此命令执行期间,将释放已保留的资源。此 PV 命令最好由用户空间从单独的线程发出。如果收到致命信号(或进程自然终止),该命令将立即终止而不会完成,并且正常的 KVM 关闭程序将负责清理所有剩余的受保护虚拟机,包括那些因进程终止而中断拆卸的虚拟机。

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

将虚拟机的 ABI 模式设置为 32 位或 64 位(长模式)。这决定了暴露给虚拟机的 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 事件通道上调的异常向量。这是由虚拟机监控程序直接注入的 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 上的事件。可以通过在后续调用中设置 KVM_XEN_EVTCHN_UPDATE 来更改 vCPU 和优先级,但对于给定的发送端口,其他字段无法更改。通过在 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 客户机通常会使用此方法作为虚拟超调用来触发事件通道传递,因此在内核中响应而不退出到用户空间是有益的。

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 超调用的 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 上调向量,该向量由 Xen 客户机通过 HVMOP_set_evtchn_upcall_vector 超调用配置。这通常由 Windows 客户机使用,并且与使用 HVM_PARAM_CALLBACK_IRQ 配置的 HVM 范围上调向量不同。通过将向量设置为零来禁用它。

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 (输出)

返回:

成功时返回 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 的标志值

KVM_SREGS2_FLAGS_PDPTRS_VALID

指示该结构包含有效的 PDPTR 值。

4.132 KVM_SET_SREGS2

功能:

KVM_CAP_SREGS2

架构:

x86

类型:

vcpu ioctl

参数:

struct kvm_sregs2 (输入)

返回:

成功时返回 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),而最后一个桶的范围是 [``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 表示统计信息数据用于测量内存大小,单位为字节、千字节、兆字节、千兆字节等。数据的单位由描述符中的 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 时钟周期。例如,-9 的指数可以与 KVM_STATS_UNIT_SECONDS 一起使用,以表示单位为纳秒。

  • KVM_STATS_BASE_POW2 刻度基于 2 的幂。它用于测量内存大小。例如,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 (输出)

返回:

成功时返回 0,错误时返回 -1

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

此 ioctl 会将当前 vcpu 的 xsave 结构复制到用户空间。它会复制在 vm 文件描述符上调用 KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) 时返回的字节数。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” 字段的任何其他值都可能导致返回错误 (-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_CHECK_EXTENSION 对于 KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES 功能会返回支持的范围,表示为一组标志。 每个标志的位索引表示 range 字段的可能值。 所有其他值都保留供将来使用,KVM 可能会返回错误。

reserved[13] 数组保留供将来使用,应为 0,否则 KVM 可能会返回错误。

KVM_ARM_FEATURE_ID_RANGE (0)

功能 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 内存映射到访客。 所有与 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 映射到访客时,KVM 根据 gfn 的 KVM_MEMORY_ATTRIBUTE_PRIVATE 状态选择共享内存与私有内存,即使用 userspace_addr 与 guest_memfd。 在 VM 创建时,所有内存都是共享的,即对于所有 gfn,PRIVATE 属性为“0”。 用户空间可以通过根据需要通过 KVM_SET_MEMORY_ATTRIBUTES 切换 KVM_MEMORY_ATTRIBUTE_PRIVATE 来控制内存是否共享/私有。

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 结构用于管理单个虚拟机的情况下使用,例如,在执行虚拟机的内部主机迁移时。

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

虚拟机管理程序不支持,或当前 vCPU 状态/模式不支持映射 GPA 的内存。

EIO

意外的错误情况(也会导致 WARN)

struct kvm_pre_fault_memory {
      /* in/out */
      __u64 gpa;
      __u64 size;
      /* in */
      __u64 flags;
      __u64 padding[5];
};

KVM_PRE_FAULT_MEMORY 会填充 KVM 的第二阶段页表,用于映射当前 vCPU 状态的内存。 KVM 映射内存的方式与 vCPU 生成第二阶段读取页故障的方式相同,例如,根据需要故障内存,但不破坏 CoW。 但是,KVM 不会将任何新创建的第二阶段 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 在可以向客户机注入外部中断时返回。与 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 由于未知原因退出。硬件退出原因中提供了更多特定于架构的信息。

/* 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。硬件入口失败原因中提供了更多特定于架构的信息。

/* 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_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 过滤器的配置启用。有关更多详细信息,请参阅通用虚拟机接口 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' 的特殊 hypercall 接口。为了启用它,我们捕获 hypercall 并使用包含所有客户机 gpr 的此出口结构退出。

如果 exit_reason 是 KVM_EXIT_OSI,则 vcpu 触发了此类 hypercall。用户空间现在可以处理 hypercall,并在完成后根据需要修改 gpr。在客户机入口时,所有客户机 GPR 都将替换为此结构中的值。

/* KVM_EXIT_PAPR_HCALL */
struct {
        __u64 nr;
        __u64 ret;
        __u64 args[9];
} papr_hcall;

当在 64 位 PowerPC 上模拟 pSeries 分区时(例如,在 qemu 中使用 “pseries” 机器类型),使用此退出。当客户机使用 ‘sc 1’ 指令进行 hypercall 时,会发生此退出。 ‘nr’ 字段包含 hypercall 编号(来自客户机 R3),‘args’ 包含参数(来自客户机 R4 - R12)。用户空间应将返回代码放在 ‘ret’ 中,并将任何额外的返回值放在 args[] 中。可能的 hypercall 在 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 被拦截时,会发生此退出。如果 dequeued 设置为 true,则已将目标子通道的挂起 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
                      __u32 type;
                      __u32 ndata;
                      __u64 data[16];
              } system_event;

如果 exit_reason 是 KVM_EXIT_SYSTEM_EVENT,则 vcpu 使用某些特定于架构的机制(hypercall 或某些特殊指令)触发了系统级事件。对于 ARM64,这是使用来自 vcpu 的基于 HVC 指令的 PSCI 调用触发的。

‘type’ 字段描述了系统级事件类型。 ‘type’ 的有效值是

  • KVM_SYSTEM_EVENT_SHUTDOWN -- 客户机已请求关闭虚拟机。用户空间没有义务遵守此请求,如果确实遵守此请求,则无需同步销毁虚拟机(即,它可以在最终关闭发生之前再次调用 KVM_RUN)。

  • KVM_SYSTEM_EVENT_RESET -- 客户机已请求重置虚拟机。与 SHUTDOWN 一样,用户空间可以选择忽略该请求,或者计划将来发生重置,并且可以再次调用 KVM_RUN。

  • KVM_SYSTEM_EVENT_CRASH -- 发生客户机崩溃,并且客户机已请求崩溃条件维护。用户空间可以选择忽略该请求,或者收集虚拟机内存核心转储和/或重置/关闭虚拟机。

  • KVM_SYSTEM_EVENT_SEV_TERM -- AMD SEV 客户机请求终止。客户机的 GHCB 的客户机物理地址存储在 data[0] 中。

  • KVM_SYSTEM_EVENT_WAKEUP -- 退出的 vCPU 处于挂起状态,并且 KVM 已识别到唤醒事件。用户空间可以通过将退出的 vCPU 标记为可运行来接受此事件,或者拒绝它并再次调用 KVM_RUN。

  • KVM_SYSTEM_EVENT_SUSPEND -- 客户机已请求挂起虚拟机。

如果存在 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 寄存器中。

_要求_ 用户空间对此类退出采取措施。它必须执行以下操作之一

  • 接受客户机挂起虚拟机的请求。用户空间可以通过将调用 vCPU 的状态设置为 KVM_MP_STATE_SUSPENDED 来请求内核模拟挂起。当恢复调用 vCPU 时,用户空间必须根据传递给 PSCI 函数的参数配置 vCPU 的状态。有关函数参数的详细信息,请参阅 ARM DEN0022D.b 5.19.1 “预期用途”。

  • 拒绝客户机挂起虚拟机的请求。有关可能的返回值,请参阅 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 合成调试器状态更改。通知用于更新 pending_page 位置,或发送控制命令(发送 send_page 中的缓冲区或接收 recv_page 中的缓冲区)。

/* KVM_EXIT_ARM_NISV */
struct {
        __u64 esr_iss;
        __u64 fault_ipa;
} arm_nisv;

用于 arm64 系统。如果访客访问内存不在内存槽中,KVM 通常会返回用户空间,并要求它代表执行 MMIO 仿真。但是,对于某些类型的指令,没有提供指令解码(方向、内存访问长度),并且从 VM 中获取和解码指令过于复杂,无法在内核中实现。

历史上,当发生这种情况时,KVM 会打印警告并终止 VM。KVM 假设如果访客访问非内存槽内存,则它正在尝试执行 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 时,对会调用 KVM 内核代码的 #GP 的寄存器的 MSR 访问,可能会改为触发读取的 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 已执行了 KVM RISC-V 内核模块未处理的 SBI 调用。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_EXIT_MEMORY_FAULT 在所有 KVM 退出原因中是唯一的,因为它伴随着返回代码 '-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,则会得到未知的结果。

        /* 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,这些字段允许用户空间访问某些访客寄存器,而无需调用 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 超级调用的拦截,否则这些超级调用将被视为要注入访客的正常系统调用。OSI 超级调用由 Mac-on-Linux 发明,目的是在访客和主机之间建立标准化的通信机制。

启用此功能后,可能会发生 KVM_EXIT_OSI。

6.2 KVM_CAP_PPC_PAPR

架构:

ppc

目标:

vcpu

参数:

返回:

成功时返回 0;错误时返回 -1

此功能启用对 PAPR 超级调用的拦截。PAPR 超级调用使用超级调用指令“sc 1”完成。

它还会将访客权限级别设置为“supervisor”模式。通常,访客在“hypervisor”权限模式下运行,但缺少一些功能。

除了以上内容,它还会更改 SDR1 的语义。在这种模式下,SDR1 的 HTAB 地址部分包含 HVA 而不是 GPA,因为 PAPR 使 HTAB 对访客不可见。

启用此功能后,可能会发生 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 返回时,共享区域将反映访客 TLB 的当前状态。如果用户空间进行任何更改,则必须在再次在此 vcpu 上调用 KVM_RUN 之前调用 KVM_DIRTY_TLB,以告知 KVM 哪些条目已更改。

对于 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),每次访客收到传递的外部中断时,它都会自动退出到用户空间,并带有 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

目标:

虚拟机

参数:

此功能为 s390 启用内核中的 irqchip。详情请参阅“4.24 KVM_CREATE_IRQCHIP”。

6.9 KVM_CAP_MIPS_FPU

架构:

mips

目标:

vcpu

参数:

args[0] 保留供将来使用(应为 0)。

此功能允许客户机使用主机浮点单元。它允许将 Config1.FP 位设置为启用客户机中的 FPU。一旦完成,就可以访问 KVM_REG_MIPS_FPR_*KVM_REG_MIPS_FCR_* 寄存器(取决于当前的客户机 FPU 寄存器模式),并且可以通过 KVM API 以及从客户机访问 Status.FR 和 Config5.FRE 位,前提是它们受 FPU 支持。

6.10 KVM_CAP_MIPS_MSA

架构:

mips

目标:

vcpu

参数:

args[0] 保留供将来使用(应为 0)。

此功能允许客户机使用 MIPS SIMD 架构 (MSA)。它允许将 Config3.MSAP 位设置为启用客户机对 MSA 的使用。一旦完成,就可以访问 KVM_REG_MIPS_VEC_*KVM_REG_MIPS_MSA_* 寄存器,并且可以通过 KVM API 以及从客户机访问 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“允许用户空间访问某些客户机寄存器,而无需调用 SET/GET_*REGS”。这通过消除用于设置和/或获取寄存器值的重复 ioctl 调用来减少开销。当用户空间进行同步客户机状态修改时,例如当在用户空间中模拟和/或拦截指令时,这一点尤其重要。

有关 s390 的详细信息,请参阅源代码。

对于 x86

  • 要复制到 kvm_run 的寄存器集由用户空间选择(而不是每次退出都复制所有集)。

  • 除了 regs 和 sregs 外,还提供 vcpu_events。

对于 x86,结构 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 设备。

7. 虚拟机上可以启用的功能

启用后,某些功能会更改虚拟机的行为。要启用它们,请参阅 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 并禁用其他 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。

此功能还启用中断请求的内核路由;当在 IRQ 路由表中使用 KVM_CAP_SPLIT_IRQCHIP 时,仅使用 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 客户机使用保护存储。

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 也必须不大于主机每个子核心的线程数。目前 flags 必须为 0。成功调用启用此功能将在随后查询 VM 的 KVM_CAP_PPC_SMT 功能时返回 vsmt_mode。此功能仅受 HV KVM 支持,并且只能在创建任何 VCPU 之前设置。KVM_CAP_PPC_SMT_POSSIBLE 功能指示可用的虚拟 SMT 模式。

7.12 KVM_CAP_PPC_FWNMI

架构:

ppc

参数:

使用此功能,客户机地址空间中的机器检查异常将导致 KVM 以 NMI 退出原因退出客户机。这使 QEMU 能够构建错误日志并分支到客户机内核注册的机器检查处理例程。如果没有此功能,KVM 将分支到客户机的 0x200 中断向量。

7.13 KVM_CAP_X86_DISABLE_EXITS

架构:

x86

参数:

args[0] 定义禁用哪些退出

返回:

成功返回 0,当 args[0] 包含无效的退出时返回 -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)

在虚拟机上启用此功能后,用户空间可以不再拦截某些指令,从而在某些工作负载中提高延迟。当 vCPU 与专用物理 CPU 相关联时,建议启用此功能。未来可能会添加更多位;用户空间可以将 KVM_CHECK_EXTENSION 的结果传递给 KVM_ENABLE_CAP,以禁用所有此类虚拟机退出。

如果禁用了 HLT 退出,请不要启用 KVM_FEATURE_PV_UNHALT。

7.14 KVM_CAP_S390_HPAGE_1M

架构:

s390

参数:

返回:

成功返回 0,如果未设置 hpage 模块参数或启用了 cmma,或虚拟机设置了 KVM_VM_S390_UCONTROL 标志,则返回 -EINVAL

使用此功能,可以为虚拟机启用通过 hugetlbfs 进行 1m 页内存支持的 KVM。启用此功能后,不能再启用 cmma,并且 pfmfi 和存储密钥解释将被禁用。如果 cmma 已启用或 hpage 模块参数未设置为 1,则返回 -EINVAL。

虽然通常可以在没有此功能的情况下创建由大页支持的虚拟机,但该虚拟机将无法运行。

7.15 KVM_CAP_MSR_PLATFORM_INFO

架构:

x86

参数:

args[0]:是否应启用该功能

使用此功能,访客可以读取 MSR_PLATFORM_INFO MSR。否则,当访客尝试访问时,会引发 #GP 异常。目前,此功能不允许访客写入此 MSR。

7.16 KVM_CAP_PPC_NESTED_HV

架构:

ppc

参数:

返回:

成功返回 0,当实现不支持嵌套 HV 虚拟化时返回 -EINVAL。

POWER9 及更高版本系统上的 HV-KVM 允许“嵌套 HV”虚拟化,这为访客虚拟机提供了一种使用 CPU 的主管模式(特权非虚拟机管理程序状态)运行访客的方式。在虚拟机上启用此功能取决于 CPU 是否具有必要的功能以及是否使用 kvm-hv 模块参数启用了该功能。

7.17 KVM_CAP_EXCEPTION_PAYLOAD

架构:

x86

参数:

args[0]:是否应启用该功能

启用此功能后,当 L1 拦截 L2 中发生的 #PF 异常时,CR2 将不会在模拟的虚拟机退出之前被修改。类似地,仅对于 kvm-intel,当 L1 拦截 L2 中发生的 #DB 异常时,DR6 将不会在模拟的虚拟机退出之前被修改。因此,当 KVM_GET_VCPU_EVENTS 报告 L2 存在待处理的 #PF(或 #DB)异常时,将设置 exception.has_payload,并且将在 exception_payload 字段中报告错误地址(或新的 DR6 位*)。同样,当用户空间使用 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 页的粒度进行操作,而不是需要同步完整的内存槽;这确保了 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 正在具有 ultravisor 固件的主机上运行,因此可以支持安全访客。在此类系统上,访客可以请求 ultravisor 使其成为安全访客,即除了显式请求与主机共享的页面外,其内存对主机不可访问。当访客请求成为安全访客时,ultravisor 会通知 KVM,并且 KVM 有机会否决转换。

如果存在,则可以为虚拟机启用此功能,这意味着 KVM 将允许转换为安全访客模式。否则,KVM 将否决转换。

7.20 KVM_CAP_HALT_POLL

架构:

全部

目标:

虚拟机

参数:

args[0] 是最大轮询时间(以纳秒为单位)

返回:

成功时返回 0;错误时返回 -1

KVM_CAP_HALT_POLL 会覆盖 kvm.halt_poll_ns 模块参数,以设置目标虚拟机中所有 vCPU 的最大暂停轮询时间。可以随时调用此功能任意次数,以动态更改最大暂停轮询时间。

有关暂停轮询的更多信息,请参阅KVM 暂停轮询系统

7.21 KVM_CAP_X86_USER_SPACE_MSR

架构:

x86

目标:

虚拟机

参数:

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 处理和/或用户通知,以告知用户 MSR 未被 KVM 模拟/虚拟化。

有效的掩码标志如下:

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

目标:

虚拟机

参数:

args[0] 定义在访客中检测到总线锁时使用的策略

返回:

成功返回 0,当 args[0] 包含无效位时返回 -EINVAL

args[0] 中的有效位如下:

#define KVM_BUS_LOCK_DETECTION_OFF      (1 << 0)
#define KVM_BUS_LOCK_DETECTION_EXIT     (1 << 1)

在虚拟机上启用此功能后,用户空间可以选择一种策略来处理在访客中检测到的总线锁。用户空间可以从 KVM_CHECK_EXTENSION 的结果中获取支持的模式,并通过 KVM_ENABLE_CAP 定义它。支持的模式是互斥的。

此功能允许用户空间在访客中检测到总线锁时强制虚拟机退出,而不管主机是否启用了拆分锁检测(这会触发 KVM 拦截的 #AC 异常)。此功能旨在缓解恶意/错误的访客利用总线锁来降低整个系统性能的攻击。

如果设置了 KVM_BUS_LOCK_DETECTION_OFF,则 KVM 不会强制访客总线锁退出虚拟机,但如果启用,则主机内核的拆分锁 #AC 检测仍然适用。

如果设置了 KVM_BUS_LOCK_DETECTION_EXIT,则 KVM 会启用 CPU 功能,以确保访客中的总线锁触发虚拟机退出,并且 KVM 会针对所有此类虚拟机退出退出到用户空间,例如,允许用户空间限制有问题的访客和/或应用其他基于策略的缓解措施。当退出到用户空间时,KVM 会在 vcpu-run->flags 中设置 KVM_RUN_X86_BUS_LOCK,并有条件地将 exit_reason 设置为 KVM_EXIT_X86_BUS_LOCK。

请注意!检测到的总线锁可能与用户空间的其他退出重合,即,如果用户空间希望对所有检测到的总线锁采取措施,则应检查 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] 是源虚拟机的 fd 返回值:成功时返回 0;错误时返回 ENOTTY

此功能允许用户空间将加密上下文从 fd 指示的虚拟机复制到调用此功能的虚拟机。

这旨在支持由主机调度的访客内工作负载。这允许访客内工作负载维护其自己的 NPT,并防止两个虚拟机因中断等原因意外覆盖彼此(单独的 APIC/MSR/等)。

7.25 KVM_CAP_SGX_ATTRIBUTE

架构:

x86

目标:

虚拟机

参数:

args[0] 是 securityfs 中 SGX 属性文件的文件句柄

返回:

成功返回 0,如果文件句柄无效或 KVM 不支持请求的属性,则返回 -EINVAL。

KVM_CAP_SGX_ATTRIBUTE 允许用户空间 VMM 授予虚拟机访问一个或多个特权飞地属性的权限。args[0] 必须保存与 KVM 支持/限制的属性(当前仅为 PROVISIONKEY)对应的有效 SGX 属性文件的文件句柄。

SGX 子系统限制对飞地属性子集的访问,以便为未受损的内核提供额外的安全性,例如,限制使用 PROVISIONKEY 以阻止恶意软件使用 PROVISIONKEY 来获取稳定的系统指纹。为了防止用户空间通过在虚拟机中运行飞地来规避此类限制,KVM 默认情况下会阻止访问特权属性。

有关更多详细信息,请参阅软件保护扩展 (SGX)

7.26 KVM_CAP_PPC_RPT_INVALIDATE

功能:

KVM_CAP_PPC_RPT_INVALIDATE

架构:

ppc

类型:

虚拟机

此功能表示内核能够处理 H_RPT_INVALIDATE hcall。

为了在客户机中使用 H_RPT_INVALIDATE,用户空间可能需要为客户机声明它。例如,如果 “ibm,hypertas-functions” 设备树属性中存在 “hcall-rpt-invalidate”,则 IBM pSeries (sPAPR) 客户机将开始使用它。

此功能在支持基数 MMU 的 POWER9 等平台上的虚拟机管理程序上启用。

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)。在创建任何 VCPU 以允许客户机访问之前,VMM 还必须启用此功能。请注意,MTE 仅适用于在 AArch64 模式下运行的客户机,启用此功能将导致尝试创建 AArch32 VCPU 失败。

启用后,客户机可以访问与分配给客户机的任何内存关联的标记。KVM 将确保在主机交换或休眠期间维护这些标记;但是,如果 VM 被迁移,则 VMM 需要手动保存/恢复这些标记。

启用此功能后,内存槽中的所有内存都必须映射为 MAP_ANONYMOUS 或使用基于 RAM 的文件映射(tmpfsmemfd),尝试使用无效的 mmap 创建内存槽将导致返回 -EINVAL。

启用后,VMM 可以使用 KVM_ARM_MTE_COPY_TAGS ioctl 执行标记到/从客户机的批量复制。

7.29 KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM

架构:

已启用 x86 SEV

类型:

虚拟机

参数:

args[0] 是源虚拟机的文件描述符

返回:

成功时为 0

此功能允许用户空间将加密上下文从文件描述符指示的 VM 迁移到调用此功能的 VM。

这旨在支持用户空间 VMM 之间 VM 的主机内迁移,从而在不中断客户机的情况下升级 VMM 进程。

7.30 KVM_CAP_PPC_AIL_MODE_3

功能:

KVM_CAP_PPC_AIL_MODE_3

架构:

ppc

类型:

虚拟机

此功能表示内核支持 “中断时地址转换模式”(又名 “备用中断位置”)资源的模式 3 设置,该资源由 H_SET_MODE 超级调用控制。

此功能允许客户机内核使用性能更好的模式来处理中断和系统调用。

7.31 KVM_CAP_DISABLE_QUIRKS2

功能:

KVM_CAP_DISABLE_QUIRKS2

参数:

args[0] - 要禁用的 KVM 怪癖集

架构:

x86

类型:

虚拟机

如果启用此功能,将导致 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

默认情况下,对于到端口 0x7e 的 OUT 指令,KVM 会在退出到用户空间之前预先递增 %rip。禁用此怪癖后,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

默认情况下,KVM 会将 MONITOR/MWAIT(如果被截获)模拟为 NOP,而不管是否根据客户机 CPUID 支持 MONITOR/MWAIT。禁用此怪癖且未设置 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,当删除或移动内存槽时,KVM 会使所有内存槽和地址空间中的所有 SPTE 失效。禁用此怪癖(或 VM 类型不是 KVM_X86_DEFAULT_VM)后,KVM 仅确保无法访问已删除或移动的内存槽的后备内存,即 KVM _可能_ 仅使与内存槽相关的 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 值清零(有两个例外,请参见下文),即,将功能 MSR 视为 CPUID 叶,并赋予用户空间对 vCPU 模型定义的完全控制权。此怪癖不会影响 VMX MSR CR0/CR4_FIXED1 (0x487 和 0x489),因为 KVM 现在不允许用户空间设置它们(出于安全目的,KVM 会根据客户机 CPUID 设置它们)。

7.32 KVM_CAP_MAX_VCPU_ID

架构:

x86

目标:

虚拟机

参数:

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

目标:

虚拟机

参数:

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.34 KVM_CAP_MEMORY_FAULT_INFO

架构:

x86

返回:

仅供参考,直接 KVM_ENABLE_CAP 时为 -EINVAL。

此功能的出现表明,如果 KVM 无法解决客户机页错误 VM 退出,例如,如果存在有效的内存槽但没有相应主机虚拟地址的后备 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 中的信息才有效。

注意:建议尝试解决内存错误以使其可以重试 KVM_RUN 的用户空间防止重复接收相同的错误/注释错误。

有关更多信息,请参见 KVM_EXIT_MEMORY_FAULT。

7.35 KVM_CAP_X86_APIC_BUS_CYCLES_NS

架构:

x86

目标:

虚拟机

参数:

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_X86_GUEST_MODE

架构:

x86

返回:

仅供参考,直接 KVM_ENABLE_CAP 时为 -EINVAL。

此功能的出现表明,KVM_RUN 将更新 kvm_run.flags 中的 KVM_RUN_X86_GUEST_MODE 位,以指示 vCPU 退出时是否正在执行嵌套客户机代码。

KVM 会退出,并根据退出时执行的 L1 或 L2 客户机的寄存器状态。用户空间必须注意区分这些情况。

8. 其他功能。

本节列出了提供有关 KVM 实现的其他功能的信息的功能。

8.1 KVM_CAP_PPC_HWRNG

架构:

ppc

如果 KVM_CHECK_EXTENSION 表示此功能可用,则表示内核具有由硬件随机数生成器支持的 H_RANDOM 超级调用的实现。如果存在,可以使用 KVM_CAP_PPC_ENABLE_HCALL 功能为客户机启用内核 H_RANDOM 处理程序。

8.2 KVM_CAP_HYPERV_SYNIC

架构:

x86

如果 KVM_CHECK_EXTENSION 指示此功能可用,则表示内核实现了 Hyper-V 合成中断控制器 (SynIC)。Hyper-V SynIC 用于支持基于 Windows Hyper-V 的客户机半虚拟化驱动程序 (VMBus)。

为了使用 SynIC,必须通过在 vcpu fd 上使用 KVM_ENABLE_CAP ioctl 设置此功能来激活它。请注意,这将禁用 APIC 硬件虚拟化的使用,即使 CPU 支持它,因为它与 SynIC 的自动 EOI 行为不兼容。

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,以创建利用它的虚拟机。

如果 kvm 虚拟机句柄上的 KVM_CHECK_EXTENSION 指示此功能可用,则表示该虚拟机正在使用该硬件的完整硬件辅助虚拟化功能。这在创建具有 KVM_VM_MIPS_DEFAULT 的虚拟机后进行检查非常有用。

KVM_CHECK_EXTENSION 返回的值应与已知值(见下文)进行比较。所有其他值均保留。这是为了允许其他可能与 MIPS VZ ASE 不兼容的硬件辅助虚拟化实现的可能性。

0

陷阱和模拟实现用于在用户模式下运行客户机代码。重新排列客户机虚拟内存段以使客户机适应用户模式地址空间。

1

正在使用 MIPS VZ ASE,提供完整的硬件辅助虚拟化,包括标准客户机虚拟内存段。

8.6 KVM_CAP_MIPS_TE

架构:

mips

如果主 kvm 句柄上的 KVM_CHECK_EXTENSION 指示此功能可用,则表示陷阱和模拟实现可用于在用户模式下运行客户机代码,即使 KVM_CAP_MIPS_VZ 指示硬件辅助虚拟化也可用。必须将 KVM_VM_MIPS_TE (0) 传递给 KVM_CREATE_VM 以创建利用它的虚拟机。

如果 kvm 虚拟机句柄上的 KVM_CHECK_EXTENSION 指示此功能可用,则表示该虚拟机正在使用陷阱和模拟。

8.7 KVM_CAP_MIPS_64BIT

架构:

mips

此功能指示客户机支持的架构类型,即支持的寄存器和地址宽度。

当通过 kvm 虚拟机句柄上的 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 指示此功能可用,则表示如果用户空间创建一个没有内核中断控制器的虚拟机,它将被通知内核模拟设备输出级别的更改,这些设备可以生成虚拟中断,呈现给虚拟机。对于此类虚拟机,每次返回用户空间时,内核都会更新 vcpu 的 run->s.regs.device_irq_level 字段,以表示设备的实际输出级别。

每当 kvm 检测到设备输出级别发生变化时,kvm 保证在运行虚拟机之前至少返回一次用户空间。此退出可能是 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.11 KVM_CAP_HYPERV_SYNIC2

架构:

x86

此功能启用较新版本的 Hyper-V 合成中断控制器 (SynIC)。与 KVM_CAP_HYPERV_SYNIC 的唯一区别在于,当通过写入相应的 MSR 启用 SynIC 消息和事件标志页时,KVM 不会清除它们。

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 工具 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 字段。当发生异常时,CPU 会生成 ESR 的其他部分(如 EC)。如果使用 AArch64 将此虚拟 SError 发送到 EL1,则此值将报告在 ESR_ELx 的 ISS 字段中。

有关更多详细信息,请参阅 KVM_CAP_VCPU_EVENTS。

8.20 KVM_CAP_HYPERV_SEND_IPI

架构:

x86

此功能指示 KVM 支持半虚拟化 Hyper-V IPI 发送超调用:HvCallSendSyntheticClusterIpi、HvCallSendSyntheticClusterIpiEx。

8.21 KVM_CAP_HYPERV_DIRECT_TLBFLUSH

架构:

x86

此功能指示在 Hyper-V 虚拟机监控程序之上运行的 KVM 为其客户机启用直接 TLB 刷新,这意味着 TLB 刷新超调用由 0 级虚拟机监控程序 (Hyper-V) 处理,从而绕过 KVM。由于 Hyper-V 和 KVM 之间超调用参数的 ABI 不同,启用此功能会有效地禁用 KVM 的所有超调用处理(因为某些 KVM 超调用可能会被 Hyper-V 错误地视为 TLB 刷新超调用),因此用户空间应在 CPUID 中禁用 KVM 识别,并且仅公开 Hyper-V 识别。在这种情况下,客户机认为它正在 Hyper-V 上运行,并且仅使用 Hyper-V 超调用。

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 可以启动受保护的虚拟机。此功能管理 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 发行版...)

如果此功能可用,则可以通过同步寄存器机制 (KVM_SYNC_DIAG318) 在 KVM 和用户空间之间同步 CPNC 和 CPVC。

8.26 KVM_CAP_X86_USER_SPACE_MSR

架构:

x86

此功能指示 KVM 支持将 MSR 读取和写入偏转到用户空间。可以在虚拟机级别启用它。如果启用,通常会通过 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,用户空间可以调用该 ioctl 来指定 KVM 应拒绝访问的 MSR 范围的位图。

结合 KVM_CAP_X86_USER_SPACE_MSR,这允许用户空间捕获和模拟 KVM 范围之外的 MSR,并限制 KVM 的 MSR 模拟代码的攻击面。

8.28 KVM_CAP_ENFORCE_PV_FEATURE_CPUID

架构:x86

启用后,KVM 将根据 KVM_CPUID_FEATURES CPUID 叶 (0x40000001) 中的位禁用提供给客户机的半虚拟化功能。否则,客户机可以使用半虚拟化功能,而不管实际通过 CPUID 叶暴露了哪些功能。

8.29 KVM_CAP_DIRTY_LOG_RING/KVM_CAP_DIRTY_LOG_RING_ACQ_REL

架构:

x86, arm64

参数:

args[0] - 脏日志环的大小

KVM 能够使用 mmap 到用户空间的环形缓冲区跟踪脏内存;每个 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 -------+
 ^                                          |
 |                                          |
 +------------------------------------------+

要收集脏页,用户空间访问 mmap 的环形缓冲区以读取脏 GFN。如果标志设置了 DIRTY 位(在此阶段必须清除 RESET 位),则表示此 GFN 是脏 GFN。用户空间应收集此 GFN 并将标志从状态 01b 标记为 1Xb(位 0 将被 KVM 忽略,但必须设置位 1 以表明此 GFN 已被收集并正在等待重置),然后继续下一个 GFN。用户空间应继续执行此操作,直到 GFN 的标志清除 DIRTY 位,这意味着它已收集了所有可用的脏 GFN。

请注意,在弱序架构上,用户空间对环形缓冲区(更具体地说是“标志”字段)的访问必须是有序的,在可用时使用 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 的功能,或者任何内存槽已存在,则无法启用 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 挂起表。

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 字段设置时,事件通道 upcall 的异常向量的传递。

KVM_XEN_HVM_CONFIG_RUNSTATE 标志表示 KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctl 支持与运行状态相关的功能 KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST。

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_PPC_MULTITCE

功能:

KVM_CAP_PPC_MULTITCE

架构:

ppc

类型:

虚拟机

此功能表示内核能够处理超级调用 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.33 KVM_CAP_HYPERV_ENFORCE_CPUID

架构:x86

启用后,KVM 将根据 Hyper-V CPUID 功能叶中的位禁用提供给客户机的模拟 Hyper-V 功能。否则,当在 HYPERV_CPUID_INTERFACE (0x40000001) 叶中设置 Hyper-V 标识时,将无条件提供所有当前实现的 Hyper-V 功能。

8.34 KVM_CAP_EXIT_HYPERCALL

功能:

KVM_CAP_EXIT_HYPERCALL

架构:

x86

类型:

虚拟机

如果启用此功能,则会导致 KVM 以 KVM_EXIT_HYPERCALL 退出原因退出到用户空间以处理某些超级调用。

调用此功能的 KVM_CHECK_EXTENSION 将返回一个位掩码,该位掩码表示可以配置为退出到用户空间的超调用。目前,唯一这样的超调用是 KVM_HC_MAP_GPA_RANGE。

KVM_ENABLE_CAP 的参数也是一个位掩码,并且必须是 KVM_CHECK_EXTENSION 结果的子集。KVM 将把参数中对应位为 1 的超调用转发到用户空间,并对其他超调用返回 ENOSYS。

8.35 KVM_CAP_PMU_CAPABILITY

功能:

KVM_CAP_PMU_CAPABILITY

架构:

x86

类型:

虚拟机

参数:

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 已被禁用。

8.36 KVM_CAP_ARM_SYSTEM_SUSPEND

功能:

KVM_CAP_ARM_SYSTEM_SUSPEND

架构:

arm64

类型:

虚拟机

启用后,KVM 将以 KVM_EXIT_SYSTEM_EVENT 类型(类型为 KVM_SYSTEM_EVENT_SUSPEND)退出到用户空间,以处理客户机挂起请求。

8.37 KVM_CAP_S390_PROTECTED_DUMP

功能:

KVM_CAP_S390_PROTECTED_DUMP

架构:

s390

类型:

虚拟机

此功能表示 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.38 KVM_CAP_VM_DISABLE_NX_HUGE_PAGES

功能:

KVM_CAP_VM_DISABLE_NX_HUGE_PAGES

架构:

x86

类型:

虚拟机

参数:

arg[0] 必须为 0。

返回:

成功时返回 0;如果用户空间进程没有 CAP_SYS_BOOT 权限,则返回 -EPERM;如果 args[0] 不为 0 或已创建任何 vCPU,则返回 -EINVAL。

此功能禁用 iTLB MULTIHIT 的 NX 大页面缓解措施。

如果未设置 nx_huge_pages 模块参数,则此功能无效。

此功能只能在创建任何 vCPU 之前设置。

8.39 KVM_CAP_S390_CPU_TOPOLOGY

功能:

KVM_CAP_S390_CPU_TOPOLOGY

架构:

s390

类型:

虚拟机

此功能表示 KVM 将提供 S390 CPU 拓扑功能,该功能包括解释函数代码 2 的 PTF 指令,以及拦截并将函数代码为 0 或 1 的 PTF 指令和 STSI(15,1,x) 指令转发到用户空间虚拟机监控程序。

在没有此功能的情况下,不应向客户机指示 stfle 功能 11(CPU 拓扑功能)。

如果存在此功能,KVM 会在 vm fd 上提供一个新的属性组 KVM_S390_VM_CPU_TOPOLOGY。此新属性允许通过 kvm_device_attr 结构获取、设置或清除 SCA 的修改的更改拓扑报告 (MTCR) 位。

在获取修改的更改拓扑报告值时,attr->addr 必须指向一个字节,该值将存储在该字节中或从中检索。

8.40 KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE

功能:

KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE

架构:

arm64

类型:

虚拟机

参数:

arg[0] 是新的拆分块大小。

返回:

成功时返回 0,如果已创建任何内存槽,则返回 -EINVAL。

此功能设置在急切页面拆分中使用的块大小。

当客户机内存由大页面支持时,急切页面拆分可提高脏日志记录(在实时迁移中使用)的性能。它避免在故障时拆分大页面(拆分为 PAGE_SIZE 页面),而是在启用脏日志记录时(使用内存区域的 KVM_MEM_LOG_DIRTY_PAGES 标志)或使用 KVM_CLEAR_DIRTY_LOG 时急切地进行拆分。

块大小指定一次要分割多少页,为每个块使用单个分配。块大小越大,需要提前分配的页越多。

块大小需要是有效的块大小。可接受的块大小列表在 KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 中作为 64 位位图(每个位描述一个块大小)公开。默认值为 0,禁用急切页面拆分。

8.41 KVM_CAP_VM_TYPES

功能:

KVM_CAP_MEMORY_ATTRIBUTES

架构:

x86

类型:

系统 ioctl

此功能返回一个支持的虚拟机类型位图。第 @n 位设置为 1 表示支持值为 @n 的虚拟机类型。@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 用于“真实”虚拟机,尤其不要在生产环境中使用。软件保护虚拟机的行为和有效 ABI 不稳定。

9. 已知的 KVM API 问题

在某些情况下,KVM 的 API 存在一些不一致或常见的陷阱,用户空间需要注意。本节详细介绍其中一些问题。

其中大多数问题特定于体系结构,因此本节按体系结构划分。

9.1. x86

KVM_GET_SUPPORTED_CPUID 问题

通常,KVM_GET_SUPPORTED_CPUID 的设计目的是使其结果可以直接传递给 KVM_SET_CPUID2。本节记录了在某些情况下需要注意的事项。

本地 APIC 功能

KVM_GET_SUPPORTED_CPUID 报告 CPU[EAX=1]:ECX[21] (X2APIC),但只有在使用 KVM_CREATE_IRQCHIPKVM_ENABLE_CAP(KVM_CAP_IRQCHIP_SPLIT) 启用内核本地 APIC 模拟时才能启用。

对于 KVM_FEATURE_PV_UNHALT 半虚拟化功能,情况也是如此。

KVM_GET_SUPPORTED_CPUID 不报告 CPU[EAX=1]:ECX[24] (TSC_DEADLINE)。如果存在 KVM_CAP_TSC_DEADLINE_TIMER 并且内核启用了本地 APIC 的内核模拟,则可以启用它。

CPU 拓扑

多个 CPUID 值包含主机 CPU 的拓扑信息:对于 Intel 系统,为 0x0b 和 0x1f;对于 AMD 系统,为 0x8000001e。不同版本的 KVM 返回此信息的值不同,用户空间不应依赖它。目前它们都返回零。

如果用户空间希望设置客户机拓扑,则应注意,这三个叶的值对于每个 CPU 都不同。特别是,APIC ID 在 0x0b 和 0x1f 的所有子叶的 EDX 中找到,在 0x8000001e 的 EAX 中找到;后者还在 EBX 和 ECX 的位 7:0 中分别编码核心 ID 和节点 ID。

过时的 ioctl 和功能

KVM_CAP_DISABLE_QUIRKS 不让用户空间知道哪些怪癖实际上可用。如果可用,请改用 KVM_CHECK_EXTENSION(KVM_CAP_DISABLE_QUIRKS2)

KVM_GET_*/KVM_SET_* ioctl 的顺序

待定