kvm是一個內核模塊,它實現了一個/dev/kvm的字符設備來與用戶進行交互,通過調用一系列ioctl函數可以實現qemu和kvm之間的切換。
1、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可以操作虛擬機。
2、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;
執行x86_cpu_realizefn調用qemu_init_vcpu-》qemu_kvm_start_vcpu-》qemu_thread_create該函數創建VCPU對應的qemu線程,線程函數是qemu_kvm_cpu_thread_fn,該線程函數中:
(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。
關於開關:
qemu-kvm線程工作過程:
1)啟動一個子線程,創建初始化vcpu,主線程等待
2)子線程創建初始化vcpu完畢,子線程等待,並等候通知主線程運行
3)主線程繼續初始化虛擬機工作,初始化完成,通知子線程繼續運行
4)子線程繼續啟動虛擬機kvm_run,主線程執行select交互處理
3、主線程main_loop
Thread1:主線程,這個線程loop循環,循環操作select.實際就是查看有無讀寫文件描述符,有的話進行讀寫操作
Thread2:子線程,異步進行i/o操作,主要針對磁盤映像操作(block drive)
Thread3:子線程,VCPU線程, kvm_run啟動和運行虛擬機
ps –ef|grep qemu
gdb –p $pid