KVM API 简介

以下笔记来自阅读:https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt

1. 基本描述

KVM API 本质上是为了控制虚拟机的方方面面而下发的一组ioctl,这些ioctl可以划分为四类:
- system ioctl: 对影响整个KVM系统的属性进行查询或设置。创建虚拟机就是其中的一个系统ioctl。
- vm ioctl: 对影响整个虚拟机的属性进行查询或设置,比如虚拟机内存布局。vm ioctl创建了虚拟机的虚拟机CPU(vcpu)和其他设备。
vm ioctl必须由创建虚拟机的进程下发。
- vcpu ioctl: 对控制单个虚拟CPU(vcpu)的属性进行查询或设置。
除了在文档中特别标注的异步vcpu ioctl,vcpu ioctl应该由创建虚拟CPU的线程下发。否则,在切换线程后的第一次ioctl调用将对性能产生影响。
- device ioctl: 对控制单个设备的属性进行查询或设置。
设备ioctl必须由创建虚拟机的进程下发。

2. 文件描述符

文件描述符是整个KVM API的核心。打开"/dev/kvm"设备后会得到一个文件描述符,该文件描述符可以用来下发system ioctl。通过这个文件描述符下发KVM_CREATE_VM ioctl将创建一个虚拟机的文件描述符。这个虚拟机的文件描述符可以用来下发vm ioctl。通过虚拟机文件描述符下发KVM_CREATE_VCPU 和 KVM_CREATE_DEVICE ioctl将创建对应的虚拟机CPU和设备,并返回对应CPU和设备的文件描述符。最后,通过虚拟CPU或者设备文件描述符下发的ioctl可以用来控制对应虚拟机CPU或者设备。对于虚拟CPU而言,这包含了其重要的工作:运行Guest代码。

一般文件描述符可以通过fork()或者Unix Domain Socket的SCM_RIGHTS特性在进程间迁移,但是KVM并不显式支持这些方式。对操作系统而言,这些行为是无害的,但是KVM API的行为将无法保证。KVM 支持的 ioctl 使用模式参考“1. 基本描述"部分。

需要重点注意的是,尽管vm ioctl只能由创建虚拟机的进程下发,VM的生命周期是和其文件描述符关联的,而不是创建这个虚拟机的进程。换句话说,虚拟机和它使用的资源,包括关联的地址空间,在虚拟机对应的文件描述符的所有引用释放之前都不会回收。例如,在ioctl(KVM_CREATE_VM)之后如果调用了fork(),那么虚拟机在父进程和它的子进程都释放虚拟机文件描述符之后才能回收资源。

因为虚拟机资源在其文件描述符的引用都释放之前不能回收,在没有考虑清楚之前,非常不推荐使用 fork(), dup()等方式增加新的描述符引用。这些方式可能带来意料之外的副作用,比如在虚拟机关机之后,虚拟机使用的内存资源并没有回收。

3. 扩展

在Linux内核版本2.6.22之后,KVM的ABI已经稳定,破坏向后兼容的改动也不被允许。但是,KVM支持对使用的API添加向后兼容的扩展。

扩展机制并不基于Linux版本号,KVM定义了扩展标识,并提供功能查询特定扩展标识是否存在。如果存在,应用程序就可以使用该扩展对应的一组ioctl。

4. API 描述

本节描述了能够控制KVM虚拟机的ioctl。对于每个ioctl,提供如下的信息:
- 能力: 该ioctl对应的KVM扩展。'basic'表明任何支持API 版本12(参考4.1)的内核都可以提供该ioctl; 'KVM_CAP_xyz'意味着需要使用KVM_CHECK_EXTENSION检查该扩展是否可用; 'none'意味着不是所有的内核都支持该ioctl,并且也没有对应的检查方式,如果不支持,ioctl会返回错误-ENOTTY。
- 架构: 包含该ioctl的指令集架构。x86即包含i386也包含x86_64。
- 类型: system、vm、vcpu或者device ioctl。
- 参数: ioctl的调用参数。
- 返回值: ioctl返回值。一般错误如EBADF、ENOMEM、EINVAL等没有详细错误信息,但是有特定含义的错误有详细信息。

System Ioctl

序号 名称 能力 架构 参数 返回值 说明
4.1 KVM_GET_API_VERSION basic all none KVM_API_VERSION(12)常量 表明当前使用的是稳定的KVM API版本。如果返回值不是12应用程序应拒绝运行。
4.2 KVM_CREATE_VM basic all 机器类型标识(KVM_VM_*) 可以控制虚拟机的vm fd 新创建的虚拟机没有vcpu也没有内存。
4.3 KVM_GET_MSR_INDEX_LIST basic x86 struct kvm_msr_list (in/out) 成功返回0,错误返回-1 获取guest支持的msr列表
KVM_GET_MSR_FEATURE_INDEX_LIST KVM_CAP_GET_MSR_FEATURES x86 struct kvm_msr_list (in/out) 成功返回0,错误返回-1 列出可以传给KVM_GET_MSRS的msr列表
4.4 KVM_CHECK_EXTENSION basic all 扩展标识(KVM_CAP_*) 不支持返回0,1或其他正值表示支持 查询KVM API扩展
4.5 KVM_GET_VCPU_MMAP_SIZE basic all none vcpu mmap区域的大小 KVM_RUN ioctl 使用一个共享内存区域与用户态通信,KVM_GET_VCPU_MMAP_SIZE 返回该区域大小
4.18 KVM_GET_MSRS KVM_CAP_GET_MSR_FEATURES x86 struct kvm_msrs (in/out) 成功返回msr 数量, 失败返回-1 读取虚拟机可使用的MSR 特性的值
4.46 KVM_GET_SUPPORTED_CPUID KVM_CAP_EXT_CPUID x86 struct kvm_cpuid2 (in/out) 成功返回0, 失败返回-1 返回x86平台和kvm默认支持的cpuid信息
4.88 KVM_GET_EMULATED_CPUID KVM_CAP_EXT_EMUL_CPUID x86 struct kvm_cpuid2 (in/out) 成功返回0, 失败返回-1 返回由KVM模拟的CPUID feature
4.104 KVM_X86_GET_MCE_CAP_SUPPORTED KVM_CAP_MCE x86 u64 mce_cap (out) 成功返回0, 失败返回-1 返回支持的MCE capability
4.110 KVM_MEMORY_ENCRYPT_OP basic x86 平台相关输入(in/out) 成功返回0, 失败返回-1 下发内存加密命令,目前用于下发SEV命令(AMD SEV)
4.111 KVM_MEMORY_ENCRYPT_REG_REGION basic x86 struct kvm_enc_region (in) 成功返回0, 失败返回-1 注册guest加密内存区域(AMD SEV)
4.112 KVM_MEMORY_ENCRYPT_UNREG_REGION basic x86 struct kvm_enc_region (in) 成功返回0, 失败返回-1 取消注册guest加密内存区域(AMD SEV)

VM Ioctl

序号 名称 能力 架构 参数 返回值 说明
4.4 KVM_CHECK_EXTENSION KVM_CAP_CHECK_EXTENSION_VM all 扩展标识(KVM_CAP_*) 不支持返回0,1或其他正值表示支持 查询VM支持的KVM API扩展
4.6 KVM_SET_MEMORY_REGION basic all struct kvm_memory_region (in) 成功返回0, 失败返回-1 该API已废弃
4.7 KVM_CREATE_VCPU basic all vcpu id (apic id on x86) 成功返回vcpu fd,失败返回-1 创建vcpu
4.8 KVM_GET_DIRTY_LOG basic all struct kvm_dirty_log (in/out) 成功返回0, 失败返回-1 返回从上一次调用该ioctl以来,memory slot页面的dirty bitmap
4.9 KVM_SET_MEMORY_ALIAS basic all struct kvm_memory_alias (in) 成功返回0, 失败返回-1 该API已废弃
4.24 KVM_CREATE_IRQCHIP KVM_CAP_IRQCHIP x86, arm, arm64 none 成功返回0, 失败返回-1 在内核中创建虚拟机对应的中断控制器
4.25 KVM_IRQ_LINE KVM_CAP_IRQCHIP x86, arm, arm64 struct kvm_irq_level 成功返回0, 失败返回-1 设置中断控制器指定中断的电位(1/0)
4.26 KVM_GET_IRQCHIP KVM_CAP_IRQCHIP x86 struct kvm_irqchip (in/out) 成功返回0, 失败返回-1 读取中断控制器状态
4.27 KVM_SET_IRQCHIP KVM_CAP_IRQCHIP x86 struct kvm_irqchip (in) 成功返回0, 失败返回-1 设置中断控制器状态
4.28 KVM_XEN_HVM_CONFIG KVM_CAP_XEN_HVM x86 struct kvm_xen_hvm_config (in) 成功返回0, 失败返回-1 设置Xen HVM Guest用来初始化hypercall所使用的msr寄存器状态
4.29 KVM_GET_CLOCK KVM_CAP_ADJUST_CLOCK x86 struct kvm_clock_data (out) 成功返回0, 失败返回-1 获取当前guest看到的kvmclock时间戳
4.30 KVM_SET_CLOCK KVM_CAP_ADJUST_CLOCK x86 struct kvm_clock_data (in) 成功返回0, 失败返回-1 设置当前guest的kvmclock为指定值
4.33 KVM_GET_DEBUGREGS KVM_CAP_DEBUGREGS x86 struct kvm_debugregs (out) 成功返回0, 失败返回-1 读取vcpu debug寄存器
4.34 KVM_SET_DEBUGREGS KVM_CAP_DEBUGREGS x86 struct kvm_debugregs (in) 成功返回0, 失败返回-1 设置vcpu debug寄存器
4.35 KVM_SET_USER_MEMORY_REGION KVM_CAP_USER_MEMORY all struct kvm_userspace_memory_region (in) 成功返回0, 失败返回-1 该API允许创建、修改、删除guest虚拟机的物理内存槽(physical memory slot)
4.36 KVM_SET_TSS_ADDR KVM_CAP_SET_TSS_ADDR x86 unsigned long tss_address (in) 成功返回0, 失败返回-1 设置VM86模式TSS所使用的地址
4.40 KVM_SET_IDENTITY_MAP_ADDR KVM_CAP_SET_IDENTITY_MAP_ADDR x86 unsigned long identity (in) 成功返回0, 失败返回-1 设置VM86模式下Guest页表的物理地址
4.41 KVM_SET_BOOT_CPU_ID KVM_SET_BOOT_CPU_ID x86 unsigned long vcpu_id 成功返回0, 失败返回-1 定义哪个vcpu是BSP(默认是0号vcpu)
4.52 KVM_SET_GSI_ROUTING KVM_CAP_IRQ_ROUTING x86, s390, arm, arm64 struct kvm_irq_routing (in) 成功返回0, 失败返回-1 设置GSI路由项
4.59 KVM_IOEVENTFD KVM_CAP_IOEVENTFD all struct kvm_ioeventfd (in) 成功返回0, 失败返回非0 挂载/卸载ioeventfd到虚拟机内的PIO和MMIO地址
4.71 KVM_SIGNAL_MSI KVM_CAP_SIGNAL_MSI x86, arm, arm64 struct kvm_msi (in) 成功下发返回>0, 虚拟机已经屏蔽该MSI返回0, 错误返回-1 注入MSI中断信息
4.71 KVM_CREATE_PIT2 KVM_CAP_PIT2 x86 struct kvm_pit_config (in) 成功返回0, 失败返回-1 创建i8254PIT(该API 序号在KVM文档中有误)
4.72 KVM_GET_PIT2 KVM_CAP_PIT_STATE2 x86 struct kvm_pit_state2 (out) 成功返回0, 失败返回-1 返回内核内PIT设备状态
4.73 KVM_SET_PIT2 KVM_CAP_PIT_STATE2 x86 struct kvm_pit_state2 (in) 成功返回0, 失败返回-1 设置内核PIT设备状态
4.75 KVM_IRQFD KVM_CAP_IRQFD x86, s390, arm, arm64 struct kvm_irqfd (in) 成功返回0, 失败返回-1 设置用于触发中断的eventfd
4.99 KVM_REINJECT_CONTROL KVM_CAP_REINJECT_CONTROL x86 struct kvm_reinject_control (in) 成功返回0, 失败返回负值(-EFAULT/-ENXIO) 设置i8254 PIT的reinject或!reinject模式
4.113 KVM_HYPERV_EVENTFD KVM_CAP_HYPERV_EVENTFD x86 struct kvm_hyperv_eventfd (in) 成功返回0, 失败返回负值(-EINVAL/-ENOENT/-EEXIST) 注册监听Hyper-V hypercall的eventfd
4.116 KVM_REGISTER_COALESCED_MMIO KVM_CAP_COALESCED_MMIO 或 KVM_CAP_COALESCED_PIO all struct kvm_coalesced_mmio_zone 成功返回0, 失败返回负值 注册coalesed mmio/pio 内存区域
KVM_UNREGISTER_COALESCED_MMIO KVM_CAP_COALESCED_MMIO 或 KVM_CAP_COALESCED_PIO all struct kvm_coalesced_mmio_zone 成功返回0, 失败返回负值 取消注册coalesed mmio/pio 内存区域
4.117 KVM_CLEAR_DIRTY_LOG KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 x86, arm, arm64, mips struct kvm_dirty_log (in) 成功返回0, 失败返回-1 清除内存页的dirty标记
4.120 KVM_SET_PMU_EVENT_FILTER KVM_CAP_PMU_EVENT_FILTER x86 struct kvm_pmu_event_filter (in) 成功返回0, 失败返回-1 限制guest可以设置的PMU事件

VCPU Ioctl

序号 名称 能力 架构 参数 返回值 说明
4.10 KVM_RUN basic all none 成功返回0, 失败返回-1 该API负责运行一个vcpu。
4.11 KVM_GET_REGS basic 除了arm和arm64以外的架构 struct kvm_regs (out) 成功返回0, 失败返回-1 获取vcpu 通用寄存器(GPR)的值
4.12 KVM_SET_REGS basic 除了arm和arm64以外的架构 struct kvm_regs (in) 成功返回0, 失败返回-1 设置vcpu的通用寄存器(GPR)的值
4.13 KVM_GET_SREGS basic x86, ppc struct kvm_sregs (out) 成功返回0, 失败返回-1 获取vcpu的特殊寄存器的值
4.14 KVM_SET_SREGS basic x86, ppc struct kvm_sregs (in) 成功返回0, 失败返回-1 设置vcpu的特殊寄存器的值
4.15 KVM_TRANSLATE basic x86 struct kvm_translation (in/out) 成功返回0, 失败返回-1 根据当前vcpu的寻址模式,将虚拟地址转换为物理地址
4.16 KVM_INTERRUPT basic x86, ppc, mips struct kvm_interrupt (in) 成功返回0, 失败返回负值 添加需要注入的中断,该中断会被保存在队列中
4.17 KVM_DEBUG_GUEST basic none none 失败返回-1 该API已删除,使用KVM_SET_GUEST_DEBUG
4.18 KVM_GET_MSRS basic x86 struct kvm_msrs (in/out) 成功返回msr 数量, 失败返回-1 读取vcpu的msr寄存器,支持的msr 索引可以通过KVM_GET_MSR_INDEX_LIST 获取
4.19 KVM_SET_MSRS basic x86 struct kvm_msrs (in) 成功返回0, 失败返回-1 设置msr寄存器的值
4.20 KVM_SET_CPUID basic x86 struct kvm_cpuid (in) 成功返回0, 失败返回-1 定义vcpu cpuid指令的返回值,如果可行,使用KVM_SET_CPUID2而不是该API
4.21 KVM_SET_SIGNAL_MASK basic all struct kvm_signal_mask (in) 成功返回0, 失败返回-1 定义在KVM_RUN过程中需要屏蔽的中断
4.22 KVM_GET_FPU basic x86 struct kvm_fpu (out) 成功返回0, 失败返回-1 读取vcpu 浮点运算状态
4.23 KVM_SET_FPU basic x86 struct kvm_fpu (in) 成功返回0, 失败返回-1 设置vcpu 浮点运算状态
4.31 KVM_GET_VCPU_EVENTS KVM_CAP_VCPU_EVENTS x86, arm , arm64 struct kvm_vcpu_event (out) 成功返回0, 失败返回-1 获取当前处于等待状态的异常、中断、nmi、smi及对应vcpu状态
4.32 KVM_SET_VCPU_EVENTS KVM_CAP_VCPU_EVENTS x86, arm , arm64 struct kvm_vcpu_event (in) 成功返回0, 失败返回-1 设置当前处于等待状态的异常、中断、nmi、smi及对应vcpu状态
4.37 KVM_ENABLE_CAP KVM_CAP_ENABLE_CAP_VM all struct kvm_enable_cap (in) 成功返回0, 失败返回-1 启用扩展
4.38 KVM_GET_MP_STATE KVM_CAP_MP_STATE x86, s390, arm, arm64 struct kvm_mp_state (out) 成功返回0, 失败返回-1 获取vcpu的处理器状态
4.39 KVM_SET_MP_STATE KVM_CAP_MP_STATE x86, s390, arm, arm64 struct kvm_mp_state (in) 成功返回0, 失败返回-1 设置vcpu的处理器状态
4.42 KVM_GET_XSAVE KVM_CAP_XSAVE x86 struct kvm_xsave (out) 成功返回0, 失败返回-1 获取vcpu xsave状态
4.43 KVM_SET_XSAVE KVM_CAP_XSAVE x86 struct kvm_xsave (in) 成功返回0, 失败返回-1 设置vcpu xsave状态
4.44 KVM_GET_XCRS KVM_CAP_XCRS x86 struct kvm_xcrs (out) 成功返回0, 失败返回-1 获取vcpu xcr寄存器状态
4.45 KVM_SET_XCRS KVM_CAP_XCRS x86 struct kvm_xcrs (in) 成功返回0, 失败返回-1 设置vcpu xcr寄存器状态
4.55 KVM_SET_TSC_KHZ KVM_CAP_TSC_CONTROL x86 virtual tsc_khz 成功返回0, 失败返回-1 设置虚拟机的tsc频率
4.56 KVM_GET_TSC_KHZ KVM_CAP_GET_TSC_KHZ x86 none 成功返回virtual tsc-khz, 失败返回负值 返回虚拟机的TSC频率
4.57 KVM_GET_LAPIC KVM_CAP_IRQCHIP x86 struct kvm_lapic_state (out) 成功返回0, 失败返回-1 返回虚拟机LAPIC寄存器内容
4.58 KVM_SET_LAPIC KVM_CAP_IRQCHIP x86 struct kvm_lapic_state (in) 成功返回0, 失败返回-1 设置虚拟机LAPIC寄存器内容
4.64 KVM_NMI KVM_CAP_USER_NMI x86 none 成功返回0, 失败返回-1 将NMI中断加入vcpu队列
4.68 KVM_SET_ONE_REG KVM_CAP_ONE_REG all struct kvm_one_reg (in) 成功返回0, 失败返回负值 设置vcpu某个寄存器的值
4.69 KVM_GET_ONE_REG KVM_CAP_ONE_REG all struct kvm_one_reg (in and out) 成功返回0, 失败返回负值 获取虚拟机某个寄存器的值
4.70 KVM_KVMCLOCK_CTRL KVM_CAP_KVMCLOCK_CTRL x86 none 成功返回0, 失败返回-1 通知内核guest已经暂停,内核会标记pvclock对应的标志位
4.80 KVM_GET_DEVICE_ATTR KVM_CAP_VCPU_ATTRIBUTES x86 struct kvm_device_attr 成功返回0, 失败返回-1 获取设备状态(x86用于获取tsc offset)
KVM_SET_DEVICE_ATTR KVM_CAP_VCPU_ATTRIBUTES x86 struct kvm_device_attr 成功返回0, 失败返回-1 设置设备状态(x86用于设置tsc offset)
4.81 KVM_HAS_DEVICE_ATTR KVM_CAP_VCPU_ATTRIBUTES x86 struct kvm_device_attr 成功返回0, 失败返回-1 检查设备是否具有某特性(x86检查vcpu是否支持tsc offset)
4.87 KVM_SET_GUEST_DEBUG KVM_CAP_SET_GUEST_DEBUG x86, s390, ppc, arm64 struct kvm_guest_debug (in) 成功返回0, 失败返回-1 配置vcpu debug寄存器和vcpu对应的debug事件处理逻辑
4.96 KVM_SMI KVM_CAP_X86_SMM x86 none 成功返回0, 失败返回-1 将SMI加入vcpu 队列
4.105 KVM_X86_SETUP_MCE KVM_CAP_MCE x86 u64 mcg_cap (in) 成功返回0, 失败返回负值(-EFAULT/-EINVAL) 初始化MCE功能
4.106 KVM_X86_SET_MCE KVM_CAP_MCE x86 struct kvm_x86_mce (in) 成功返回0, 失败返回负值(-EFAULT/-EINVAL) 为Guest注入MCE
4.114 KVM_GET_NESTED_STATE KVM_CAP_NESTED_STATE x86 struct kvm_nested_state (in/out) 成功返回0, 失败返回-1 获取vcpu嵌套虚拟化状态
4.115 KVM_SET_NESTED_STATE KVM_CAP_NESTED_STATE x86 vcpu iostl struct kvm_nested_state (in) 成功返回0, 失败返回-1
4.118 KVM_GET_SUPPORTED_HV_CPUID KVM_CAP_HYPERV_CPUID x86 struct kvm_cpuid2 (in/out) 成功返回0, 失败返回-1 返回KVM模拟的与Hyper-V相关的CPUID信息
  • 只展示了x86支持的KVM API