虛擬化中設備直通的實現


虛擬化中設備直通的實現

設備直通的實現大致分為四個部分,分別是直通設備發現,虛擬PCI配置空間,中斷重映射,DMA重映射。

直通設備發現

如何讓虛擬機發現直通設備

操作系統初始化時會進行PCI設備的設備枚舉,設備枚舉從根節點HOST-PCI橋(Header Type為1的PCI設備),首先探測總線0上的各個設備。每當發現一個橋設備,當將它為根節點往下探測,如此反復直到所有設備都被探測完畢。
探測的方法很直接,從0到PCI_SLOTMAX枚舉device number,再結合所在總線的bus number與默認的function number(0)組合成bdf,通過將bdf寫入CONFIG_ADDRESS(0xcf8端口),然后向CONFIG_DATA中寫入值便可以讀該個PCI插槽上的PCI設備。通過讀取PCI設備"Vendor ID"和"Device ID"能夠知道這個PCI設備是否存在。如果發現該設備一個PCI-PCI橋,則創建一個pci_bus數據結構並且連入到由pci_root_buses指向的pci_bus和pci_dev數據結構組成的樹中。

直通設備發現的關鍵步驟

截獲操作系統對PCI總線的訪問(CONFIG_ADDRESS,CONFIG_DATA)

HV將0xcf8端口與0xcfc端口從VMCS中的IO位圖中關閉,操作系統對這兩個端口的訪問將下陷到hypervisor中。

將直通設備記錄在pci_vdevs數組中

HV需要對每個虛擬機模擬對應的PCI總線,記錄當前給虛擬機模擬的PCI設備,當給UOS assign一個直通設備時,需要給這個設備建立一個vdev結構體,並將其加入到UOS對應的pci_vdevs數組中,當操作系統對PCI設備進行枚舉時,能夠發現到這個直通設備。

虛擬PCI配置空間

設備直通的一個關鍵點是讓虛擬機能夠訪問設備的真實IO空間,它的關鍵是虛擬機對設備PCI配置空間的訪問。

PCI配置空間介紹

CONFIG_ADDRESS

x86平台上操作系統通過IO端口0xCF8-0xCFF訪問PCI設備,前32位是CONFIG_ADDRESS,后32位是CONFIG_DATA,CONFIG_ADDRESS中包括BDF和register number,可以索引到PCI設備上的寄存器。

預定義頭部

  • Header Type 決定PCI設備類型,共有三種類型:普通PCI設備,PCI橋,CardBus橋,每種PCI設備的配置空間結構都不相同,上圖展示的是普通PCI設備的配置空間。
  • Base Address Registers,基地址寄存器,它記錄PCI寄存器或者設備RAM在I/O端口(或者物理地址空間)的地址。
  • Capabilities Pointer,capabilities list的頭指針
  • Interrupt Pin,Interrupt Line,設備中斷引腳與中斷線

為什么要虛擬PCI配置空間

PCI配置空間包括預定義頭部(predefined header region)與設備相關部分(device dependent region)。預定義頭部除了包括vendor id,device id,type之外,還包括了六個bar register。PCI設備有自己的板上存儲空間,這些存儲空間映射的系統軟件的地址空間中,它們具體的地址就存在於bar register中。由於虛擬機不能夠直接訪問物理內存,所以它也不能夠直接訪問存儲了物理地址的bar register。
設備相關部分包括了PCI MSI中斷信息,MSI通過在PCI配置空間中存儲中斷對象與中斷號,能夠繞過IOAPIC,直接向LAPIC發起中斷。如果虛擬機可以直接讀寫真實設備的設備相關部分,它將有能力向其他核或者其他虛擬機發起中斷。這是不可行的。
因此虛擬機監控器需要針對直通設備虛擬出PCI配置空間。

如何虛擬PCI配置空間

  1. HV 啟動時深度優先掃描並記錄所有的PCI總線與設備
  2. 關閉I/O bitmap讓虛擬機對PCI設備的端口訪問產生下陷(正如前文介紹,虛擬機通過CONFIG_ADDRSS與CONFIG_DATA兩個端口訪問PCI設備)。
  3. 建立轉換表,報告虛擬的PCI BAR給虛擬機,當虛擬機通過IO端口訪問PCI設備(操作系統只能通過端口0xCF8,0xCFC訪問PCI設備配置空間)時,HV可以截獲操作並通過轉換表把I/O請求轉發到設備的I/O地址空間。
  4. 虛擬機不能直接讀寫PCI配置空間,但是可以直接讀寫PCI板上內存。由於HV為虛擬機寫入BAR寄存器的GPA建立了第二階段頁表映射,當虛擬機訪問BAR寄存器上的GPA指向的地址時,第二階段翻譯能夠將GPA翻譯成PCI設備真正映射的物理地址。於是虛擬機能夠訪問直通設備的板上內存而無需VMM處理。

中斷重映射

為了避免虛擬機對外設發送惡意中斷,從而對主機或者虛擬機進行攻擊。硬件廠商引入了中斷重映射機制,在外設與CPU之間加了一個硬件中斷重映射單元。當接收到來自外設的中斷時,硬件重映射單元會對中斷請求的來源進行有效性驗證,然后以中斷號為索引查詢中斷重映射表,代替外設向目標cpu發送中斷。中斷重映射表由虛擬機進行設置與安裝。

VT-d對中斷重映射的支持

下面以Intel VT-d技術為例介紹硬件對於中斷重映射的支持。
為了支持中斷重映射,需要對中斷源進行升級,包括(I/O APIC,MSI,MSI-X),讓中斷重映射硬件能夠從中斷消息中提出中斷重映射表的索引。因此VT-d設計了可重映射的中斷消息格式。

中斷重映射硬件能夠通過handle與subhandle計算出中斷在中斷重映射表的索引值。
為了讓中斷重映射硬件知道中斷重映射表的位置,需要在HV初始化的時候分配一塊區域作為中斷重映射表,並將該區域寫入中斷重映射表地址寄存器。
中斷重映射表里的中斷重映射條目(IRTE)如下

MSI中斷發送流程

先介紹MSI中斷的發送流程

  1. PCIe 設備在發送 MSI/MSI-X中斷請求之前,系統軟件需要合理設置PCIe設備MSI/MSI-X Capability 寄存器,使 Message Address寄存器的值為0xFEExx00y,同時合理地設置 Message Data寄存器Vector字段。
  2. PCIe設備提交MSI/MSI-X中斷請求時,需要向0xFEExx00y地址寫Message Data寄存器中包含的數據,並以存儲器寫TLP的形式發送到RC。當橋片收到這個TLP后,發現這個TLP的目 的地址在系統總線Interrupts存儲器空間中,則將PCIe總線的存儲器寫請求轉換為系統總線Interrupt Message總線事務,並在系統總線上廣播。
  3. 系統總線上的CPU,根據APIC ID信息,選擇是否接收這個Interrupt Message總線事務,並進入中斷狀態,之后該CPU將直接從這個總線事務中獲得中斷向量號,執行相應的中斷服 務例程,而不需要從APIC中斷控制器獲得中斷。

設置中斷重映射表

以MSI中斷為例,為了之后使用MSI中斷,操作系統啟動時需要對PCI配置空間中的MSI capability進行設置,包括:

  1. 讀取設備的消息控制寄存器的Mulitple Message Capable欄位獲得設備支持的消息數量以及是否支持64bit消息地址。然后使能對應的enable bit。
  2. 分配base message data pattern以及Message Address。
  3. 最后使能MSI enable bit並關閉其它的中斷選項。
    當虛擬機設置直通設備的MSI(X)信息時,將觸發VM-Exit,此時HV可以設置中斷重映射表,並向Message Address中寫入可重映射的中斷消息。
    當在Message Address中寫入可重映射的中斷消息后,設備發送MSI中斷時將發送這個中斷消息到總線上,VT-d硬件能夠讀懂這個消息,並利用可重映射的中斷消息索引出中斷重映射條目,將其發送給LAPIC。

DMA重映射

DMA重映射的實現介紹正在整理中。

參考資料

https://projectacrn.github.io/2.4/developer-guides/hld/hv-dev-passthrough.html#hv-device-passthrough
https://kernelgo.org/armv8-virt-guide.html
https://kernelgo.org/vfio-insight.html
https://github.com/minosproject/minos
PCIE_Base_Specification_Revision_4_0_Version 1_0.pdf
vt-directed-io-spec.pdf
https://zhuanlan.zhihu.com/p/326412992
https://luohao-brian.gitbooks.io/interrupt-virtualization/content/vt-d-dma-remapping-fen-xi.html
https://zhuanlan.zhihu.com/p/194244760


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM