How x86-64 turns a virtual address into physical RAM: segmentation (flat model) vs paging, the 4-level page-table walk & PTE flags, per-process page tables & isolation, the TLB (flushes, shootdowns, huge pages), the user/kernel address-space split & KPTI, and NUMA nodes/zones.
How the CPU turns an address in your program into a physical byte in RAM — the foundation everything else (paging, process isolation, the page cache) builds on. This is an original, interview-focused tour of x86-64 memory addressing as Linux uses it.
Three address spaces: a logical/virtual address (what your code sees) → the MMU walks page tables → a physical address in RAM. The TLB caches recent translations so this isn't done from scratch every access.
On x86-64, a 48-bit virtual address is translated through a 4-level page table (5 levels with LA57). Each level indexes a table; the final entry (PTE) gives the physical frame + flags:
virtual addr → PGD → PUD → PMD → PTE → physical frame + offset
(Linux names: pgd → p4d → pud → pmd → pte)
PTE flags: Present, R/W, User/Supervisor, Accessed, Dirty, NX (no-execute), Global
mm->pgd),
so the same virtual address maps to different physical memory in different processes — that's
isolation. A context switch loads the new page-table root (CR3).Walking 4 levels per access would be ruinous, so the MMU caches translations in the TLB. A hit is ~1 cycle; a miss triggers the walk. Consequences you should know:
invlpg, or a full flush on
CR3 reload) — expensive; cross-CPU flushes are TLB shootdowns (IPIs).| Region | x86-64 |
|---|---|
| User space | Lower canonical half (per-process, isolated) |
| Kernel space | Upper canonical half — includes a direct map of all physical RAM (fast phys↔virt), vmalloc area, etc. |
Every process shares the same kernel mapping (so a syscall doesn't switch page tables), but user mappings are private. KPTI (Meltdown mitigation) partly breaks that sharing by unmapping most of the kernel while in user mode.
struct page array. On NUMA it's split into
nodes (per-socket memory), each into zones (DMA, DMA32, Normal, Movable) for
allocation constraints.