C++ / a working model

127 / 163   ·   C11   ·   8 min

Complete VM Systems

Keep this sentence

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
  1. Problems a Complete VM System Must Solve
  2. VAX Tiny Pages and How Page Tables Were Compressed
  3. Null-Pointer Detection and Shared Kernel Mapping
  4. Example
  5. Exercise

Official chapter PDF

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 && ./example

Expected 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.

Back to the catalog