首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ARM上的walkup页表

ARM上的walkup页表
EN

Stack Overflow用户
提问于 2016-10-06 10:23:11
回答 1查看 872关注 0票数 0

我试图模仿arm平台的函数lookup_address(http://lxr.free-electrons.com/source/arch/x86/mm/pageattr.c#L373) (以及内核可分页)。

关键是我从TTBR1那里得到了TTBR1的地址,到目前为止还在工作。我和gdb查过了:

代码语言:javascript
复制
(gdb) file vmlinux
Reading symbols from vmlinux...done.
(gdb) p init_mm.pgd
$1 = (pgd_t *) 0xc0004000
(gdb)

我模块里的代码是:

代码语言:javascript
复制
 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;
}

以及产出:

代码语言:javascript
复制
bananapi kernel: [ 5665.358139] mod: get_global_pgd: c0004000

到目前为止这是匹配的。现在,我正在计算右pgd的地址,执行:

代码语言:javascript
复制
pgd = get_global_pgd() + pgd_index (addr);

由于(addr >> 21)是0x600,我得到0xc0007000。然后我继续说:

代码语言:javascript
复制
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);

产出:

代码语言:javascript
复制
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处获得一个地址:

代码语言:javascript
复制
c0008054 t __create_page_tables

我可以从gdb那里读到:

代码语言:javascript
复制
(gdb) x/2x 0xc0008054
0xc0008054 <__create_page_tables>:  0xe2884901  0xe1a00004
(gdb)

但是我从这个地址得到的pte没有现在的旗帜:

我正在检查它(这个pte是我从我的lookup_address上得到的):

代码语言:javascript
复制
ret = pte_present (*pte);
pr_info ("pte_present: %d\n", ret);

pte_present是0(检查定义的L_PTE_PRESENT标志包含/asm/pgtable-2 long .h),但只要我能在GDB中读取,就不应该是0。

我用其他地址进行了测试,例如: 0xc0035618:

代码语言:javascript
复制
c0035618 T __put_task_struct

而对于这一个,L_PTE_PRESENT大号已经设置好了。

我很确定我错过了什么,或者我弄错了。

提前感谢!

EN

回答 1

Stack Overflow用户

发布于 2016-10-10 19:52:03

我已经读过所有的指向链接,但我还是不明白整个情况。我将试着解释我到目前为止所理解的:

在include/asm/pgtable-2 like .h中,它看起来像是一个页面存储:

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

实际上,我在early_pte_alloc函数中也看到了这一点,它为pte分配了4096字节:

代码语言:javascript
复制
     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 ),并使用保护标志(如果来自kernel_domain,则应该是PMD_TYPE_TABLE )。

代码语言:javascript
复制
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 (addr)
  • pud_offset (pgd,addr)
  • pmd_offset (pud,addr)
  • pte_offset_kernel (pmd,addr)

pte_offset_kernel给出存储在pmd中的pmd_val的虚拟地址。(它还使用PHYS_MASK和PAGE_MASK来处理值),并添加pte_index (addr)。此时,我应该具有linux_pte_0的虚拟地址的值(因为前面的带有PAGE_MASK的AND将我带到了页面的顶部)。

因此,我认为此时我应该能够检查L_PTE_*标志。

我说错了吗?

提前感谢

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39893480

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档