kvm虚拟化的特点是什么?(虚拟化之路-KVM虚拟化)
kvm虚拟化的特点是什么?(虚拟化之路-KVM虚拟化)kvm_arch_check_processor_compat函数用来用来检测所有CPU的特性是否一致。该函数通过调用Intel x86实现的chech_processor_compatibility回调函数vmx_check_processor_compat。注意kvm_init对每一个在线的CPU都调用kvm_arch_check_processor_compat函数。vmx_check_processor_compat调用函数setup_vmcs_config函数为所有物理CPU构造vmcs_conf,hardware_setup函数通过setup_vmcs_config函数用当前运行的物理CPU特性构造一个全局的vmcs_config,vmx_check_processor_compat函数这里将每个物理CPU的vmcs_conf与全局的vmcs_config进行比较,确保所有的物
(1)KVM初始化代码流程
(2)kvm初始化代码流程解析
KVM模块的初始化包括:架构无关部分的初始化,架构相关的数据初始化。intel-kvm.ko模块的注册函数时vmx_init,其调用架构无关函数kvm_init进行KVM模块的初始化。
kvm_init(&vmx_x86_ops sizeof(struct vcpu_vmx) __alignof__(struct vcpu_vmx) THIS_MODULE);
参数vmx_x86_ops包含Intel VT-x具体实现的各种回调函数。包括硬件检测、创建VCPU的实现、一些寄存器的设置、虚拟机退出的处理函数等。第二个参数表示VMX实现的VCPU结构体的大小。
kvm_arch_init函数初始化架构相关的代码, KVM实现的结构体会被赋值到全局变量kvm_x86_ops,即将参数vmx_x86_ops的内容赋值给kvm_x86_ops,因此kvm_x86_ops中也包含了Intel CPU KVM实现的各种回调函数。确保仅有一个KVM实现能够架构加载到内核,通过回调函数CPU_has_kvm_support判断CPU是否支持VMX,以CPUID指令的返回值作为判断依据(CPUID.1:EXC.VMX[bit 5]=1)。通过回调函数disabled_by_bios判断BIOS是否开启VT-x特性,以MSR寄存器的值作为判断依据。其他工作如:分配一个percpu变量shared_msrs、kvm_mmu_module_init完成内存虚拟化的初始化工作、调用kvm_set_mmio_spte_mask设置MMIO内存的标识符,该标识符通过shadow_mmio_mask表示。最后通过kvm_timer_init初始化timer,通过kvm_lapic_init初始化lapic等。
kvm_irqfd_init初始化irqfd相关的数据,主要是创建一个线程,该函数通过调用evenfd.c的alloc_workqueue函数实现。
kvm_arch_hardware_setup函数用来创建一些和启动KVM密切相关的数据结构以及初始化一些硬件特性。以Intel为例,该函数主要调用Intel虚拟化实现的hardware_setup函数,该函数首先分配了多个bitmap,这些bitmap都是VMCS中可能需要用到的,典型的如两个IO位图vmx_io_bitmap_a/b,且都设置为1,所以一开始会拦截所有的端口读写。调用setup_vmCS_config函数设置一个全局变量vmcs_config,该函数根据查看CS的特性支持填写vmcs_config,之后在创建虚拟CPU时,用这个配置来初始化VMCS,根据CPU特性设置一些全局变量,如是否支持EPT的enable_ept变量。通过alloc_kvm_area函数为每一个物理CPU分配一个VMCS结构,并放到vmxarea这个percpu变量中。
kvm_arch_check_processor_compat函数用来用来检测所有CPU的特性是否一致。该函数通过调用Intel x86实现的chech_processor_compatibility回调函数vmx_check_processor_compat。注意kvm_init对每一个在线的CPU都调用kvm_arch_check_processor_compat函数。vmx_check_processor_compat调用函数setup_vmcs_config函数为所有物理CPU构造vmcs_conf,hardware_setup函数通过setup_vmcs_config函数用当前运行的物理CPU特性构造一个全局的vmcs_config,vmx_check_processor_compat函数这里将每个物理CPU的vmcs_conf与全局的vmcs_config进行比较,确保所有的物理CPU的vmcs_conf一样,这样就保证VCPU在物理CPU上调度的时候不会出现错误。
通过函数register_cpu_notifier和register_boot_notifier分别注册通知对象kvm_cpu_notifier和kvm_reboot_notifier,当CPU在热插拔时kvm_cpu_notifier会收到通知,当系统重启时kvm_reboot_notifier会收到通知。
创建VCPU结构体的cache赋值给kvm_vcpu_cache,实现快速的分配VCPU空间。
设置3个file_operations的owner为当前模块,kvm_chardev_ops表示“/dev/kvm”设备对应的fd的file_operations,kvm_vm_fops表示创建虚拟机VM对应的fd的file_operations,kvm_vcpu_fops表示创建VCPU对应的d的file_operations。
设置kvm_preempt_ops的sched_in和sched_out,当虚拟机VCPU所在线程被抢占或被调度时对调用这两个函数。
kvm_init通过misc_register注册/dev/kvm设备,该设备支持ioctl系统调用,如open和close这些系统调用会被misc设备框架处理。具体参见后续分析kvm_dev_ioctl函数。
kvm_init通过kvm_init_debug函数和kvm_vfio_ops_init函数初始先关数据。
从架构角度看,“/dev/kvm”设备的ioctl接口分为两类:(1)通用接口,如KVM_API_VERSION和KVM_CREATE_VM;(2)与架构相关的接口,如ioctl由kvm_arch_dev_ioctl处理。
从内容角度看,KVM的ioctl处理整个KVM层面的请求,如KVM_GET_API_VERSION返回的KVM的版本号,KVM_CREATE_VM创建一台虚拟机,KVM_CHECK_EXITENSION检查KVM是否支持一些通用扩展,KVM_GET_VCPU_MMAP_SIZE返回VCPU中QEMU和KVM共享内存的大小等。与KVM层面对应的ioctl是VM层面和VCPU层面的ioctl,分别在kvm_vm_fops和kvm_vcpu_fops这两个file_operations中定义。
总结,KVM模块的初始化工作:(1)对硬件进行检查,(2)分配一些常用结构体的缓存,(3)创建“/dev/kvm”misc设备,(4)初始化VMCS的配置结构体vmcs_config,(5)根据物理CPU特性设置一些全局变量,(6)为每一个物理CPU分配一个VNCS结构。注意此时物理CPU还没处于VMX模式,在vmx_init初始化过程中没有向CR4.VMXE写1,也没有分配VMXON区域。这里使用一种惰性加载,如加载KVM模块,没有创建虚拟机,就不需要使物理CPU进入VMX模式。VMX模式真正的开启是在创建第一个虚拟机时。