云计算国产化之路 vnc登录 文件系统直通(virtio-9p) 扩展qemu接口 gpg WARNING 珍藏博客 虚拟内存情况dommemstat分析 免密码自动登录脚本 Linux网桥 测试网段IP占用情况 Linux 进程状态 systemc强制依赖 调试openstack ut uefi p2v 重做ubuntu内核 virsh创建虚拟机简介 virtio IO路径 虚拟化层升级后磁盘无法卸载卷 vmtouch使用 Taint flags 主机和虚拟机文件共享处理的几种方法 kvm分析工具 kvm中对磁盘的io cache 虚拟化不同导致的guestos中软件安装差异(未解决) 设备直通(PCI Assignment)到底是咋整的 virtio到底是咋整的 内核启动参数 虚拟化实时性提升(零)之配置步骤 中断虚拟化(pic)到底是咋整的 中断虚拟化(apic)到底是咋整的 Raid卡配置丢失导致服务器无法启动 tainted kernels cpu stuck for 23s问题分析 虚拟化实时性提升(一)之hostOS切换为强实时系统 内存虚拟化到底是咋整的 qemu-kvm中vcpu虚拟化到底是咋整的 风河虚拟化技术点分析 使用qga的好处 qemu迁移代码分析 虚拟机串口配置及其导出到主机pts和console.log System-based I/O vs. Raw I/O 虚拟机使用Hugepage(大页) 硬件辅助分页(hardware assisted paging) 修改centos7默认启动项目 virtio的工作流程——kernel中virtio-pci初始化(2) virtio的工作流程——qemu中virtio-backend初始化(1) qmp ceilometer取不到memory.usage指标 Virtio-Balloon超详细分析 slabtop输出 虚拟机磁盘cache导致的host os kernel崩溃 虚拟机cpu和memory性能优化测评 PCI配置空间(PCI Configuration Space) centos下网卡设备直通(VT-dpci passthrough)遇到的问题及其解决思路 libguestfs详解 yum卸载软件包及其依赖 通过原始Centos ISO来定制自己的ISO centos下网卡设备直通(VT-d,pci passthrough) (占位符)window虚拟机中拔盘如何通知到libvirt和qemu后端的 cirrus漏洞分析CVE-2017-2615 XSA-208 qcow2随笔 控制寄存器概览 ceilometer对接postgresql 解压initrd和vmlinuz qemu guest agent验证 QEMU升级指南(待续) ubuntu中kdump的配置 qemu(2.3)接口梳理 热迁移导致的FC存储场景下的multipath卷残留问题分析 virsh命令(4)secret,snapshot,pool,volume部分 virsh命令(3)之interface,filter,network virsh命令(2)monitor,host,nodedev部分 virsh命令(1)之domain部分 QEMU内存管理之FlatView模型(QEMU2.0.0) ovirt基于sanock的高可用(主机粒度HA) Sanlock防脑裂场景功能测试用例 gnocchi配置及与ceilometer对接指南 make patch for libvirt in centos centos使用sanlock指导 高可用nfs资料 ubuntu14中使用sanlock指导 LVM操作指南 sanlock相关功能验证流程汇总 make patch for libvirt in ubuntu libvirt.so.0-version `LIBVIRT_PRIVATE_1.2.7' not found gdb debug libvirt 基于ubuntu社区源码包编译libvirt compile libvirt(centos) No PCI buses available nfs lead to Linux halt nfs install and config anti-virus for cloud platform nova fetch image from glance(something about _base) token auth process ovs入门指南 virt software anti-virus something about ceilometer disk sample context interview questions openstack vm injection openstack Restful and RPC murano 概览 创建虚拟机流程(compute节点)之网络创建 创建虚拟机流程之compute_api之虚拟机实例填充之配额检测 创建虚拟机流程之compute_api之基本参数生成 创建虚拟机流程之compute_api 创建虚拟机流程(主) 创建虚拟机之image 创建虚拟机流程之准备网桥 创建虚拟机流程之virt 创建虚拟机流程之compute节点 CI/CD研发流程之工程创建 CI/CD研发流程之代码合入 CI/CD研发流程之UT(单元测试) 向openstack社区合入代码记 openstack/ceilometer/gnocchi杂谈 影子页表原理 mem_add(exec.c) qemu编译安装调试 openstack/ceilometer/gnocchi之Grafana简介 openstack wiki etcd openstack计量ceilometer openstack计费cloudKitty enventlet backdoor USB 安装VMWARE ESX pycharm设置指南 无法执行modprobe -a kvm-intel解决办法 QEMU配置项 网络不通小记 libvirt之XML(虚拟机定义文件) openstack-horizon 证书认证 ceilometer与ceph对接 openstack定时任务剖析(TODO) 服务器重启后mongodb进程无法启动 ubuntu14下新增openstack服务到service的导引 ERROR 1045(28000)-数据库连不上 Python两个内置函数—locals和globals unknown exit, hardware reason 31

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

2017年05月05日

一句话总结

实例化一个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_fd
vcpu的运行是在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-entry

kvm_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
继续执行下一次循环