标签(空格分隔): KVM架构
上一篇文章笼统的介绍了一个虚拟机的诞生过程,从demo中也能够看到,运行一个虚拟机不再须要像之前想象的那样,须要用软件来模拟硬件指令集了。虚拟机的指令集直接运行在宿主机物理CPU上,当虚拟机中的指令设计到IO操做或者一些特殊指令的时候,控制权转让给了宿主机(这里实际上是转让给了vm monitor,下面检查VMM),也就是一个demo进程,他在宿主机上的表现形式也就是一个用户级进程。app
用一张图来解释更为贴切。函数
VMM完成vCPU,内存的初始化后,经过ioctl调用KVM的接口,完成虚拟机的建立,并建立一个线程来运行VM,因为VM在前期初始化的时候会设置各类寄存器来帮助KVM查找到须要加载的指令的入口(main函数)。因此线程在调用了KVM接口后,物理CPU的控制权就交给了VM。VM运行在VMX non-root模式,这是Intel-V或者AMD-V提供的一种特殊的CPU执行模式。而后当VM执行了特殊指令的时候,CPU将当前VM的上下文保存到VMCS寄存器(这个寄存器是一个指针,保存了实际的上下文地址),而后执行权切换到VMM。VMM 获取 VM 返回缘由,并作处理。若是是IO请求,VMM 能够直接读取VM的内存并将IO操做模拟出来,而后再调用VMRESUME指令,VM继续执行,此时在VM看来,IO操做的指令被CPU执行了。ui
Intel-V 技术是Intel为了支持虚拟化而提供的一套CPU特殊运行模式。操作系统
Intel-V 在IA-32处理器上扩展了处理器等级,原来的CPU支持ring0~ring3 4个等级,可是Linux只使用了其中的两个ring0,ring3。当CPU寄存器标示了当前CPU处于ring0级别的时候,表示此时CPU正在运行的是内核的代码。而当CPU处于ring3级别的时候,表示此时CPU正在运行的是用户级别的代码。当发生系统调用或者进程切换的时候,CPU会从ring3级别转到ring0级别。ring3级别是不容许执行硬件操做的,全部硬件操做都须要系统提供的API来完成。
好比说一个IO操做:线程
int nread = read(fd, buffer, 1024);
当执行到此段代码的时候,而后查找到系统调用号,保存到寄存器eax,而后会将对应的参数压栈后产生一个系统调用中断,对应的是 int $0x80。产生了系统调用中断后,此时CPU将切换到ring0模式,内核经过寄存器读取到参数,并完成最后的IO后续操做,操做完成后返回ring3模式。debug
movel $3,%eax movel fd,%ebx movel buffer,%ecx movel 1024,%edx int $0x80
Intel-V 在 ring0~ring3 的基础上,增长了VMX模式,VMX分为root和non-root。这里的VMX root模式是给VMM(前面有提到VM monitor),在KVM体系中,就是qemu-kvm进程所运行的模式。VMX non-root模式就是运行的Guest,Guest也分ring0~ring3,不过他并不感知本身处于VMX non-root模式下。设计
Intel的虚拟架构基本上分两个部分:指针
虚拟机监视器在宿主机上表现为一个提供虚拟机CPU,内存以及一系列硬件虚拟的实体,这个实体在KVM体系中就是一个进程,如qemu-kvm。VMM负责管理虚拟机的资源,并拥有全部虚拟机资源的控制权,包括切换虚拟机的CPU上下文等。
这个Guest在前面的Demo里面也提到,多是一个操做系统(OS),也可能就是一个二进制程序,whatever,对于VMM来讲,他就是一堆指令集,只须要知道入口(rip寄存器值)就能够加载。
Guest运行须要虚拟CPU,当Guest代码运行的时候,处于VMX non-root模式,此模式下,该用什么指令仍是用什么指令,该用寄存器该用cache仍是用cache,可是在执行到特殊指令的时候(好比Demo中的out指令),把CPU控制权交给VMM,由VMM来处理特殊指令,完成硬件操做。
Guest与VMM之间的切换分两个部分:VM entry 和 VM exit。有几种状况会致使VM exit,好比说Guest执行了硬件访问操做,或者Guest调用了VMCALL指令或者调用了退出指令或者产生了一个page fault,或者访问了特殊设备的寄存器等。当Guest处于VMX模式的时候,没有提供获取是否处于此模式下的指令或者寄存器,也就是说,Guest不能判断当前CPU是否处于VMX模式。当产生VM exit的时候,CPU会将exit reason保存到MSRs(VMX模式的特殊寄存器组),对应到KVM就是vCPU->kvm_run->exit_reason。VMM根据exit_reason作相应的处理。
如上图所示,VMM 开始于VMXON 指令,结束与VMXOFF指令。
第一次启动Guest,经过VMLAUNCH指令加载Guest,这时候一切都是新的,好比提及始的rip寄存器等。后续Guest exit后再entry,是经过VMRESUME指令,此指令会将VMCS(后面会介绍到)所指向的内容加载到当前Guest的上下文,以便Guest继续执行。
顾名思义,VMCS就是虚拟机控制结构,前面提到过不少次,Guest Exit的时候,会将当前Guest的上下文保存到VMCS中,Guest entry的时候把VMCS上下文恢复到VMM。VMCS是一个64位的指针,指向一个真实的内存地址,VMCS是以vCPU为单位的,就是说当前有多少个vCPU,就有多少个VMCS指针。VMCS的操做包括VMREAD,VMWRITE,VMCLEAR。
下面是qemu-kvm定义的exit reason。能够看到有不少可能会致使Guest转让控制权。选取几个解释一下。
static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { [EXIT_REASON_EXCEPTION_NMI] = handle_exception, [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault, [EXIT_REASON_NMI_WINDOW] = handle_nmi_window, // 访问了IO设备 [EXIT_REASON_IO_INSTRUCTION] = handle_io, // 访问了CR寄存器,地址寄存器,和DR寄存器(debug register)同样,用于调试 [EXIT_REASON_CR_ACCESS] = handle_cr, [EXIT_REASON_DR_ACCESS] = handle_dr, [EXIT_REASON_CPUID] = handle_cpuid, // 访问了MSR寄存器 [EXIT_REASON_MSR_READ] = handle_rdmsr, [EXIT_REASON_MSR_WRITE] = handle_wrmsr, [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, // Guest执行了HLT指令,Demo开胃菜就是这个指令 [EXIT_REASON_HLT] = handle_halt, [EXIT_REASON_INVD] = handle_invd, [EXIT_REASON_INVLPG] = handle_invlpg, [EXIT_REASON_RDPMC] = handle_rdpmc, // 不太清楚如下VM系列的指令有什么用,猜想是递归VM(虚拟机里面运行虚拟机) [EXIT_REASON_VMCALL] = handle_vmcall, [EXIT_REASON_VMCLEAR] = handle_vmclear, [EXIT_REASON_VMLAUNCH] = handle_vmlaunch, [EXIT_REASON_VMPTRLD] = handle_vmptrld, [EXIT_REASON_VMPTRST] = handle_vmptrst, [EXIT_REASON_VMREAD] = handle_vmread, [EXIT_REASON_VMRESUME] = handle_vmresume, [EXIT_REASON_VMWRITE] = handle_vmwrite, [EXIT_REASON_VMOFF] = handle_vmoff, [EXIT_REASON_VMON] = handle_vmon, [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold, // 访问了高级PCI设备 [EXIT_REASON_APIC_ACCESS] = handle_apic_access, [EXIT_REASON_APIC_WRITE] = handle_apic_write, [EXIT_REASON_EOI_INDUCED] = handle_apic_eoi_induced, [EXIT_REASON_WBINVD] = handle_wbinvd, [EXIT_REASON_XSETBV] = handle_xsetbv, // 进程切换 [EXIT_REASON_TASK_SWITCH] = handle_task_switch, [EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check, // ept 是Intel的一个硬件内存虚拟化技术 [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation, [EXIT_REASON_EPT_MISCONFIG] = handle_ept_misconfig, // 执行了暂停指令 [EXIT_REASON_PAUSE_INSTRUCTION] = handle_pause, [EXIT_REASON_MWAIT_INSTRUCTION] = handle_invalid_op, [EXIT_REASON_MONITOR_INSTRUCTION] = handle_invalid_op, [EXIT_REASON_INVEPT] = handle_invept, };
KVM的CPU虚拟化依托于Intel-V提供的虚拟化技术,将Guest运行于VMX模式,当执行了特殊操做的时候,将控制权返回给VMM。VMM处理完特殊操做后再把结果返回给Guest。 CPU虚拟化能够说是KVM的最关键的核心,弄清楚了VM Exit和VM Entry。后续的IO虚拟化,内存虚拟化都是创建在此基础上。下一章介绍内存虚拟化。