127 / 163 · C11 · 8 min
Complete VM Systems
Using VAX/VMS and Linux as concrete examples, this chapter shows how page-table designs, TLB handling, page replacement and extra features for performance, security and functionality are combined into a complete virtual-memory system that works from embedded devices to supercomputers.
In this lesson
Problems a Complete VM System Must Solve
Page tables, TLBs and replacement algorithms are only the foundation. A complete system must also cope with wildly different hardware, let the kernel touch user data easily, help debugging and keep strong isolation. Early VAX/VMS already used software tricks to hide hardware flaws; those ideas still appear in Linux today.
VAX Tiny Pages and How Page Tables Were Compressed
512-byte pages would give every process a linear page table of tens of millions of entries. VAX divided the 32-bit space into P0, P1 and system segments so only two user page tables cover the regions actually used. Even better, those two page tables live in the kernel’s own virtual address space and can be paged out when memory is tight.
Null-Pointer Detection and Shared Kernel Mapping
Page 0 of the address space is marked invalid so a null pointer faults at once. Kernel code and data appear in the high addresses of every process; the system-segment registers stay unchanged across a context switch. Hardware protection bits guarantee that user code cannot read or write kernel pages, letting the kernel act like a protected shared library.
Pitfalls
- Underestimating how large page tables become with tiny pages, so memory is eaten by the tables themselves
- Leaving the kernel unmapped from user space, making it painful to copy user buffers during system calls
- Forgetting to invalidate page 0, so null-pointer errors silently corrupt memory instead of being caught immediately
Run an example
Minimum C11 · complete program · Download .c
#include <stdio.h>
#include <stdint.h>
int main(void) {
printf("VAX-like 32-bit address space simulation (512-byte pages)\n");
printf("VPN = VA >> 9 (23 bits); segment from top 2 bits of VPN\n\n");
const uint32_t examples[7] = {
0x00000000u,
0x00001000u,
0x3FFFFFFFu,
0x40000000u,
0x7FFFFFFFu,
0x80000000u,
0xC0000000u
};
const char *names[7] = {
"null page",
"user code",
"end of P0 heap",
"start of P1 stack",
"end of P1",
"kernel start",
"unused"
};
for (int i = 0; i < 7; i++) {
uint32_t va = examples[i];
uint32_t offset = va & 0x1FFu;
uint32_t vpn = va >> 9;
uint32_t seg = (vpn >> 21) & 3u;
const char *segname;
switch (seg) {
case 0: segname = "P0 (process)"; break;
case 1: segname = "P1 (process)"; break;
case 2: segname = "S (system)"; break;
default: segname = "unused"; break;
}
printf("VA=0x%08X VPN=%7u off=%3u seg=%s [%s]%s\n",
va, vpn, offset, segname, names[i],
(va < 512 ? " INVALID" : ""));
}
printf("\nNote: page 0 is marked invalid to catch null-pointer bugs.\n");
printf("Kernel (S) is mapped in every process for easy pointer passing.\n");
return 0;
}
Compile locally
gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-23-complete-vm.c -o example && ./exampleExpected result
VAX-like 32-bit address space simulation (512-byte pages)
VPN = VA >> 9 (23 bits); segment from top 2 bits of VPN
VA=0x00000000 VPN= 0 off= 0 seg=P0 (process) [null page] INVALID
VA=0x00001000 VPN= 8 off= 0 seg=P0 (process) [user code]
VA=0x3FFFFFFF VPN=2097151 off=511 seg=P0 (process) [end of P0 heap]
VA=0x40000000 VPN=2097152 off= 0 seg=P1 (process) [start of P1 stack]
VA=0x7FFFFFFF VPN=4194303 off=511 seg=P1 (process) [end of P1]
VA=0x80000000 VPN=4194304 off= 0 seg=S (system) [kernel start]
VA=0xC0000000 VPN=6291456 off= 0 seg=unused [unused]
Note: page 0 is marked invalid to catch null-pointer bugs.
Kernel (S) is mapped in every process for easy pointer passing.
CHECK YOUR UNDERSTANDING
Close the answer. Explain it.
Why did VAX place user page tables in kernel virtual memory rather than physical memory? What extra benefit does this give?
Show a reference answer
The page tables themselves can then be swapped to disk, freeing physical frames for real user data under pressure. The kernel can also access those tables with ordinary virtual addresses, simplifying the implementation.
Check the sources
Drafts and official chapters change. The version mark is only the example’s minimum.