写点什么

QEMU 与 KVM 架构介绍

  • 2023-01-19
    广东
  • 本文字数:4178 字

    阅读完需:约 14 分钟

QEMU与KVM架构介绍

关注微信公众号:Linux 内核拾遗

文章来源:https://mp.weixin.qq.com/s/SjTJgHhL21OhICDeW-i1ZQ


最近在阅读李强编著的《QEMU/KVM 源码解析与应用》这本书来学习 Linux 内核虚拟化相关知识,通过读书笔记的方式来提炼和归纳书中重要的知识点。本文主要内容是关于虚拟化思想的概述以及 QEMU/KVM 架构的整体概括。

1 虚拟化简介

1.1 虚拟化思想

虚拟化的主要思想是,通过分层将底层的复杂、难用的资源虚拟抽象成简单、易用的资源,提供给上层使用。


本质上,计算机的发展过程也是虚拟化不断发展的过程,底层的资源或者通过空间的分割,或者通过时间的分割,将下层的资源通过一种简单易用的方式转换成另一种资源,提供给上层使用。


  • CPU 抽象:CPU 内部的数字逻辑电路只能识别二进制的机器码,通过从机器码、汇编语言到 C 语言、再到高级语言的不断虚拟的过程,将底层复杂的接口逐渐转变成易于使用的接口

  • 存储抽象:传统机械硬盘通过柱面、磁道、扇区来组织数据信息,操作系统通过文件和目录抽象为应用程序提供了便捷的数据读写接口

  • 网络抽象:TCP/IP 协议栈模型将网卡设备中传递的二进制数据,经过网络层、传输层的抽象后,为应用程序提供了便捷的网络包处理接口,而无需关心底层的 IP 路由、分片等细节

  • 进程抽象:操作系统通过进程抽象为不同的应用程序提供了安全隔离的执行环境,并且有着独立的 CPU 和内存等资源

1.2 虚拟机

虚拟机的核心能力在于提供一个执行环境,并在其中完成用户的指定任务。


虚拟机有多种不同的形式,包括提供指令执行环境的进程、模拟器和高级语言虚拟机,或者是提供一个完整的系统环境的系统虚拟机。

1.2.1 最简单的虚拟机——进程

进程可以看作是一组资源的集合,有自己独立的进程地址空间以及独立的 CPU 和寄存器,执行程序员编写的指令,完成一定的任务。操作系统可以创建多个进程,每一个进程都可以看成一个独立的虚拟机,它们在执行指令、访问内存的时候并不会相互影响影响。


1.2.2 模拟器

模拟器通过解释执行或者二进制翻译的方式,使得为一种硬件指令集(Instruction Set Architecture,ISA)编译的程序,能够运行在运行在另一种硬件指令集上。


  • 解释执行:对程序的源 ISA 指令逐条分析并执行等效操作

  • 二进制翻译:首先将程序中所有的源 ISA 指令翻译成目标 ISA 上的等效指令,然后在目标 ISA 指令机器上执行


典型的模拟器有 QEMU(Quick Emulator)的用户态程序模拟、Bochs 模拟器等。



1.2.3 高级语言虚拟机

在高级语言虚拟机中,通常会设计一种全新的虚拟 ISA(字节码),并在其中定义新的指令集、数据操作、寄存器的使用等类似于物理 ISA 中的规范。任何想要运行这种虚拟 ISA 指令的物理 ISA 平台都需要实现一个虚拟机,该虚拟机能够执行虚拟机 ISA 指令到物理 ISA 指令的转换。典型的高级语言虚拟机有 JVM 虚拟机、Python 虚拟机等。


1.2.4 系统虚拟机

通过系统虚拟化技术,能够在单个的宿主机硬件平台上运行多个虚拟机,每个虚拟机都有着完整的虚拟机硬件,如虚拟的 CPU、内存、虚拟的外设等,并且虚拟机之间能够实现完整的隔离。


在系统虚拟化中,管理全局物理资源的软件叫作虚拟机监控器(Virtual Machine Monitor,VMM),VMM 之于虚拟机就如同操作系统之于进程,VMM 利用时分复用或者空分复用的办法将硬件资源在各个虚拟机之间进行分配。


2 整体架构

2.1 概述

2.1.1 QEMU

QEMU 是一种模拟器,它能够完成用户程序模拟和系统虚拟化模拟:


  • 用户程序模拟:QEMU 能够将为一个平台编译的二进制文件运行在另一个不同的平台。

  • 系统虚拟化模拟:QEMU 能够模拟一个完整的系统虚拟机,该虚拟机有自己的虚拟 CPU、芯片组、虚拟内存以及各种虚拟外部设备,能够为虚拟机中运行的操作系统和应用软件呈现出与物理计算机完全一致的硬件视图。QEMU 能够模拟 x86、ARM、MIPS、PPC 等多个平台。

2.1.2 KVM

KVM 本身是一个内核模块,它导出了一系列的接口到用户空间,用户态程序可以使用这些接口创建虚拟机。最开始 KVM 只负责最核心的 CPU 虚拟化和内存虚拟化部分,使用 QEMU 作为其用户态组件,负责完成大量外设的模拟,当时的方案被称为 QEMU-KVM。

2.2 QEMU-KVM 架构

QEMU 与 KVM 的完整架构如下图所示,比较完整地展现了 QEMU 的运行机制、KVM 的组成、QEMU 与 KVM 的关系,以及虚拟机 CPU、内存、外设等的虚拟化。



VMX root 和 VMX non-root 模式是 CPU 的运行模式,它是在 CPU 引入了支持硬件虚拟化的指令集 VT-x 之后出现的概念,可以简单理解为:


  • VMX root 是宿主机模式,此时 CPU 在运行包括 QEMU 在内的普通进程和宿主机的操作系统内核;

  • VMX non-root 是虚拟机模式,此时 CPU 在运行虚拟机中的用户程序和操作系统代码。


CPU 的运行模式与 CPU 运行时的特权等级是相互正交的,虚拟机在 VMX root 模式和 VMX non-root 模式下都有 ring 0 到 ring 3 四个特权级别。

2.2.1 VMX root 模式的应用层(上半部分左边)

QEMU 在初始化虚拟机的时候需要完成:


  1. 创建模拟的芯片组

  2. 创建 CPU 线程来表示虚拟机的 CPU 执行流

  3. 在 QEMU 的虚拟地址空间中分配空间作为虚拟机的物理地址

  4. 根据用户在命令行指定的设备为虚拟机创建对应的虚拟设备


QEMU 在虚拟机运行期间需要完成:


  1. 在主线程中监听多种事件,包括虚拟机对设备的 I/O 访问、用户对虚拟机管理界面、虚拟设备对应的宿主机上的一些 I/O 事件(比如虚拟机网络数据的接收)等

  2. QEMU 应用层接收到这些事件之后会调用预先定义好的函数进行处理

2.2.2 VMX root 模式的内核层(下半部分)

VMX root 模式的内核层主要包含 KVM 驱动,一方面,KVM 通过“/dev/kvm”设备导出了一系列的接口供 QEMU 等用户态程序控制虚拟机的各个方面,比如 CPU 个数、内存布局、运行等。另一方面,KVM 需要截获虚拟机产生的虚拟机退出(VM Exit)事件并进行处理。

2.2.3 VMX non-root 模式的运行虚拟机(上半部分右边)

  1. 虚拟机的一个 CPU 对应为 QEMU 进程中的一个线程,通过 QEMU 和 KVM 的相互协作,这些线程会被宿主机操作系统正常调度,直接执行虚拟机中的代码

  2. 虚拟机中的物理内存对应为 QEMU 进程中的虚拟内存,虚拟机中的操作系统有自己的页表管理,完成虚拟机虚拟地址到虚拟机物理地址的转换,再经过 KVM 的页表完成虚拟机物理地址到宿主机物理地址的转换

  3. 虚拟机中的设备是通过 QEMU 呈现的,在运行过程中,虚拟机操作系统通过设备的 I/O 端口(Port IO、PIO)或者 MMIO(Memory Mapped I/O)进行交互,KVM 会截获这个请求,大多数时候 KVM 会将请求分发到用户空间的 QEMU 进程中,由 QEMU 处理这些 I/O 请求

2.3 组件虚拟化

2.3.1 CPU 虚拟化

QEMU 在初始化虚拟机的 CPU 线程时,首先设置好相应的虚拟 CPU 寄存器的值,然后调用 KVM 的接口将虚拟机运行起来,这样 CPU 线程就会被调度在物理 CPU 上执行虚拟机的代码。


虚拟机运行过程中会不断在 VM Exit 和 VM Entry 两种状态之间转换,它伴随着 CPU 加载对应的宿主机状态或者虚拟机状态。KVM 将虚拟机的状态保存在一个叫做 VMCS 的结构中。



  1. VM Exit:当虚拟机中的代码是敏感指令或者说满足了一定的退出条件时,CPU 会从 VMX non-root 模式退出到 KVM,这叫作 VM Exit,这就像在用户态执行指令陷入内核一样。

  2. VM Entry:虚拟机的退出首先陷入到 KVM 中进行处理,如果 KVM 无法处理,比如说虚拟机写了设备的寄存器地址,那么 KVM 会将这个写操作分派到 QEMU 中进行处理,当 KVM 或者 QEMU 处理好了退出事件之后,又可以将 CPU 置于 VMX non-root 模式以运行虚拟机代码,这叫作 VM Entry。

2.3.2 内存虚拟化

QEMU 在初始化的时候会通过 mmap 系统调用分配虚拟内存空间作为虚拟机的物理内存,QEMU 在不断更新内存布局的过程中会持续调用 KVM 接口通知内核 KVM 模块虚拟机的内存分布。


虚拟机在运行过程中,首先需要将虚拟机的虚拟地址(Guest Virtual Address,GVA)转换成虚拟机的物理地址(Guest Physical Address,GPA),然后将虚拟机的物理地址转换成宿主机的虚拟地址(Host Virtual Address,HVA),最终转换成宿主机的物理地址(Host Physical Address,HPA)。


  1. 软件实现的虚拟机内存寻址——影子页表:早期 CPU 不支持 EPT 时的方案,效率低下

  2. 硬件实现的虚拟机内存寻址——扩展页表(Extended Page Table,EPT):整个过程全部由硬件完成,效果很高


在支持 EPT 的环境中,虚拟机在第一次访问内存的时候就会陷入到 KVM,KVM 会逐渐建立起所谓的 EPT 页面。这样虚拟机的虚拟 CPU 在后面访问虚拟机虚拟内存地址的时候,首先会被转换为虚拟机物理地址,接着会查找 EPT 页表,然后得到宿主机物理地址。


2.3.3 外设虚拟化

设备模拟的本质是要为虚拟机提供一个与物理设备接口完全一致的虚拟接口。


虚拟机中的操作系统与设备进行的数据交互或者由 QEMU 和(或)KVM 完成,或者由宿主机上对应的后端设备完成。


QEMU 在初始化过程中会创建好模拟芯片组和必要的模拟设备,包括南北桥芯片、PCI 根总线、ISA 根总线等总线系统,以及各种 PCI 设备、ISA 设备等。


外设虚拟化主要有如下几种方式:


  1. 纯软件模拟(完全虚拟化):QEMU 最早的方案,虚拟机内核不用做任何修改,每一次对设备的寄存器读写都会陷入到 KVM,进而到 QEMU,QEMU 再对这些请求进行处理并模拟硬件行为。软件模拟会导致非常多的 QEMU/KVM 接入,效率低下。

  2. virtio 设备(半虚拟化):virtio 设备是一类特殊的设备,并没有对应的物理设备,所以需要虚拟机内部操作系统安装特殊的 virtio 驱动。相比软件模拟,virtio 方案提高了虚拟设备的性能。

  3. 设备直通:将物理硬件设备直接挂到虚拟机上,虚拟机直接与物理设备交互,尽可能在 I/O 路径上减少 QEMU/KVM 的参与。设备直通经常搭配硬件虚拟化支持技术 SRIOV(Single Root I/O Virtualization,单根输入/输出虚拟化)使用,SRIOV 能够将单个的物理硬件高效地虚拟出多个虚拟硬件。



2.3.4 中断虚拟化

操作系统通过写设备的 I/O 端口或者 MMIO 地址来与设备交互,设备通过发送中断来通知操作系统事件。


QEMU/KVM 一方面需要完成这项中断设备的模拟,另一方面需要模拟中断的请求。


QEMU 支持单 CPU 的 Intel 8259 中断控制器以及 SMP 的 I/O APIC(I/O Advanced Programmable Interrupt Controller)和 LAPIC(Local Advanced Programmable Interrupt Controller)中断控制器。在这种方式下,虚拟外设通过 QEMU 向虚拟机注入中断,需要先陷入到 KVM,然后由 KVM 向虚拟机注入中断,这是一个非常费时的操作。


为了提高虚拟机的效率,KVM 自己也实现了中断控制器 Intel 8259、I/O APIC 以及 LAPIC。用户可以有选择地让 QEMU 或者 KVM 模拟全部中断控制器,也可以让 QEMU 模拟 Intel 8259 中断控制器和 I/O APIC,让 KVM 模拟 LAPIC。



3 参考文献

  1. QEMU/KVM 源码解析与应用 - 李强


关注微信公众号:Linux 内核拾遗

文章来源:https://mp.weixin.qq.com/s/SjTJgHhL21OhICDeW-i1ZQ


用户头像

还未添加个人签名 2023-01-12 加入

还未添加个人简介

评论

发布
暂无评论
QEMU与KVM架构介绍_Linux_Linux内核拾遗_InfoQ写作社区