QEMU 工作原理简介

QEMU是一款开源的模拟器和虚拟机监视器(Virtual Machine Monitor, VMM)。QEMU主要提供两个功能给用户使用:

  • 作为用户态模拟器:通过动态代码翻译机制来执行不同架构的代码,例如在X86平台上模拟ARM平台下执行环境。
  • 作为虚拟机监视器:模拟全系统,利用其它VMM(Xen,KVM等等)来使用硬件提供的虚拟化支持,创建接近于主机性能的虚拟机。

QEMU虚拟化的主要原理

系统虚拟化最重要的就是虚拟化出计算机系统中最重要的三大组件:CPU、内存和IO设备。QEMU虚拟出来的CPU成为vCPU,为了提升vCPU执行Guest OS中指令的效率,通过KVM、Xen等虚拟化技术,直接利用CPU硬件虚拟化的支持,在主机上安全地执行虚拟机代码(需要BIOS中CPU开启对应的硬件虚拟化支持)。

在x86平台上最常见的虚拟化组合就是QEMU/KVM的组合了,其中利用QEMU来模拟IO外设,通过KVM来捕获Guest OS中运行的指令并将其中非特权指令在物理CPU上直接运行,达到硬件加速的目的。

KVM内核模块对用户空间只暴露出一个/dev/kvm的设备文件,然后通过ioctl命令与QEMU进程进行通信,KVM利用硬件扩展直接将虚拟机代码运行于主机之上,当vCPU需要执行访问IO设备寄存器的指令时,vCPU就会停止从退回到QEMU进程中,由QEMU去模拟操作的结果。

KVM 虚拟化原理简介

  • KVM是Linux内核的一个虚拟化特性,由一组内核模块文件组成,它可以让QEMU中运行的Guest OS的指令直接在Host OS上的CPU中执行,前提是Guest OS和Host OS的硬件架构相同
  • KVM解决了虚拟化中的哪个痛点?有什么优势? KVM主要解决的虚拟化中CPU虚拟化的问题,这部分详细内容可以参见CPU虚拟化相关内容。
    • 没有KVM虚拟化加速 QEMU需要截获Guest OS中运行的所有指令,然后通过软件的方式模拟执行,如果是跨平台架构的Guest OS,那么还需要额外的二进制指令翻译,将Guest OS中目标架构的指令翻译成Host OS上所能执行的指令,导致虚拟化的效率非常低。
    • 有KVM虚拟化加速 如果QEMU中运行的Guest OS和Host OS的硬件架构相同,那么Guest OS中的指令可以直接在Host OS上的物理CPU上执行,而不需要通过QEMU软件模拟的方式去执行Guest OS中的指令,大大提高了Guest虚拟机的性能。
  • QEMU结合KVM执行Guest OS指令的步骤简要描述1

    打开/dev/kvm设备文件、创建虚拟机、创建vCPU、向KVM模块发送KVM_RUN的ioctl调用,接下来KVM模块利用CPU上的硬件虚拟化扩展功能来直接执行guest的运行。当guest在执行过程中遇到读取硬件设备寄存器等I/O操作、暂停guest CPU或其他特殊指令等KVM无法执行的操作时,会退出当前KVM并交由Qemu处理。Qemu模拟器判断退出原因并执行相应的操作:如果是遇到I/O操作或特殊指令,Qemu会去模拟执行这些操作;如果是暂停guest CPU操作,Qemu停止并等待下一次guest中断。 上述流程用下面的代码来简单表示:

      open("/dev/kvm")
        
      ioctl(KVM_CREATE_VM)
        
      ioctl(KVM_CREATE_VCPU)
        
      for (;;) {
        
           ioctl(KVM_RUN)
        
           switch (exit_reason) { /* 分析退出原因,并执行相应操作 */
        
           case KVM_EXIT_IO:  /* ... */
        
           case KVM_EXIT_HLT: /* ... */
        
           }
        
      }
    
  • Host, QEMU, Guest之间的关系图

参考文章