2016-10-06 101 views
0

我試圖爲arm平臺(僅針對內核頁表)模擬函數lookup_address(http://lxr.free-electrons.com/source/arch/x86/mm/pageattr.c#L373)。在ARM上跳轉頁表

重點是我從TTBR1獲取swapper_pg_dir的地址,到目前爲止這工作。 我用gdb檢查了它:

(gdb) file vmlinux 
Reading symbols from vmlinux...done. 
(gdb) p init_mm.pgd 
$1 = (pgd_t *) 0xc0004000 
(gdb) 

,並從我的模塊代碼:

static pgd_t *get_global_pgd (void) 

{ 
     pgd_t *pgd; 
     unsigned int ttb_reg; 

     asm volatile (
     "  mrc  p15, 0, %0, c2, c0, 1" 
     : "=r" (ttb_reg)); 

     ttb_reg &= TTBR_MASK; 
     pgd = __va (ttb_reg); 
     pr_info ("get_global_pgd: %p\n", pgd); 

     return pgd; 
} 

和輸出:

bananapi kernel: [ 5665.358139] mod: get_global_pgd: c0004000 

到目前爲止,這是匹配。 現在我計算正確的PGD的地址,這樣做的:

pgd = get_global_pgd() + pgd_index (addr); 

而且,由於(地址>> 21)是0x600,我得到0xc0007000。 然後我繼續:

pud = pud_offset (pgd, addr); 
pr_info ("pud: 0x%0x - %p\n",pud_val (*pud), pud); 
pmd = pmd_offset (pud, addr); 
pr_info ("pmd: 0x%0x - %p\n", pmd_val (*pmd), pmd); 
if (pmd == NULL || pmd_none (*pmd)) { 
     return NULL; 
} 
return pte_offset_kernel (pmd, addr); 

輸出:

bananapi kernel: [ 5665.390391] mod: pud: 0x4001140e - c0007000 
bananapi kernel: [ 5665.401603] mod: pmd: 0x4001140e - c0007000 
bananapi kernel: [ 5665.423838] mod: pte: 0xe59f119c - c0011020 

的問題是,我得到的PTE似乎並沒有被罰款,因爲該PTE的屬性不匹配。 讓我們的地址從/ proc/kallsyms:

c0008054 t __create_page_tables 

我可以使用gdb閱讀:

(gdb) x/2x 0xc0008054 
0xc0008054 <__create_page_tables>: 0xe2884901 0xe1a00004 
(gdb) 

但是我從這個地址獲得PTE,不具有本旗:

我與檢查它(PTE是一個我從我的lookup_address了):

ret = pte_present (*pte); 
pr_info ("pte_present: %d\n", ret); 

pte_present是0(它檢查L_PTE_PRESENT標誌定義的include/asm/pgtable-2level.h),但只要我可以在GDB中讀取它就不應該爲0。

我已經與其他一些測試的地址,例如:0xc0035618:

c0035618 T __put_task_struct 

而對於這一個L_PTE_PRESENT大設置。

我很確定我錯過了什麼,或者我錯了。

提前致謝!

+0

'L_ *'屬性是Linux特有的,不一定是硬件。這裏已經有很多關於ARM Linux [爲這些維護第二組影子頁表的問題]的問題(http://lxr.free-electrons.com/source/arch/arm/include/asm/pgtable-2level)。 H)。 – Notlikethat

+0

是的,我知道。實際上我認爲ARM不提供這些位,所以linux必須通過添加這些位來解決它。但是,當頁面錯誤被觸發時,Linux正在檢查這些位,所以我認爲它們是正確的。謝謝 – leberus

+0

[ARM表的內核中的[頁表入口(PTE)描述符的可能的重複](http://stackoverflow.com/questions/16909101/page-table-entry-pte-descriptor-in-linux-kernel-for- arm) –

回答

0

我已閱讀所有尖銳的鏈接,但我失敗了,我仍然沒有得到整個圖片。 我會盡力解釋我到目前爲止所瞭解的內容:

from include/asm/pgtable-2level。h時,它看起來像一個頁面存儲:

  • 0 - pte1_linux
  • 1024 - pte2_linux
  • 2048 - pte1_hw
  • 3072 - pte2_hw

其實我也看到了這一點early_pte_alloc功能,其爲pte分配4096字節:

 static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot) 

    { 
     if (pmd_none(*pmd)) { 
       pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); 
       __pmd_populate(pmd, __pa(pte), prot); 
     } 
     BUG_ON(pmd_bad(*pmd)); 
     return pte_offset_kernel(pmd, addr); 
} 

然後,在__pmd_populate中,我們取先前分配的內存的phys地址,我們添加2048(對於hw pte),並且我們或者使用保護標誌(它來自kernel_domain的情況下應該是PMD_TYPE_TABLE)。

static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte, 
            pmdval_t prot) 
{ 
     pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot; 
     pmdp[0] = __pmd(pmdval); 
#ifndef CONFIG_ARM_LPAE 
     pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t)); 
#endif 
     flush_pmd_entry(pmdp); 
} 

到目前爲止很清楚。 鑑於這一信息,行走頁面應該是這樣的:

  • pmd_offset_k(地址)
  • pud_offset(PGD,地址)
  • pmd_offset(PUD,地址)
  • pte_offset_kernel(PMD,地址)

pte_offset_kernel給出存儲在pmd中的pmd_val的虛擬地址。 (它也與PHYS_MASK和PAGE_MASK的值相和),並添加pte_index(addr)。 在這一點上,我應該有linux_pte_0的虛擬地址的值(因爲與PAGE_MASK的以前的AND帶我到頁面的頂部)。

所以我認爲在這一點上,我應該能夠檢查L_PTE_ *標誌。

我錯了嗎?

在此先感謝