KVM初始化過程

2021-08-28 10:56:35 字數 3959 閱讀 3275

之前打算整理一下在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函式:

system_fd = open("/dev/kvm", ordwr);

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.

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.

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.

static struct  accel_list = ,,,

,};

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除錯打出其呼叫關係.

#0 qemu_init_vcpu (cpu=0x55555681ea90) at /home/dashu/kvm/qemu/qemu-dev-zwu/cpus.c:1084

#1 0x0000555555909f1e in x86_cpu_realizefn (dev=0x55555681ea90, errp=0x7fffffffd8f8) at /home/dashu/kvm/qemu/qemu-dev-zwu/target-i386/cpu.c:2399

#2 0x00005555556c768a in device_set_realized (obj=0x55555681ea90, value=true, err=0x7fffffffda88) at hw/core/qdev.c:699

#3 0x000055555580b93f in property_set_bool (obj=0x55555681ea90, v=0x5555565bab20, opaque=0x5555565375a0, name=0x555555a01f88 "realized", errp=0x7fffffffda88) at qom/object.c:1300

#4 0x000055555580a484 in object_property_set (obj=0x55555681ea90, v=0x5555565bab20, name=0x555555a01f88 "realized", errp=0x7fffffffda88) at qom/object.c:788

#5 0x000055555580bbea in object_property_set_qobject (obj=0x55555681ea90, value=0x555556403e40, name=0x555555a01f88 "realized", errp=0x7fffffffda88) at qom/qom-qobject.c:24

#6 0x000055555580a770 in object_property_set_bool (obj=0x55555681ea90, value=true, name=0x555555a01f88 "realized", errp=0x7fffffffda88) at qom/object.c:851

#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

#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

#9 0x00005555558a923b in pc_init1 (system_memory=0x5555562a7240, system_io=0x5555562a7f60, ram_size=1073741824, boot_device=0x555555a0248a "cad", kernel_filename=0x0, kernel_cmdline=0x5555559f85be "",

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

#10 0x00005555558a9a36 in pc_init_pci (args=0x7fffffffdf10) at /home/dashu/kvm/qemu/qemu-dev-zwu/hw/i386/pc_piix.c:245

#11 0x00005555558a9a7f in pc_init_pci_1_6 (args=0x7fffffffdf10) at /home/dashu/kvm/qemu/qemu-dev-zwu/hw/i386/pc_piix.c:255

#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之間如何協同工作的.

類初始化和例項初始化過程

類初始化過程 乙個類要建立例項需要先載入並初始化該類 main方法所在的類需要先載入和初始化 乙個子類要初始化需要先初始化父類 乙個類初始化就是執行 方法 由靜態類變數賦值 和靜態 塊組成 靜態類變數賦值 和靜態 塊從上往下執行 方法只執行一次 例項初始化過程 例項初始化就是執行 方法 方法可能過載...

記憶體初始化過程

1,物理記憶體資訊的獲取 0x15中斷,功能號 e820h,e801h,e88h 見檔案 linux arch i386 boot setup.s 執行完上面的 後,記憶體資訊被分為多條資訊放在e820map位置處,每個資訊條目長20位元組,包含乙個記憶體區間的資訊,條目數放在e820nr處。即實際...

Struts初始化過程

sturts初始化過程取決於在web.xml檔案中配置的初始化引數,servlet容器在首次啟動或servlet的第一次請求到達時載入struts actionservlet。在這兩種情況下,要保證init 方法被呼叫,並且必須在servlet處理任何請求之前完成。當init 被呼叫時,struts...