ARM結構和MIPS結構的地址空間
無論在哪種體系結構中,地址空間的訪問都是CPU執行的基本,CPU的每一條指令的地址,都必須在CPU所能訪問的地址空間內,當然這個空間指的是虛擬地址空間。每個CPU所能訪問多大的虛擬地址這是和CPU的位數有關的,32位地址匯流排,最大的虛擬地址就是2的32次方,64位同理。當然在實際的使用中,是不會出現這麼大的地址範圍的,我們都會根據裝置的地址和記憶體的範圍來配置一些視窗來給CPU訪問,這就限制了CPU實際所使用的地址空間的大小。這些虛擬地址空間又是如何對映到實際的實體地址(裝置地址和記憶體地址)的,每種結構的對映方法可能不同。不過大同小異,只要掌握一種其他的都不難理解。
簡單的講CPU拿到的地址都是虛擬地址,CPU區訪問地址的時候,有的地址是落在了記憶體上,而有的地址落在了裝置的暫存器上,這是怎麼實現的呢,主要是通過視窗的配置實現的。核心通過MMU的分段管理和分頁管理機制來管理核心的記憶體對映。
CPU拿到虛擬地址後經過MMU的分段管理得到了線性地址,線性地址又經過分頁管理得到了實體地址,邏輯地址基於分段管理或者分頁管理中基於基址的偏移值。(分段管理和分頁管理這裡不做詳細介紹)程序使用的虛擬地址,由作業系統協助相關硬體,把它“轉換”成真正的實體地址。虛擬地址通過頁表(Page Table)對映到實體記憶體,頁表由作業系統維護並被處理器引用。核心空間在頁表中擁有較高特權級,因此使用者態程式試圖訪問這些頁時會導致一個頁錯誤(page fault)。在Linux中,核心空間是持續存在的,並且在所有程序共享。核心程式碼和資料總是可定址,隨時準備處理中斷和系統呼叫。與此相反,使用者模式地址空間的對映隨程序切換的發生而不斷變化。
(1)ARM地址空間
32ARM結構地址空間劃分:
地址分佈如下圖所示:
如上圖所示:
使用者空間(0—3G),這段空間對映到實體記憶體的高階記憶體
核心空間(3G—4G),這段空間對映到低端記憶體,這段空間又分為以下四部分,分別為
(a)直接對映區(0—896M):這段虛擬地址空間和低端記憶體地址存線上性的地址關係即虛擬地址3G+X=實體地址X
(b)動態對映區(896—1016M):這段 空間具體對映到實體記憶體的什麼位置不確定,該區域的地址由核心中的vmalloc來實現 分配,其特點是虛擬地址空間連續,但是實體地址空間不一定連續。vmalloc函式返回的是虛擬地址,但是其對映的實體地址有可能在高階記憶體,也有可能在低端記憶體。
(c)永久記憶體對映區(pkmap1016—1020M):使用kmap函式將高階記憶體的地址對映到這部分割槽域,這樣就可以通過這個 虛擬地址來訪問高階記憶體的地址。通過這4M的視窗可以重複對映所有的高階記憶體。
(d)固定對映區:(1020—1024M):這4M的地址是有特定用途的固定地址,這4M的區域對映的實體記憶體作為ACPI電源管理等暫存器的地址。
64位ARM地址空間的劃分:
ARM64架構處理器採用48位物理定址,最大可以支援256T的地址空間,對於目前的應用來說已經足夠了。但是虛擬地址依然採用64,虛擬地址遠遠大於實體地址。所以在處理器架構設計上,把虛擬地址空間劃分為三部分,分別為使用者空間,非規範區和核心空間,其中核心空間和使用者空間每個部分最大支援256T的訪問。
使用者空間:(0x0000_0000_0000_0000——0x0000_FFFF_FFFF_FFFF)256T
核心空間:(0xFFFF_0000_0000_0000——0xFFFF_FFFF_FFFF_FFFF)256T
其餘部分被稱為非規範區域。
核心空間由做了詳細的劃分,分為以下部分:
(a)Vmalloc區域:0xFFFF_0000_0000_0000——0xFFFF_7BFF_BFFF_0000(126974G)
(b)Vmemmap區域:0xFFFF_7BFF_C000_0000——0xFFFF_7FFF_C000_0000(4096G)
(c)PCI I/O區域:0xFFFF_7FFF_AE00_0000——0xFFFF_7FFF_BE00_0000(16M)
(d)Moudules區域:0xFFFF_7FFF_C000_0000——0xFFFF_8000_0000_0000(64M)
(e)Normal memory線性對映區:0xFFFF_8000_0000_0000——0xFFFF_FFFF_FFFF_FFFF(128T)
如下圖所示:
(2)MIPS結構的地址空間
32位MIPS地址空間劃分(loongson平臺):
如下圖所示:
如上圖所示:在mips結構上,32位虛擬地址空間也同樣分為兩部分,即使用者空間和核心空間。只不過哦與ARM結構不同,這裡的核心空間是2G大小。
(a)核心空間(0x8000_0000—0xFFFF_FFFF)2G
(b)使用者空間(0x0000_0000——0x7FFF_FFFF)2G
核心空間又做了比較詳細的劃分,分別為kseg0,kseg1,kseg2。
kseg0:(0x8000_0000——0x9FFF_FFFF)512M
這部分虛擬地址被對映到實體記憶體的0到512M空間內,訪問這個視窗的地址是需要cache的,也就意味著CPU來這個視窗取記憶體的資料的時候,會將資料新增到cache中,下次再取的時候就可以直接從cache中獲取。
kseg1:(0xA000_0000——0xBFFF_FFFF)512M
這部分虛擬地址也被對映到實體記憶體的0到512M空間內,和上面屬於重複對映,讀取的資料屬於記憶體的同一塊記憶體,只不過這部分地址不經過cache,也就是CPU用這個視窗的指令去記憶體中取資料的時候是不經過cache的,cache中沒有資料的拷貝。每次取都要從記憶體中讀取。
kseg2:(0xC000_0000——0xFFFF_FFFF)1G
這部分虛擬地址被對映到實體記憶體的0x4000_000到0x7FFF_FFFF這1G的記憶體地址空間,作為PCI的memory空間。這個對映是TLB完成的。
使用者空間虛擬地址0x0000_0000——0x7FFF_FFFF經過TLB被對映到實體記憶體的0x8000_0000向上的實體記憶體,這裡面需要扣掉
0x8000_0000——0x9000_0000這256M的記憶體,因為這部分地址被reserved掉了不是用。所以使用者空間真正的實體記憶體是0x9000_0000向上的地址空間。
64位MIPS地址空間劃分(loongson平臺)
64位地址空間劃分的比較複雜,和ARM一樣虛擬地址還是採用64位地址,實體地址採用了48位的實體地址,但是48位中高4位為節點號,其餘的44位才是每個裝置內的實體地址分佈。
節點空間分佈如下圖所示:
而每個節點內的地址空間分佈如下圖所示:
如上圖所示,核心模式下,虛擬地址被劃分為以下五部分:
(a)使用者空間:0x0000_0000_0000_0000——0x0001_0000_0000_0000(256T)
(b)地址空洞:如上圖中紫色部分,核心模式下訪問會出錯的地址
(c)可擴充套件區:0x4000_0000_0000_0000——0x4000_FFFF_FFFF_FFFF和
0xC000_0000_0000_0000——0xC000_00FF_7FFF_FFFF(257T+2G)
(d)xkphys段:0x8000_0000_0000_0000——0xBFFF_FFFF_FFFF_FFFF(4E)
(e)完全複用32位地址的部分:0xFFFF_FFFF_8000_0000——0xFFFF_FFFF_FFFF_FFFF(4G)
如何用64位地址來訪問48位的實體地址呢?請看下圖:
我們在軟體程式碼上,要用64位的虛擬地址來訪問裝置,只需要牢記,用0x9800_xxxx_xxxx_xxxx和0x9000_xxxx_xxxx_xxxx的地址就可以訪問全部48位地址空間,用0x98開頭的地址是經過cache的,0x90開頭的地址是不經過cache的,其中低32位地址完全複用32位模式下的地址即可。