kvm是一個內核模塊,它實現了一個/dev/kvm的字符設備來與用戶進行交互,經過調用一系列ioctl函數能夠實現qemu和kvm之間的切換。 異步
一、qemu發起KVM_CREATE_VM的ioctl建立虛擬機函數
qemu從vl.c/main開始,經過configure_accelerator根據當前current_machine調用對應的accel_init_machine,若是是kvm則具體是kvm_init。當要建立虛擬機,kvm_init函數中會s->fd = qemu_open("/dev/kvm", O_RDWR);打開/dev/kvm設備,獲取虛擬機句柄fd,在該fd上ret = kvm_ioctl(s, KVM_CREATE_VM, type); s->vmfd = ret;此ioctl函數在kvm中的實現爲kvm_main.c中kvm_dev_ioctl函數。當傳入的參數爲KVM_CREATE_VM時,該函數會建立一個VM,而且返回一個vm_fd,經過該vm_fd能夠操做虛擬機。oop
二、qemu中建立虛擬機的vcpu和qemu線程關係,並切換到kvm中線程
在vl.c/main的最開始會module_call_init(MODULE_INIT_MACHINE)本質就是把pc_init1賦值給了mc->init。在kvm_init建立完虛擬機後,會返回到main中,調用machine_class->init(current_machine);即會調用以前註冊的pc_init1,該函數中有兩個重要的pc_cpus_init和pc_memory_init,即CPU和內存的初始化,在pc_cpus_init-》pc_new_cpu-》(1)cpu_x86_create主要就是把CPUX86State填充了一下,涉及到CPUID和其餘的feature。(2)object_property_set_bool-》object_property_set_qobject-》object_property_set-》property_set_bool-》device_set_realized-》dc->realize此即爲X86_cpu_common_class_init設置了處理函數dc->realize = x86_cpu_realizefn;3d
執行x86_cpu_realizefn調用qemu_init_vcpu-》qemu_kvm_start_vcpu-》qemu_thread_create該函數建立VCPU對應的qemu線程,線程函數是qemu_kvm_cpu_thread_fn,該線程函數中:blog
(1)kvm_init_vcpu(1.1)經過ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)kvm_arch_vcpu_id(cpu));建立虛擬機的vcpu。對應到kvm的kvm_main.c中kvm_vm_ioctl函數,當傳入的參數爲VM_CREATE_VCPU時,與KVM_CREATE_VM過程相似,它建立一個vcpu而且返回能夠操做該vcpu的vcpu_fd;(1.2)mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);cpu->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, cpu->kvm_fd, 0);獲取kvm_run對應的內存映射(1.3)kvm_arch_init_vcpu則填充對應的kvm_arch內容。內存
(2)在kvm_init_vcpu返回後會先設置開關qemu_cond_signal(&qemu_cpu_cond);打開這個開關(貌似再通過pc_memory_init設置好內存後,pc_init1完成,便可運行)纔會while循環kvm_cpu_exec,該函數會run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);切換到kvm中運行。對應到kvm的:kvm_main.c中kvm_vcpu_ioctl函數,若傳入的參數爲KVM_RUN,它最終會調用vcpu_enter_guest函數進入guest vm。get
關於開關:虛擬機
qemu-kvm線程工做過程:
1)啓動一個子線程,建立初始化vcpu,主線程等待
2)子線程建立初始化vcpu完畢,子線程等待,並等候通知主線程運行
3)主線程繼續初始化虛擬機工做,初始化完成,通知子線程繼續運行
4)子線程繼續啓動虛擬機kvm_run,主線程執行select交互處理it
三、主線程main_loop
Thread1:主線程,這個線程loop循環,循環操做select.實際就是查看有無讀寫文件描述符,有的話進行讀寫操做
Thread2:子線程,異步進行i/o操做,主要針對磁盤映像操做(block drive)
Thread3:子線程,VCPU線程, kvm_run啓動和運行虛擬機
ps –ef|grep qemu
gdb –p $pid