內存管理1(內核情景分析)

linux定義了三層映射,頁面目錄稱爲PGD, 中間目錄爲PMD,頁面表爲PT.

linux將最高1G字節(0xc0000000-0xffffffff)用於內核本身稱爲"系統空間", 將較低3G字節(0x0-0xbfffffff)用作各個進程"用戶空間".

以i386爲例,從線性地址到物理地址的獲取,在頁面映射過程中,CPU需要訪問內存三次,第一次頁面目錄,第二次頁面表,第三次真正目標,所以虛存高效實現有賴於高速緩存實現。有高速緩存後一般都在高速緩存找到,不需要讀內存,另一方面,整個過程是硬件實現,所以速度快。

linux爲線性地址到物理地址的映射定義數據類型:pgd_t,pmd_t,pte_t。另一個說明頁面保護的結構:pgprot_t,其中與i386MMU的頁面表項的低12位相對應。
目錄項結構:
typedef struct {
unsigned int ptba:20; /* 頁表及地址的高 20 位*/
unsigned int avail:3; /* 供系統程序員使用 */
unsigned int g:1; /* global,全局性頁面 */
unsigned int ps:1; /* 頁面大小,0 表示 4K 字節 */
unsigned int reserved:1; /* 保留,永遠是 0 */
unsigned int a:1; /* accessed已被訪問過 */
unsigned int pcd:1; /* 關閉(不使用)緩衝存儲器 */
unsigned int pwt:1; /* Write Through用於緩衝存儲器 */
unsigned int u_s:1; /* 爲 0時表示系統(或超級)權限,爲 1時表示用戶權限 */
unsigned int r_w:1; /* 只讀或可寫*/
unsigned int p:1; /* 爲0時表示相應的頁面不在內存中 */
} 目錄項;
-----------------------------------------------------------------------------------
獲得頁表表項:
#define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) } )
#define __mk_pte(page_nr, pgprot) __pte(((page_nr)<<PAGE_SHIFT)|pgprot_val(pgprot))
------------------------------------------------------------------------------------

物理頁面:內核中有個全局量mem_map,是個指向一個page數據結構數組,每個page數據結構代表一個物理頁面,整個數組代表系統中的全部物理頁面。對於軟件,將頁面表項的高20位作下標可以從mem_map找到代表這個物理頁面的page數據結構。對於硬件,低12位補0就是物理頁面的起始地址.
------------------------------------------------------------------------------------
根據虛存地址找相應物理頁面:
#define pte_page(x) (mem_map+((unsigned long)(((x).pte_low >> PAGE_SHIFT))))
------------------------------------------------------------------------------------
物理頁面mem_map_t的數據數組,根據數組下標劃分成ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM管理區.每個管理區都有一個zone_struct(zone_t) 數據結構,每個結構都有一組"空閒空間"(free_area_t)隊列.管理區數據結構中既要有一個隊列來保持一些離散(連續長度爲1)的物理頁面,還要有一個隊列來保持一個連續長度爲2的頁面塊以及連續長度爲4、8、16、…、直至2^MAX_ORDER的頁面塊。常數MAX_ORDER定義爲10,也就是說最大的連續頁面塊可以達到2^10=1024個頁面,即4M自己。(.....無語中,不懂,--->夥伴算法???)

引入NUMA後,在zone_struct解構上有了另一層代表着存儲節點的pglist_data數據結構.

虛擬空間: vm_area_struct,mm_struct數據結構.



ps:物理空間像倉庫,物理空間管理好比倉庫管理;虛擬空間以進程爲基礎,從"需"的角度來管理.mm_struct和

vm_area_struct說明了對頁面的需求,前面page,zone_struct等結構則說明了對頁的供應;而頁面目錄,中間目錄以及頁面表則是兩者中間橋樑.


linux在i386內存管理的特殊點:
1.i386從線性地址到物理地址是兩級映射(MMU識別兩層),PMD等同於PT.
2.內核GDT只使用了四種不同段寄存器,兩種內核,兩種用作所有進程.第2項和第3項分別用於內核的代碼段和數據段,第4項和第5項永遠用於當前進程的代碼段和數據段.RPL等級內核0用戶進程3.(見GDT寄存器定義)
typedef struct {
unsigned int index:13; /*  描述表項號*/
unsigned int ti:1; /* 選擇GDTR或LDTR*/
unsigned int rpl:2; /* 特權等級 */
} 段描述表寄存器;
3.段描述符項使用平面地址,段描述符項2,3,4,5差不多,區別在於dpl(訪問本段所需權限),s(描述項類型1表示系統0表示代碼或數據),type(段的類型,讀寫,是否訪問等).
ps:看2,3點得知linux內核裝模作樣的糊弄i386的段式處理.

問題1: 32位i386的linux中進程的最大理論數計算?
每個進程的局部段描述表LDT都作爲一個獨立的段而存在,在全局段描述表GDT中要有一個表項指向這個段的起始地址,並說明該段的長度以及其他一些參數。除上之外,每個進程還有一個TSS結構(任務狀態段)也是一樣。所以,每個進程都要在全局段描述表GDT中佔據兩個表項。那麼,GDT的容量有多大呢?段寄存器中用作GDT表下標的位段寬度是13位,所以GDT中可以有8192個描述項。除一些系統的開銷(例如GDT中的第2項和第3項分別用於內核的代碼段和數據段,第4項和第5項永遠用於當前進程的代碼段和數據段,第1項永遠是0,等等)以外,尚有8180個表項可供使用,所以理論上系統中最大的進程數量是4090。

問題2: i386、linux下,c語言中*和&,彙編中的符號地址到底是什麼地址?
c語言用的是虛擬地址,彙編用的是線性地址。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章