您好,登錄后才能下訂單哦!
這篇文章給大家介紹如何解析KVM虛擬化原理中的內(nèi)存虛擬化,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
下面介紹一下KVM的內(nèi)存虛擬化原理??梢哉f內(nèi)存是除了CPU外最重要的組件,Guest最終使用的還是宿主機(jī)的內(nèi)存,所以內(nèi)存虛擬化其實(shí)就是關(guān)于如何做Guest到宿主機(jī)物理內(nèi)存之間的各種地址轉(zhuǎn)換,如何轉(zhuǎn)換會(huì)讓轉(zhuǎn)換效率更高呢,KVM經(jīng)歷了三代的內(nèi)存虛擬化技術(shù),大大加快了內(nèi)存的訪問速率。
在保護(hù)模式下,普通的應(yīng)用進(jìn)程使用的都是自己的虛擬地址空間,一個(gè)64位的機(jī)器上的每一個(gè)進(jìn)程都可以訪問0到2^64的地址范圍,實(shí)際上內(nèi)存并沒有這么多,也不會(huì)給你這么多。對于進(jìn)程而言,他擁有所有的內(nèi)存,對內(nèi)核而言,只分配了一小段內(nèi)存給進(jìn)程,待進(jìn)程需要更多的進(jìn)程的時(shí)候再分配給進(jìn)程。
通常應(yīng)用進(jìn)程所使用的內(nèi)存叫做虛擬地址,而內(nèi)核所使用的是物理內(nèi)存。內(nèi)核負(fù)責(zé)為每個(gè)進(jìn)程維護(hù)虛擬地址到物理內(nèi)存的轉(zhuǎn)換關(guān)系映射。
首先,邏輯地址需要轉(zhuǎn)換為線性地址,然后由線性地址轉(zhuǎn)換為物理地址。
邏輯地址 ==> 線性地址 ==> 物理地址
邏輯地址和線性地址之間通過簡單的偏移來完成。
一個(gè)完整的邏輯地址 = [段選擇符:段內(nèi)偏移地址],查找GDT或者LDT(通過寄存器gdtr,ldtr)找到描述符,通過段選擇符(selector)前13位在段描述符做index,找到Base地址,Base+offset就是線性地址。
為什么要這么做?據(jù)說是Intel為了保證兼容性。
邏輯地址到線性地址的轉(zhuǎn)換在虛擬化中沒有太多的需要介紹的,這一層不存在實(shí)際的虛擬化操作,和傳統(tǒng)方式一樣,最重要的是線性地址到物理地址這一層的轉(zhuǎn)換。
傳統(tǒng)的線性地址到物理地址的轉(zhuǎn)換由CPU的頁式內(nèi)存管理,頁式內(nèi)存管理。
頁式內(nèi)存管理負(fù)責(zé)將線性地址轉(zhuǎn)換到物理地址,一個(gè)線性地址被分五段描述,第一段為基地址,通過與當(dāng)前CR3寄存器(CR3寄存器每個(gè)進(jìn)程有一個(gè),線程共享,當(dāng)發(fā)生進(jìn)程切換的時(shí)候,CR3被載入到對應(yīng)的寄存器中,這也是各個(gè)進(jìn)程的內(nèi)存隔離的基礎(chǔ))做運(yùn)算,得到頁表的地址index,通過四次運(yùn)算,最終得到一個(gè)大小為4K的頁(有可能更大,比如設(shè)置了hugepages以后)。整個(gè)過程都是CPU完成,進(jìn)程不需要參與其中,如果在查詢中發(fā)現(xiàn)頁已經(jīng)存在,直接返回物理地址,如果頁不存在,那么將產(chǎn)生一個(gè)缺頁中斷,內(nèi)核負(fù)責(zé)處理缺頁中斷,并把頁加載到頁表中,中斷返回后,CPU獲取到頁地址后繼續(xù)進(jìn)行運(yùn)算。
由于qemu-kvm進(jìn)程在宿主機(jī)上作為一個(gè)普通進(jìn)程,那對于Guest而言,需要的轉(zhuǎn)換過程就是這樣。
Guest虛擬內(nèi)存地址(GVA) | Guest線性地址 | Guest物理地址(GPA) | Guest ------------------ | HV HV虛擬地址(HVA) | HV線性地址 | HV物理地址(HPA)
What's the fu*k ?這么多...
別著急,Guest虛擬地址到HV線性地址之間的轉(zhuǎn)換和HV虛擬地址到線性地址的轉(zhuǎn)換過程可以省略,這樣看起來就更清晰一點(diǎn)。
Guest虛擬內(nèi)存地址(GVA) | Guest物理地址(GPA) | Guest ------------------ | HV HV虛擬地址(HVA) | HV物理地址(HPA)
前面也說到KVM通過不斷的改進(jìn)轉(zhuǎn)換過程,讓KVM的內(nèi)存虛擬化更加的高效,我們從最初的軟件虛擬化的方式介紹。
第一層轉(zhuǎn)換,由GVA->GPA的轉(zhuǎn)換和傳統(tǒng)的轉(zhuǎn)換關(guān)系一樣,通過查找CR3然后進(jìn)行頁表查詢,找到對應(yīng)的GPA,GPA到HVA的關(guān)系由qemu-kvm負(fù)責(zé)維護(hù),我們在第二章KVM啟動(dòng)過程的demo里面就有介紹到怎樣給KVM映射內(nèi)存,通過mmap的方式把HV的內(nèi)存映射給Guest。
struct kvm_userspace_memory_region region = { .slot = 0, .guest_phys_addr = 0x1000, .memory_size = 0x1000, .userspace_addr = (uint64_t)mem, };
可以看到,qemu-kvm的kvm_userspace_memory_region結(jié)構(gòu)體描述了guest的物理地址起始位置和內(nèi)存大小,然后描述了Guest的物理內(nèi)存在HV的映射userspace_addr
,通過多個(gè)slot,可以把不連續(xù)的HV的虛擬地址空間映射給Guest的連續(xù)的物理地址空間。
軟件模擬的虛擬化方式由qemu-kvm來負(fù)責(zé)維護(hù)GPA->HVA的轉(zhuǎn)換,然后再經(jīng)過一次HVA->HPA的方式,從過程上來看,這樣的訪問是很低效的,特別是在當(dāng)GVA到GPA轉(zhuǎn)換時(shí)候產(chǎn)生缺頁中斷,這時(shí)候產(chǎn)生一個(gè)異常Guest退出,HV捕獲異常后計(jì)算出物理地址(分配新的內(nèi)存給Guest),然后重新Entry。這個(gè)過程會(huì)可能導(dǎo)致頻繁的Guest退出,且轉(zhuǎn)換過程過長。于是KVM使用了一種叫做影子頁表的技術(shù)。
影子頁表的出現(xiàn),就是為了減少地址轉(zhuǎn)換帶來的開銷,直接把GVA轉(zhuǎn)換到HVP的技術(shù)。在軟件虛擬化的內(nèi)存轉(zhuǎn)換中,GVA到GPA的轉(zhuǎn)換通過查詢CR3寄存器來完成,CR3保存了Guest中的頁表基地址,然后載入MMU來做地址轉(zhuǎn)換。
在加入了影子頁表的技術(shù)后,當(dāng)訪問到CR3寄存器的時(shí)候(可能是由于Guest進(jìn)程后導(dǎo)致的),KVM捕獲到這個(gè)操作,CPU虛擬化章節(jié) EXIT_REASON_CR_ACCESS,qemu-kvm通過載入特俗的CR3和影子頁表來欺騙Guest這個(gè)就是真實(shí)的CR3,后面的操作就和傳統(tǒng)的訪問內(nèi)存的方式一致,當(dāng)需要訪問物理內(nèi)存的時(shí)候,只會(huì)經(jīng)過一層的影子頁表的轉(zhuǎn)換。
影子頁表由qemu-kvm進(jìn)程維護(hù),實(shí)際上就是一個(gè)Guest的頁表到宿主機(jī)頁表的映射,每一級(jí)的頁表的hash值對應(yīng)到qemu-kvm中影子頁表的一個(gè)目錄。在初次GVA->HPA的轉(zhuǎn)換時(shí)候,影子頁表沒有建立,此時(shí)Guest產(chǎn)生缺頁中斷,和傳統(tǒng)的轉(zhuǎn)換過程一樣,經(jīng)過兩次轉(zhuǎn)換(VA->PA),然后影子頁表記錄GVA->GPA->HVA->HPA。這樣產(chǎn)生GVA->GPA的直接關(guān)系,保存到影子頁表中。
EPT(extended page table)可以看做一個(gè)硬件的影子頁表,在Guest中通過增加EPT寄存器,當(dāng)Guest產(chǎn)生了CR3和頁表的訪問的時(shí)候,由于對CR3中的頁表地址的訪問是GPA,當(dāng)?shù)刂窞榭諘r(shí)候,也就是Page fault后,產(chǎn)生缺頁異常,如果在軟件模擬或者影子頁表的虛擬化方式中,此時(shí)會(huì)有VM退出,qemu-kvm進(jìn)程接管并獲取到此異常。但是在EPT的虛擬化方式中,qemu-kvm忽略此異常,Guest并不退出,而是按照傳統(tǒng)的缺頁中斷處理,在缺頁中斷處理的過程中會(huì)產(chǎn)生EXIT_REASON_EPT_VIOLATION,Guest退出,qemu-kvm捕獲到異常后,分配物理地址并建立GVA->HPA的映射,并保存到EPT中,將EPT載入到MMU,下次轉(zhuǎn)換時(shí)候直接查詢根據(jù)CR3查詢EPT表來完成GVA->HPA的轉(zhuǎn)換。以后的轉(zhuǎn)換都由硬件直接完成,大大提高了效率,且不需要為每個(gè)進(jìn)程維護(hù)一套頁表,減少了內(nèi)存開銷。
在筆者的測試中,Guest和HV的內(nèi)存訪問速率對比為3756MB/s對比4340MB/s??梢钥吹絻?nèi)存訪問已經(jīng)很接近宿主機(jī)的水平了。
KVM內(nèi)存的虛擬化就是一個(gè)將虛擬機(jī)的虛擬內(nèi)存轉(zhuǎn)換為宿主機(jī)物理內(nèi)存的過程,Guest使用的依然是宿主機(jī)的物理內(nèi)存,只是在這個(gè)過程中怎樣減少轉(zhuǎn)換帶來的開銷成為優(yōu)化的主要點(diǎn)。
KVM經(jīng)過軟件模擬->影子頁表->EPT的技術(shù)的進(jìn)化,效率也越來越高。
關(guān)于如何解析KVM虛擬化原理中的內(nèi)存虛擬化就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。