最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊

一文分析Linux虛擬化KVM-Qemu分析之內(nèi)存虛擬化

2023-01-05 14:54 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

說明:

  1. KVM版本:5.9.1

  2. QEMU版本:5.0.0

  3. 工具:Source Insight 3.5, Visio

1. 概述

《Linux虛擬化KVM-Qemu分析(二)之ARMv8虛擬化》文中描述過內(nèi)存虛擬化大體框架,再來回顧一下:

  1. 非虛擬化下的內(nèi)存的訪問

圖片
  • CPU訪問物理內(nèi)存前,需要先建立頁表映射(虛擬地址到物理地址的映射),最終通過查表的方式來完成訪問。在ARMv8中,內(nèi)核頁表基地址存放在TTBR1_EL1中,用戶空間頁表基地址存放在TTBR0_EL0中;

  1. 虛擬化下的內(nèi)存訪問

圖片
  • 虛擬化情況下,內(nèi)存的訪問會(huì)分為兩個(gè)Stage,Hypervisor通過Stage 2來控制虛擬機(jī)的內(nèi)存視圖,控制虛擬機(jī)是否可以訪問某塊物理內(nèi)存,進(jìn)而達(dá)到隔離的目的;

  • Stage 1VA(Virtual Address)->IPA(Intermediate Physical Address),Host的操作系統(tǒng)控制Stage 1的轉(zhuǎn)換;

  • Stage 2IPA(Intermediate Physical Address)->PA(Physical Address),Hypervisor控制Stage 2的轉(zhuǎn)換;

猛一看上邊兩個(gè)圖,好像明白了啥,仔細(xì)一想,啥也不明白,本文的目標(biāo)就是將這個(gè)過程講明白。

在開始細(xì)節(jié)講解之前,需要先描述幾個(gè)概念:

圖片
  • Guest OS中的虛擬地址到物理地址的映射,就是典型的常規(guī)操作,參考之前的內(nèi)存管理模塊系列文章;

鋪墊了這么久,來到了本文的兩個(gè)主題:

  1. GPA->HVA;

  2. HVA->HPA;

開始吧!


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ??


2. GPA->HVA

還記得上一篇文章深入探索Linux虛擬化KVM-Qemu分析之CPU虛擬化中的Sample Code嗎?KVM-Qemu方案中,GPA->HVA的轉(zhuǎn)換,是通過ioctl中的KVM_SET_USER_MEMORY_REGION命令來實(shí)現(xiàn)的,如下圖:

圖片

找到了入口,讓我們進(jìn)一步揭開神秘的面紗。

2.1 數(shù)據(jù)結(jié)構(gòu)

關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)如下:

圖片
  • 虛擬機(jī)使用slot來組織物理內(nèi)存,每個(gè)slot對應(yīng)一個(gè)struct kvm_memory_slot,一個(gè)虛擬機(jī)的所有slot構(gòu)成了它的物理地址空間;

  • 用戶態(tài)使用struct kvm_userspace_memory_region來設(shè)置內(nèi)存slot,在內(nèi)核中使用struct kvm_memslots結(jié)構(gòu)來將kvm_memory_slot組織起來;

  • struct kvm_userspace_memory_region結(jié)構(gòu)體中,包含了slot的ID號(hào)用于查找對應(yīng)的slot,此外還包含了物理內(nèi)存起始地址及大小,以及HVA地址,HVA地址是在用戶進(jìn)程地址空間中分配的,也就是Qemu進(jìn)程地址空間中的一段區(qū)域;

2.2 流程分析

數(shù)據(jù)結(jié)構(gòu)部分已經(jīng)羅列了大體的關(guān)系,那么在KVM_SET_USER_MEMORY_REGION時(shí),圍繞的操作就是slots的創(chuàng)建、刪除,更新等操作,話不多說,來圖了:

圖片
  • 當(dāng)用戶要設(shè)置內(nèi)存區(qū)域時(shí),最終會(huì)調(diào)用到__kvm_set_memory_region函數(shù),在該函數(shù)中完成所有的邏輯處理;

  • __kvm_set_memory_region函數(shù),首先會(huì)對傳入的struct kvm_userspace_memory_region的各個(gè)字段進(jìn)行合法性檢測判斷,主要是包括了地址的對齊,范圍的檢測等;

  • 根據(jù)用戶傳遞的slot索引號(hào),去查找虛擬機(jī)中對應(yīng)的slot,查找的結(jié)果只有兩種:1)找到一個(gè)現(xiàn)有的slot;2)找不到則新建一個(gè)slot;

  • 如果傳入的參數(shù)中memory_size為0,那么會(huì)將對應(yīng)slot進(jìn)行刪除操作;

  • 根據(jù)用戶傳入的參數(shù),設(shè)置slot的處理方式:KVM_MR_CREATE,KVM_MR_MOVE,KVM_MEM_READONLY

  • 根據(jù)用戶傳遞的參數(shù)決定是否需要分配臟頁的bitmap,標(biāo)識(shí)頁是否可用;

  • 最終調(diào)用kvm_set_memslot來設(shè)置和更新slot信息;

2.2.1 kvm_set_memslot

具體的memslot的設(shè)置在kvm_set_memslot函數(shù)中完成,slot的操作流程如下:

圖片
  • 首先分配一個(gè)新的memslots,并將原來的memslots內(nèi)容復(fù)制到新的memslots中;

  • 如果針對slot的操作是刪除或者移動(dòng),首先根據(jù)舊的slot id號(hào)從memslots中找到原來的slot,將該slot設(shè)置成不可用狀態(tài),再將memslots安裝回去。這個(gè)安裝的意思,就是RCU的assignment操作,不理解這個(gè)的,建議去看看之前的RCU系列文章。由于slot不可用了,需要解除stage2的映射;

  • kvm_arch_prepare_memory_region函數(shù),用于處理新的slot可能跨越多個(gè)用戶進(jìn)程VMA區(qū)域的問題,如果為設(shè)備區(qū)域,還需要將該區(qū)域映射到Guest IPA中;

  • update_memslots用于更新整個(gè)memslots,memslots基于PFN來進(jìn)行排序的,添加、刪除、移動(dòng)等操作都是基于這個(gè)條件。由于都是有序的,因此可以選擇二分法來進(jìn)行查找操作;

  • 將添加新的slot后的memslots安裝回KVM中;

  • kvfree用于將原來的memslots釋放掉;

2.2.2 kvm_delete_memslot

kvm_delete_memslot函數(shù),實(shí)際就是調(diào)用的kvm_set_memslot函數(shù),只是slot的操作設(shè)置成KVM_MR_DELETE而已,不再贅述。

3. HVA->HPA

光有了GPA->HVA,似乎還是跟Hypervisor沒有太大關(guān)系,到底是怎么去訪問物理內(nèi)存的呢?貌似也沒有看到去建立頁表映射???跟我走吧,帶著問題出發(fā)!

之前內(nèi)存管理相關(guān)文章中提到過,用戶態(tài)程序中分配虛擬地址vma后,實(shí)際與物理內(nèi)存的映射是在page fault時(shí)進(jìn)行的。那么同樣的道理,我們可以順著這個(gè)思路去查找是否HVA->HPA的映射也是在異常處理的過程中創(chuàng)建的?答案是顯然的。

回顧一下前文深入探索Linux虛擬化KVM-Qemu分析之CPU虛擬化的一張圖片:

圖片
  • 當(dāng)用戶態(tài)觸發(fā)kvm_arch_vcpu_ioctl_run時(shí),會(huì)讓Guest OS去跑在Hypervisor上,當(dāng)Guest OS中出現(xiàn)異常退出到Host時(shí),此時(shí)handle_exit將對退出的原因進(jìn)行處理;

異常處理函數(shù)arm_exit_handlers如下,具體調(diào)用選擇哪個(gè)處理函數(shù),是根據(jù)ESR_EL2, Exception Syndrome Register(EL2)中的值來確定的。

用你那雙水汪汪的大眼睛掃描一下這個(gè)函數(shù)表,發(fā)現(xiàn)ESR_ELx_EC_DABT_LOWESR_ELx_EC_IABT_LOW兩個(gè)異常,這不就是指令異常和數(shù)據(jù)異常嗎,我們大膽的猜測,HVA->HPA映射的建立就在kvm_handle_guest_abort函數(shù)中。

3.1?kvm_handle_guest_abort

先來補(bǔ)充點(diǎn)知識(shí)點(diǎn),可以更方便的理解接下里的內(nèi)容:

  1. Guest OS在執(zhí)行到敏感指令時(shí),產(chǎn)生EL2異常,CPU切換模式并跳轉(zhuǎn)到EL2el1_syncarch/arm64/kvm/hyp/entry-hyp.S)異常入口;

  2. CPU的ESR_EL2寄存器記錄了異常產(chǎn)生的原因;

  3. Guest退出到kvm后,kvm根據(jù)異常產(chǎn)生的原因進(jìn)行對應(yīng)的處理。

簡要看一下ESR_EL2寄存器:

圖片
  • EC:Exception class,異常類,用于標(biāo)識(shí)異常的原因;

  • ISS:Instruction Specific Syndrome,ISS域定義了更詳細(xì)的異常細(xì)節(jié);

  • kvm_handle_guest_abort函數(shù)中,多處需要對異常進(jìn)行判斷處理;

kvm_handle_guest_abort函數(shù),處理地址訪問異常,可以分為兩類:

  1. 常規(guī)內(nèi)存訪問異常,包括未建立頁表映射、讀寫權(quán)限等;

  2. IO內(nèi)存訪問異常,IO的模擬通常需要Qemu來進(jìn)行模擬;

先看一下kvm_handle_guest_abort函數(shù)的注釋吧:

  • 到達(dá)Host的abort都是由于缺乏Stage 2頁表轉(zhuǎn)換條目導(dǎo)致的,這個(gè)可能是Guest需要分配更多內(nèi)存而必須為其分配內(nèi)存頁,或者也可能是Guest嘗試去訪問IO空間,IO操作由用戶空間來模擬的。兩者的區(qū)別是觸發(fā)異常的IPA地址是否已經(jīng)在用戶空間中注冊為標(biāo)準(zhǔn)的RAM;

調(diào)用流程來了:

圖片
  • kvm_vcpu_trap_get_fault_type用于獲取ESR_EL2的數(shù)據(jù)異常和指令異常的fault status code,也就是ESR_EL2的ISS域;

  • kvm_vcpu_get_fault_ipa用于獲取觸發(fā)異常的IPA地址;

  • kvm_vcpu_trap_is_iabt用于獲取異常類,也就是ESR_EL2EC,并且判斷是否為ESR_ELx_IABT_LOW,也就是指令異常類型;

  • kvm_vcpu_dabt_isextabt用于判斷是否為同步外部異常,同步外部異常的情況下,如果支持RAS,Host能處理該異常,不需要將異常注入給Guest;

  • 異常如果不是FSC_FAULT,FSC_PERMFSC_ACCESS三種類型的話,直接返回錯(cuò)誤;

  • gfn_to_memslot,gfn_to_hva_memslot_prot這兩個(gè)函數(shù),是根據(jù)IPA去獲取到對應(yīng)的memslot和HVA地址,這個(gè)地方就對應(yīng)到了上文中第二章節(jié)中地址關(guān)系的建立了,由于建立了連接關(guān)系,便可以通過IPA去找到對應(yīng)的HVA;

  • 如果注冊了RAM,能獲取到正確的HVA,如果是IO內(nèi)存訪問,那么HVA將會(huì)被設(shè)置成KVM_HVA_ERR_BAD。kvm_is_error_hva或者(write_fault && !writable)代表兩種錯(cuò)誤:1)指令錯(cuò)誤,向Guest注入指令異常;2)IO訪問錯(cuò)誤,IO訪問又存在兩種情況:2.1)Cache維護(hù)指令,則直接跳過該指令;2.2)正常的IO操作指令,調(diào)用io_mem_abort進(jìn)行IO模擬操作;

  • handle_access_fault用于處理訪問權(quán)限問題,如果內(nèi)存頁無法訪問,則對其權(quán)限進(jìn)行更新;

  • user_mem_abort,用于分配更多的內(nèi)存,實(shí)際上就是完成Stage 2頁表映射的建立,根據(jù)異常的IPA地址,已經(jīng)對應(yīng)的HVA,建立映射,細(xì)節(jié)的地方就不表了。

原文作者:LoyenWang



一文分析Linux虛擬化KVM-Qemu分析之內(nèi)存虛擬化的評論 (共 條)

分享到微博請遵守國家法律
海淀区| 禹州市| 饶平县| 湟中县| 鹤山市| 莱芜市| 崇明县| 泽州县| 石林| 海晏县| 鱼台县| 鄱阳县| 莱阳市| 江都市| 壶关县| 昌邑市| 周至县| 卓资县| 新和县| 雷州市| 东乡族自治县| 台北市| 桂平市| 余姚市| 贡山| 屯留县| 青阳县| 星座| 攀枝花市| 平阳县| 民丰县| 于都县| 新宾| 招远市| 临沭县| 偃师市| 宝鸡市| 禄丰县| 博湖县| 绥棱县| 湘潭县|