1、QEMU創建虛擬機發起:kvm_ioctl(s, KVM_CREATE_VM, type);
KVM中kvm_dev_ioctl判斷參數-》kvm_dev_ioctl_create_vm-》kvm_create_vm該函數中創建並初始化了對應qemu模擬的內存條模型kvm->memslots【kvm結構體】
2、QEMU創建vcpu發起:kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)kvm_arch_vcpu_id(cpu));
KVM中kvm_vm_ioctl判斷參數-》kvm_vm_ioctl_create_vcpu-》
(1)kvm_arch_vcpu_create借助kvm_x86_ops->vcpu_create即vmx_create_vcpu完成任務:(1.1)kvm_vcpu_init初始化,主要是填充結構體【kvm_vcpu】,注意vcpu->run分派了一頁內存,該函數繼續kvm_arch_vcpu_init負責填充x86 CPU結構體【kvm_vcpu_arch】,該函數還kvm_mmu_create則是初始化MMU的函數,每個MMU都是vcpu獨有。(1.2)分配一頁給vmcs(執行vm entry的時候將vmm狀態保存到vmcs的host area,並加載對應vm的vmcs guest area信息到CPU中,vm exit的時候則反之,vmcs具體結構分配由硬件實現,程序員只需要通過VMWRITE和VMREAD指令去訪問)(1.3)vmx_vcpu_load加載VCPU的信息,切換到指定cpu,進入到vmx模式,將loaded_vmcs的vmcs和當前cpu的vmcs綁定到一起(1.4)vmx_vcpu_setup則是初始化vmcs內容,主要是賦值計算
(2)kvm_arch_vcpu_setup-》kvm_x86_ops->vcpu_load(vcpu, cpu)即vmx_vcpu_load,就是進入vcpu模式下准備工作。
(3)create_vcpu_fd為proc創建控制fd,讓qemu使用
3、QEMU要運行vcpu發起:kvm_vcpu_ioctl(cpu, KVM_RUN, 0);
KVM中kvm_vcpu_ioctl判斷參數-》kvm_arch_vcpu_ioctl_run-》__vcpu_run-》
(1)在while循環里面調用vcpu_enter_guest進入guest模式,該函數(1.1)首先處理vcpu->requests,對應的request做處理,kvm_mmu_reload加載mmu,通過kvm_x86_ops->prepare_guest_switch(vcpu)准備陷入到guest,prepare_guest_switch實現是vmx_save_host_state,顧名思義,就是保存host的當前狀態(1.2)然后加載guest的寄存器等信息,fpu,xcr0,將vcpu模式設置為guest狀態,屏蔽中斷響應,准備進入guest。但仍進行一次檢查,vcpu->mode和vcpu->requests等,如果有問題,則恢復host狀態。(1.3)kvm_guest_enter做了兩件事:account_system_vtime計算虛擬機系統時間;rcu_virt_note_context_switch對rcu鎖數據進行保護,完成上下文切換。(1.4)准備工作搞定,kvm_x86_ops->run(vcpu),開始運行guest,由vmx_vcpu_run實現,該函數主要是內聯匯編。(1.5)vmx_vcpu_run退出后返回到vcpu_enter_guest通過hw_breakpoint_restore恢復硬件斷點(1.6)走到kvm_x86_ops->handle_exit(vcpu);即vmx_handle_exit處理虛擬機的退出:主要設置vcpu->run->exit_reason,讓外部感知退出原因,並對應handle_exit函數集處理(有handle_task_switch進行任務切換,handle_io處理qemu的外部模擬IO等)。
(2)退回到__vcpu_run函數,在while (r > 0)中,循環受vcpu_enter_guest返回值控制,只有運行異常的時候才退出循環,否則通過kvm_resched一直運行下去。
(3)再退就到了kvm_arch_vcpu_ioctl_run函數,return到kvm_vcpu_ioctl,就ioctl返回到qemu的kvm_cpu_exec中,此時kvm run的執行也結束。
4、QEMU初始化虛擬機內存發起:kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
KVM中kvm_vm_ioctl把參數copy_from_user復制后-》kvm_vm_ioctl_set_memory_region逐層調用到__kvm_set_memory_region在KVM中建立與QEMU相對應的內存槽結構-》
(1)id_to_memslot根據qemu的內存槽號得到kvm結構下的內存槽號 kvm_memory_slot,轉換關系來自id_to_index數組(在kvm_create_vm虛擬機創建過程中,kvm_init_memslots_id初始化對應關系slots->id_to_index[i] = slots->memslots[i].id = i)。
(2)根據slot中的值和要設置的值,決定要操作的類別KVM_MR_CREATE/DELETE/MOVE/_FLAGS_ONLY。如果是CREATE則kvm_arch_create_memslot函數,里面主要是一個循環做了一個3級軟件頁表;無論刪除還是移動, 先申請一個slots,把kvm->memslots暫存到這里,通過id_to_memslot獲取kvm_memory_slot,並將應標記為KVM_MEMSLOT_INVALID,然后是install_new_memslots,其實就是更新了一下slots->generation的值(也就是把剛新申請的slots裝載到kvm->memslots)(這里為何先不用原來slot而是申請新的slot “如果添加的section的屬性變了,如從RAM變成了ROM,那么重新進行添加也是必要的”並不理解https://blog.csdn.net/leoufung/article/details/48781185 )。