qemu內存管理——扁平視圖

qemu爲了模擬虛機內存,必須對虛擬機的內存地址空間進行管理,當內存拓撲發生變化時qemu模擬的內存映像需要隨之調整。本文主要介紹爲了管理虛機內存的地址空間,qemu設計的FlatView和FlagRange數據結構

扁平化視圖

FlatView

數據結構

  • FlatView是AdressSpace扁平化展開後的視圖。表示虛擬機的物理地址空間。
/* Flattened global view of current active memory hierarchy.  Kept in sorted
 * order.
 */
struct FlatView {
    struct rcu_head rcu;
    unsigned ref;
    FlatRange *ranges;	/* 每個FlatView包含一組內存地址區間,構成整個內存地址空間 */
    unsigned nr;
    unsigned nr_allocated;
    struct AddressSpaceDispatch *dispatch;
    MemoryRegion *root;	/* 指向關聯的Root MR  */
}; 

FlatView初始化

  • 每個FlatView都關聯到一個地址空間,地址空間初始化時由Root MR作爲輸入

FlatRange

數據結構

  • FlatRange表示虛機的一段物理地址區間,一個MR由多個FlatRang,FlatRange與MR是多對一的關係
/* Range of memory in the global map.  Addresses are absolute. */
struct FlatRange {
    MemoryRegion *mr;			/* 指向所屬的MR */
    hwaddr offset_in_region;	/* 相對MR的offset */
    AddrRange addr;				/* 虛機的物理地址區間,由起始地址(start)和長度(size)組成 */
    uint8_t dirty_log_mask;
    bool romd_mode;
    bool readonly;
    bool nonvolatile;
    int has_coalesced_range;
}; 
  • TODO

組織結構

初始狀態

  • 以虛擬機IO地址空間爲例,在IO地址空間初始化之後,打印出IO地址空間的組織結構如下:
  1. 虛擬機的IO地址區間爲0 ~ 65535,有一個全局變量address_space_io指向IO地址區間,表示一個邏輯地址空間,這個結構體沒有記錄虛機物理地址範圍
    在這裏插入圖片描述
  2. AdressSpace沒有記錄虛機物理地址範圍,它的兩個字段root和current_map從不同角度描述了這段內存,並且都記錄了虛機的IO地址區間範圍,兩個字段的類型分別時MemoryRegion和FlatView
    在這裏插入圖片描述
  3. IO地址區間在初始化後,其組織結構如下:
    在這裏插入圖片描述

新增IO區間

  1. IO MemoryRegion是個容器,當qemu在初始化增加新的硬件設備時,該設備可能會佔用IO地址空間,在虛擬機裏面通過/proc/ioports可以查詢。添加新的IO地址區間會分割系統的IO MR,將其逐漸碎片化。這裏我們以增加kvmvapic爲例,這個MR屬於IO地址區間的子MR,佔兩個字節,地址區間爲126 ~ 128,如下:
    在這裏插入圖片描述
  2. 當IO MemoryRegion容器成功添加kvmvapic MR之後,會對應的生成一段FlatRange,它是MR對應的扁平化視圖,子MR的添加將原來的FlatRange分成了三個區間,區間1是0 ~ 126,區間2是126 ~ 128,區間3是128 ~ 65535,如下圖所示:
    在這裏插入圖片描述
    在這裏插入圖片描述
  3. 通過virsh qemu-monitor-command vm --hmp info mtree命令查看IO地址空間,可以驗證上面的組織結構信息
    在這裏插入圖片描述

內存拓撲變更分析

  • qemu在虛機啓動過程中,首先爲虛機提供一個邏輯物理地址空間,隨着硬件的增加,這個物理區間被不斷分割,變成一段一段更小的虛機物理地址區間,直到最終完成整個虛機硬件的模擬。這個過程中,address_spaces保存了物理地址空間鏈表頭,隨qemu初始化而不斷更新,flat_views保存地址空間關聯的(Root MR,FlatView)鍵值對,也會隨qemu初始化不斷更新。通過分析這兩個數據結構,可以更感性地認識qemu的內存組織結構。

新建內存和IO地址空間

static void memory_map_init(void)
{   
    system_memory = g_malloc(sizeof(*system_memory));
    memory_region_init(system_memory, NULL, "system", UINT64_MAX);
    address_space_init(&address_space_memory, system_memory, "memory");

    system_io = g_malloc(sizeof(*system_io));
    memory_region_init_io(system_io, NULL, &unassigned_io_ops, NULL, "io", 65536);                              
    address_space_init(&address_space_io, system_io, "I/O");
}
  1. 內存地址空間是qemu創建的第一個地址空間,在創建該地址空間之前,address_spaces僅僅完成了初始化,而flat_views還是空的
    在這裏插入圖片描述
  2. 執行 address_space_init(&address_space_memory, system_memory, "memory")函數之後,內存地址空間初始化完成,有了第一個地址空間,此時address_spaces和flat_views信息如下。可以看到,內存地址空間初始化完成後,只是將flat_views初始化並設置了默認的空FlatView,這個hash表裏面沒有實際的內存地址區間信息,因此,可以說,內存地址空間初始化之後,對應的Root MR沒有生成對應的FlatView並添加到全局的hash表中。
    在這裏插入圖片描述
  3. 執行 address_space_init(&address_space_io, system_io, "I/O")函數之後,IO地址空間初始化完成,IO地址空間的增加改變了內存的拓撲,flat_views hash表中記錄了IO地址空間生成的FlatView,此時IO地址空間由一段FlatRange組成,隨着初始化的進行,IO地址空間會進一步被切割成多段。
    在這裏插入圖片描述

細分內存地址空間

  1. 從上面看出,qemu在初始化內存地址空間和IO地址空間時,內存地址空間並沒有生成FlatView。在cpu初始化過程中,對msi類型的中斷實現,qemu需要實現內存模擬,這段內存是MMIO類型的物理內存。中斷控制器的MR的聲明和初始化流程如下,MR被保存到了APICCommonState結構體的io_memory字段中
x86_cpu_apic_realize
		/* 聲明並初始化kvm-apic-msi的MR */
	    object_property_set_bool(OBJECT(cpu->apic_state), true, "realized", errp);                      
			k->realize = kvm_apic_realize
		    	memory_region_init_io(&s->io_memory, OBJECT(s), &kvm_apic_io_ops, s,  "kvm-apic-msi", APIC_SPACE_SIZE);
		apic = APIC_COMMON(cpu->apic_state);
		/* 將kvm-apic-msi的MR添加到系統內存中,地址區間爲(apicbase,apicbase + mr->size)*/
        memory_region_add_subregion_overlap(get_system_memory(),
                                            apic->apicbase &
                                            MSR_IA32_APICBASE_BASE,
                                            &apic->io_memory,
                                            0x1000);         
  1. kvm-apic-msi的MR申請之後,就向系統內存空間中添加此MR,這一步在memory_region_add_subregion_overlap中完成。這個過程涉及到內存地址空間拓撲的更新,在此之前地址空間有三個,分別是memory,I/O和cpu-memory-0:
    在這裏插入圖片描述
  2. flat_views存儲的(MR,FlatView)鍵值對有兩個,一個默認的empty_view,一個是IO地址空間的MR和FlatView
    在這裏插入圖片描述
  3. 在往系統的內存地址空間中添加子MR apic->io_memory之後,flat_views包含的鍵值對增加了1個,如下圖所示,這個鍵值對的key是系統內存的根MR,但對應的FlatView只包含了一個range並且沒有將根MR描述的2^64大小的區間表示完,它只是其中的一個子集(0xfee00000,0xfee00000 + 100000)
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章