xv6, line by line
tour 24
Tours24 The kernel page table and turning paging on

Tour 24 · Memory · about 31 minutes · 19 steps

The kernel page table and turning paging on

Until now, every address the kernel used went straight to physical memory. That cannot last: user processes need their own private views of memory, kernel stacks need guard pages, and the trampoline must appear at the same address in every address space. All of that needs virtual memory, and virtual memory needs a page table.

This tour watches hart 0 build the kernel’s page table during main, one mapping at a time, with real addresses and real page-table entries read out of memory with gdb. You will see walk allocate the tree’s pages as it goes (each one through kmem.lock), the device registers, kernel code, RAM, the trampoline and 64 kernel stacks being mapped, and then the single csrw satp that switches translation on, first on hart 0, later on harts 1 and 2.

The page table that results is shared by all three harts and is never changed by software again. Understanding why that makes it lock-free, and why each hart must still flush its own TLB (translation lookaside buffer), is the point of the tour.

Best after: 3. main: one hart builds the kernel, the others wait

Who is running where

Hart What it is doing
0 In main, just past kinit: about to call kvminit. Paging off, interrupts off
1 Spinning on started with paging off (Tour 3: main: one hart builds the kernel, the others wait)
2 The same as hart 1

The free-page list holds every page from 0x80021000 to 0x88000000, with 0x87fff000 at its head.

Three harts are running. This tour follows one path through the code, but the machine has three CPUs executing at the same time. Watch the locks held display at the top of each step, and read the Meanwhile, on other harts boxes: they show what the other CPUs could be doing at that very moment.
The route
  1. 1The root of the tree kernel/vm.c
  2. 2How Sv39 splits an address kernel/riscv.h
  3. 3mappages, one page at a time kernel/vm.c
  4. 4walk grows the tree kernel/vm.c
  5. 5Every table page passes through kmem.lock kernel/kalloc.c
  6. 6Devices first kernel/vm.c
  7. 7Kernel code read-execute, everything else read-write kernel/vm.c
  8. 8The trampoline, mapped twice kernel/vm.c
  9. 964 kernel stacks with guard pages kernel/proc.c
  10. 10The finished table kernel/memlayout.h
  11. 11Building the value for satp kernel/riscv.h
  12. 12The fence before the switch kernel/vm.c
  13. 13The instant paging turns on kernel/vm.c
  14. 14Flushing hart 0's TLB kernel/vm.c
  15. 15Harts 1 and 2 are let in, still with paging off kernel/main.c
  16. 16Harts 1 and 2 load the same table kernel/vm.c
  17. 17One table, three walkers, no lock kernel/vm.c
  18. 18Every trap comes back to this table kernel/trap.c
  19. 19What it cost, and what it bought kernel/vm.c

Keys: ← → step · Home start