如之前分析,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);
- }