LINUX 内核代码备忘录

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];
posted @ 2010-12-14 13:22  DOF_KL  阅读(1464)  评论(0编辑  收藏  举报