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