xv6, line by line
tour 10
Tours10 Exceptions and faults

Tour 10 · Traps and system calls · about 39 minutes · 22 steps

Exceptions and faults

A system call is a trap the program asks for. An exception is a trap the program did not ask for: it touched memory it has no page for, wrote to its own code, or executed an instruction it is not allowed to execute. The hardware stops the instruction halfway, records what went wrong in three CSRs, and jumps into the kernel. The kernel then has exactly three choices: fix the problem and retry the instruction, kill the process, or, if the faulting code was the kernel itself, stop the whole machine.

This tour shows all three, using real programs and real numbers from runs of this build (scenes 1–2) and of a scratch copy we modified (scenes 3–4):

  1. usertests lazy_alloc asks for a gigabyte with sbrklazy and then stores into it. Each first touch of a page is a page fault that vmfault quietly repairs.
  2. usertests nowrite stores into its own read-only code page. The fault cannot be repaired, so the kernel prints usertrap(): unexpected scause 0xf and kills the child.
  3. A test program we added to a scratch copy (it is not in xv6) executes csrr mhartid, a machine-mode instruction, and is killed for an illegal instruction.
  4. A bug we deliberately planted in a scratch copy of the kernel (not in xv6’s source) makes the kernel itself read address 0. That ends in panic: kerneltrap, and we watch what the panic does to the other two harts.

The trap entry itself (trampoline, trapframe, usertrap's first lines) is covered by Tour 5: Life of a system call and Tour 7: The trampoline and the trapframe. Here we go deeper into what happens after scause says “this was not a system call”.

Best after: 5. Life of a system call, 7. The trampoline and the trapframe

Who is running where

The machine has three harts. The four faults come from separate runs; for the first one, in the run we traced with gdb:

Hart What it is doing
0 Idle in its scheduler (init and sh are asleep in wait), or running whatever is runnable
1 Running pid 4, the child that usertests forked to run lazy_alloc: the process we follow first
2 Idle in its own scheduler, or running whatever else is runnable

usertests itself (pid 3) is asleep in kwait, waiting for pid 4. Later scenes move to hart 2 (the nowrite children and the kernel fault) and back to hart 0 (a hart that is caught printing during a panic, in a hypothetical scene).

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. 1lazy_alloc asks for a gigabyte it will barely use user/usertests.c
  2. 2sys_sbrk only moves the size kernel/sysproc.c
  3. 3The store that the hardware refuses user/usertests.c
  4. 4usertrap, the path not taken by system calls kernel/trap.c
  5. 5vmfault decides whether the fault is legitimate kernel/vm.c
  6. 6ismapped looks without touching kernel/vm.c
  7. 7kalloc takes a page from the shared free list kernel/kalloc.c
  8. 8Zero the page, then map it kernel/vm.c
  9. 9mappages writes one PTE kernel/vm.c
  10. 10Return without advancing, and the store runs again kernel/trap.c
  11. 114096 faults later user/usertests.c
  12. 12nowrite stores into its own code user/usertests.c
  13. 13vmfault says no, and usertrap says so kernel/trap.c
  14. 14printk serializes the two lines, and only per call kernel/printk.c
  15. 15setkilled marks the process, under its lock kernel/proc.c
  16. 16kexit, with status -1 kernel/proc.c
  17. 17An illegal instruction takes the same road kernel/trap.c
  18. 18A bug in the kernel reads address 0 kernel/sysproc.c
  19. 19kerneltrap has no repair to offer kernel/trap.c
  20. 20panic sets two flags and never returns kernel/printk.c
  21. 21Other harts freeze the moment they print kernel/uart.c
  22. 22Three outcomes of one question kernel/trap.c

Keys: ← → step · Home start