vSVA邏輯分析
-v0.1 2020.2.29 Sherlock init.
-v0.2 2020.4.16 Sherlock add missing pasid logic in guest.
-v0.3 2020.4.27 Sherlock update vSMMU/SMMU CD base update.
簡介:本文分析Linux vSVA現在的構架邏輯。目前爲止Linux vSVA的代碼還在構架討論和代碼review階段。
- qemu基礎認識
qemu裏linux系統的用戶態代碼跑在cpu EL0, qemu裏linux系統的內核態代碼跑在cpu EL1。
qemu創建虛擬機的時候ioctl(CREATE_VM,VCPU,MEMORY)會到cpu EL2創建VM的記錄信息。
ioctl(VM_RUN)會把PC指向虛擬機起始地址,然後退出到EL1。EL2只起到虛擬機管理的作用,
虛擬機上的代碼正常運行時,代碼佔據真實的CPU,並且如果是用戶態代碼,跑在物理CPU
的EL0, 如果是內核態代碼就直接跑到物理CPU的EL1。當CPU訪問物理內存的時候,VA->IPA
的轉換由MMU S1直接支持, 當IPA的地址落在之前ioctl註冊的虛擬機地址空間時,硬件自動
完成MMU S2的轉換。可見,虛擬機裏的進程頁表是直接放到虛擬機內核地址空間的。
虛擬機裏的代碼運行在CPU EL0/EL1。當有IO訪問的時候, 因爲之前創建虛擬機的時候
已經把IO地址空間配置給虛擬機,這裏有IO訪問的時候會觸發CPU異常,虛擬機退出,CPU
進入EL2, CPU在EL2處理後退出到虛擬機qemu裏,qemu可以具體去處理這個IO,比如是一個
網絡IO,那qemu可以直接起socket,把報文發出去。注意,這裏的虛擬機退出是指CPU不再
運行虛擬機裏執行的代碼,因爲CPU並不知道如果控制IO。
- vSVA
vSVA的目標是在虛擬機裏(qemu),使的IO設備可以直接使用進程VA。所以,我們這裏的
假設是物理IO設備已經通過host上vfio驅動直通給虛擬機。
要實現vSVA的目標,我們需要同時使能SMMU的S1,S2地址翻譯,S1進行VA->IPA翻譯,S2
進行IPA->PA翻譯,如果是host vfio使能,我們認爲S2的翻譯已經通過vfio配置在SMMU裏。
所以,vSVA的方案需要把虛擬機系統裏的進程頁表同步到host SMMU上。因爲是vSVA,就
有可能出現設備發起內存訪問的時候,host SMMU上虛擬機裏的進程頁表項不存在的情況,
所以,host上的SMMU要可以支持S1缺頁。因爲,S2用vfio支持,vfio採用pin內存的方式,
暫時我們不需要S2的缺頁。這裏說的host上SMMU支持S1缺頁,並不是在host系統上做S1缺頁,
我們這裏討論的是nested SMMU, 所以在host SMMU硬件檢測到S1缺頁的時候,應該把這個
信息上報給guest裏的SMMU,guest裏使用和host一樣的SMMU驅動處理缺頁,當guest處理完
這個缺頁後,應該把對應的頁表信息同步到SMMU的物理硬件上(SMMU.CD.TT0裏)。因爲,
guest裏的進程頁表和SMMU CD上的頁表物理上不是一個,很明顯這裏有一個設備和vcpu頁
表的同步問題,在host SVA上這個問題不存在,因爲host SVA上cpu和SMMU是物理上共用
相同頁表。因此,在需要在vcpu無效化頁表的時候,需要把信息同步到host的SMMU上,
這個信息包括頁表項和TLB。host SVA上也有這個問題,但是如果用SMMU stall mode, 可
以配置DVM,把CPU側TLB invalidate廣播到SMMU,這樣就不需要軟件同步。
在guest裏多進程使用一個設備的資源,就需要支持PASID。這裏的邏輯和上面的是一樣的,
只不過擴展到多進程。
- 軟件框架
+----------------------+
| guest user |
| |
| |
| |
|----------------------| -------------------- VA
| kernel | +------------+
| | | page table |
| | +------------+
| | ^
+----------------------+ |
+----------------------+ -------------------- IPA |
| host | |
| | |
| | +---------+ |
| | | DDR | PA |
| | +---------+ |
| | |
| | |
| | |
| | |
+----------------------+ |
| |
| +-----+ |
| +------> | S1 | VA->IPA <------------------+
+--+---+ -----+ +-----+
| SMMU |
+------+ -----+ +-----+
^ +------> | S2 | IPA->PA
| +-----+
+-----+
| dev |
+-----+
我們順着具體的數據流看看需要的接口,在dev的控制寄存器被map到guest的用戶態後,
用戶態可以直接給guest VA配置給dev,啓動dev從VA處讀寫數據。dev發出的訪問到達
SMMU後首先要進過S1的翻譯,得到IPA,所以S1需要guest裏的進程的頁表。
目前Redhat的Eric在做ARM nested SMMU的支持,他把相關的補丁集合到了他的分支裏,
你可以在這個地方看到完整的內核補丁:https://github.com/eauger/linux branch:
v5.6-2stage-v11_10.1。這組補丁裏給vfio加了一個ioctl(VFIO_IOMMU_SET_PASID_TABLE),
用這個ioctl把虛擬機裏的SMMU的CD地址(IPA)直接傳給host,並且配置給物理SMMU的CD
基地址。對於預先在vcpu一側有缺頁的情況,這裏S1可以查頁表翻譯,SMMU硬件在nested
模式下,會對CD基地址做S2翻譯的到CD的真正物理地址,然後找見頁表做翻譯。可見qemu
裏的SMMU驅動使用和host SMMU相同的驅動,初始化qemu裏SMMU的CD.TT0, 然後把CD直接
通過系統調用配置到物理SMMU上。需要注意,這裏CD裏的頁表基地址是IPA,SMMU硬件
會先根據S2頁表翻譯IPA到PA得到頁表物理基地址。
對於dev傳給SMMU的VA沒有頁表的情況, S1要做缺頁處理。這裏的缺頁處理在邏輯上應該
上報給guest,因爲要做vSVA,是要給虛擬機裏的進程的頁表加頁表項。Eric這組補丁裏,
在vfio里加了一個event queue的隊列,mmap到host用戶態,用來傳遞這個信息。邏輯上看,
qemu應該處理並上報這個缺頁請求,qemu裏的SMMU驅動做缺頁處理。在qemu的SMMU驅動做
缺頁處理的時候,來自dev的請求是stall在SMMU裏的,所以,SMMU缺頁處理完畢後,應該
有通知機制通知到host SMMU,使能stall的請求繼續。
可以看到當頁表有變動的時候,在guest和物理SMMU上同步頁表的開銷是很大的。
當guest裏的進程有退出或者內存有釋放時,需要更新guest裏進程的頁表,vcpu tlb,
host SMMU上相關進程頁表和tlb。Eric補丁裏vfio裏提供了ioctl(VFIO_IOMMU_CACHE_INVALIDATE)
用來更新host SMMU上的相關tlb。這裏vcpu可以做帶VMID/ASID的DVM, 直接無效化相關的tlb。
- virtio iommu
以上的分析都是基於nested IOMMU/SMMU的方案。目前Jean在做virtio iommu的方案。
這個方案在qemu裏實現一個virtio iommu的虛擬設備qemu/hw/virtio/virtio-iommu.c,
虛擬機內核裏的drivers/iommu/virtio-iommu.c驅動這個虛擬設備,現在看來這個是
用純軟件實現VA->IPA的映射。
基於以上的分析,可以基於vfio接口在virtio iommu裏實現有物理SMMU支持的virtio-iommu。
但是,這個需要virtio-iommu協議的支持。目前,Jean在搞virt-iommu的協議
jpbrucker.net/virtio-iommu/spec, 目前看virtio iommu spec中PASID/fault的支持
還不完善。