QEMU-KVM框架總結


kvm模塊的加載

arch/x86/kvm/vmx/vmx.c

載入kvm模塊時,調用順序為module_init()->vmx_init()->kvm_init(),所以kvm_init()為核心函數

int kvm_init()
{
	...
	/*
    /* 1. 將vmx_x86_ops重命名為kvm_x86_ops
	/* 2. 檢查cpu是否支持kvm
	/* 3. 檢查是否包含FPU Feature,並為FPU分配存儲空間
	/* 4. 為所有CPU分配共享MSR 
	/* 5. 初始化及設置MMU 
	/* 6. 設置一個回調函數,用於獲取guest信息
	/* 7. 初始化LAPIC 
	*/
	r = kvm_arch_init(opaque); // 這里的opaque為一個結構體(vmx_x86_ops),包含一系列kvm主要操作
	...
	/*
	/* 1. 對kvm_x86_ops結構中與硬件相關的內容進行初始化賦值
	/* 2. 為每個cpu申請vmcs空間
	/* 3. 設置TSC
	*/
	r = kvm_arch_hardware_setup();
   
}

kvm模塊加載完成后,在系統的/dev目錄下出現kvm設備,用於外界與kvm交互


kvm模塊向外界提供的ioctl分類

virt/kvm/kvm_main.c

分為3大類,大多都在kvm_main.c中實現,剩余一小部分在arch/x86/kvm/vmx/vmx.c中.3類ioctl分別為設備、虛擬機、虛擬cpu級別.3個層次逐級概念變小,虛擬機由設備層面的ioctl創建,而虛擬cpu由虛擬機級別的ioctl創建.

設備級別ioctl

kvm_dev_ioctl為前綴,負責以下通用設備級別的ioctl功能的處理

  • [ ] KVM_GET_API_VERSION
  • [ ] KVM_CREATE_VM
  • [ ] KVM_CHECK_EXTENSION
  • [ ] KVM_GET_VCPU_MMAP_SIZE
  • [ ] KMV_TRACE_ENABLE/PAUSE/DISABLE

其余設備級別的ioctl功能與架構有關,因此在kvm_arch_dev_ioctl()中實現.

虛擬機級別ioctl

kvm_vm_ioctl為前綴,負責以下通用虛擬機級別的ioctl功能的處理

  • [ ] KVM_CREATE_VCPU
  • [ ] KVM_ENABLE_CAP
  • [ ] KVM_SET_USER_MEMORY_REGION
  • [ ] KVM_GET/CLEAR_DIRTY_LOG
  • [ ] KMV_REGISTER/UNREGISTER_CONESCED_MMIO
  • [ ] KVM_IRQFD
  • [ ] KVM_IOEVENTFD
  • [ ] KVM_SIGNAL_MSI
  • [ ] KVM_IRQ_LINE_STATUS
  • [ ] KVM_IRQ_LINE
  • [ ] KVM_SET_GSI_DORTINE
  • [ ] KVM_CREATE_DEVICE
  • [ ] KVM_CHECK_EXTENSION

其余虛擬機級別的ioctl功能與架構有關,因此在kvm_arch_vm_ioctl()中實現.

虛擬CPU級別ioctl

kvm_vcpu_ioctl為前綴,負責以下通用虛擬CPU級別的ioctl功能的處理

  • [ ] KVM_RUN
  • [ ] KVM_SET/GET_REGS
  • [ ] KVM_SET/GET_SPGGS
  • [ ] KVM_SET/GET_MPSTATE
  • [ ] KVM_TRANSLATE
  • [ ] KVM_SET_GUEST_DEBUG
  • [ ] KVM_SET_SIGNAL_MASK
  • [ ] KVM_SET/GET_FPU

其余虛擬CPU級別的ioctl功能與架構有關,因此在kvm_arch_vcpu_ioctl()中實現.


kvm中虛擬機的創建流程

主要創建流程就是dev->vm->vcpu,這期間最重要的數據結構為kvm_x86_ops(在vmx.c中定義),但是在ioctl函數中展現的形式與實際調用的函數形式有些許不同. 如在創建vm時,函數調用流程為:

kvm_dev_ioctl_create_vm() -> kvm_create_vm() -> kvm_arch_alloc_vm()

kvm_arch_alloc_vm()中,具體實現只有一句return kvm_x86_ops->vm_alloc(),此時使用vim插件無法找到vm_alloc()的定義,但在vmx.c中可以看到類似.vm_alloc = vmx_vm_alloc, 因此其實vm_alloc()調用的是vmx_vm_alloc,其它kvm_x86_ops的子方法也可以使用類似的方法找到.

創建vm

kvm_dev_ioctl_create_vm() -> kvm_create_vm() -> kvm_arch_alloc_vm() -> vmx_vm_alloc()

​ | -> kvm_arch_init_vm() | -> vmx_vm_init()

因此可以通過調用kvm_dev_ioctl_create_vm()完成對一個vm的內存分配和初始化,最終返回的是一個kvm_vmx結構的結構.

創建vCPU

kvm_vm_ioctl_create_vcpu() -> kvm_arch_vcpu_create() -> vmx_create_vcpu()

​ | -> kvm_arch_vcpu_setup() -> vmx_vcpu_setup()

​ | -> create_vcpu_fd

kvm_arch_vcpu_create()vcpu_vmx結構申請空間,初始化vcpu,為guest_msr,vmcs結構申請空間,並利用vmx_vcpu_setup()vmcs設置為實模式狀態,利用vmx_vcpu_put()准備將vcpu切換至host狀態.

運行vCPU

kvm_vcpu_ioctl(...,KVM_RUN,...) -> kvm_arch_vcpu_ioctl_run() -> vcpu_run() -> vcpu_enter_guest()|

​ -> need_resched() <-|

vcpu_enter_guest()使虛擬vcpu進入non-root操作,退出該函數等效於執行了VM exit,如果退出該函數時返回1,即代表guest無法處理本次exit reasion,需要進入到用戶空間(qemu),使用qemu對本次exit reason進行處理,處理完成之后再進入vcpu_enter_guest().


QEMU與KVM的交互

QEMU的ioctl

由於這部分與qemu有交互的部分,因此我提前對qemu進行了學習.

qemu與kvm對應有4大類的ioctl,用於對kvm提供的3個級別的fd進行控制.

  • kvm_device_ioctl()

用於對device_fd(/dev/kvm)進行操作 ---> hypervisor

  • kvm_ioctl()

用於對KVMState結構體中的fd進行操作 ---> 對應kvm的device級別

  • kvm_vm_ioctl()

用於對KVMState結構體中vmfd進行操作 ---> 對應kvm的vm級別

  • kvm_vcpu_ioctl()

用於對CPUState結構體中的kvm_fd進行操作 ---> 對應kvm的vcpu級別

kvm的kvm_vcpu結構體中含有kvm_run結構,用於QEMU的用戶空間和kvm模塊的交互. 例如在VM exit時,為了對虛擬硬件的訪問進行模擬,kvm必須返回到QEMU用戶空間中,因此kvm將相關信息存儲到kvm_run結構中,留給QEMU獲取信息.

【update】 2019.11.22

QEMU配置加速器(kvm)

qemu使用了大量面向對象的編程方式,並用c語言實現了類的構建、析構函數等。

qemu將kvm定義為一種加速類型(AccelClass),注冊到了type_table中,因此通過初始化對象就可以直接調用對象所屬類的方法。

AccelClassinit_machine()方法可以獲得vm_fd.

QEMU設置vCPU

與加速器類似,vCPU也被設計為一種CPU類型(x86_vcpu_type), 將qemu的main函數中的current_machine->type指向x86_vcpu_type,即可調用該類的方法使用vCPU.

x86_vcpu_typex86_vcpu_common_class_init()方法可以獲得vCPU的inode(qemu中稱為kvm_fd).

值得注意的是qemu為每個vCPU申請了一個線程(thread),所占空間在qemu本身在host上所占的空間中.

QEMU的main函數中與kvm有關的部分

QEMU的main函數中與kvm有關的部分對應的為配置加速器設置vCPU兩部分,以及最后的循環運行vCPU,主要函數為:

configure_accelerator();
current_machine->cpu_type的賦值;
main_loop();

我對qemu-kvm框架整理后,畫了以下結構圖.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM