日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 内存查看 kvm,Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

發布時間:2024/1/8 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 内存查看 kvm,Linux虚拟化KVM-Qemu分析(五)之内存虚拟化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原標題:Linux虛擬化KVM-Qemu分析(五)之內存虛擬化

背景

Read the fucking source code! --By 魯迅

A picture is worth a thousand words. --By 高爾基

說明:

KVM版本:5.9.1

QEMU版本:5.0.0

工具:Source Insight 3.5, Visio

文章同步在博客園: https://www.cnblogs.com/LoyenWang/

1. 概述

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

非虛擬化下的內存的訪問

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

虛擬化下的內存訪問

虛擬化情況下,內存的訪問會分為兩個 Stage , Hypervisor 通過 Stage 2 來控制虛擬機的內存視圖,控制虛擬機是否可以訪問某塊物理內存,進而達到隔離的目的;

Stage 1 : VA(Virtual Address)->IPA(Intermediate Physical Address) ,Host的操作系統控制 Stage 1 的轉換;

Stage 2 : IPA(Intermediate Physical Address)->PA(Physical Address) ,Hypervisor控制 Stage 2 的轉換;

猛一看上邊兩個圖,好像明白了啥,仔細一想,啥也不明白,本文的目標就是將這個過程講明白。

在開始細節講解之前,需要先描述幾個概念:

gva - guest virtualaddress

gpa - guest physical address

hva - host virtualaddress

hpa - host physical address

Guest OS中的虛擬地址到物理地址的映射,就是典型的常規操作,參考之前的內存管理模塊系列文章;

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

GPA->HVA ;

HVA->HPA ;

開始吧!

2. GPA->HVA

還記得上一篇文章 《Linux虛擬化KVM-Qemu分析(四)之CPU虛擬化(2)》 中的Sample Code嗎?KVM-Qemu方案中,GPA->HVA的轉換,是通過 ioctl 中的 KVM_SET_USER_MEMORY_REGION 命令來實現的,如下圖:

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

2.1 數據結構

關鍵的數據結構如下:

虛擬機使用 slot 來組織物理內存,每個 slot 對應一個 struct kvm_memory_slot ,一個虛擬機的所有 slot 構成了它的物理地址空間;

用戶態使用 struct kvm_userspace_memory_region 來設置內存 slot ,在內核中使用 struct kvm_memslots 結構來將 kvm_memory_slot 組織起來;

struct kvm_userspace_memory_region 結構體中,包含了 slot 的ID號用于查找對應的 slot ,此外還包含了物理內存起始地址及大小,以及HVA地址,HVA地址是在用戶進程地址空間中分配的,也就是Qemu進程地址空間中的一段區域;

2.2 流程分析

數據結構部分已經羅列了大體的關系,那么在 KVM_SET_USER_MEMORY_REGION 時,圍繞的操作就是 slots 的創建、刪除,更新等操作,話不多說,來圖了:

當用戶要設置內存區域時,最終會調用到 __kvm_set_memory_region 函數,在該函數中完成所有的邏輯處理;

__kvm_set_memory_region 函數,首先會對傳入的 struct kvm_userspace_memory_region 的各個字段進行合法性檢測判斷,主要是包括了地址的對齊,范圍的檢測等;

根據用戶傳遞的 slot 索引號,去查找虛擬機中對應的 slot ,查找的結果只有兩種:1)找到一個現有的slot;2)找不到則新建一個slot;

如果傳入的參數中 memory_size 為0,那么會將對應 slot 進行刪除操作;

根據用戶傳入的參數,設置 slot 的處理方式: KVM_MR_CREATE , KVM_MR_MOVE , KVM_MEM_READONLY ;

根據用戶傳遞的參數決定是否需要分配臟頁的bitmap,標識頁是否可用;

最終調用 kvm_set_memslot 來設置和更新 slot 信息;

2.2.1 kvm_set_memslot

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

首先分配一個新的 memslots ,并將原來的 memslots 內容復制到新的 memslots 中;

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

kvm_arch_prepare_memory_region 函數,用于處理新的 slot 可能跨越多個用戶進程VMA區域的問題,如果為設備區域,還需要將該區域映射到 Guest IPA 中;

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

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

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

2.2.2 kvm_delete_memslot

kvm_delete_memslot 函數,實際就是調用的 kvm_set_memslot 函數,只是 slot 的操作設置成 KVM_MR_DELETE 而已,不再贅述。

3. HVA->HPA

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

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

回顧一下前文 《Linux虛擬化KVM-Qemu分析(四)之CPU虛擬化(2)》 的一張圖片:

當用戶態觸發 kvm_arch_vcpu_ioctl_run 時,會讓 Guest OS 去跑在 Hypervisor 上,當 Guest OS 中出現異常退出到 Host 時,此時 handle_exit 將對退出的原因進行處理;

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

staticexit_handle_fn arm_exit_handlers[] = {

[ 0... ESR_ELx_EC_MAX] = kvm_handle_unknown_ec,

[ESR_ELx_EC_WFx] = kvm_handle_wfx,

[ESR_ELx_EC_CP15_32] = kvm_handle_cp15_32,

[ESR_ELx_EC_CP15_64] = kvm_handle_cp15_64,

[ESR_ELx_EC_CP14_MR] = kvm_handle_cp14_32,

[ESR_ELx_EC_CP14_LS] = kvm_handle_cp14_load_store,

[ESR_ELx_EC_CP14_64] = kvm_handle_cp14_64,

[ESR_ELx_EC_HVC32] = handle_hvc,

[ESR_ELx_EC_SMC32] = handle_smc,

[ESR_ELx_EC_HVC64] = handle_hvc,

[ESR_ELx_EC_SMC64] = handle_smc,

[ESR_ELx_EC_SYS64] = kvm_handle_sys_reg,

[ESR_ELx_EC_SVE] = handle_sve,

[ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort,

[ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort,

[ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug,

[ESR_ELx_EC_WATCHPT_LOW]= kvm_handle_guest_debug,

[ESR_ELx_EC_BREAKPT_LOW]= kvm_handle_guest_debug,

[ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug,

[ESR_ELx_EC_BRK64] = kvm_handle_guest_debug,

[ESR_ELx_EC_FP_ASIMD] = handle_no_fpsimd,

[ESR_ELx_EC_PAC] = kvm_handle_ptrauth,

};

用你那雙水汪汪的大眼睛掃描一下這個函數表,發現 ESR_ELx_EC_DABT_LOW 和 ESR_ELx_EC_IABT_LOW 兩個異常,這不就是指令異常和數據異常嗎,我們大膽的猜測, HVA->HPA 映射的建立就在 kvm_handle_guest_abort 函數中。

3.1 kvm_handle_guest_abort

先來補充點知識點,可以更方便的理解接下里的內容:

Guest OS在執行到敏感指令時,產生EL2異常,CPU切換模式并跳轉到 EL2 的 el1_sync ( arch/arm64/kvm/hyp/entry-hyp.S )異常入口;

CPU的 ESR_EL2 寄存器記錄了異常產生的原因;

Guest退出到kvm后,kvm根據異常產生的原因進行對應的處理。

簡要看一下 ESR_EL2 寄存器:

EC :Exception class,異常類,用于標識異常的原因;

ISS :Instruction Specific Syndrome,ISS域定義了更詳細的異常細節;

在 kvm_handle_guest_abort 函數中,多處需要對異常進行判斷處理;

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

常規內存訪問異常,包括未建立頁表映射、讀寫權限等;

IO內存訪問異常,IO的模擬通常需要Qemu來進行模擬;

先看一下 kvm_handle_guest_abort 函數的注釋吧:

/**

* kvm_handle_guest_abort - handles all 2nd stage aborts

*

* Any abort that gets to the host is almost guaranteed to be caused by a

* missing second stage translation table entry, which can mean that either the

* guest simply needs more memory and we must allocate an appropriate page or it

* can mean that the guest tried to access I/O memory, which is emulated by user

* space. The distinction is based on the IPA causing the fault and whether this

* memory region has been registered as standard RAM by user space.

*/

到達Host的abort都是由于缺乏Stage 2頁表轉換條目導致的,這個可能是Guest需要分配更多內存而必須為其分配內存頁,或者也可能是Guest嘗試去訪問IO空間,IO操作由用戶空間來模擬的。兩者的區別是觸發異常的IPA地址是否已經在用戶空間中注冊為標準的RAM;

調用流程來了:

kvm_vcpu_trap_get_fault_type 用于獲取 ESR_EL2 的數據異常和指令異常的 fault status code ,也就是 ESR_EL2 的ISS域;

kvm_vcpu_get_fault_ipa 用于獲取觸發異常的IPA地址;

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

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

異常如果不是 FSC_FAULT , FSC_PERM , FSC_ACCESS 三種類型的話,直接返回錯誤;

gfn_to_memslot , gfn_to_hva_memslot_prot 這兩個函數,是根據IPA去獲取到對應的memslot和HVA地址,這個地方就對應到了上文中第二章節中地址關系的建立了,由于建立了連接關系,便可以通過IPA去找到對應的HVA;

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

handle_access_fault 用于處理訪問權限問題,如果內存頁無法訪問,則對其權限進行更新;

user_mem_abort ,用于分配更多的內存,實際上就是完成Stage 2頁表映射的建立,根據異常的IPA地址,已經對應的HVA,建立映射,細節的地方就不表了。

來龍去脈摸清楚了,那就草草收場吧,下回見了。

參考

《Arm Architecture Registers Armv8, for Armv8-A architecture profile》 返回搜狐,查看更多

責任編輯:

總結

以上是生活随笔為你收集整理的linux 内存查看 kvm,Linux虚拟化KVM-Qemu分析(五)之内存虚拟化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 黄色a在线 | 乱色精品无码一区二区国产盗 | 成人久久久精品国产乱码一区二区 | ts人妖在线观看 | 亚洲成人第一 | 欧美日韩电影一区二区三区 | 久久久天堂国产精品女人 | 亚洲黄色免费网站 | 中文字幕精品一区久久久久 | 久久精品99久久久久久久久 | 久久精品影视 | av在线播放免费 | 97人妻天天摸天天爽天天 | 91蝌蚪少妇偷拍 | 在线观看免费www | 日韩一区二区av | 免费小视频 | 久久综合久久综合久久综合 | 长篇乱肉合集乱500小说日本 | 性――交――性――乱a | 污污网站在线观看 | 波多野结衣视频免费 | www.亚洲激情 | 日本一区二区成人 | 自拍偷拍国产 | av影院在线 | 精品视频不卡 | 全程粗话对白视频videos | 男女爱爱福利视频 | 国产草草 | 老妇高潮潮喷到猛进猛出 | 久久久久久久偷拍 | 一区二区在线观看免费视频 | 青青操在线观看视频 | 视频免费在线 | 四虎国产在线观看 | 91视频免费视频 | 精品一区二区三区在线播放 | 高h文在线 | 国产香蕉在线 | 欧美xxxx×黑人性爽 | 99er在线观看 | 草草视频网站 | 亚洲国产精品免费在线观看 | 国产精品高清在线 | 国产亚洲精品成人无码精品网站 | 中国大陆一级片 | 韩国美女毛片 | 欧美日韩www | av男人在线 | 韩日精品在线 | 成年人福利 | 美日韩av | 日韩成人在线观看视频 | 性做久久久久久久久 | 中文一区在线观看 | 色一情一伦一子一伦一区 | 国产孕交 | 欧美午夜精品一区二区三区电影 | 日韩一级黄 | 在线免费看毛片 | 亚洲高清在线 | 九九操| 午夜视频在线免费看 | 夜夜爽夜夜操 | 日本人做受免费视频 | 20日本xxxxxxxxx46 欧美激情一级 | 亚洲欧美日本另类 | 超碰国产人人 | 国产一区视频在线观看免费 | 久久激情综合 | 波多野结衣a级片 | 精品久草| 国产一区视频在线观看免费 | 国产精品999999| 黄色a毛片| 色网在线免费观看 | 黄色天堂 | 免费av网站在线观看 | 欧美 日韩 国产精品 | 精品九九 | 日韩少妇av| 免费av电影网址 | 亚洲国产mv | 性色av一区二区三区 | 9191国产精品| 波多野结衣在线视频免费观看 | 国产精品乱 | 在线免费观看黄视频 | 日韩高清不卡在线 | 国产伦一区二区 | 日本不卡视频一区二区三区 | 日韩在线播放av | 国产成人无码精品久在线观看 | 欧美天堂视频 | 91porn在线 | 自拍欧美亚洲 | 亚洲在线一区二区 | 久久午夜精品人妻一区二区三区 |