天天看點

Linux系統虛拟記憶體空間

首先借用網上一張圖,感覺這個比較清晰:

Linux系統虛拟記憶體空間

Linux系統虛拟記憶體空間一般布局示意圖

線性位址空間:是指Linux系統中從0x00000000到0xFFFFFFFF整個4GB虛拟存儲空間。線性空間又分為使用者空間和核心空間。

使用者空間是指從0x00000000到0xBFFFFFFF共3GB的線性位址空間,每個程序都有一個獨立的3GB使用者空間,是以使用者空間由每個程序獨有,但是核心線程沒有使用者空間,因為它不産生使用者空間位址。另外子程序共享(繼承)父程序的使用者空間隻是使用與父程序相同的使用者線性位址到實體記憶體位址的映射關系,而不是共享父程序使用者空間。運作在使用者态和核心态的程序都可以通路使用者空間。

    linux采用虛拟記憶體管理技術,每一個程序都有一個3G大小的獨立的程序位址空間,這個位址空間就是使用者空間。每個程序的使用者空間都是完全獨立、互不相幹的。程序通路核心空間的方式:系統調用和中斷。

    建立程序等程序相關操作都需要配置設定記憶體給程序。這時程序申請和獲得的不是實體位址,僅僅是虛拟位址。 實際的實體記憶體隻有當程序真的去通路新擷取的虛拟位址時,才會由“請頁機制”産生“缺頁”異常,進而進入配置設定實際頁框的程式。該異常是虛拟記憶體機制賴以存在的基本保證,它會告訴核心去為程序配置設定實體頁,并建立對應的頁表,這之後虛拟位址才實實在在的映射到了實體位址上。

Linux系統虛拟記憶體空間

核心空間表示運作在處理器最進階别的超級使用者模式(supervisor mode)下的代碼或資料,核心空間占用從0xC0000000到0xFFFFFFFF的1GB線性位址空間,核心線性位址空間由所有程序共享,但隻有運作在核心态的程序才能通路,使用者程序可以通過系統調用切換到核心态通路核心空間,程序運作在核心态時所産生的位址都屬于核心空間。

核心空間又可分為以下幾個線性空間:

1. 核心邏輯位址空間

是指從PAGE_OFFSET(3G)3G+896)之間的線性位址空間,是系統實體記憶體映射區,它映射了全部或部分(如果系統包含高端記憶體)實體記憶體。核心邏輯位址空間中的位址與RAM記憶體實體位址空間中對應的位址隻差一個固定偏移量(3G),如果RAM記憶體實體位址空間從0x00000000位址編址,那麼這個偏移量就是PAGE_OFFSET。

2. 高端線性位址空間:從high_memory(3G+896M)到0xFFFFFFFF之間的線性位址空間屬于高端線性位址空間,其中VMALLOC_START~VMALLOC_END之間線性位址:(1)被vmalloc()函數用來配置設定實體上不連續但線性位址空間連續的高端實體記憶體,或者(2)被vmap()函數用來映射高端或低端實體記憶體,或者(3)由ioremap()函數來重新映射I/O實體空間。其中PKMAP_BASE開始的LAST_PKMAP(一般等于1024)頁線性位址空間:被kmap()函數用來永久映射高端實體記憶體。FIXADDR_START開始的KM_TYPE_NR*NR_CPUS頁線性位址空間:被kmap_atomic()函數用來臨時映射高端實體記憶體,其他未用高端線性位址空間可以用來在系統初始化期間永久映射I/O位址空間。

核心邏輯位址空間所映射實體記憶體就是低端記憶體(實際實體記憶體的大小,但是小于896),低端記憶體在Linux線性位址空間中始終有永久的一一對應的核心邏輯位址,系統初始化過程中将低端記憶體永久映射到了核心邏輯位址空間,為低端記憶體建立了虛拟映射頁表。低端記憶體内實體記憶體的實體位址與線性位址之間的轉換可以通過__pa(x)和__va(x)兩個宏來進行,#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) __pa(x)将核心邏輯位址空間的位址x轉換成對應的實體位址,相當于__virt_to_phys((unsigned long)(x)),__va(x)則相反,把低端實體記憶體空間的位址轉換成對應的核心邏輯位址,相當于((void *)__phys_to_virt((unsigned long)(x)))。

低端記憶體位址之上的實體記憶體是高端記憶體(實體記憶體896之上),高端記憶體在Linux線性位址空間中沒有沒有固定的一一對應的核心邏輯位址,系統初始化過程中不會為這些記憶體建立映射頁表将其固定映射到Linux線性位址空間,而是需要使用高端記憶體的時候才為配置設定的高端實體記憶體建立映射頁表,使其能夠被核心使用,否則不能被使用。高端記憶體的實體位址于線性位址之間的轉換不能使用上面的__pa(x)和__va(x)宏。

高端記憶體概念的由來:如上所述,Linux将4GB的線性位址空間劃分成兩部分,從0x00000000到0xBFFFFFFF共3GB空間作為使用者空間由使用者程序獨占,這部分線性位址空間并沒有固定映射到實體記憶體空間上;從0xC0000000到0xFFFFFFFF的第4GB線性位址空間作為核心空間,在嵌入式系統中,這部分線性位址空間除了映射實體記憶體空間之外還要映射處理器内部外設寄存器空間等I/O空間。0xC0000000~high_memory之間的核心邏輯位址空間專用來固定映射系統中的實體記憶體,也就是說0xC0000000~high_memory之間空間大小與系統的實體記憶體空間大小是相同的(當然在配置了CONFIG_DISCONTIGMEMD選項的非連續記憶體系統中,核心邏輯位址空間和實體記憶體空間一樣可能存在記憶體孔洞),如果系統中的實體記憶體容量遠小于1GB,那麼核心線性位址空間中核心邏輯位址空間之上的high_memory~0xFFFFFFFF之間還有足夠的空間來固定映射一些I/O空間。可是,如果系統中的實體記憶體容量(包括記憶體孔洞)大于1GB,那麼就沒有足夠的核心線性位址空間來固定映射系統全部實體記憶體以及一些I/O空間了,為了解決這個問題,在x86處理器平台設定了一個經驗值:896MB,就是說,如果系統中的實體記憶體(包括記憶體孔洞)大于896MB,那麼将前896MB實體記憶體固定映射到核心邏輯位址空間0xC0000000~0xC0000000+896MB(=high_memory)上,而896MB之後的實體記憶體則不建立到核心線性位址空間的固定映射,這部分記憶體就叫高端實體記憶體。此時核心線性位址空間high_memory~0xFFFFFFFF之間的128MB空間就稱為高端記憶體線性位址空間,用來映射高端實體記憶體和I/O空間。896MB是x86處理器平台的經驗值,留了128MB線性位址空間來映射高端記憶體以及I/O位址空間,在嵌入式系統中可以根據具體情況修改這個門檻值,比如,MIPS中将這個值設定為0x20000000B(512MB),那麼隻有當系統中的實體記憶體空間容量大于0x20000000B時,核心才需要配置CONFIG_HIGHMEM選項,使能核心對高端記憶體的配置設定和映射功能。什麼情況需要劃分出高端實體記憶體以及高端實體記憶體門檻值的設定原則見上面的記憶體頁區(zone)概念說明。

Linux系統虛拟記憶體空間

繼續閱讀