Describe the role of the page table entry (PTE) in a page table

Describe the role of the page table entry (PTE) in a page table

If you zoom all the way into the machinery of virtual memory, past the TLB, past the multi-level page table structure, you eventually land on the smallest meaningful unit of the whole system: the Page Table Entry, or PTE. Every single virtual-to-physical mapping in a running system ultimately comes down to one of these small structures. I want to go through exactly what a PTE contains, how it’s used, and why its individual bits matter far more than their small size suggests.

Where the PTE Sits in the Page Table Hierarchy

On x86-64 Linux, address translation walks through up to four (or five, with 5-level paging on newer hardware) levels of tables before reaching the actual page frame:

PGD (Page Global Directory)
   -> PUD (Page Upper Directory)
       -> PMD (Page Middle Directory)
           -> PTE (Page Table Entry)   <-- final level
               -> Physical page frame

Every level above the PTE is really just a table of pointers to the next level down. The PTE is the only one that actually points to real data memory rather than to another table (with the exception of hugepage entries, discussed below, which terminate the walk one or two levels early). It’s the final, authoritative answer to “where does this virtual page actually live in physical RAM, and what am I allowed to do with it.”

What’s Inside a PTE

A PTE is typically a single machine word (64 bits on x86-64), tightly packed with both the physical frame address and a set of control bits. The exact layout is architecture-specific, but on x86-64 it looks roughly like this:

 63     62  ...  12   11 ... 9    8   7   6   5   4   3   2   1   0
+----+-------------+---------+---+---+---+---+---+---+---+---+---+
| NX | Physical     | Avail   |G  |PAT|D  |A  |PCD|PWT|U/S|R/W|P  |
|    | Frame Number |(for OS) |   |   |   |   |   |   |   |   |   |
+----+-------------+---------+---+---+---+---+---+---+---+---+---+

The key fields worth knowing:

Why the Accessed and Dirty Bits Matter So Much

These two bits deserve special attention because they quietly enable some of the most important memory management decisions the OS makes, entirely in hardware, with zero software overhead per access.

Without the Accessed bit, the OS would have no cheap way to know which pages are being actively used and which are sitting idle — information it desperately needs to decide what to evict under memory pressure. Instead of trapping every memory access (which would be catastrophically slow), the CPU silently sets this bit whenever it walks a PTE to satisfy an access. The OS periodically scans and clears these bits, and pages that get re-marked “accessed” between scans are considered hot; pages that stay untouched are strong eviction candidates. This is the hardware foundation underneath Linux’s active/inactive LRU-ish page reclaim lists.

Without the Dirty bit, the OS would have to assume every resident page might have been modified, forcing it to write every evicted page back to disk/swap even if it was never actually changed — hugely wasteful for read-only or unmodified pages. The Dirty bit lets the kernel skip that write-back entirely for clean pages, which is a meaningful I/O savings on any real workload.

PTEs and Hugepages

Normally, the walk goes all the way down to a PTE describing a single 4KB page. But architectures supporting large pages let a PMD (or even PUD) entry directly describe a mapping to a large contiguous physical region — 2MB at the PMD level, 1GB at the PUD level on x86-64 — terminating the walk one or two levels early and skipping the PTE level entirely for that mapping. This is exactly how hugepages reduce TLB pressure: one PMD-level “PTE-equivalent” entry now covers 512 times the address space a standard PTE would, meaning far fewer entries are needed to map a large working set, and far fewer TLB misses occur as a result.

How the OS Manipulates PTEs

The kernel doesn’t just read PTEs passively — huge amounts of memory management logic boil down to setting, clearing, or checking specific PTE bits:

PTEs on Other Platforms

The concept is universal even though the exact bit layout differs:

Troubleshooting and Inspection

Best Practices

Summary

The Page Table Entry is deceptively small — a single machine word on most architectures — but it’s the actual, final source of truth for every virtual memory mapping in the system: where a page physically lives, whether it’s present, what’s allowed to touch it, and whether it’s been read or written recently. Nearly every high-level virtual memory feature you’d recognize — copy-on-write, swapping, memory protection, page reclaim, hugepages — ultimately comes down to the OS reading or manipulating specific bits within these entries. Small structure, enormous responsibility.

FAQs

What information does a PTE actually store? A physical frame number plus control bits: present/valid, read/write permission, user/supervisor access level, accessed, dirty, cacheability, and no-execute, among others (exact layout is architecture-specific).

What is the Accessed bit used for? It lets the CPU mark, in hardware and with no extra overhead, which pages have been recently touched, giving the OS the information it needs to decide what to evict under memory pressure without trapping every access.

How do hugepages relate to PTEs? Hugepages let a higher-level table entry (PMD or PUD) directly describe a large contiguous mapping, terminating the page table walk before reaching the PTE level and covering far more address space per entry, reducing TLB pressure.

Does every operating system use the same PTE format? No — the format is defined by the CPU architecture (x86-64, ARM, etc.), not the OS, though every format serves the same conceptual purpose: physical address plus permission and status bits.

References

Exit mobile version