xv6, line by line
tour 48
Tours48 Breaking the invariants

Tour 48 · The dance of privilege · about 29 minutes · 18 steps

Breaking the invariants

The transitions of this group work because a handful of rules hold at every instant: a lock here, interrupts off there, a page mapped twice, a register copied before it can be lost. The code states some of them as panic checks and leaves others implicit. Each is load-bearing: remove it, and something specific breaks.

This tour does not ask you to take that on faith. For each rule we show the code that keeps it, then break it in a scratch copy of xv6, boot that copy in QEMU on three harts, run usertests (or a single test), and report exactly what happened: the console output, and where gdb found each hart afterwards. Some breaks crash at once, some corrupt silently, and one did not reproduce at all. All results are from our runs of this build; a rerun may land differently where we say so.

The last steps turn to beliefs rather than code: common misconceptions about this dance, each checked against the source and the measurements of earlier tours.

Best after: 13. swtch and the lock handed across a context switch, 41. Every transition: mode, stack and page table, 44. One interrupt, three landing sites, 45. One complete time slice on three harts, 47. Where a suspended process lives

Who is running where

Every experiment starts from the same place: a fresh copy of the source tree and a fresh disk image, one change, three harts.

Hart What it is doing
0 Booting, then running whatever the scheduler gives it
1 The same
2 The same

The unmodified kernel is the control: in our run it passed usertests -q on three harts (ALL TESTS PASSED).

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. 1Invariant 1: interrupts are off across swtch kernel/proc.c
  2. 2Break 1, and the panic it produces kernel/proc.c
  3. 3Invariant 2: exactly one lock across swtch kernel/sysproc.c
  4. 4Break 2b, with the check removed too kernel/trap.c
  5. 5Invariant 3: the trampoline at one address in both page tables kernel/vm.c
  6. 6Why that fault can never be handled kernel/proc.c
  7. 7Invariant 4: sepc is saved before interrupts come back on kernel/trap.c
  8. 8How a one-instruction window was hit every time kernel/trap.c
  9. 9Invariant 5: stvec matches what the hart is doing kernel/trap.c
  10. 10Two ways to die in the wrong handler kernel/trampoline.S
  11. 11Invariant 6: the scheduler stands on a stack no process owns kernel/main.c
  12. 12Break 6, and three harts on one stack kernel/proc.c
  13. 13Invariant 7: started publishes the kernel with release and acquire kernel/main.c
  14. 14Break 7: fifty boots, no failure kernel/main.c
  15. 15Myth: the hardware switches the page table, or the stack kernel/trampoline.S
  16. 16Myth: swtch is a big, privileged operation kernel/swtch.S
  17. 17Myth: each process has its own kernel page table and allocates its kernel stack kernel/proc.c
  18. 18What broke, and how loudly kernel/proc.c

Keys: ← → step · Home start