On Mon, Aug 25, 2025 at 2:12 AM Marc Zyngier maz@kernel.org wrote:
So: where do the terms P4D, PUD, and PMD fit in here? And which one's our missing fencepost? PGD ----> ??? ----> ??? ----> ??? ----> ??? ----> PTE (|| low VA bits = final PA)
I'm struggling to see what you consider a problem, really. For me, the original mistake is that you seem to have started off the LSBs of the VA, instead of the MSBs.
Right; I did my example MMU walk in reverse to start with the levels that are never folded and work my way up to the PGD level, since I was trying to deduce PTRS_PER_PGD, essentially.
As for the ultimate source of my confusion, it's best explained in this paragraph from the paging documentation [0] (emphasis my own):
The entry part of the name is a bit confusing because while in Linux 1.0 this did refer to a single page table entry in the single top level page table, it was retrofitted to be an array of mapping elements when two-level page tables were first introduced, ***so the pte is the lowermost page table, not a page table entry.***
As I see it, this creates a habit of using the names for the table entries and the tables themselves interchangeably. Kernel folk who don't work on the MM subsystem much (like myself) don't share this habit. So when I say something like "an 'array of PGDs' is nonsense," I mean "an 'array of top-level page tables' is an oxymoron: if there's an array of them, they aren't top-level." But someone more seasoned like you thinks I'm saying "array of PGD entries" and asks "What's the problem? That's, tautologically, what the PGD is..."
It's absolutely on me for not thinking to RTFM earlier. Thank you for your patience. In my defense, I don't think there's any way I could have known that "PTE" was a misnomer. The RISC-V team added a few helpful comments in their pgtable*.h that probably helps people encountering these MM terms for the first time through those files. I'm considering sending a patch to clarify the comments on the ARM64 #defines similarly.
I've included a glossary of terms [1] in case this confusion comes up again with somebody else.
I find it much easier to reason about a start level (anywhere from -1 to 2, depending on the page size and the number of VA bits), and the walk to always finish at level 3. The x86 naming is just compatibility cruft that I tend to ignore.
Indeed, I think this is probably what most seasoned ARM people do. People who are first mentally visualizing the tree -- and specifically Linux's intent with the tree -- will probably still be relying on the PxD terms to bootstrap their understanding, however.
Thank you once again for your patience, Sam
[0]: https://docs.kernel.org/mm/page_tables.html [1]: "PTE" A newcomer probably thinks: "Page Table Entry, the final descriptor at the end of an MMU walk." Actual meaning: Bottom-most translation table *OR* an entry of that table. It was once an initialism, but it's taken on a meaning of its own.
"PGD" A newcomer probably thinks: "Page Global Directory, or the pointer thereto -- the thing you find in TTBRn_ELx" Actual meaning: Page Global Directory or the pointer thereto *OR* Page Global Descriptor: an entry of the Page Global Directory, which encodes a pointer to the P4DIR if 5-level translation is enabled, or a lower PxDIR if not.
#define PTRS_PER_PTE A newcomer probably thinks: "Number of frames pointed from a single Page Table Entry (so... er... 1???)" Actual meaning: Number of entries in the "PTE," the final translation table.
#define PGDIR_SIZE A newcomer probably thinks: "Number of bytes of VM represented by one PGDIR." (or even "Number of bytes the top-level page table occupies in memory.") Actual meaning: Number of bytes of VM represented by *one entry* of the PGDIR. The 'DIR' is a misnomer here.
#define PGD_SIZE Actual meaning: Number of bytes the top-level page table occupies in memory. Defined separately from PAGE_SIZE because it may be smaller (never larger).