IOMMU是如何劃分PCI device group的?
IOMMU的一個主要作用就是將IO裝置發出的請求地址IOVA(I/O Virtual Address)轉化為實體記憶體地址,如果沒有IOMMU,那麼所有的IO裝置都將使用相同的實體地址空間訪問實體記憶體。引入IOMMU後,就會引入IOVA這個地址空間,IO裝置可以通過IOVA虛擬地址訪問實體記憶體。
在虛擬化引入之前,IOMMU主要有兩個功能:
- 建立IOVA到HPA的對映,讓裝置能夠訪問任意實體記憶體。比如,有些I/O裝置的定址空間只有4G,但是平臺的實體記憶體大於4G,為了讓這樣的I/O裝置能夠訪問4G空間以上的記憶體,就需要建立一個IOVA -> HPA的對映。
- 通過IOVA -> HPA的對映,建立記憶體連續的DMA訪問,提高系統效能。比如,核心分配2個不相鄰的4KB記憶體頁,若沒有IOMMU,需要建立兩次DMA操作才能訪問到這兩個記憶體頁,若有IOMMU,則可以將這兩個不相鄰的實體記憶體頁對映到相鄰的IOVA上,這樣裝置只需要建立一次DMA操作,即可訪問到這兩個不相鄰的實體記憶體頁。
除了以上功能,虛擬化對IOMMU的主要應用就是對裝置的隔離。在引入PCIe之前,傳統的PCI匯流排對裝置的隔離是很難實現的,因為傳統的PCI匯流排採用的是匯流排仲裁機制,同一時間只有一個PCI裝置獨佔整個PCI匯流排,裝置發出的TLP包不包含requester ID,導致RC(Root Complex)或者其他接收裝置無法分辨出接收到的TLP包來自哪個裝置,也就無法達到裝置區分和隔離的目的。雖然PCI-X在一定程度上引入了requester ID,但是有些規則還是不夠完善,還做不到完全的隔離。
對於PCIe架構而言,PCIe裝置發出的所有TLP包都會包含一個requester ID(即PCI裝置的Bus、Device和Function Number),這個ID可以唯一地辨別一個PCI裝置,TLP的接收裝置可以使用這個ID來查詢IOVA的地址轉換頁表,這樣PCIe裝置就可以使用虛擬地址(IOVA)訪問實體記憶體。這時候,對於透傳給虛擬機器的PCI裝置,軟體需要做的就是將PCIe裝置所在的虛擬機器的虛擬機器實體地址GPA(Guest Physical Address)到主機實體地址HPA(Host Physical Address)的對映告知IOMMU,當PCIe裝置發生DMA的時候,IOMMU選擇目標虛擬機器的GPA->HPA的對映表對地址進行轉換,這樣就能夠讓透傳的PCI裝置只能訪問到虛擬機器的實體地址空間,即分配給虛擬機器的實體記憶體,達到裝置隔離的目的。
device group指的是從IOMMU角度看能夠進行隔離的最小裝置集。device group的劃分規則包括:
- device group中所有的裝置將會共享一個IOVA地址空間。對於傳統PCI匯流排上的裝置而言,TLP中不包含Requester ID,無法進行裝置區分,所以整個傳統PCI匯流排上的裝置都將被劃分到同一個device group上。PCIe裝置發出的TLP帶有requester ID,所以可以進行裝置區分,也就是可以使用獨立的IOVA地址空間。
- 從裝置發出的TLP是否都能夠到達IOMMU,如果裝置發出的TLP可以不經過IOMMU,IOMMU就無法對TLP中包含的地址進行轉換,即IOMMU無法控制裝置的訪問地址,無法達到隔離的目的。
PCIe ACS(Access Control Service) Extended Capability是PCIe標準中引入的用於控制對接收到的TLP(Transaction Layer Packets)進行正常的路由(即向上提交),阻塞或者是重定向轉發的特性,該特性可以實現PCIe裝置peer-to-peer的資料傳輸,即裝置之間的資料互動可以不經過IOMMU。ACS位於Root Complex,downstream port或者Muti-Function Devices(包括支援SR-IOV特性的PCIe裝置),downstream port經常以PCI bridge的形式表現出來。
例如,可以在連線PCIe Root Port的PCI Bridge中找到了ACS Capability。
帶有SR-IOV功能的網路卡也可能提供ACS特性
總的來說,iommu device group的劃分總體來說按照以下兩個規則 :
- 一條傳統PCI匯流排或者PCI-X匯流排上的PCI裝置都劃分到同一個device group。
- 從上往下看,若某一個PCIe downstream port或者multif-function device開啟了ACS特性,該PCIe port或者multi-function下面的所有裝置也都劃分到同一個device group。否則每個PCIe裝置都劃分為一個獨立的device group。
比如,以下面的拓撲圖為例
- 紅框中的PCI Express-PCI/PCI-X Bridge下面掛的裝置都將被劃分到同一個iommu device group中。
- PCIe switch的某個downstream port開啟了ACS特性,則該PCIe switch port可能將接收到的PCIe裝置發出的TLP包轉發到該switch port下面的其他裝置,所以為了保證完全的隔離,只能將該switch port下面的所有裝置都歸到同一個device group中。
- 系統中其餘的PCIe switch port,root port或PCIe Endpoint device都沒有開啟ACS特性,所以其餘的PCIe裝置,每個裝置都可以各自獨立為一個iommu device group。
核心函式pci_device_group()用於對pci裝置進行device group的劃分,對於一個pci device而言,其主體結構如下所示:
struct iommu_group *pci_device_group(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
/*
* Find the upstream DMA alias for the device. A device must not
* be aliased due to topology in order to have its own IOMMU group.
* If we find an alias along the way that already belongs to a
* group, use it.
*/
if (pci_for_each_dma_alias(pdev, get_pci_alias_or_group, &data))
return data.group;
/*
* Continue upstream from the point of minimum IOMMU granularity
* due to aliases to the point where devices are protected from
* peer-to-peer DMA by PCI ACS. Again, if we find an existing
* group, use it.
*/
for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
if (!bus->self)
continue;
if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
break;
pdev = bus->self;
group = iommu_group_get(&pdev->dev);
if (group)
return group;
}
return iommu_group_alloc();
}
函式會從PCI裝置往上直到root(包括各種橋)進行檢測,檢測裝置是否支援ACS(Access Control Service)特性,如果一路上都沒有開啟ACS特性,則呼叫iommu_group_alloc()為該裝置新增一個新的iommu device group。如果裝置位於傳統的PCI bus(不是PCIe)上,則當該傳統PCI bus上已經有裝置分配了iommu device group,則將會呼叫pci_for_each_dma_alias()函式,將該裝置直接新增到目標iommu device group中。
相關文章
- 符合PCI的Web應用開發指南:PCI是線上支付必過關卡Web
- IP地址的分類:A、B、C、D、E五類IP地址是如何劃分的
- MySQL的Group By分組MySql
- 如何劃分微服務微服務
- bzoj1821: [JSOI2010]Group 部落劃分 Group(最小生成樹)JS
- 代理IP的型別如何劃分?型別
- Temkin Group:亞馬遜是客戶體驗評分最高的科技公司亞馬遜
- Bucket(free list) 是如何來劃分記憶體chunk大小範圍的?記憶體
- IP地址的A、B、C類如何劃分?
- 用例顆粒度劃分的原則是什麼?如何計算功能點?
- group by分組查詢
- SQL 分組排序group bySQL排序
- Linux 上如何劃分VLANLinux
- 元件的劃分元件
- zone的劃分
- 如何在Linux上劃分VLANLinux
- linux nvidia驅動錯誤--NVRM: This PCI I/O region assigned to your NVIDIA device is invalidLinuxVRdev
- PCI-E介面知識科普 顯示卡PCI/AGP/PCI-E介面有什麼區別?
- WAF的幾種劃分方法和劃分型別型別
- IDC機房等級是怎樣劃分的?-VeCloudCloud
- 產品經理和產品負責人之間的職責是如何劃分? - Reddit
- 如何對BUG進行等級劃分?分享一份我整理的BUG等級劃分表
- Android2.0 如何設定和讀取聯絡人的分組(Group)Android
- 架構分層的小糾結-層級該如何劃分與定位?架構
- 動態規劃之數的劃分動態規劃
- 機器學習是如何區分貓和狗的?機器學習
- 資料倉儲主題域如何劃分
- Oracle和MySQL分組查詢GROUP BYOracleMySql
- 學大資料,你的職業是如何規劃的?大資料
- Havas Group:未來的特徵是性別平等特徵
- 豐田的“人機分離”是如何實現的?
- [譯] React 是如何區分 Class 和 Function 的 ?ReactFunction
- 面試題——Mybatis是如何進行分頁的面試題MyBatis
- PCI裝置的地址空間 【轉】
- sql中的left切割 與 group by後的兩次分組SQL
- 【TCP/IP】IP地址的劃分及其分類TCP
- 開發ejb如何劃分模組,使模組粒度合理
- 解決DDD最大難題-如何劃分領域