qemu-kvm中vcpu虚拟化到底是咋整的?

一句话总结

实例化一个vcpu就是在hostOS中创建了一个线程,线程里有个while循环,循环里不停的调用kvm_cpu_exec方法,kvm_cpu_exec方法调用通过kvm_vcpu_ioctl(cpu, KVM_RUN, 0)使得kvm切换为no-root模式。在no-root模式下处理特权指令的时候,会退回root模式,然后一步步返回到kvm_cpu_exec中根据不同原因,处理返回异常。

如此一个轮回结束,周而复始,vcpu。

再补充说一点,内存中申请一块内存,根模式和非根模式切换的时候,先把当前寄存器值放到这块内存中,然后设置物理cpu使得进入对应模式,这块内存叫vmcs。

背景

vcpu初始化的时候(qemu_init_vcpu)是启动了一个线程,也就是说vcpu其实就是一个线程.线程运行方法是qemu_kvm_cpu_thread_fn

kvm_init_vcpu调用KVM_CREATE_VCPU创建了vcpu返回vm_fdvcpu的运行是在kvm_cpu_exec里面的,这里调用如下命令进入kvm

run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);

进入KVM后,KVM会切入Guest OS,假如Guest OS运行运行,需要访问IO等也就是说要访问physical device,那么Qemu与KVM就要进行emulate。如果是KVM emulate的则由KVM emulate,然后切回Guest OS。如果是Qemu emulate的,则从KVM中进入Qemu,等Qemu中的device model执行完emulate之后,再次在Qemu中调用kvm_vcpu_ioctl(vcpu_fd, KVM_RUN, xxx)进入KVM运行,然后再切回Guest OS

vm-entrykvm_vcpu_ioctl(kvm_main.c)-->kvm_arch_vcpu_ioctl_run(kvm/x86.c)-->vcpu_run(kvm/x86.c)-->vcpu_enter_guest(kvm/x86.c)在qemu中kvm_vcpu_ioctl(cpu, KVM_RUN, 0)调用kvm后代码层层调用最终核心实现的方法是vcpu_enter_guest

vcpu->requests 处理

上次VM-Exit时可能调用kvm_make_request设置不同的request下次准备VM-Entry时需要处理这些request.

prepare_guest_switch

 (vmx.c)
.prepare_guest_switch = vmx_save_host_state,
  1. 保存host的fs和gs的断选择子(segment selector)到vmcs
  2. kvm_set_shared_msr设置host对应的msr寄存器 MSR 总体来是为了设置CPU 的工作环境和标示CPU 的工作状态,包括温度控制,性能监控等guest的msr在handle_wrmsr 最终是在vmx_set_msr中更新
  3. 判断当前是否满足vm-entry vcpu的mode不对,有requests请求,需要重新调度,有pending的信号有异常任何情况,不进入vm_entry开中断,开抢占(在此之前已经关抢占,关中断)

4.kvm_x86_ops->run(vcpu)-->vmx_vcpu_run(vmx.c)更新vmcs中的GUEST_RSP和 GUEST_RIP刷新vmcs中的HOST_CR4字段(其他寄存器在 kvm_arch_vcpu_ioctl_set_regs时设置)(段寄存器在vmx_vcpu_reset时设置)下面调用汇编代码,保存host相关内容,然后加载vmcs中的guest的寄存器值,跳转至guest中代码

vm-exit

前半部分我们知道了如何vm-entry此时进入no-root非根模式执行guest的指令当指令访问特权指令如访问io访问设备的时候会vm-exit

1.vmx_vcpu_run后半段

vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
vmx->loaded_vmcs->launched = 1;
vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);

2.加入vm-exit是由于EXIT_REASON_MCE_DURING_VMENTRY或者EXIT_REASON_EXCEPTION_NMI导致的在vmx_complete_atomic_exit方法中需要进行特殊处理(kvm_machine_check)(kvm_before_handle_nmi和kvm_after_handle_nmi)

  1. 如果有事件模拟的virtual nmi中断,则用vmx_recover_nmi_blocking处理
  2. 获取与预处理导致的中断由vmx_complete_interrupts-->__vmx_complete_interrupts处理

(至此退出vmx_vcpu_run重返vmx_vcpu_run)

kvm_x86_ops->handle_exit-->vmx_handle_exit根据不同情况处理异常

至此从kvm中返回到用户态qemu中kvm_cpu_exec方法

根据不同退出原因,处理异常然后退出到线程方法qemu_kvm_cpu_thread_fn继续执行下一次循环

原文发布于微信公众号 - TStack(gh_035269c8aa5f)

原文发表时间:2018-03-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏偏前端工程师的驿站

CentOS6.5菜鸟之旅:U盘安装CentOS64位

一、前言                                      之前下载了个CentOS7 32位版,一下就安装成功了,但由于其目录结构等与...

38050
来自专栏杂烩

Rancher运行dubbo服务 原

        5、dubbo是dubbo-spring-boot-starter:1.0.0

17620
来自专栏Petrichor的专栏

ubuntu: wget 指令

13420
来自专栏大魏分享(微信公众号:david-share)

OpenShift企业版安装:单Master集群

OpenShift企业版安装:单Master集群 项目描述本文目的本文描述搭建红帽OpenShift容器平台单Master集群的过程。 适合用于在没有互联网连接...

2.4K30
来自专栏小狼的世界

Kubernetes基础

Kubernetes是当今最流行的开源容器管理平台,它就是大名鼎鼎的Google Borg的开源版本。Google在2014年推出了Kubernetes,本文发...

33720
来自专栏jeremy的技术点滴

搭建简易的docker集群

47350
来自专栏康怀帅的专栏

Docker PHP 最佳实践

参考示例配置文件在 config/nginx 新建 *.conf NGINX 配置文件

70670
来自专栏写代码的海盗

Docker学习总结之Run命令介绍 Operator exclusive options

Docker学习总结之Run命令介绍 本文由Vikings(http://www.cnblogs.com/vikings-blog/) 原创,转载请标明.谢谢!...

33750
来自专栏NetCore

给Ocelot做一个Docker 镜像

写在前面 在微服务架构中,ApiGateway起到了承前启后,不仅可以根据客户端进行分类,也可以根据功能业务进行分类,而且对于服务调用服务也起到了很好的接口作用...

299100
来自专栏北京马哥教育

KVM虚拟化平台部署及管理

前言 KVM即Kernel Virtual Machine,最初是由以色列公司Qumranet开发。2007年2月被导入Linux 2.6.20核心中,成为内核...

55970

扫码关注云+社区

领取腾讯云代金券