PCI裝置的地址空間 【轉】

vc66vcc發表於2016-10-13
PCI配置空間(PCI Configuration Space)
PCI裝置的地址空間 【轉】 - 喧鬧的寂寞 - 荊瓜牛
 
圖 1. 標準 PCI 匯流排的組織結構圖

PCI裝置(PCI device)都有一個配置空間,大小為256位元組,實際上是一組連續的暫存器,位於裝置上。配置空間的前64位元組是配置空間起始段,它對於每種型別的裝置都是相同的。顯示了PCI 裝置的配置空間起始段。 
其中頭部64位元組是PCI標準規定的,格式如下:

PCI裝置的地址空間 【轉】 - 喧鬧的寂寞 - 荊瓜牛

圖 2. PCI 裝置的配置空間起始段

還有PCI網橋的地址空間:

PCI裝置的地址空間 【轉】 - 喧鬧的寂寞 - 荊瓜牛

圖 3. PCI 橋的配置空間起始段  

 
剩餘的部分是PCI裝置自定義的。
PCI配置空間頭部有6個BAR(Base Address Registers),BAR記錄了裝置所需要的地址空間的型別(memory space或者I/O space),基址以及其他屬性。BAR的格式如下:

PCI裝置的地址空間 【轉】 - 喧鬧的寂寞 - 荊瓜牛

 
可以看出,裝置可以申請兩類地址空間,memory space和I/O space,它們用BAR的最後一位區別開來。
說到地址空間,計算機系統中,除了我們常說的memory address(包括邏輯地址、虛擬地址(線性地址)、CPU地址(實體地址)),還有I/O address,這是為了訪問I/O裝置(主要是裝置中的暫存器)而設立的,大部分體系結構中,memory address和I/O address都是分別編址的,且使用不同的定址指令,構成了兩套地址空間,也有少數體系結構將memory address和I/O address統一編址(如ARM)。
有兩套地址空間並不意味著計算機系統中需要兩套地址匯流排,實際上,memory address和I/O address是共用一套地址匯流排,但通過控制匯流排上的訊號區別當前地址匯流排上的地址是memory address還是I/O address。北橋晶片(Northbridge,Intel稱其Memory Controller Hub,MCH)負責地址的路由工作,它內部有一張address map,記錄了memory address,I/O address的對映資訊,一個典型的address map如圖:

PCI裝置的地址空間 【轉】 - 喧鬧的寂寞 - 荊瓜牛

 
我們來看北橋是如何進行地址路由的。根據控制匯流排上的訊號,北橋首先可以識別地址屬於memory space還是I/O space,然後分別做處理。
比如若是memory space,則根據address map找出目標裝置(DRAM或Memory Mapped I/O),若是DRAM或VGA,則轉換地址然後傳送給記憶體控制器或VGA控制器,若是其它I/O裝置,則傳送給南橋。
若是I/O space,則傳送給南橋(Southbridge,Intel稱其I/O Controller Hub,ICH),南橋負責解析出目標裝置的bus, device, function號,併傳送資訊給它。
PCI裝置會向計算機系統申請很多資源,比如memory space, I/O space, 中斷請求號等,相當於在計算機系統中佔位,使得計算機系統認識自己。
PCI裝置可以通過兩種方式將自己的I/O儲存器(Registers/RAM/ROM)暴露給CPU:
在memory space申請地址空間,或者在I/O space申請地址空間。
這樣,PCI裝置的I/O儲存器就分別被對映到CPU-relative memory space和CPU-relative I/O space,使得驅動以及作業系統得以正常訪問PCI裝置。對於沒有獨立I/O space的體系結構(如ARM),memory space和I/O space是統一編址的,也就是說memory space與I/O space等價了,這時,即使PCI裝置在BAR表明了要申請I/O space,實際上也是分配在memory space的,所以驅動無法使用I/O埠指令訪問I/O,只能使用訪存指令。在Windows驅動開發中,PCM_PARTIAL_RESOURCE_DESCRIPTOR記錄了為PCI裝置分配的硬體資源,可能有CmResourceTypePort, CmResourceTypeMemory等,後者表示一段memory地址空間,顧名思義,是通過memory space訪問的,前者表示一段I/O地址空間,但其flag有CM_RESOURCE_PORT_MEMORY和CM_RESOURCE_PORT_IO兩種,分別表示通過memory space訪問以及通過I/O space訪問,這就是PCI請求與實際分配的差異,在x86下,CmResourceTypePort的flag都是CM_RESOURCE_PORT_IO,即表明PCI裝置請求的是I/O地址空間,分配的也是I/O地址空間,而在ARM或Alpha等下,flag是CM_RESOURCE_PORT_MEMORY,表明即使PCI請求的I/O地址空間,但分配在了memory space,我們需要通過memory space訪問I/O裝置(通過MmMapIoSpace對映實體地址空間到虛擬地址空間,當然,是核心的虛擬地址空間,這樣驅動就可以正常訪問裝置了)。
 
為了為PCI裝置分配CPU-relative space,計算機系統需要知道其所申請的地址空間的型別、基址等,這些資訊記錄在裝置的BAR中,每個PCI配置空間擁有6個BAR,因此每個PCI裝置最多能對映6段地址空間(實際很多裝置用不了這麼多)。PCI配置空間的初始值是由廠商預設在裝置中的,於是裝置需要哪些地址空間都是其自己定的,可能造成不同的PCI裝置所對映的地址空間衝突,因此在PCI裝置列舉(也叫匯流排列舉,由BIOS或者OS在啟動時完成)的過程中,會重新為其分配地址空間,然後寫入PCI配置空間中。
 
通過memory space訪問裝置I/O的方式稱為memory mapped I/O,即MMIO,這種情況下,CPU直接使用普通訪存指令即可訪問裝置I/O。
通過I/O space訪問裝置I/O的方式稱為port I/O,或者port mapped I/O,這種情況下CPU需要使用專門的I/O指令如IN/OUT訪問I/O埠。
 
常見的MMIO例子有,VGA card將framebuffer對映到memory space,NIC將自己的片上緩衝對映到memory space,實際上,最典型的MMIO應該是DRAM,它將自己的儲存空間對映到memory space,是佔用CPU地址空間最多的“裝置”。
 

相關文章