內核頁表的初始化

1.

swapper_pg_dir : Global Page Directory (全局頁目錄,即最頂層頁目錄,PGD) 的地址

pgd_index(addr): 宏函數,返回PGD包含的項中,地址字段 值爲addr的項的索引。

PAGE_OFFSET:宏函數,返回進程地址空間(線性地址)中kernel所屬的地址空間的起始地址,x86_32下是0xc0000000

PAGE_SIZE:宏函數,返回頁大小(4096B或2MB)

max_low_pfn:宏函數,返回一個物理內存的頁塊號,該頁塊是最後一個由kernel直接進行 邏輯/物理 映射的頁塊

set_pmd:宏函數,將值寫入PMD(Page Middle Directory)中指定的項

__pmd:宏函數,將一個無符號整數值轉換成PMD表項類型,即pmd_t

pgprot_val:宏函數,將一個無符號整數轉換成__prot類型,該類型保存一個頁表/頁目錄項的保護標誌位

__pgprot:宏函數,將一個__prot類型的值轉換成一個無符號整數

 

物理內存在4GB以內時,kernel重初始化內核頁表的過程。(此時爲2級分頁PGD->PTE->PF),由於LINUX內核總是使用大頁面(即一頁面爲2MB或4MB,而非常規的4096B),即PTE->PF(共10+12=22位,4MB)不設置頁表,而是直接將內存看作頁面。此模式下,PGD共有1024項,其中內核佔768~1023項,總計內核尋址空間爲256*4MB = 1GB


pgd = swapper_pg_dir + pgd_index(PAGE_OFFSET); /* 768 */
phys_addr
= 0x00000000;
while (phys_addr < (max_low_pfn * PAGE_SIZE) ) {
pmd
= one_md_table_init(pgd); /* returns pgd itself */
set_pmd(pmd, __pmd(phys_addr
| pgprot_val( __pgprot(0x1e3))));
/* 0x1e3 == Present , Accessed ,Dirty, Read/Write, Page Size, Global */
phys_addr
+= PTRS_PER_PTE * PAGE_SIZE; /* 0x400000 */
++pgd;
}


開啓PAE(Physical Address Extending)或物理內存大於4GB時,kernel重初始化內核頁表的過程。(此時爲3級分頁PGD->PMD->PTE->PF),在這種情況下,PTE與PF尋址位數爲9+12=21,即此時LINUX內核使用2MB大小的頁面。此模式下,PDG共4項,其中內核佔第三項,PMG共512項,總計內核尋址空間爲512*2MB = 1GB

 

pgd_idx = pgd_index(PAGE_OFFSET); /* 3 */
for (i=0; i<pdg_idx; i++)
set_pgd(swapper_pg_dir
+ i , __pgd( __pa(empty_zero_page) | 0x001) );
/* 0x001 == Present */
pgd
= swapper_pg_dir + pgd_idx;
phys_addr
= 0x00000000;
for( ; i<PTRS_PER_PGD; ++i , ++pgd) {
pmd
= (pmd_t*) alloc_bootmem_low_pages(PAGE_SIZE);
set_pgd(pgd, __pa(pmd)
| 0x001); /* 0x001 == Present */
if( phys_addr < max_low_pfn * PAGE_SIZE)
for(j=0; j<PTRS_PER_PMD && hys_addr < max_low_pfn * PAGE_SIZE; ++j) {
set_pmd(pmd, __pmd(phys_addr
| pgprot_val(__pgprot(0x1e3))));
/* 0x1e3 == Present , Accessed ,Dirty, Read/Write, Page Size, Global */
phys_addr
+= PTRS_PER_PMD * PAGE_SIZE;
}
}
swapper_pg_dir[
0] = swapper_pg_dir[pgd_idx];




one_md_table_init()

直接返回pgd所指向的頁目錄表項

static pmd_t * __init one_md_table_init(pgd_t *pgd)
{
    pud_t *pud;
    pmd_t *pmd_table;
#ifdef CONFIG_X86_PAE
    pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); 
    set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); 
    pud = pud_offset(pgd, 0);
    if (pmd_table != pmd_offset(pud, 0))
        BUG();
#else


pmd_table和pgd指向同一個頁目錄項
|-------------------------------------|
|   pud = 
pud_offset(pgd, 0);         |
|   pmd_table = 
pmd_offset(pud, 0);   |
|-------------------------------------|

#endif
    return pmd_table;
}

#define pud_offset(pgd, start)      (pgd)
static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
{           
   
return (pmd_t *)pud;
}

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