linux 啟動過程臨時頁表到底映射了多大記憶體?
來源:互聯網
上載者:User
從linux-2.4核心開始,在建立臨時頁表的時候,一般的教科書都說是映射了8M的實體記憶體,但是為什麼是映射8M呢?當時網上有資料說,8M足夠了,但為什麼就足夠了,一直沒有徹底搞清楚,今天又重新分析這部分的代碼(linux-2.6.24)。 先看下面記憶體布局圖:在建立臨時頁表時到底映射多大的記憶體取決於以下幾個方面:(1)保護模式下核心的尺寸: 毫無疑問核心代碼必須被映射(2)臨時頁表所佔的空間尺寸: 假設臨時頁表映射整個4G的線性地址空間,那麼: 頁面個數 = 4G/4k = 1M個頁面 每個頁面對應一個頁表項,佔4個位元組,那麼總共佔有4M的空間(3)bootmem allocator是用來在真正的頁表建立好之前用於記憶體管理的,他用一個位元影像表來管理整個記憶體,每一bit代表一個頁框,假設有4G的實體記憶體,那麼1M個頁面共佔有空間 = 1M/8 = 128K。(4)由於對齊佔有的空間(可以忽略,感覺k的數量級吧)綜合上述幾個方面,需要映射的實體記憶體大約等於: 保護模式核心尺寸 + 臨時頁表佔用空間尺寸 + bootmem allocator位元影像表尺寸 = 現在核心大約4M
最大4M 128K = 8M + 128K 在linux核心的head_32.S中下面代碼: movl $(pg0 - __PAGE_OFFSET), %edi
movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
movl $0x007, %eax /* 0x007 = PRESENT+RW+USER */
10:
leal 0x007(%edi),%ecx /* Create PDE entry */
movl %ecx,(%edx) /* Store identity PDE entry */
movl %ecx,page_pde_offset(%edx) /* Store kernel PDE entry */
addl $4,%edx
movl $1024, %ecx
11:
stosl
addl $0x1000,%eax
loop 11b
/* End condition: we must map up to and including INIT_MAP_BEYOND_END */
/* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */
leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp
cmpl %ebp,%eax
jb 10b
movl %edi,(init_pg_tables_end - __PAGE_OFFSET) 紅字部分與映射記憶體有關:INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_SIZE_asm = 128K + (4K + 4 )*4K = 128K + 4M + 4K所以是映射了8M實體記憶體, 即10:之後的代碼執行了兩次,這完全滿足前面分析的需要映射的實體記憶體的大小。可以從核心代碼中的注釋中得到驗證:/*
* paging_init() sets up the page tables - note that the first 8MB are
* already mapped by head.S.
*
* This routines also unmaps the page at virtual kernel address 0, so
* that we can trap those pesky NULL-reference errors in the kernel.
*/這裡還提到了:把虛擬位址=0開始的第一個頁的映射解除,主要是為了跟蹤對NULL指標引用的錯誤。 上面是我進來看代碼的一些心得,可能考慮不對,希望大家指教,相互交流。