On 7/13/26 17:38, Arnd Bergmann wrote:
> On Mon, Jul 13, 2026, at 15:55, Yeoreum Yun wrote:
>> From: "David Hildenbrand (Arm)" <[email protected]>
>>
>> We don't want pgd_t to be an array, as it prohibits returning it from a
>> function, like pgdp_get().
> 
> What should pgdp_get() return on ARM 2-stage page tables then?
> Does it return just the first entry or concatenate the two?

It is rather obscure what we do (below).

This patch tries to keep the existing behavior.

> 
>> +typedef u64 pgdval_t;
> 
>> +static inline pmdval_t pgd_val(pgd_t pgd)
>> +{
>> +    return (*(pmdval_t (*)[2])&pgd)[0];
>> +}
> 
> This could use a comment to explain what this actually
> returns and why the second entry is discarded.

It's rather crazy. We have two page table levels, but fake that we have 3.


There is some documentation in arch/arm/include/asm/pgtable-2level.h

/*
 * Hardware-wise, we have a two level page table structure, where the first
 * level has 4096 entries, and the second level has 256 entries.  Each entry
 * is one 32-bit word.  Most of the bits in the second level entry are used
 * by hardware, and there aren't any "accessed" and "dirty" bits.
 *
 * Linux on the other hand has a three level page table structure, which can
 * be wrapped to fit a two level page table structure easily - using the PGD
 * and PTE only.  However, Linux also expects one "PTE" table per page, and
 * at least a "dirty" bit.
 *
 * Therefore, we tweak the implementation slightly - we tell Linux that we
 * have 2048 entries in the first level, each of which is 8 bytes (iow, two
 * hardware pointers to the second level.)  The second level contains two
 * hardware PTE tables arranged contiguously, preceded by Linux versions
 * which contain the state information Linux needs.  We, therefore, end up
 * with 512 entries in the "PTE" level.
 *
 * This leads to the page tables having the following layout:
 *
 *    pgd             pte
 * |        |
 * +--------+
 * |        |       +------------+ +0
 * +- - - - +       | Linux pt 0 |
 * |        |       +------------+ +1024
 * +--------+ +0    | Linux pt 1 |
 * |        |-----> +------------+ +2048
 * +- - - - + +4    |  h/w pt 0  |
 * |        |-----> +------------+ +3072
 * +--------+ +8    |  h/w pt 1  |
 * |        |       +------------+ +4096
 *

So we interpret two 32bit entries as a pair (64bit value). Together they span
2x256 values.

Then we make PTRS_PER_PTE = 512, to iterate all of them (both pairs).

Let me do some more digging to come up with something I can confidentially
document here ... maybe I'll just refer to the comment in pgtable-2level.h.

-- 
Cheers,

David

Reply via email to