如之前分析,kvm虚拟机通过对/dev/kvm字符设备的ioctl的System指令KVM_CREATE_VM进行创建。
对虚拟机(VM)来说,kvm结构体是关键,一个虚拟机对应一个kvm结构体,虚拟机的创建过程实质为kvm结构体的创建和初始化过程。
本文简单解释及分析在3.10版本内核代码中的相关流程,用户态qemu-kvm部分暂不包括。
2、大致流程如下:
用户态ioctl(fd,KVM_CREATE_VM,..)
内核态kvm_dev_ioctl()
kvm_dev_ioctl_create_vm()
kvm_create_vm() //实现虚拟机创建的主要函数
kvm_arch_alloc_vm() // 分配kvm结构体
kvm_arch_init_vm() // 初始化kvm结构中的架构相关部分,比如中断
hardware_enable_all() // 使能硬件,架构相关操作
hardware_enable_nolock
kvm_arch_hardware_enable()
kvm_x86_ops->hardware_enable()
kzalloc() // 分配memslots结构,并初始化为0
kvm_init_memslots_id() // 初始化内存槽位(slot)的id信息
kvm_eventfd_init() // 初始化事件通道
kvm_init_mmu_notifier() // 初始化mmu操作的通知链
list_add(&kvm->vm_list, &vm_list) // 将新创建的虚拟机的kvm结构,加入到全局链表vm_list中
3、代码分析
kvm结构体:
点击(此处)折叠或打开
- 
				/*
 
- 
				  * kvm中全局的数据结构,其中包含kvm相关的重要数据信息,包括memslot等
 
- 
				  */
 
- 
				struct kvm {
 
- 
				    // 用于保护mmu的spin_lock
 
- 
				    spinlock_t mmu_lock;
 
- 
				    struct mutex slots_lock;
 
- 
				    // 指向qemu用户态进程的mm_struct?
 
- 
				    struct mm_struct *mm; /* userspace tied to this vm */
 
- 
				    /* 
 
- 
				     * kvm_mem_slot是kvm内存管理相关主要数据结构,用来表示虚拟机GPA和主机HVA之间的
 
- 
				     * 映射关系,一个kvm_mem_slot表示一段内存区域(slot)的映射关系,kvm_memslots结构体是
 
- 
				     * kvm_mem_slot的封装,其中包含一个kvm_mem_slot的数组,对应于该虚拟机使用的所有
 
- 
				     * 内存区域(slot)。
 
- 
				     */
 
- 
				    struct kvm_memslots *memslots;
 
- 
				    struct srcu_struct srcu;
 
- 
				#ifdef CONFIG_KVM_APIC_ARCHITECTURE
 
- 
				    u32 bsp_vcpu_id;
 
- 
				#endif
 
- 
				    // 虚拟机中包含的VCPU结构体数组,一个VCPU对应一个数组成员。
 
- 
				    struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
 
- 
				    // online的vcpu数量
 
- 
				    atomic_t online_vcpus;
 
- 
				    int last_boosted_vcpu;
 
- 
				    struct list_head vm_list;
 
- 
				    struct mutex lock;
 
- 
				    //虚拟机中包括的IO总线结构体数组,一条总线对应一个kvm_io_bus结构体,如ISA总线、PCI总线。
 
- 
				    struct kvm_io_bus *buses[KVM_NR_BUSES];
 
- 
				    // 事件通道相关
 
- 
				#ifdef CONFIG_HAVE_KVM_EVENTFD
 
- 
				    struct {
 
- 
				        spinlock_t        lock;
 
- 
				        struct list_head  items;
 
- 
				        struct list_head  resampler_list;
 
- 
				        struct mutex      resampler_lock;
 
- 
				    } irqfds;
 
- 
				    struct list_head ioeventfds;
 
- 
				#endif
 
- 
				    // 虚拟机中的运行时状态信息,比如页表、MMU等状态。
 
- 
				    struct kvm_vm_stat stat;
 
- 
				    // 架构相关的部分。
 
- 
				    struct kvm_arch arch;
 
- 
				    // 引用计数
 
- 
				    atomic_t users_count;
 
- 
				#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
 
- 
				    struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
 
- 
				    spinlock_t ring_lock;
 
- 
				    struct list_head coalesced_zones;
 
- 
				#endif
 
- 
				
 
- 
				    struct mutex irq_lock;
 
- 
				#ifdef CONFIG_HAVE_KVM_IRQCHIP
 
- 
				    /*
 
- 
				     * Update side is protected by irq_lock and,
 
- 
				     * if configured, irqfds.lock.
 
- 
				     */
 
- 
				    // irq相关部分
 
- 
				    struct kvm_irq_routing_table __rcu *irq_routing;
 
- 
				    struct hlist_head mask_notifier_list;
 
- 
				    struct hlist_head irq_ack_notifier_list;
 
- 
				#endif
 
- 
				
 
- 
				#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
 
- 
				    // mmu通知链
 
- 
				    struct mmu_notifier mmu_notifier;
 
- 
				    unsigned long mmu_notifier_seq;
 
- 
				    long mmu_notifier_count;
 
- 
				#endif
 
- 
				    // dirty TLB数量
 
- 
				    long tlbs_dirty;
 
- 
				    struct list_head devices;
 
- };
kvm_dev_ioctl()-->kvm_dev_ioctl_create_vm()-->kvm_create_vm():
点击(此处)折叠或打开
- 
				/* 
 
- 
				 * 实现虚拟机创建的主要函数
 
- 
				 */
 
- 
				static struct kvm *kvm_create_vm(unsigned long type)
 
- 
				{
 
- 
				    int r, i;
 
- 
				    /* 
 
- 
				     * 分配kvm结构体,一个虚拟机对应一个kvm结构,其中包括了虚拟机中的
 
- 
				     * 关键系统,比如内存、中断、VCPU、总线等信息,该结构体也是kvm的关键结
 
- 
				     * 构体之一
 
- 
				     */
 
- 
				    struct kvm *kvm = kvm_arch_alloc_vm();
 
- 
				
 
- 
				    if (!kvm)
 
- 
				        return ERR_PTR(-ENOMEM);
 
- 
				    // 初始化kvm结构中的架构相关部分,比如中断
 
- 
				    r = kvm_arch_init_vm(kvm, type);
 
- 
				    if (r)
 
- 
				        goto out_err_nodisable;
 
- 
				    // 硬件使能,最终调用架构相关的kvm_x86_ops->hardware_enable()接口
 
- 
				    r = hardware_enable_all();
 
- 
				    if (r)
 
- 
				        goto out_err_nodisable;
 
- 
				
 
- 
				#ifdef CONFIG_HAVE_KVM_IRQCHIP
 
- 
				    INIT_HLIST_HEAD(&kvm->mask_notifier_list);
 
- 
				    INIT_HLIST_HEAD(&kvm->irq_ack_notifier_list);
 
- 
				#endif
 
- 
				
 
- 
				    BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
 
- 
				
 
- 
				    r = -ENOMEM;
 
- 
				    // 分配memslots结构,并初始化为0
 
- 
				    kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);
 
- 
				    if (!kvm->memslots)
 
- 
				        goto out_err_nosrcu;
 
- 
				    // 初始化内存槽位(slot)的id信息,便于后续索引
 
- 
				    kvm_init_memslots_id(kvm);
 
- 
				    if (init_srcu_struct(&kvm->srcu))
 
- 
				        goto out_err_nosrcu;
 
- 
				    // 初始化虚拟机的bus信息。
 
- 
				    for (i = 0; i < KVM_NR_BUSES; i++) {
 
- 
				        kvm->buses[i] = kzalloc(sizeof(struct kvm_io_bus),
 
- 
				                    GFP_KERNEL);
 
- 
				        if (!kvm->buses[i])
 
- 
				            goto out_err;
 
- 
				    }
 
- 
				    // 初始化mmu_lock
 
- 
				    spin_lock_init(&kvm->mmu_lock);
 
- 
				    // 设置虚拟机的mm(mm_struct)为当前进程的mm
 
- 
				    kvm->mm = current->mm;
 
- 
				    atomic_inc(&kvm->mm->mm_count);
 
- 
				    // 初始化事件通道
 
- 
				    kvm_eventfd_init(kvm);
 
- 
				    mutex_init(&kvm->lock);
 
- 
				    mutex_init(&kvm->irq_lock);
 
- 
				    mutex_init(&kvm->slots_lock);
 
- 
				    atomic_set(&kvm->users_count, 1);
 
- 
				    INIT_LIST_HEAD(&kvm->devices);
 
- 
				
 
- 
				    // 初始化mmu操作的通知链
 
- 
				    r = kvm_init_mmu_notifier(kvm);
 
- 
				    if (r)
 
- 
				        goto out_err;
 
- 
				
 
- 
				    raw_spin_lock(&kvm_lock);
 
- 
				    // 将新创建的虚拟机的kvm结构,加入到全局链表vm_list中
 
- 
				    list_add(&kvm->vm_list, &vm_list);
 
- 
				    raw_spin_unlock(&kvm_lock);
 
- 
				
 
- 
				    return kvm;
 
- 
				
 
- 
				out_err:
 
- 
				    cleanup_srcu_struct(&kvm->srcu);
 
- 
				out_err_nosrcu:
 
- 
				    hardware_disable_all();
 
- 
				out_err_nodisable:
 
- 
				    for (i = 0; i < KVM_NR_BUSES; i++)
 
- 
				        kfree(kvm->buses[i]);
 
- 
				    kfree(kvm->memslots);
 
- 
				    kvm_arch_free_vm(kvm);
 
- 
				    return ERR_PTR(r);
 
- }
