PCIE匯流排的地址問題
本文總結一下PCIE的地址使用問題,這個問題在PCIE標準中語焉不詳,很多東西是留給實現者的,所以這個問題就值得探討了。
PCIE的匯流排的體系結構示例抽象如下(只能用示例才比較好表述,否則更難理解):
我特別高亮這裡的三個特徵:
第一,PCIE匯流排是個點到點的串列匯流排。現在的高速匯流排基本上都是串列匯流排,這是硬體工藝決定的,並行匯流排速度做不上去。所以這個topo模型(hierarchy)中,每個End Point都可以用一個地址來標識(所以才有本文的地址問題),每個Switch或者網橋可以看作是一個調度器,它根據地址來調度讀寫請求發到哪裡。連在RC上的EP稱為RCiEP,一般都不是什麼正常的東西,我們後面討論中忽略它。
第二,我們注意到,PCIE標準演進到現在,從來沒有認真討論過RC是什麼東西,這個部分是實現相關的,什麼邏輯搞不定了,都說,這玩意兒RC提供,RC怎麼提供呢?那是實現者的事,你問他們去。我們得對這東西有這樣的認識。
第三,PCIE匯流排是一個子匯流排,是和別人共存的,我們把和CPU發出地址的那個匯流排稱為系統匯流排,和RC一樣,系統匯流排也是個實現相關的概念。
從軟體的角度來說,對某個設備定址,就是往系統匯流排裡面寫一個地址。對系統匯流排來說,如果這個地址在RC的範圍內,就把這個讀寫請求發到RC上,RC怎麼處理剩下的細節,那就是PCIE標準要解決的問題了。
本文要探討的,就是從軟體角度怎麼理解這個地址的使用問題。
PCIE匯流排體系把地址空間分成兩個部分,第一個部分叫ECAM空間,是PCIE的標準配置空間,提供標準的控制整個PCIE功能的基本語義,它的地址組成是「RC基地址+16位BDF+偏移」(BDF是Bus,Device,Function的簡稱,在Linux上lspci就能看見)。通過對這個空間定址,就可以實現對PCIE匯流排系統的配置。
第二個部分我這裡簡稱BAR空間,這個空間是RC和系統匯流排設計者討論決定的,在對ECAM進行配置的時候,軟體和硬體進行協商,最後在某個BDF的ECAM空間的Base Address Register(BAR)中指向分配好的,給這個EP的一組IO空間。
所以RC是個很吃資源的玩意兒,匯流排的地址空間是有限的,但匯流排上會插入什麼EP,插入多少個EP呢,這些都不確定。你可能插入3張高速網卡,也可能插入20個NVMe控制器,每個要多少IO空間呢?用的時候才知道。但RC需要多大的ECAM和BAR空間,這在設計階段就要決定。
當然,那個問題我們可以留給匯流排設計者。我們現在關心的問題是地址。CPU發出一個物理地址,落入分配給RC的空間,這個地址就進入PCIE的調度體系。就可以從RC開始,變成PCIE自己的消息(TLP)。
TLP主要依靠BDF(在TLP中稱為RequesterID和CompleterID)來定址,因為無論如何,一個地址請求,終究目的是發給一個設備的某個Function,然後定址這個Function裡面的某個偏移。
如果CPU發出的地址落在ECAM的範圍內,就變成配置消息,基於解碼出來的BDF就可以發到對應的EP上了。調度系統也可以基於配置找到對應的BDF來發送。
如果是BAR空間,這個東西如何分配給每個BDF的,RC肯定也是清楚的,同樣可以轉化為BDF,發送給對應的EP,這個過程沒有問題。
現在的問題是:反過來呢?CPU把一個物理地址交給一個EP,EP訪問這個地址,怎麼回到匯流排上?
EP本身就是TLP Aware的。所以它可以直接控制它發出的消息類型,不需要匹配這個地址是個BAR空間還是ECAM空間。如果它發出的是內存定址,這個很簡單,直接回到RC,RC自己和系統匯流排搞定就好了。
如果發出的地址是IO空間內的,橋就需要知道這在不在自己下屬的EP上。所以橋需要知道自己和下屬的所有BAR空間的範圍——很幸運,這個在枚舉設備,指配匯流排ID的時候是可以給出來的(因為配置枚舉配置橋的時候,是要給定橋的BAR空間的,而橋的BAR空間,就是它下屬所有節點的預留空間)。換句話說,橋是知道某個地址是屬於本橋之內的,還是必須往回送的。
這樣,如果CPU和EP都使用物理地址,整個定址就沒有問題了。
現在看虛擬地址的情況,PCIE通過ATS支持虛擬地址。ATS服務對應著MMU和IOMMU地址翻譯服務。
MMU給CPU提供了虛擬地址能力,這種能力讓CPU可以給每個進程,或者每個虛擬機分配獨立的地址空間。使用了MMU,CPU可以發出虛擬地址VA,這個地址通過MMU系統翻譯成物理地址PA。
現代MMU可以提供多級的地址翻譯能力,把虛擬機中的進程,從進程虛擬地址翻譯為虛擬機虛擬地址,最後變成物理地址。
IOMMU提供設備一側的翻譯能力,讓設備直接訪問虛擬地址,經過一樣的翻譯過程,讓設備可以直接認知和使用CPU一側提供的虛擬地址。
這種能力Map到PCIE中,就是ATS服務了。ATS服務在上面的Topo中是這樣的定義的:
AT是地址翻譯代理,正如前面說的,它的行為特徵,實現方法,這都是RC的爛事,PCIE標準是不管的。PCIE標準只關心請求到了RC,你給我搞定它。在具體實現的時候,這個東西可能實現為x86的IOMMU或者ARM的SMMU等具體的地址翻譯機制(但請注意,IOMMU,SMMU會實現AT要求之外的功能,比如安全保護)。
而ATC相當於CPU的TLB,就是地址翻譯的Cache。這就是說,有ATS能力的EP,自帶地址翻譯功能,如果它要發出一個地址,進入PCIE匯流排的時候,一定程度上可以認為就是物理地址了,這就完全和我們前面談到的調度邏輯自恰了。因為參與匯流排topo調度的都是物理地址。
當然,我們這裡說「一定程度」。這還是需要解釋一下的,實際情況是,EP在發出ATC中沒有Cache的地址的時候,是直接發出VA的,只是在這個訪問請求中帶了一個標記(AT),說明我這個是個VA,請求RC支援。這樣的地址橋就直接向上送,一直通到RC,讓RC給它響應,更新ATC,下次再發訪問請求,就可以使用不帶AT標記的PA地址了。
但ATS並不是必須的特性,某個EP可以沒有實現ATC,但如果RC上有地址翻譯功能,比如實現了SMMU,那麼EP也可以發出虛擬地址,讓它一路直接上傳到RC上,然後讓RC來完成地址翻譯。
但如果這樣做,有一個嚴重的問題,如果這個虛擬地址正好落在橋的BAR空間的範圍內怎麼辦呢?這你就需要ACS服務了,ACS服務作用在所有有調度功能的節點上,包括橋,Switch乃至帶VF的PF。你可以通過ACS服務要求禁止P2P消息發送,這樣所有的地址請求都會路由回RC,由RC來解釋(比如基於SMMU來解釋)。
另外謝謝 @Byron 的信息:https://cloudplatform.googleblog.com/2017/02/fuzzing-PCI-Express-security-in-plaintext.html,從這個博客上我們還看到,雖然IOMMU等設計可以在RC以上控制設備寫入內存的範圍,但由於P2P消息的存在,這些設備有可能攻擊其他EP,這也需要ACS服務對這種高危設備進行隔離。ACS還可以用于禁止ATS服務。ATS服務最大的問題在於它是基於信任的,是ATC自己聲稱它發出的地址是經過翻譯還是沒有經過翻譯的,如果ATC生成這個地址已經翻譯,就可以越過IOMMU的隔離(fixme:不知道這個問題在SMMU上是不是同樣存在?),這個問題也可以通過ACS來保護(ACS可以在橋上禁止ATS消息)。
推薦閱讀:
※守弱的內涵和外延
※氣和深度學習1:綜述
※找到道法自然的「度」
※Specification的寫法問題
TAG:軟體架構 |