2016-10-06 72 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_ *标志。

我错了吗?

在此先感谢