1、基本原理
如之前的文章分析,在KVM虚拟化环境中, 硬件虚拟化使用 VCPU(Virtual CPU) 描述符来描述虚拟 CPU ,VCPU 描述符与 OS 中进程描述符类似,本质是一个结构体kvm_vcpu,其中包含如下信息:

VCPU标识信息,如VCPU的ID号,VCPU属于哪个Guest等。

虚拟寄存器信息,在VT-x的环境中,这些信息包含在VMCS中。

VCPU状态信息,标识白VCPU当前所处的状态(睡眠、运行等),主要供调度器使用。

额外的寄存器/部件信息,主要指未包含在VMCS中的寄存器或CPU部件,比如:浮点寄存器和虚拟的LAPIC等。

其他信息:用户VMM进行优化或存储额外信息的字段,如:存放该VCPU私有数据的指针。

当 VMM 创建虚拟机时,首先要为虚拟机创建 VCPU ,整个虚拟机的运行实际上可以看做 VMM 调度不同的 VCPU 运行 。
虚拟机的VCPU通过ioctl VM指令 K VM_CREATE_VCPU实现 ,实质为创建kvm_vcpu结构体,并进行相关初始化。本文简单分析VCPU创建过程,qemu-kvm用户态实现部分暂不包括。

2、基本流程
kvm_vm_ioctl() // kvm ioctl vm指令入口
    kvm_vm_ioctl_create_vcpu() // 为虚拟机创建VCPU的ioctl调用的入口函数
        kvm_arch_vcpu_create() // 创建vcpu结构,架构相关,对于intel x86来说,最终调用vmx_create_vcpu
        kvm_arch_vcpu_setup() // 设置VCPU结构
        create_vcpu_fd() // 为新创建的vcpu创建对应的fd,以便于后续通过该fd进行ioctl操作
        kvm_arch_vcpu_postcreate() // 架构相关的善后工作,比如再次调用vcpu_load,以及tsc相关处理

3、代码分析
kvm_vcpu结构:

点击(此处)折叠或打开

  1. struct kvm_vcpu {
  2. // 指向此vcpu所属的虚拟机对应的kvm结构
  3. struct kvm *kvm;
  4. #ifdef CONFIG_PREEMPT_NOTIFIERS
  5. struct preempt_notifier preempt_notifier;
  6. #endif
  7. int cpu;
  8. // vcpu id,用于唯一标识该vcpu
  9. int vcpu_id;
  10. int srcu_idx;
  11. int mode;
  12. unsigned long requests;
  13. unsigned long guest_debug;
  14. struct mutex mutex;
  15. // 执行虚拟机对应的kvm_run结构
  16. struct kvm_run *run;
  17. int fpu_active;
  18. int guest_fpu_loaded, guest_xcr0_loaded;
  19. wait_queue_head_t wq;
  20. struct pid *pid;
  21. int sigset_active;
  22. sigset_t sigset;
  23. // vcpu状态信息
  24. struct kvm_vcpu_stat stat;
  25. // mmio相关部分
  26. #ifdef CONFIG_HAS_IOMEM
  27. int mmio_needed;
  28. int mmio_read_completed;
  29. int mmio_is_write;
  30. int mmio_cur_fragment;
  31. int mmio_nr_fragments;
  32. struct kvm_mmio_fragment mmio_fragments[KVM_MAX_MMIO_FRAGMENTS];
  33. #endif
  34. #ifdef CONFIG_KVM_ASYNC_PF
  35. struct {
  36. u32 queued;
  37. struct list_head queue;
  38. struct list_head done;
  39. spinlock_t lock;
  40. } async_pf;
  41. #endif
  42. #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
  43. /*
  44. * Cpu relax intercept or pause loop exit optimization
  45. * in_spin_loop: set when a vcpu does a pause loop exit
  46. * or cpu relax intercepted.
  47. * dy_eligible: indicates whether vcpu is eligible for directed yield.
  48. */
  49. struct {
  50. bool in_spin_loop;
  51. bool dy_eligible;
  52. } spin_loop;
  53. #endif
  54. bool preempted;
  55. // 架构相关部分,包括的寄存器、apic、mmu相关等架构相关的内容
  56. struct kvm_vcpu_arch arch;
  57. };

kvm_vm_ioctl()-->kvm_vm_ioctl_create_vcpu():

点击(此处)折叠或打开

  1. /*
  2. * 为虚拟机创建VCPU的ioctl调用的入口函数,本质为创建vcpu结构并初始化,并将其填入kvm结构中。
  3. */
  4. static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
  5. {
  6. int r;
  7. struct kvm_vcpu *vcpu, *v;
  8. // 创建vcpu结构,架构相关,对于intel x86来说,最终调用vmx_create_vcpu
  9. vcpu = kvm_arch_vcpu_create(kvm, id);
  10. if (IS_ERR(vcpu))
  11. return PTR_ERR(vcpu);
  12. preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops);
  13. /*
  14. * 设置vcpu结构,主要调用kvm_x86_ops->vcpu_load,KVM虚拟机VCPU数据结构载入物理CPU,
  15. * 并进行虚拟机mmu相关设置,比如进行ept页表的相关初始工作或影子页表
  16. * 相关的设置。
  17. */
  18. r = kvm_arch_vcpu_setup(vcpu);
  19. if (r)
  20. goto vcpu_destroy;
  21. mutex_lock(&kvm->lock);
  22. if (!kvm_vcpu_compatible(vcpu)) {
  23. r = -EINVAL;
  24. goto unlock_vcpu_destroy;
  25. }
  26. if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) {
  27. r = -EINVAL;
  28. goto unlock_vcpu_destroy;
  29. }
  30. // 检测分配的vcpu id是否已经存在
  31. kvm_for_each_vcpu(r, v, kvm)
  32. if (v->vcpu_id == id) {
  33. r = -EEXIST;
  34. goto unlock_vcpu_destroy;
  35. }
  36. /*
  37. * kvm->vcpus[]数组包括该vm的所有vcpu,定义为KVM_MAX_VCPUS大小的数组。
  38. * 在kvm结构初始化时,其中所有成员都初始化为0,在vcpu还没有
  39. * 分配之前,如果不为0,那就是bug了。
  40. */
  41. BUG_ON(kvm->vcpus[atomic_read(&kvm->online_vcpus)]);
  42. /* Now it's all set up, let userspace reach it */
  43. // 增加kvm的引用计数
  44. kvm_get_kvm(kvm);
  45. // 为新创建的vcpu创建对应的fd,以便于后续通过该fd进行ioctl操作
  46. r = create_vcpu_fd(vcpu);
  47. if (r < 0) {
  48. kvm_put_kvm(kvm);
  49. goto unlock_vcpu_destroy;
  50. }
  51. // 将新创建的vcpu填入kvm->vcpus[]数组中
  52. kvm->vcpus[atomic_read(&kvm->online_vcpus)] = vcpu;
  53. // 内存屏障,防止同时访问kvm结构时乱序
  54. smp_wmb();
  55. // 增加online vcpu的数量
  56. atomic_inc(&kvm->online_vcpus);
  57. mutex_unlock(&kvm->lock);
  58. // 架构相关的善后工作,比如再次调用vcpu_load,以及tsc相关处理
  59. kvm_arch_vcpu_postcreate(vcpu);
  60. return r;
  61. unlock_vcpu_destroy:
  62. mutex_unlock(&kvm->lock);
  63. vcpu_destroy:
  64. kvm_arch_vcpu_destroy(vcpu);
  65. return r;
  66. }

kvm_vm_ioctl()-->kvm_vm_ioctl_create_vcpu()-->kvm_arch_vcpu_create()-->kvm_x86_ops->vcpu_create()-->vmx_create_vcpu():

点击(此处)折叠或打开

  1. /*
  2. * Intel x86架构中创建并初始化VCPU中架构相关部分
  3. */
  4. static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
  5. {
  6. int err;
  7. // 从slab中,分配vcpu_vmx结构体,其中包括VMX技术硬件相关信息。
  8. struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
  9. int cpu;
  10. if (!vmx)
  11. return ERR_PTR(-ENOMEM);
  12. // 分配vpid,vpid为VCPU的唯一标识。
  13. allocate_vpid(vmx);
  14. // 初始化vmx中的vcpu结构
  15. err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
  16. if (err)
  17. goto free_vcpu;
  18. // 分配Guest的msr寄存器保存区
  19. vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
  20. err = -ENOMEM;
  21. if (!vmx->guest_msrs) {
  22. goto uninit_vcpu;
  23. }
  24. vmx->loaded_vmcs = &vmx->vmcs01;
  25. /*
  26. * 分配VMCS结构,该结构用于保存虚拟机和虚拟机监控器的系统编程接口状态。
  27. * 当执行VM exit和VM entry操作时,VT-x自动根据VMCS中的内容完成虚拟机和虚拟机监
  28. * 控器间的系统编程接口状态切换。
  29. */
  30. vmx->loaded_vmcs->vmcs = alloc_vmcs();
  31. if (!vmx->loaded_vmcs->vmcs)
  32. goto free_msrs;
  33. // 是否设置了vmm_exclusive
  34. if (!vmm_exclusive)
  35. // VMXON指令用于开启VMX模式
  36. kvm_cpu_vmxon(__pa(per_cpu(vmxarea, raw_smp_processor_id())));
  37. loaded_vmcs_init(vmx->loaded_vmcs);
  38. if (!vmm_exclusive)
  39. // VMXON指令用于关闭VMX模式
  40. kvm_cpu_vmxoff();
  41. // 当前cpu
  42. cpu = get_cpu();
  43. // KVM虚拟机VCPU数据结构载入物理CPU
  44. vmx_vcpu_load(&vmx->vcpu, cpu);
  45. vmx->vcpu.cpu = cpu;
  46. // 设置vmx相关信息
  47. err = vmx_vcpu_setup(vmx);
  48. vmx_vcpu_put(&vmx->vcpu);
  49. put_cpu();
  50. if (err)
  51. goto free_vmcs;
  52. if (vm_need_virtualize_apic_accesses(kvm)) {
  53. err = alloc_apic_access_page(kvm);
  54. if (err)
  55. goto free_vmcs;
  56. }
  57. // 是否支持EPT
  58. if (enable_ept) {
  59. if (!kvm->arch.ept_identity_map_addr)
  60. kvm->arch.ept_identity_map_addr =
  61. VMX_EPT_IDENTITY_PAGETABLE_ADDR;
  62. err = -ENOMEM;
  63. // 分配identity页表
  64. if (alloc_identity_pagetable(kvm) != 0)
  65. goto free_vmcs;
  66. // 初始化identity页表
  67. if (!init_rmode_identity_map(kvm))
  68. goto free_vmcs;
  69. }
  70. vmx->nested.current_vmptr = -1ull;
  71. vmx->nested.current_vmcs12 = NULL;
  72. return &vmx->vcpu;
  73. free_vmcs:
  74. free_loaded_vmcs(vmx->loaded_vmcs);
  75. free_msrs:
  76. kfree(vmx->guest_msrs);
  77. uninit_vcpu:
  78. kvm_vcpu_uninit(&vmx->vcpu);
  79. free_vcpu:
  80. free_vpid(vmx);
  81. kmem_cache_free(kvm_vcpu_cache, vmx);
  82. return ERR_PTR(err);
  83. }

kvm_vm_ioctl()-->kvm_vm_ioctl_create_vcpu()-->kvm_arch_vcpu_setup():

点击(此处)折叠或打开

  1. int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
  2. {
  3. int r;
  4. vcpu->arch.mtrr_state.have_fixed = 1;
  5. // KVM虚拟机VCPU数据结构载入物理CPU
  6. r = vcpu_load(vcpu);
  7. if (r)
  8. return r;
  9. // vcpu重置,包括相关寄存器、时钟、pmu等,最终调用vmx_vcpu_reset
  10. kvm_vcpu_reset(vcpu);
  11. /*
  12. * 进行虚拟机mmu相关设置,比如进行ept页表的相关初始工作或影子页表
  13. * 相关的设置。
  14. */
  15. r = kvm_mmu_setup(vcpu);
  16. vcpu_put(vcpu);
  17. return r;
  18. }

kvm_vm_ioctl()-->kvm_vm_ioctl_create_vcpu()-->kvm_arch_vcpu_setup()-->kvm_mmu_setup()-->init_kvm_mmu():

点击(此处)折叠或打开

  1. static int init_kvm_mmu(struct kvm_vcpu *vcpu)
  2. {
  3. // NPT(Nested page table,AMD x86硬件提供的内存虚拟化技术,相当于Intel中的EPT技术)相关初始化
  4. if (mmu_is_nested(vcpu))
  5. return init_kvm_nested_mmu(vcpu);
  6. /*
  7. * EPT(Extended page table,Intel x86硬件提供的内存虚拟化技术)相关初始化
  8. * 主要是设置一些函数指针,其中比较重要的如缺页异常处理函数
  9. */
  10. else if (tdp_enabled)
  11. return init_kvm_tdp_mmu(vcpu);
  12. // 影子页表(软件实现内存虚拟化技术)相关初始化
  13. else
  14. return init_kvm_softmmu(vcpu);
  15. }

KVM vCPU创建过程相关推荐

  1. kernel 3.10代码分析--KVM相关--虚拟机创建\VCPU创建\虚拟机运行

    分三部分:一是KVM虚拟机创建.二是VCPU创建.三是KVM虚拟机运行 第一部分: 1.基本原理 如之前分析,kvm虚拟机通过对/dev/kvm字符设备的ioctl的System指令KVM_CREAT ...

  2. Ubuntu20.4系统下安装kvm并创建虚拟机

    Ubuntu20.4系统下安装kvm并创建虚拟机 一.安装Ubuntu20.4系统 二.在Ubuntu20.4系统下安装KVM 三.kvm虚拟机及其磁盘映像文件(CentOS 7.9)制作 一.安装U ...

  3. java初始化实例化_Java对象的创建过程:类的初始化与实例化

    一.Java对象创建时机 我们知道,一个对象在可以被使用之前必须要被正确地实例化.在Java代码中,有很多行为可以引起对象的创建,最为直观的一种就是使用new关键字来调用一个类的构造函数显式地创建对象 ...

  4. iOS 的本地化使用和创建过程

    在使用本地化语言之前,来看看本地化语言文件内容的结构(这里我以Chinese为例): "Cancel"="取消"; "OK"="确 ...

  5. python不能创建新变量_Python之变量的创建过程!

    Python之变量的创建过程 一.变量创建过程 首先,当我们定义了一个变量name = 'Kwan'的时候,在内存中其实是做了这样一件事: 程序开辟了一块内存空间,将'Kwan'存储进去,再让变量名n ...

  6. 深入浅出Spring Security(二):FilterChainProxy的创建过程

    上篇回顾 框架的核心是一个过滤器,这个过滤器名字叫springSecurityFilterChain,类型是FilterChainProxy WebSecurity和HttpSecurity都是建造者 ...

  7. OpenStack虚机网卡的创建过程

    OpenStack虚机网卡的创建过程 OpenStack最基本和常用的操作就是启动虚机.虚机启动的过程中涉及很多内容,其中非常重要的一个环节就是创建并绑定虚机的虚拟网卡.虚机的创建和管理是Nova的任 ...

  8. 深入理解WMS(一):Window的创建过程

    8.3 Window的创建过程 View是Android中的视图的呈现方式,但是View不能单独存在,它必须附着在Window这个抽象的概念上面,因此有视图的地方就有Window.Android中可以 ...

  9. Android10.0应用进程创建过程以及Zygote的fork流程-[Android取经之路]

    摘要:点击手机桌面图标,例如微信,它是如何启动的呢,让我们从系统源码级来一起分析. 阅读本文大约需要花费1小时. 文章的内容主要还是从源码进行分析,虽然又臭又长,但是如果想要学习Android系统源码 ...

  10. netty 5 alph1源码分析(服务端创建过程)

    研究了netty的服务端创建过程.至于netty的优势,可以参照网络其他文章.<Netty系列之Netty 服务端创建>是 李林锋撰写的netty源码分析的一篇好文,绝对是技术干货.但抛开 ...

最新文章

  1. DayDayUp:寒门女孩考入北大→换角度看待表达《感谢贫穷》—关于吃苦与穷~~~Python之wordcloud词云图可视化
  2. 从营销手段到商业新基建,“以旧换新”还有多少价值等待挖掘?
  3. k8s集群部分常见问题处理
  4. C# 动态创建数据库三(MySQL)
  5. win7局域网计算机 慢,Win7系统开机宽带连接很慢怎么办?
  6. vivado中如何读取十进制小数_二进制十进制间小数怎么转换,原来是这样的
  7. centos搭建rsync服务!
  8. 域管理员在域计算机安装程序,本人电脑菜鸟,现在正用管理员用户登录,如何设置某个域用户拥有安装软件的权限?尽量详解。谢谢!...
  9. JS If...Else
  10. Extjs GridPanel用法详解
  11. 多维数组的本质和指针数组
  12. Spring扩展之BeanFactoryPostProcessor接口
  13. 字符串逆序输出的三种方法
  14. 数据治理标准体系框架
  15. INVECAS发布全球首创的HDMI(R)2.1,搭载HDCP2.3芯片和IP解决方案,适用于电视、AVR、条形音响和机顶盒
  16. 世界 6 大航空动力巨头企业
  17. Yahoo.cn邮箱的IMAP设置方法
  18. Qt中qrc文件编译后缺少预编译头文件
  19. 如何利用python给女友制造惊喜(微信每日weather report)
  20. 初学者如何查阅自然语言处理(NLP)领域学术会议

热门文章

  1. Windows设置防火墙允许指定应用正常使用网络
  2. PB高拍仪无纸化软件方案
  3. .net core全开源商城源码,支持可视化布局小程序,前后端分离,跨平台运行
  4. cdr三角形转化为圆角_cdr怎么把直角变成圆角
  5. 原生js实现图片验证码
  6. 离线强化学习总结!(原理、数据集、算法、复杂性分析、超参数调优等)
  7. 维宏云智能工厂系统1.0全面升级,带你体验豪华智能制造
  8. VS中使用ankhSVN
  9. 软件工程学习笔记(全)
  10. 基于ABAQUS蠕变储层稠油蒸汽吞吐开发过程数值模拟