sep11
2011
10 comments
written bychen
linux核心位址對映模型
x86 cpu採用了段頁式位址對映模型。程序**中的位址為邏輯位址,經過段頁式位址對映後,才真正訪問物理記憶體。
段頁式機制如下圖。
linux核心位址空間劃分
通常32位linux核心位址空間劃分0~3g為使用者空間,3~4g為核心空間。注意這裡是32位核心位址空間劃分,64位核心位址空間劃分是不同的。
linux核心高階記憶體的由來
當核心模組**或執行緒訪問記憶體時,**中的記憶體位址都為邏輯位址,而對應到真正的物理記憶體位址,需要位址一對一的對映,如邏輯位址0xc0000003對應的實體地址為0×3,0xc0000004對應的實體地址為0×4,… …,邏輯位址與實體地址對應的關係為
實體地址 = 邏輯位址 – 0xc0000000
邏輯位址
物理記憶體位址
0xc0000000
0×00xc0000001
0×10xc0000002
0×20xc0000003
0×3…
… 0xe0000000
0×20000000……
0xffffffff
0×40000000 ??
假設按照上述簡單的位址對映關係,那麼核心邏輯位址空間訪問為0xc0000000 ~ 0xffffffff,那麼對應的物理記憶體範圍就為0×0 ~ 0×40000000,即只能訪問1g物理記憶體。若機器中安裝8g物理記憶體,那麼核心就只能訪問前1g物理記憶體,後面7g物理記憶體將會無法訪問,因為核心的位址空間已經全部對映到物理記憶體位址範圍0×0 ~ 0×40000000。即使安裝了8g物理記憶體,那麼實體地址為0×40000001的記憶體,核心該怎麼去訪問呢?**中必須要有記憶體邏輯位址的,0xc0000000 ~ 0xffffffff的位址空間已經被用完了,所以無法訪問實體地址0×40000000以後的記憶體。
顯然不能將核心位址空間0xc0000000 ~ 0xfffffff全部用來簡單的位址對映。因此x86架構中將核心位址空間劃分三部分:zone_dma、zone_normal和zone_highmem。zone_highmem即為高階記憶體,這就是記憶體高階記憶體概念的由來。
在x86結構中,三種型別的區域如下:
zone_dma記憶體開始的16mb
zone_normal16mb~896mb
zone_highmem896mb ~ 結束
linux核心高階記憶體的理解
前面我們解釋了高階記憶體的由來。 linux將核心位址空間劃分為三部分zone_dma、zone_normal和zone_highmem,高階記憶體high_mem位址空間範圍為0xf8000000 ~ 0xffffffff(896mb~1024mb)。那麼如核心是如何借助128mb高階記憶體位址空間是如何實現訪問可以所有物理記憶體?
當核心想訪問高於896mb實體地址記憶體時,從0xf8000000 ~ 0xffffffff位址空間範圍內找一段相應大小空閒的邏輯位址空間,借用一會。借用這段邏輯位址空間,建立對映到想訪問的那段物理記憶體(即填充核心pte頁面表),臨時用一會,用完後歸還。這樣別人也可以借用這段位址空間訪問其他物理記憶體,實現了使用有限的位址空間,訪問所有所有物理記憶體。如下圖。
例如核心想訪問2g開始的一段大小為1mb的物理記憶體,即實體地址範圍為0×80000000 ~ 0x800fffff。訪問之前先找到一段1mb大小的空閒位址空間,假設找到的空閒位址空間為0xf8700000 ~ 0xf87fffff,用這1mb的邏輯位址空間對映到實體地址空間0×80000000 ~ 0x800fffff的記憶體。對映關係如下:
邏輯位址
物理記憶體位址
0xf8700000
0×80000000
0xf8700001
0×80000001
0xf8700002
0×80000002
… …
0xf87fffff
0x800fffff
當核心訪問完0×80000000 ~ 0x800fffff物理記憶體後,就將0xf8700000 ~ 0xf87fffff核心線性空間釋放。這樣其他程序或**也可以使用0xf8700000 ~ 0xf87fffff這段位址訪問其他物理記憶體。
從上面的描述,我們可以知道高階記憶體的最基本思想:借一段位址空間,建立臨時位址對映,用完後釋放,達到這段位址空間可以迴圈使用,訪問所有物理記憶體。
看到這裡,不禁有人會問:萬一有核心程序或模組一直占用某段邏輯位址空間不釋放,怎麼辦?若真的出現的這種情況,則核心的高階記憶體位址空間越來越緊張,若都被占用不釋放,則沒有建立對映到物理記憶體都無法訪問了。
在香港尖沙咀有些寫字樓,洗手間很少且有門鎖的。客戶要去洗手間的話,可以向前臺拿鑰匙,方便完後,把鑰匙歸還到前台。這樣雖然只有乙個洗手間,但可以滿足所有客戶去洗手間的需求。要是某個客戶一直占用洗手間、鑰匙不歸還,那麼其他客戶都無法上洗手間了。linux核心高階記憶體管理的思想類似。
linux核心高階記憶體的劃分
核心將高階記憶體劃分為3部分:vmalloc_start~vmalloc_end、kmap_base~fixaddr_start和fixaddr_start~4g。
對於高階記憶體,可以通過 alloc_page() 或者其它函式獲得對應的 page,但是要想訪問實際物理記憶體,還得把 page 轉為線性位址才行(為什麼?想想 mmu 是如何訪問物理記憶體的),也就是說,我們需要為高階記憶體對應的 page 找乙個線性空間,這個過程稱為高階記憶體對映。
對應高階記憶體的3部分,高階記憶體對映有三種方式:
對映到」核心動態對映空間」(noncontiguous memory allocation)
這種方式很簡單,因為通過 vmalloc() ,在」核心動態對映空間」申請記憶體的時候,就可能從高階記憶體獲得頁面(參看 vmalloc 的實現),因此說高階記憶體有可能對映到」核心動態對映空間」中。
如果是通過 alloc_page() 獲得了高階記憶體對應的 page,如何給它找個線性空間?
核心在 fixaddr_start 到 fixaddr_top 之間保留了一些線性空間用於特殊需求。這個空間稱為」固定對映空間」在這個空間中,有一部分用於高階記憶體的臨時對映。
這塊空間具有如下特點:
(1)每個 cpu 占用一塊空間
(2)在每個 cpu 占用的那塊空間中,又分為多個小空間,每個小空間大小是 1 個 page,每個小空間用於乙個目的,這些目的定義在 kmap_types.h 中的 km_type 中。
當要進行一次臨時對映的時候,需要指定對映的目的,根據對映目的,可以找到對應的小空間,然後把這個空間的位址作為對映位址。這意味著一次臨時對映會導致以前的對映被覆蓋。通過 kmap_atomic() 可實現臨時對映。
常見問題:
1、使用者空間(程序)是否有高階記憶體概念?
使用者程序沒有高階記憶體概念。只有在核心空間才存在高階記憶體。使用者程序最多隻可以訪問3g物理記憶體,而核心程序可以訪問所有物理記憶體。
2、64位核心中有高階記憶體嗎?
目前現實中,64位linux核心不存在高階記憶體,因為64位核心可以支援超過512gb記憶體。若機器安裝的物理記憶體超過核心位址空間範圍,就會存在高階記憶體。
3、使用者程序能訪問多少物理記憶體?核心**能訪問多少物理記憶體?
32位系統使用者程序最大可以訪問3gb,核心**可以訪問所有物理記憶體。
64位系統使用者程序最大可以訪問超過512gb,核心**可以訪問所有物理記憶體。
4、高階記憶體和實體地址、邏輯位址、線性位址的關係?
高階記憶體只和實體地址有關係,和線性位址、邏輯位址沒有直接關係。
5、為什麼不把所有的位址空間都分配給核心?
若把所有位址空間都給記憶體,那麼使用者程序怎麼使用記憶體?怎麼保證核心使用記憶體和使用者程序不起衝突?
Linux核心高階記憶體
linux核心位址對映模型 x86 cpu採用了段頁式位址對映模型。程序 中的位址為邏輯位址,經過段頁式位址對映後,才真正訪問物理記憶體。段頁式機制如下圖。linux核心位址空間劃分 通常32位linux核心位址空間劃分0 3g為使用者空間,3 4g為核心空間。注意這裡是32位核心位址空間劃分,64...
Linux核心高階記憶體
x86 cpu採用了段頁式位址對映模型。程序 中的位址為邏輯位址,經過段頁式位址對映後,才真正訪問物理記憶體。段頁式機制如下圖。通常32位linux核心位址空間劃分03g為使用者空間,34g為核心空間。注意這裡是32位核心位址空間劃分,64位核心位址空間劃分是不同的。當核心模組 或執行緒訪問記憶體時...
Linux記憶體管理 核心高階記憶體
linux核心位址對映模型 x86 cpu採用了段頁式位址對映模型。程序 中的位址為邏輯位址,經過段頁式位址對映後,才真正訪問物理記憶體。段頁式機制如下圖 linux核心位址空間劃分 通常32位linux核心位址空間劃分0 3g為使用者空間,3 4g為核心空間。注意這裡是32位核心位址空間劃分,64...