• 基于armv8的kvm实现分析(三)kvm初始化流程


    本文基于以下软硬件假定:

    架构:AARCH64

    内核版本:5.14.0-rc5

    1 kvm概述

      kvm是基于linux内核实现的一种type 2虚拟化方案,它作为内核的一个模块负责虚拟化环境初始化,虚拟机和虚拟cpu模拟,以及IO捕获与转发等功能。在kvm中虚拟机和虚拟cpu分别通过host os的进程和线程实现,并且由host os的调度器对其进行调度。

      由于除了像中断控制器之类的关键设备之外,kvm并不会执行设备模拟工作,因此它通常需要与qemu结合使用。由qemu执行实际的IO设备模拟,以及虚拟机创建和参数配置功能。为此,kvm需要通过ioctl向用户态导出一组虚拟机管理相关的接口,它们之间的关系如下图:

    2 初始化总体流程

      kvm初始化的主要目的是为虚拟机的创建和运行提供必要的软硬件环境,其总体流程图如下:

    从上图可看出,kvm的初始化流程比较清晰,其主要包含以下几部分:
    (1)架构相关的初始化流程
    (2)为电源管理接口注册回调函数,以处理kvm在电源管理流程中的行为
    (3)为kvm注册字符设备以为用户态提供ioctl接口
    (4)其它一些辅助接口

    由于架构相关的初始化流程比较复杂,我们将在后面单独用一章进行讨论,因此下面将分别介绍其它的一些流程

    2.1 电源管理回调注册

      由于在cpu热插拔和系统休眠唤醒流程中需要执行cpu的offline和online状态转换,因此对于需要控制cpu的相关模块,在这一流程中需要正确管理本模块的cpu状态设置。在电源管理流程中,相关模块可以向电源管理模块注册回调,当对应的电源管理事件发生时,该回调函数将会被调用。

      其中cpuhp_setup_state_nocalls用于注册cpu热插拔时的回调,register_syscore_op用于注册系统休眠唤醒时的回调,而register_reboot_notifier用于注册系统重启时的通知。它们最终都由kvm_arch_hardware_enable和kvm_arch_hardware_disable实现,用于在cpu下线时关闭hypervisor,并在cpu上线时重新初始化hypervisor。

    2.2 ioctl接口注册

      从在上一章图中可看到kvm一共为用户态提供了三组ioctl接口:kvm ioctl、vm ioctl和vcpu ioctl。它们分别为用于控制kvm全局、特定虚拟机以及特定vcpu相关的操作。

      其中kvm全局ioctl通过misc_register()接口以字符设备的方式注册,而vm ioctl和vcpu ioctl则通过anon_inode_getfd()接口以匿名inode方式注册。

      Linux中一般的文件都包含一个inode和与若干个其关联的dentry,其中dentry用于表示其在文件系统中的路径。若用户态希望操作该文件时,可通过打开dentry对应的文件名,并获取一个fd。

      但是有些文件操作希望将fd与inode直接关联起来,其文件名不在文件系统中被显示,这就是匿名inode。如vm的匿名inode在下图所示的虚拟机创建流程中建立:

    而vcpu的匿名inode同样在vcpu创建流程中建立,其流程如下:

    2.3 其它辅助接口

    (1)kvm_irqfd_init():为eventfd创建一个全局的工作队列,它用于在虚拟机被关闭时,关闭所有与其相关的irqfd,并等待该操作完成

    (2)kmem_cache_create_usercopy()和kvm_async_pf_init()用于创建特定的slab

    (3)kvm_init_debug()用于为kvm创建debugfs相关接口

    (4)kvm_vfio_ops_init()用于为vfio注册设备回调函数

    3 架构相关初始化

      Armv8的虚拟化方案具有两种实现方式nvhe和vhe,在vhe实现中host os和hypervisor都运行在EL2中,此时host os与hypervisor共用所有的EL2寄存器,且host可以直接通过函数调用方式调用hypervisor的接口。因此对于运行在vhe模式下的kvm模块,其初始化流程比较简单,主要包括一些host context的初始化,以及虚拟gic和timer初始化等流程。

      相对而言,vnhe由于host os和hypervisor运行在如下图所示的不同异常等级下,因此其初始化流程更加复杂。

  • 相关阅读:
    82 # koa-bodyparser 中间件的使用以及实现
    SpringBoot整合QQ邮箱发送验证码
    【网络安全篇】PHP文件与目录操作(一文带你手撕迷茫)
    ReentrantReadWriteLock读写锁实现原理详解
    不会写单元测试的程序员不是一个合格的滴滴司机
    技术干货:spring boot面试题及答案
    数据科学与大数据(3)
    “探索前后端分离架构下的Vue.js应用开发“
    LeetCode刷题(11)
    IO进线程:共享内存
  • 原文地址:https://blog.csdn.net/lingshengxiyou/article/details/127985430