[Elinux-discuss] doubt regarding page tables layout on arm

Oscar Salvador osalvador.vilardaga at gmail.com
Tue Oct 11 10:38:15 UTC 2016


Hi all,

I'm writing here because after been reading a lot of papers regarding this
topic, I still can't get the point with it.
Let me explain it:

I'm writing a module, and within this module I'm trying to emulate the
lookup_address from x86, but on arm.

I'm getting the value of swapper_pg_dir through the TTBR1 (which is the
same value I get if I try to print the memory address of swapper_pg_dir
with GDB).

Then, since I'm working on arm32 without LPAE, Linux is just using PMD (pgd
and pud are gone).

As it explains here: include/asm/pgtable-2level.h
The layout pte page tables looks like:

- linux_pte_0
- linux_pte_1
- arm_pte_0
- arm_pte_1

That's within a page.

linux_pte_* are being used in order that linux can check for dirty/young
bits since ARM does not provide such bits.

When creating the mappings through __create_mapping function, we set up the
page table permissions of arm page tables depending of the permissions this
type of memory has (this flags are being set in static struct mem_type
mem_types[]).

For example:

In function alloc_init_pte we call arm_pte_alloc in order:

- Allocate PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE bytes (4096bytes)
- populate pmd with (function __pmd_populate):
       - physical memory of space allocated before + PTE_HWTABLE_OFF
(2048bytes) | protecion_bits
        - this ends up with: pmdval of this pmd stores:
physical_address_of_arm_pte|protection_bits

code from __pmd_populate:

 pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot;
 pmdp[0] = __pmd(pmdval);

Once this is done, arm_pte_alloc returns with pte_offset_kernel, which does
this steps:

 - ANDs the value of this pmd with PHYS_MASK && PAGE_MASK
 - return the virtual address of the value stored before (returns vaddrr of
the top of page=
 - adds virtual_address of this page + pte_index (addr)

Once this is done, the arm page tables permissions are being set with:

set_pte_ext function, that in my case is going to call cpu_v7_set_pte_ext
function from mm/proc-v7-2level.S.
There r3 is being set depending of L_PTE_* bits, and then r3 is being
written in linux_pte + 2048 (whete it points the arm_pte).

Given this explanation I'll what I'm doing:

Let's say I want to get the pte of X (X is a linear address)

pgd = get_global_pgd_from_ttbr1 (same value as swapper_pg_dir)
pgd += pgd_index (X)
pud = pud_offset (pgd, X)
pmd = pmd_offset (pud, X)

At this point, pmd should contain: (pte + PTE_HWTABLE_OFF) | prot  (since
it was populated with this value).

Then:

pte = pte_offset_kernel (pmd, X) (gets virtual address of pmd_val masked
with PHYS_MASK && PAGE_MASK and adds it the pte_index (X))

Here I should get a pointer of the pte related to X address, and since I
points to the top (where Linux PTE are), I should be able to check L_PTE_
bits, but I'm afraid i'm getting weird values here.


I hope I could explain my question as clear as I wanted.

Thank you very much
Oscar Salvador
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.elinux.org/pipermail/elinux-discuss/attachments/20161011/00d479cd/attachment.html>


More information about the Elinux-discuss mailing list