我试图模仿arm平台的函数lookup_address(http://lxr.free-electrons.com/source/arch/x86/mm/pageattr.c#L373) (以及内核可分页)。
关键是我从TTBR1那里得到了TTBR1的地址,到目前为止还在工作。我和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);由于(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标志包含/asm/pgtable-2 long .h),但只要我能在GDB中读取,就不应该是0。
我用其他地址进行了测试,例如: 0xc0035618:
c0035618 T __put_task_struct而对于这一个,L_PTE_PRESENT大号已经设置好了。
我很确定我错过了什么,或者我弄错了。
提前感谢!
发布于 2016-10-10 19:52:03
我已经读过所有的指向链接,但我还是不明白整个情况。我将试着解释我到目前为止所理解的:
在include/asm/pgtable-2 like .h中,它看起来像是一个页面存储:
实际上,我在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 ),并使用保护标志(如果来自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);
}到目前为止是清楚的。考虑到这些信息,步行页面应该是这样的:
pte_offset_kernel给出存储在pmd中的pmd_val的虚拟地址。(它还使用PHYS_MASK和PAGE_MASK来处理值),并添加pte_index (addr)。此时,我应该具有linux_pte_0的虚拟地址的值(因为前面的带有PAGE_MASK的AND将我带到了页面的顶部)。
因此,我认为此时我应该能够检查L_PTE_*标志。
我说错了吗?
提前感谢
https://stackoverflow.com/questions/39893480
复制相似问题