一. linux位址空間
arm的32位系統共支援4g的記憶體空間,其中0-3g為使用者空間,3g-4g是核心空間,
arm採用2級頁表,32位位址空間address分別為 pgd|pte|12bits, 在核心**中分別為pgd 11位,pte 9 位,頁內位址12位;但是在mmu系統中對於arm的二級分頁設定分別為pgd 12位,pte 8位,頁內位址為12位。在核心**層次雖然是11位,但是經過**中的設定,最後都對映到mmu起作用時的pgd12位,pte8位。看**定義。
#define ptrs_per_pgd 2048 //pgd頁中的指標數
#definepgdir_shift 21 //位址中偏移位數,去前11位,因為要右移21位
#define pgdir_size (1ul<< pgdir_shift) 0x20 0000
#define user_ptrs_per_pgd (task_size/ pgdir_size)
在linux-3.5中,使用者空間大小task_size定義如下
#define task_size (ul(config_page_offset)- ul(0x01000000))
#define config_page_offset 0xc000 0000
在linux-2.6.25中,使用者空間大小task_size定義
#define task_size 0xc000 0000
二. 頁表
頁表分為使用者空間頁表和核心空間頁表,不同的程序,它使用者空間是不同的,所以它的使用者空間頁表是不同的,但是不同的程序它的核心空間是共享的,它的核心空間頁表也是相同的。
在建立乙個程序時,會為它建立乙個頁表指標,即mm_struct資料結構中的pgd_t * pgd;分配的函式是mm_init ()->mm_alloc_pgd(struct mm_struct mm) ->pgd_alloc(structmm_struct mm) ->#define __pgd_alloc() (pgd_t)__get_free_pages(gfp_kernel, 2),分配的空間為16k, 即40964bytes,從此處分配的頁表空間包括了使用者空間頁表和核心空間頁表。
使用者空間頁表映**位址0x0000 0000到0xc000 0000的空間,即為task_size的大小。然後
#define user_ptrs_per_pgd (task_size/pgdir_size)=0xc0000000/0x20 0000 =0x600=1536
核心空間的頁表映**位址0xc000 0000到0xffff ffff的空間,為1g,然後
0x40000000/pgdir_size=0x4000 0000/0x20 0000 = 512,
所以頁表的項數共為1536+512 =2048項。
考慮到硬體的位址對映,pgd實際為12位,即只需要右移20位,而不是21位,pgdir_shift的數值,所以實際上頁表的項數實際應該為20482的4096個項數,然後每項為4個位元組,最後與上文分配的16k位址對應起來,即40964bytes=16k.
三. 引導**的核心頁表分配
linux-2.6的s3c2410上,當系統啟動的時候,核心頁表的位址是0x3000 4000, 核心的載入位址是0x3000 8000,所以核心頁表的最大空間是0x4000,4位元組,也為16k。
#define config_page_offset 0xc000 0000
#definepage_offset ul(config_page_offset)
#definekernel_ram_vaddr (page_offset +text_offset)
#definepg_dir_size 0x4000
空閒程序的頁表初始化在引導**的彙編中實現,__create_page_tables
四. 程序核心空間頁表的分配
上面已經討論了程序頁表分為使用者空間頁表和核心空間頁表,當程序建立的時候會把
new_pgd = __pgd_alloc();
if (!new_pgd)
goto no_pgd;
memset(new_pgd, 0, user_ptrs_per_pgd *sizeof(pgd_t));
/** copy over the kernel and io pgd entries
*/init_pgd = pgd_offset_k(0);
memcpy(new_pgd + user_ptrs_per_pgd,init_pgd + user_ptrs_per_pgd,
(ptrs_per_pgd - user_ptrs_per_pgd) *sizeof(pgd_t));
#definepgd_index(addr) ((addr)>> pgdir_shift)
#definepgd_offset(mm, addr) ((mm)->pgd +pgd_index(addr))
#definepgd_offset_k(addr) pgd_offset(&init_mm,addr)
memcpy()函式中引數的解析
#defineptrs_per_pgd 2048,總的頁數(暫時這麼說)。
#defineuser_ptrs_per_pgd (task_size /pgdir_size) 1536
核心頁表和程序頁表
初學核心時,經常被 核心頁表 和 程序頁表 搞暈,不知道這到底是個啥東東,跟我們平時理解的頁表有和關係 核心頁表 程序頁表 每個程序自己的頁表,放在程序自身的頁目錄task struct.pgd中。在保護模式下,從硬體角度看,其執行的基本物件為 程序 或執行緒 而定址則依賴於 程序頁表 在程序排程而...
Linux核心頁表初始化
linux在核心啟動過程中start kernel setup arch會呼叫如下兩個函式對頁表進行初始化和建立。static inline void prepare page table void 由於arm採用兩級對映,pmd不占用字段,pmd pgd,而這裡一次清了兩個pgd,和pgd的定義正...
關於使用者程序頁表和核心頁表
普通使用者程序的頁表也是存在核心空間的。這很容易理解,畢竟頁表沒有vma來對應。在應用程序建立的時候,task struct m struct描述記憶體資訊,mm gpd指定頁表基位址。頁表的分配是通過呼叫核心夥伴演算法介面分配到物理記憶體,核心在啟動階段已經建立了核心頁表,使用者程序的頁表可以分為...