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];

你可能感兴趣的:(linux)