[kvm][qemu]CPU虚拟化

前言: 这里作者再次自不量力了,以一点微末的道行分析一下KVM的CPU虚拟化部分的代码。 分析: 1,分析具体代码逻辑之前,可以先使用strace大致看一下qemu启动的时候,和kernel的交互。 在正常启动qemu的命令之前加入strace即可:strace qemu-system-x86_64 -enable-kvm -m 2048 -drive if=virtio,file=/home/ubuntu-server-1604.qcow2,cache=none -redir :8090::80 -redir :8022::22 -cpu qemu64,+vmx -vnc :0 -smp 2

通过这段trace可以大致看出来,qemu首先打开/dev/kvm这个device,然后通过ioctl和它交互。 重点关注KVM_CREATE_VM,又创建出来了新的fd。 查看qemu打开的所有文件(包括设备,Linux上一切皆文件),可以使用lsof -p PID,或者ls -al /proc/PID/fd:

结合上述的strace,不难发现,先打开/dev/kvm作为文件描述符9,再通过ioctl 9得到文件描述符10,即anon_inode:kvm-vm;同理继续可以分析出来其他的fd。大致可以简单了解逻辑。 2,/dev/kvm 先来分析一下/dev/kvm的创建过程。代码在linux-4.0.4/virt/kvm目录。 在kvm_main.c中,kvm_init函数中会注册一个device(by misc_register(&kvm_dev)),

kvm_dev的名字就是“kvm”,即之前看到的/dev/kvm设备,KVM_MINOR是宏定义232,通过命令可以验证:file /dev/kvm /dev/kvm: character special (10/232) /dev/kvm的ioctl就是通过kvm_chardev_ops.kvm_dev_ioctl函数。 3,KVM_CREATE_VM 从kvm_dev_ioctl中选择KVM_CREATE_VM分支,即kvm_dev_ioctl_create_vm函数:

kvm_create_vm函数主要用来创建并初始化kvm数据结构,包括lock,memslot,mmu notifier等,并把数据结构加入到vm_list(双链表,用来保存本机上KVM创建的的所有vm)中; coalesced mmio不在这里分析。 anon_inode_getfd函数创建一个名为“kvm-vm”的一个新的匿名文件,即上文的文件描述符为10的anon_inode:kvm-vm,并注册这个文件的file operation-----kvm_vm_fops。 4,create vcpu 通过函数kvm_vm_fops .kvm_vm_ioctl的KVM_CREATE_VCPU分支----kvm_vm_ioctl_create_vcpu。

首先创建kvm_vcpu类型的vcpu数据结构。intel架构下,会使用linux-4.0.4/arch/x86/kvm/vmx.c中的vmx_create_vcpu函数。函数中初始化vcpu,并分配vmx数据结构,同时申请vmcs(vmcs很复杂,需要参考文档:https://software.intel.com/en-us/articles/intel-sdm,3B部分介绍intel的VMX)。 然后添加vcpu到vm中。当然,这里会根据id检查是否已经添加过了。 最后,还是会通过create_vcpu_fd函数创建匿名文件kvm-vcpu,即上文的anon_inode:kvm-vcpu。同理,用户进程可以通过这个匿名文件的描述符进行ioctl操作。 5,vcpu run anon_inode:kvm-vcpu提供了kvm_vcpu_ioctl函数进行vcpu的ioctl。 当用户进程请求了KVM_RUN之后,会通过这样的路径让CPU进入vm模式: kvm_arch_vcpu_ioctl_run(linux-4.0.4/arch/x86/kvm/x86.c)->__vcpu_run->vcpu_enter_guest->vmx_vcpu_run(linux-4.0.4/arch/x86/kvm/vmx.c) cpu进入到了vm模式,就在跑虚拟机中的代码。在虚拟机中,这就是一个cpu。如果遇到异常,比如说Guest使用了IO指令访问,那么就会让cpu退出vm模式,并把异常原因交给qemu来处理;如果qemu进程发生了缺页中断,那么host就需要给qemu进程分配page,分配之后,qemu进程继续跑,不需要qemu进程处理什么,当然,Guest中也不感知。 6,qemu KVM_CREATE_VM qemu中,init machine中,因为选择了kvm硬件加速,所以会通过kvm_init函数创建kvm的vm。下图是backtrace。

7,qemu KVM_CREATE_VCPU & KVM_RUN

pthread_create中会调用clone创建新的线程,由上图的backtrace可见,每一个vcpu都对应一个用户态的线程。用户态的多线程同时在跑,对应的就是vm中的多核心在跑。

创建完vcpu,qemu通过kvm_cpu_exec,进而进入vm模式(by kvm_vcpu_ioctl(cpu, KVM_RUN, 0))。 8,vcpu exit 如上文所说,vcpu如果遇到异常,且是需要qemu来处理的情况下,那么将会退出vm模式。qemu继续执行kvm_cpu_exec函数。 qemu从kernel的kvm中获取到exit reason,然后做出相应的逻辑:

例如,Guest中访问使用了IO指令导致了退出了vm模式,那么qemu会调用kvm_handle_io。处理完成后,继续进入vm模式执行。 后记: 水平有限,CPU过于相关的,包括一些汇编代码,都需要对照intel的开发文档来分析。这里只对整体逻辑做了简单分析。 惭愧,惭愧~

原文发布于微信公众号 - AlwaysGeek(gh_d0972b1eeb60)

原文发表时间:2017-02-05

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏写写代码吃吃瓜

Ubuntu环境下Tornado环境部署

19370
来自专栏建站达人秀

如何搭建 Ghost 博客

Ghost是一个轻量级(~7.5MB)的开源博客平台,非常易于使用。Ghost是完全可定制的。互联网上有很多可供Ghost使用的免费或付费的主题。

46230
来自专栏云计算教程系列

如何在CentOS上创建Kubernetes集群

在本教程中,您将使用Ansible和Kubeadm从头开始设置Kubernetes集群,然后给它部署一个容器化的Nginx程序。

5.9K120
来自专栏编程坑太多

『高级篇』docker之DockerSwarm的集群环境搭建(28)

PS:以上就完成高可用的docker swarm的集群环境,其实真心比其他的简单。

13420
来自专栏实战docker

Docker学习笔记之一:准备,安装,初体验

想实践一下Docker,手头是个windows电脑,由于想在linux下实践,所以第一步是装虚拟机,我用的是VMware Workstation 12 Play...

383100
来自专栏编程坑太多

『中级篇』 容器之间的Link(27)

PS:用户自定义的bridge 和 docker0 这个bridge他们之前的区别,docker0 如果通过名称想找到需要通过link,实际的项目中很少使用li...

14270
来自专栏数据和云

独家 | 通过Docker技术在macOS上部署3实例MGR环境

自从有了Docker,各种环境部署都简单从容起来,还记得我们曾经分享过:在macOS 上部署Oracle数据库环境,其实MySQL的环境部署起来同样得心应手。 ...

36680
来自专栏性能与架构

使用Docker创建MongoDB复制集

MongoDB复制集由一组MongoDB实例节点组成,包含一个Primary节点、多个Secondary节点 客户端写入的数据会被写入Primary节点,Sec...

39250
来自专栏破晓之歌

linux下docker+sentry安装配置

注意:接下来所有命令都需要用到 Redis、 PostgreSQL、 Outbound Email中的环境变量,所有命令中需要将将三个镜像连接起来

22310
来自专栏有困难要上,没有困难创造困难也要上!

TensorFlow 分布式集群 Local Server

291100

扫码关注云+社区

领取腾讯云代金券