I'm trying to emulate the function lookup_address(http://lxr.free-electrons.com/source/arch/x86/mm/pageattr.c#L373) for arm platform (and just for kernel pagetables).
The point is I'm getting the address of swapper_pg_dir from TTBR1, and so far that's working. I checked it with gdb:
(gdb) file vmlinux
Reading symbols from vmlinux...done.
(gdb) p init_mm.pgd
$1 = (pgd_t *) 0xc0004000
(gdb)
and the code from my module:
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;
}
and the output:
bananapi kernel: [ 5665.358139] mod: get_global_pgd: c0004000
So far, this is matching. Now I'm computing the addr of the right pgd, doing:
pgd = get_global_pgd() + pgd_index (addr);
And since (addr >> 21) is 0x600, I get 0xc0007000. Then I continue with:
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);
output:
bananapi kernel: [ 5665.390391] mod: pud: 0x4001140e - c0007000
bananapi kernel: [ 5665.401603] mod: pmd: 0x4001140e - c0007000
bananapi kernel: [ 5665.423838] mod: pte: 0xe59f119c - c0011020
The problem is that the pte I get seems not to be fine, because the attributes of the pte don't match. Let's take an address from /proc/kallsyms:
c0008054 t __create_page_tables
I can read it with gdb:
(gdb) x/2x 0xc0008054
0xc0008054 <__create_page_tables>: 0xe2884901 0xe1a00004
(gdb)
But the pte I get from this address, doesn't have the present flag:
I'm checking it with (this pte is the one I got from my lookup_address):
ret = pte_present (*pte);
pr_info ("pte_present: %d\n", ret);
The pte_present is 0 (which checks L_PTE_PRESENT flag defined include/asm/pgtable-2level.h), but shoudln't be 0 as long as I can read from it in GDB.
I've tested with some other addresses, for instance: 0xc0035618:
c0035618 T __put_task_struct
And for this one the L_PTE_PRESENT big is set.
I'm pretty sure I'm missing something, or I got it wrong.
Thanks in advance!