通常X86系統中會存在四大地址空間:進程地址空間、內核地址空間、物理地址空和PCI地址空間。這幾大 地址空間有些是硬件領域的相關內容,例如PCI地址空間,PCI Hole;有些是軟件研發需要了解的。這幾大地 址空間有什麼不同?他們之間是如何聯系在一起的呢?
下圖是進程地址空間、內核地址空間以及物理地址 空間之間的聯系,下面對幾大地址空間的聯系進行闡述。
進程地址空間大家比較熟悉,很多人都知道通過虛擬內存機制,在32位平台上每個進程都可以獲得4GB大小 的地址空間。在32位Linux系統中,高1GB空間是每個進程共享的內核地址空間,0~3GB的空間是每個進程獨享 的地址空間。進程地址空間通過頁表與物理地址空間建立聯系,為了減少這種映射帶來的開銷損失,X86處理 器硬件提供了TLB頁表Cache。由於訪存具有很高的時空局部性,因此TLB Cache的命中率很高,為虛擬內存機 制的工程應用奠定了基礎。從硬件上講,進程虛擬地址映射最重要的模塊是MMU,只有擁有MMU的處理器才可以 支持虛擬地址機制。從軟件上來講,虛擬地址最重要的是頁表管理。操作系統需要為虛擬內存建立頁表,當 TLB Cache Miss的時候,處理器會產生中斷,然後進行頁表映射,並且加載頁表。在進程的用戶空間,很多時 候也希望直接對PCI的設備內存空間直接進行操作,例如很多應用程序想直接操作顯卡內存,獲得性能上的優 勢。為了達到這種目的,需要將處理器域PCI設備內存地址映射至進程地址空間。在Linux中提供了mmap函數實 現IO地址與虛擬地址之間的映射。這種映射本質上與物理內存的映射是一樣的,同樣需要建立頁表。
OS內核地址空間占據了3~4GB,共1GB大小的地址空間。其中,絕大部分地址(3G~Vmalloc_end)都是 通過線性映射的方式進行映射,起始的一段物理內存空間被直接映射至內核空間。因此,內核空間的這種線性 映射的地址也稱為邏輯地址,這種地址無需頁表進行映射,物理地址和邏輯地址之間的轉換可以通過簡單的偏 移運算即可完成。內核空間中也存在虛擬地址,這段地址空間為Vmalloc_end~4GB。內核空間通過Vmalloc函數 為這段虛擬地址空間建立頁表,與物理內存建立聯系。另外,在實際的系統中,除了物理內存之外,PCI設備 同樣占據處理器物理地址空間,內核空間想要訪問PCI設備內存時,需要通過ioremap函數將處理器域PCI設備 內存地址映射到內核空間。這種映射與vmalloc的方式一樣,同樣需要建立頁表。我們可以看到,實際上,在 32位Linux中,虛擬地址空間不是很大,默認情況下只有幾百兆的空間。那麼,如果用戶想映射一塊非常大的 PCI設備內存空間至內核,怎麼辦呢?我想如果用戶有這方面的需求,那麼只能通過調整vmalloc_end參數將虛 擬地址空間擴大。另外,在ARM嵌入式系統中,由於系統的內存資源有限,32位Linux預留的內核空間地址足夠 ,而且物理內存通常會小於1GB,因此,PCI物理地址空間往往會落在1GB以內。在這種情況下,PCI設備內存的 映射可以采用內核空間邏輯地址映射的方式,直接通過偏移操作進行物理地址和IO虛擬地址的轉換,而無需調 用ioremap進行頁表操作(ARM嵌入式系統中會定義_REG宏實現虛實地址轉換)。
CPU物理地址空 間理解上比較容易,就是處理器訪問內存的地址空間。但是,值得注意的是,處理器內存地址空間並非全部用 於物理內存的訪問(DIMM),其中有一部分用於訪問PCI設備地址空間。因此,如果處理器地址總線寬度為32 位,擁有4GB地址空間,那麼,其中只有一部分地址是用於訪問物理內存的。因此,32位的地址總線無法支持 4GB大內存。為了解決這個問題,Intel和AMD處理器在推出64位處理器之前采用了PAE技術,即Intel處理器將 地址總線擴展到36位;AMD處理器擴展到40位。在軟件的處理上,對頁表也進行了修改,實現32位虛擬地址與 36/40位物理地址的映射。從上圖我們可以看出,當系統中安裝的物理內存比較少時,例如只安裝了1GB內存, 那麼物理地址空間還會存在空閒地址,4GB的頂端地址空間會分配給PCI設備,並且PCI設備地址空間與物理內 存空間沒有交叉。前幾年這樣的系統大量存在。但是,伴隨著物理內存的日益廉價,大內存的系統大量出現, 例如很多系統都配備大於4GB的內存。這樣的系統會存在一個問題:PCI設備地址和物理內存存在地址交叉,處 理器無法訪問被PCI地址空間覆蓋的物理內存。這也就在物理內存空間形成了一個地址空洞,這個空洞通常被 稱為PCI Hole。為了解決這個問題,芯片組提供了一組寄存器將被PCI設備地址覆蓋的那部分物理內存重新映 射到其它地址空間,從而實現將這部分遺失的內存回收。這種映射是通過硬件實現的。目前,在64位處理器上 依然存在PCI Hole的問題,主要考慮到兼容性的問題。未來如果把PCI設備地址空間直接放到64位地址空間的 頂端,PCI Hole這個問題也就不存在了。
很多人在開發PCI設備的時候很 疑惑,什麼是PCI地址空間?PCI地址和處理器地址是一回事嗎?其實在X86系統中,PCI地址和處理器地址在數 值方面是相同的,但是這兩個地址仍然屬於兩個不同的地址域。上面討論的物理地址所指的就是處理器域的物 理地址,是站在處理器的角度來看待訪問地址的。PCI地址不是站在處理器角度的地址,而是PCI總線域的地址 ,是站在PCI橋、PCI設備看到的地址。如上圖所示,PCI總線域地址和處理器域地址是通過PCI主橋(Host或者 Complex)進行映射轉換的。位於處理器的軟件如果想訪問PCI設備,那麼直接采用處理器域的PCI設備地址, 當然位於內核的驅動程序需要采用ioremap之後的虛擬地址進行訪問。位於設備端的DMA控制器需要進行數據傳 輸時,需要采用PCI總線域的地址。有趣的是,X86處理器對這兩個空間的地址進行等值映射,所以看到的值是 相同的,但是PowerPC則進行了線性映射,兩個值是不相同的。
這裡對計算機系統中的幾個地址進行了 說明,希望對大家有所幫助,如有不對的地方請指正,在此謝過。
出處 http://alanwu.blog.51cto.com/3652632/1082195