A.INTRODUCTION (32位系統)
Linux 簡化了分段機制,使得虛擬位址(邏輯地址)與線性地址總是一致,因此,Linux的虛擬位址空間也為0~4G(2^32)。
Linux核心將這4G位元組的空間分為兩部分。將最高的 1G位元組(從虛擬位址0xC0000000到0xFFFFFFFF),供核心使用,稱為“核心空間”。而將較低的3G位元組(從虛擬位址 0x00000000到0xBFFFFFFF),供各個進程使用,稱為“使用者空間“。因為每個進程可以通過系統調用進入核心,因此,Linux核心由系統 內的所有進程共用。於是,從具體進程的角度來看,每個進程可以擁有4G位元組的虛擬空間。
|
*進程定址空間0~4G *進程在使用者態只能訪問0~3G,只有進入核心態才能訪問3G~4G *進程通過系統調用進入核心態 *每個進程虛擬空間的3G~4G部分是相同的 *進程從使用者態進入核心態不會引起CR3的改變但會引起堆棧的改變 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
關於虛擬核心空間(邏輯地址)到物理空間的映射:
當核心模組代碼或線程訪問記憶體時,代碼中的記憶體位址都為邏輯地址,而對應到真正的實體記憶體地址,需要地址一對一的映射,如邏輯地址0xc0000003對應的物理地址為0×3,0xc0000004對應的物理地址為0×4,… …,邏輯地址與物理地址對應的關係為
物理地址 = 邏輯地址 – 0xC0000000
| 邏輯地址 |
實體記憶體地址 |
| 0xc0000000 |
0×0 |
| 0xc0000001 |
0×1 |
| 0xc0000002 |
0×2 |
| 0xc0000003 |
0×3 |
| … |
… |
| 0xe0000000 |
0×20000000 |
| … |
… |
| 0xffffffff |
0×40000000 ?? |
對核心空間來說,其地址映射是很簡單 的線性映射,0xC0000000就是物理地址與線性地址之間的位移量,在Linux代碼中就叫做PAGE_OFFSET。
B.outline
一、Linux使用者空間與核心空間
refer: http://blog.chinaunix.net/uid-15007890-id-3415331.html
二、Linux進程地址空間的一步步探究 refer:http://soft.chinabyte.com/os/51/12324551.shtml
C.contents
一、Linux使用者空間與核心空間
Linux 作業系統和驅動程式運行在核心空間,應用程式運行在使用者空間,兩者不能簡單地使用指標傳遞資料,因為Linux使用的虛擬記憶體機制,使用者空間的資料可能被換出,當核心空間使用使用者空間指標時,對應的資料可能不在記憶體中。
我們知道,linux作業系統每個進程的地址空間都是獨立的,其實這裡的獨立說得是物理空間上得獨立。
1. Linux核心地址映射模型
x86 CPU採用了段頁式地址映射模型。進程代碼中的地址為邏輯地址,經過段頁式地址映射後,才真正訪問實體記憶體。
段頁式機制如下圖。
2.Linux核心地址空間劃分
通常32位Linux核心地址空間劃分0~3G為使用者空間,3~4G為核心空間。注意這裡是32位核心地址空間劃分,64位核心地址空間劃分是不同的。
3.Linux核心高端記憶體的由來
當核心模組代碼或線程訪問記憶體時,代碼中的記憶體位址都為邏輯地址,而對應到真正的實體記憶體地址,需要地址一對一的映射,如邏輯地址0xc0000003對應的物理地址為0×3,0xc0000004對應的物理地址為0×4,… …,邏輯地址與物理地址對應的關係為
物理地址 = 邏輯地址 – 0xC0000000
| 邏輯地址 |
實體記憶體地址 |
| 0xc0000000 |
0×0 |
| 0xc0000001 |
0×1 |
| 0xc0000002 |
0×2 |
| 0xc0000003 |
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_NORMAL 16MB~896MB
ZONE_HIGHMEM 896MB ~ 結束
4.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 |
| … |
|