KVM的初始化过程

之前打算整理一下在Guest VM, KVM, QEMU中IO处理的整个流程,通过查阅资料和阅读源码,已经大致知道IO在Guest KVM中的处理流程.当想要整理IO在KVM和QEMU中的处理时,发现很难理清楚QEMU和KVM之间的跳转和交互的过程,于是促使自己去了解QEMU和KVM启动的过程.(本文展示的代码中,qemu版本为1.6.0, linux内核版本为3.7.10)

为了介绍qemu和kvm的交互过程,我首先介绍一下kvm给用户提供的接口.kvm是一个内核模块,它实现了一个/dev/kvm的字符设备来与用户进行交互,通过调用一系列ioctl函数可以实现qemu和kvm之间的切换.当要创建一个新的虚拟机时,首先打开/dev/kvm设备,在其上调用ioctl函数:

[cpp] view plaincopy

  1. system_fd = open("/dev/kvm", ORDWR);
  2. vm_fd = ioctl(system_fd, KVM_CREATE_VM, 0);

ioctl函数在kvm中的实现为virt/kvm/kvm_main.c中kvm_dev_ioctl函数,当传入的参数为KVM_CREATE_VM时,该函数会创建一个VM,并且返回一个fd,通过该fd可以操作虚拟机.

创建完虚拟机之后,需要在该虚拟机上面创建vcpu,调用的接口也是ioctl,只是此时对应的fd为创建虚拟机时返回的fd.

[cpp] view plaincopy

  1. vcpu_fd = ioctl(vm_fd, VM_CREATE_VCPU, 0)

此时ioctl函数对应的实现为virt/kvm/kvm_main.c中kvm_vm_ioctl函数,当传入的参数为VM_CREATE_VCPU时,与KVM_CREATE_VM过程类似,它创建一个vcpu并且返回可以操作该vcpu的fd.

创建完vcpu后,可以在该vcpu上面调用ioctl函数进入guest vm.

[cpp] view plaincopy

  1. ret = ioctl(vcpu_fd, KVM_RUN, 0);

此时ioctl函数对应的实现为virt/kvm/kvm_main.c中kvm_vcpu_ioctl函数,若传入的参数为KVM_RUN,它最终会调用vcpu_enter_guest函数进入guest vm.

qemu作为一个user mode的程序,其入口为main函数,该main函数定义在vl.c文件中.main函数比较长,其中跟KVM初始化相关的主要有两个函数:configure_accelerator()和machine->init(&args). cofigure_accelerator()函数选择运用哪一种虚拟化方案,其应用到的数据结构为accel_list,会调用accel_list[i].init函数.accel_list的初始化如下所示,当使用kvm虚拟化解决方案时,accel_list[i].init对应的函数即为kvm_init.

[cpp] view plaincopy

  1. static struct {
  2. const char *opt_name;
  3. const char *name;
  4. int (*available)(void);
  5. int (*init)(void);
  6. bool *allowed;
  7. } accel_list[] = {
  8. { "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
  9. { "xen", "Xen", xen_available, xen_init, &xen_allowed },
  10. { "kvm", "KVM", kvm_available, kvm_init, &kvm_allowed },
  11. { "qtest", "QTest", qtest_available, qtest_init, &qtest_allowed },
  12. };

kvm_init函数定义在kvm-all.c文件中,其主要功能是打开/dev/kvm设备,创建一个虚拟机.

machine->init(&arg)函数主要初始化硬件设备,并且调用qemu_init_vcpu为每一个vcpu创建一个线程,线程执行的函数为qemu_kvm_cpu_thread_fn.从qemu main到qemu_init_vcpu之间函数调用关系涉及到一些函数指针的赋值源码比较难于读懂,以下是使用gdb调试打出其调用关系.

[cpp] view plaincopy

  1. #0 qemu_init_vcpu (cpu=0x55555681ea90) at /home/dashu/kvm/qemu/qemu-dev-zwu/cpus.c:1084
  2. #1 0x0000555555909f1e in x86_cpu_realizefn (dev=0x55555681ea90, errp=0x7fffffffd8f8) at /home/dashu/kvm/qemu/qemu-dev-zwu/target-i386/cpu.c:2399
  3. #2 0x00005555556c768a in device_set_realized (obj=0x55555681ea90, value=true, err=0x7fffffffda88) at hw/core/qdev.c:699
  4. #3 0x000055555580b93f in property_set_bool (obj=0x55555681ea90, v=0x5555565bab20, opaque=0x5555565375a0, name=0x555555a01f88 "realized", errp=0x7fffffffda88) at qom/object.c:1300
  5. #4 0x000055555580a484 in object_property_set (obj=0x55555681ea90, v=0x5555565bab20, name=0x555555a01f88 "realized", errp=0x7fffffffda88) at qom/object.c:788
  6. #5 0x000055555580bbea in object_property_set_qobject (obj=0x55555681ea90, value=0x555556403e40, name=0x555555a01f88 "realized", errp=0x7fffffffda88) at qom/qom-qobject.c:24
  7. #6 0x000055555580a770 in object_property_set_bool (obj=0x55555681ea90, value=true, name=0x555555a01f88 "realized", errp=0x7fffffffda88) at qom/object.c:851
  8. #7 0x00005555558a7de0 in pc_new_cpu (cpu_model=0x555555a0200b "qemu64", apic_id=0, icc_bridge=0x55555655b2c0, errp=0x7fffffffdac8) at /home/dashu/kvm/qemu/qemu-dev-zwu/hw/i386/pc.c:922
  9. #8 0x00005555558a7fed in pc_cpus_init (cpu_model=0x555555a0200b "qemu64", icc_bridge=0x55555655b2c0) at /home/dashu/kvm/qemu/qemu-dev-zwu/hw/i386/pc.c:978
  10. #9 0x00005555558a923b in pc_init1 (system_memory=0x5555562a7240, system_io=0x5555562a7f60, ram_size=1073741824, boot_device=0x555555a0248a "cad", kernel_filename=0x0, kernel_cmdline=0x5555559f85be "",
  11. initrd_filename=0x0, cpu_model=0x0, pci_enabled=1, kvmclock_enabled=1) at /home/dashu/kvm/qemu/qemu-dev-zwu/hw/i386/pc_piix.c:105
  12. #10 0x00005555558a9a36 in pc_init_pci (args=0x7fffffffdf10) at /home/dashu/kvm/qemu/qemu-dev-zwu/hw/i386/pc_piix.c:245
  13. #11 0x00005555558a9a7f in pc_init_pci_1_6 (args=0x7fffffffdf10) at /home/dashu/kvm/qemu/qemu-dev-zwu/hw/i386/pc_piix.c:255
  14. #12 0x00005555558584fe in main (argc=10, argv=0x7fffffffe148, envp=0x7fffffffe1a0) at vl.c:4317

qemu_kvm_cpu_thread_fn函数创建vcpu,然后调用kvm_cpu_exec函数.kvm_cpu_exec函数调用ioctl进入kvm并最终进入guest vm.

以上即为qemu调用kvm的接口初始化kvm的过程.后续我会整理出IO在kvm和qemu之间执行过程,同时描述kvm和qemu之间如何协同工作的.

参考资料:

1. qemu-kvm的初始化与客户系统的执行:http://blog.csdn.net/lux_veritas/article/details/9383643

2. 内核虚拟化kvm/qemu----guest os,kvm,qemu工作流程:http://www.360doc.com/content/12/0619/13/7982302_219186951.shtml

转载:http://blog.csdn.net/dashulu/article/details/17074675

时间: 2024-08-30 07:51:37

KVM的初始化过程的相关文章

java代码的初始化过程研究

刚刚在ITeye上看到一篇关于java代码初始化的文章,看到代码我试着推理了下结果,虽然是大学时代学的知识了,没想到还能做对.(看来自己大学时掌握的基础还算不错,(*^__^*) 嘻嘻--)但是博主写的不够详细具体,我想在这详细谈一下java代码的具体初始化过程. 首先要清楚,初始化分为两个过程:类初始化.对象初始化. 类初始化是指类加载器将类加载到内存时,对类成员的初始化过程,也就是有static修饰的变量.对于加载完的类,它的类变量都会赋一个默认值,即使你定义时就赋值了.比如int类型就是0

JAVA对象的初始化过程

出处:http://blog.csdn.net/andrew323/article/details/4665379 下面我们通过两个例题来说明对象的实例化过程. 例1:   编译并运行该程序会有以下输出 Static Block Employee Company:china soft Non-Static Block Employee phone:0755-51595599 Employee(String) Empoloyee() 下面我们来对结果做分析: 1 在代码34行实例化对象时, 先对给

Java对象相关元素的初始化过程

1.类的成员变量.构造函数.成员方法的初始化过程 当一个类使用new关键字来创建新的对象的时候,比如Person per = new Person();JVM根据Person()寻找匹配的类,然后找到这个类相匹配的构造方法,这里是无参构造,如果程序中没有给出任何构造方法,则JVM默认会给出一个无参构造.当创建一个对象的时候一定对调用该类的构造方法,构造方法就是为了对对象的数据进行初始化.JVM会对给这个对象分配内存空间,也就是对类的成员变量进行分配内存空间,如果类中在定义成员变量就赋值的话,就按

对Socket CAN的理解(5)——【Socket CAN控制器的初始化过程】

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 对于一般的CAN模块,进行初始化时,最关键的是以下两步: 1.  配置CAN的位时序: 2.  配置CAN的消息报文: 下面,我们来详细分析上面提到的关键两步. 一.初始化步骤: 1.  第一步,进入初始化模式,在CAN控制寄存器中,将Init位置1: 2.  第二步,在CAN控制寄存器中,将CCE位置1: 3.  第三步,等待Init位置1,此步聚为了确保已经进入初始化模式: 4.  第四步,将位时序的值写入到

IOC容器的初始化过程

1.ClassPathXmlApplicationContext类体系结构 左边的黄色部分是ApplicationContext体系继承结构,右边是BeanFactory结构体系,两个体系是典型的模板方法设计模式的使用. 从该继承体系可以看出: (1)BeanFactory是一个bean工厂的最基本定义,里面包含了一个bean工厂的几个最基本方法:getBean(),containsBean()等,是一个很纯粹的bean工厂,不关注资源.资源位置.事件等. ApplicationContext是

Java初始化过程

以下程序执行的结果是: class X{ Y y=new Y(); public X(){ System.out.print("X"); } } class Y{ public Y(){ System.out.print("Y"); } } public class Z extends X{ Y y=new Y(); public Z(){ System.out.print("Z"); } public static void main(Stri

启动期间的内存管理之初始化过程概述----Linux内存管理(九)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检测到可用内存和寄存器. 而我们今天要讲的boot阶段就是系统初始化阶段使用的内存分配器. 1 前景回顾 1.1

继承的初始化过程

看think in java 7.9.1继承的初始化过程的例子,并没有讲到static 代码块的初始化顺序 类在初次使用的时候才会被加载,static代码会在加载的时候初始化,所以一个类按照先加载static变量—>static 代码块->普通变量->构造器代码 的顺序进行初始化 而出现继承的时候,类的初始化顺序如下 1.父类的static 变量 2.父类的static 代码块 3.子类的static 变量 4.子类的static 代码块 5.父类的变量 6 父类的构造器 7 子类的变量

Java父类子类的对象初始化过程

摘要 Java基本的对象初始化过程,子类的初始化,以及涉及到父类和子类的转化时可能引起混乱的情况. 1. 基本初始化过程: 对于一个简单类的初始化过程是: static 修饰的模块(static变量和static 块)  ---> 按照代码顺序依次执行. | 实例变量  及非static模块---> 按照代码顺序依次执行. | 构造函数 ---> 执行对应的构造函数. 子类的初始化过程. 父类static修饰的模块 | 子类static修饰模块 | 父类实例变量和非static块 | 父