1. 程式人生 > >Qemu-KVM虛擬機器初始化及建立過程原始碼簡要分析(一)

Qemu-KVM虛擬機器初始化及建立過程原始碼簡要分析(一)

    我們知道,Qemu-KVM實際上包括Qemu和KVM兩部分,那麼在建立以及初始化虛擬機器時,實際上也是在這兩部分進行的。

    KVM實際上就是kvm核心模組,包括kvm.ko、kvm-intel.ko、kvm-amd.ko三部分,後兩部分分別對應Intel體系的VMX技術以及AMD體系的SVM技術。

    首先,我們需要載入模組,當我們載入kvm-xxx.ko模組時,會呼叫對應的module_init()函式,然後呼叫vmx_init()或者svm_init()函式,最後進入到統一的kvm.ko模組中的kvm_init()函式,現在正式開始進行虛擬機器的初始化工作。


module_init(vmx_init)    //位於vmx.c檔案
static int __init vmx_init(void)    //位於vmx.c檔案
{
       ..............//省略部分程式碼
       r= kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx),
                   __alignof__(struct vcpu_vmx),THIS_MODULE);
       ................//省略部分程式碼
}
int kvm_init(void *opaque, unsigned vcpu_size,unsigned vcpu_align,
                struct module *module)    //位於kvm_main.c檔案
{
       ......................//省略部分程式碼
       r= kvm_arch_init(opaque);
       ........................//省略部分程式碼
}

    在進入到kvm_init()函式後,進行了很多初始化的相關工作,這裡單獨強調一下kvm_arch_init()函式。

    在vmx.c檔案中宣告並定義了一個結構體vmx_x86_ops,這是函式指標的集合,其實就是各種操作的一個集合。內部很多函式是後續的初始化工作需要具體呼叫到的,比如很多Qemu層的ioctl呼叫到核心層實際上就是執行這內部的一些函式。具體的內容如下:

static struct kvm_x86_ops vmx_x86_ops = {
       .cpu_has_kvm_support= cpu_has_kvm_support,
       .disabled_by_bios= vmx_disabled_by_bios,
       .hardware_setup= hardware_setup,
       .hardware_unsetup= hardware_unsetup,
       .check_processor_compatibility= vmx_check_processor_compat,
       .hardware_enable= hardware_enable,
       .hardware_disable= hardware_disable,
       .cpu_has_accelerated_tpr= report_flexpriority,
 
       .vcpu_create= vmx_create_vcpu,
       .vcpu_free= vmx_free_vcpu,
       .vcpu_reset= vmx_vcpu_reset,
 
       .prepare_guest_switch= vmx_save_host_state,
       .vcpu_load= vmx_vcpu_load,
       .vcpu_put= vmx_vcpu_put,
 
       .update_db_bp_intercept= update_exception_bitmap,
       .get_msr= vmx_get_msr,
       .set_msr= vmx_set_msr,
       .get_segment_base= vmx_get_segment_base,
       .get_segment= vmx_get_segment,
       .set_segment= vmx_set_segment,
       .get_cpl= vmx_get_cpl,
       .get_cs_db_l_bits= vmx_get_cs_db_l_bits,
       .decache_cr0_guest_bits= vmx_decache_cr0_guest_bits,
       .decache_cr3= vmx_decache_cr3,
       .decache_cr4_guest_bits= vmx_decache_cr4_guest_bits,
       .set_cr0= vmx_set_cr0,
       .set_cr3= vmx_set_cr3,
       .set_cr4= vmx_set_cr4,
       .set_efer= vmx_set_efer,
       .get_idt= vmx_get_idt,
       .set_idt= vmx_set_idt,
       .get_gdt= vmx_get_gdt,
       .set_gdt= vmx_set_gdt,
       .set_dr7= vmx_set_dr7,
       .cache_reg= vmx_cache_reg,
       .get_rflags= vmx_get_rflags,
       .set_rflags= vmx_set_rflags,
       .fpu_activate= vmx_fpu_activate,
       .fpu_deactivate= vmx_fpu_deactivate,
 
       .tlb_flush= vmx_flush_tlb,
 
       .run= vmx_vcpu_run,
       .handle_exit= vmx_handle_exit,
       .skip_emulated_instruction= skip_emulated_instruction,
       .set_interrupt_shadow= vmx_set_interrupt_shadow,
       .get_interrupt_shadow= vmx_get_interrupt_shadow,
       .patch_hypercall= vmx_patch_hypercall,
       .set_irq= vmx_inject_irq,
       .set_nmi= vmx_inject_nmi,
       .queue_exception= vmx_queue_exception,
       .cancel_injection= vmx_cancel_injection,
       .interrupt_allowed= vmx_interrupt_allowed,
       .nmi_allowed= vmx_nmi_allowed,
       .get_nmi_mask= vmx_get_nmi_mask,
       .set_nmi_mask= vmx_set_nmi_mask,
       .enable_nmi_window= enable_nmi_window,
       .enable_irq_window= enable_irq_window,
       .update_cr8_intercept= update_cr8_intercept,
       .set_virtual_x2apic_mode= vmx_set_virtual_x2apic_mode,
       .vm_has_apicv= vmx_vm_has_apicv,
       .load_eoi_exitmap= vmx_load_eoi_exitmap,
       .hwapic_irr_update= vmx_hwapic_irr_update,
       .hwapic_isr_update= vmx_hwapic_isr_update,
       .sync_pir_to_irr= vmx_sync_pir_to_irr,
       .deliver_posted_interrupt= vmx_deliver_posted_interrupt,
 
       .set_tss_addr= vmx_set_tss_addr,
       .get_tdp_level= get_ept_level,
       .get_mt_mask= vmx_get_mt_mask,
 
       .get_exit_info= vmx_get_exit_info,
 
       .get_lpage_level= vmx_get_lpage_level,
 
       .cpuid_update= vmx_cpuid_update,
 
       .rdtscp_supported= vmx_rdtscp_supported,
       .invpcid_supported= vmx_invpcid_supported,
 
       .set_supported_cpuid= vmx_set_supported_cpuid,
 
       .has_wbinvd_exit= cpu_has_vmx_wbinvd_exit,
 
       .set_tsc_khz= vmx_set_tsc_khz,
       .read_tsc_offset= vmx_read_tsc_offset,
       .write_tsc_offset= vmx_write_tsc_offset,
       .adjust_tsc_offset= vmx_adjust_tsc_offset,
       .compute_tsc_offset= vmx_compute_tsc_offset,
       .read_l1_tsc= vmx_read_l1_tsc,
 
       .set_tdp_cr3= vmx_set_cr3,
 
       .check_intercept= vmx_check_intercept,
       .handle_external_intr= vmx_handle_external_intr,
};

    這個結構體作為引數傳遞到kvm_init()函式,再傳遞到kvm_arch_init()函式,再傳遞到全域性變數kvm_x86_ops中,註冊各種操作函式,後續可以呼叫。隨後還進行了一些內部資料結構以及定時器、除錯資訊等的一些初始化工作。與此同時,qemu層也會進行大部分的初始化工作,這一部分後一篇再講。