xv6, line by line
tour 5
Tours5 Life of a system call

Tour 5 · Traps and system calls · about 42 minutes · 26 steps

Life of a system call

You type echo hi at the xv6 shell, and two letters appear on your screen. Between those two events, a user program asks the kernel for help, the CPU changes privilege mode twice, two page tables take turns, a process goes to sleep on one CPU and wakes up on another, and a device interrupt is handled by a third.

This tour follows one system call, write(1, "hi", 2), from the moment echo makes it to the moment echo continues with the next line, through every layer of xv6: the user-space system call stub, the trampoline page, usertrap, the system call table, the file layer, the console driver and the UART, and all the way back.

It is the single most important path in the kernel. Almost every other tour is a detour from it.

Best after: 2. Power-on to main, on every hart at once, 4. From the first process to the shell prompt

Who is running where

The machine has three harts. When the tour starts:

Hart What it is doing
0 Its scheduler is looping, looking for something to run
1 Running echo (pid 3) in user mode: the process this tour follows
2 Running whatever else is runnable, or idle in its own scheduler

The shell (pid 2) is asleep in kwait, waiting for echo to finish.

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. 1echo asks for help user/echo.c
  2. 2The stub puts a number in a7 and executes ecall user/usys.S
  3. 3Landing in the trampoline, with the wrong page table kernel/trampoline.S
  4. 4Saving every user register kernel/trampoline.S
  5. 5ld sp: echo's kernel stack, and the kernel's other notes kernel/trampoline.S
  6. 6Switching to the kernel's world kernel/trampoline.S
  7. 7usertrap takes charge kernel/trap.c
  8. 8It is a system call. Turn interrupts back on kernel/trap.c
  9. 9Dispatching through the system-call table kernel/syscall.c
  10. 10sys_write fetches its arguments kernel/sysfile.c
  11. 11From descriptor to open file, without a lock kernel/sysfile.c
  12. 12filewrite dispatches to the console driver kernel/file.c
  13. 13consolewrite copies the bytes in, 32 at a time kernel/console.c
  14. 14copyin walks echo's page table by hand kernel/vm.c
  15. 15Taking the UART's sleep-lock kernel/sleeplock.c
  16. 16Ready? Send. Busy? Register, then sleep kernel/uart.c
  17. 17Going to sleep, holding the right lock kernel/proc.c
  18. 18The UART interrupts, and hart 2 answers kernel/trap.c
  19. 19wakeup visits every process kernel/proc.c
  20. 20Resumed on a different hart kernel/uart.c
  21. 21The result travels back up kernel/syscall.c
  22. 22Back in usertrap, preparing to leave kernel/trap.c
  23. 23prepare_return records the new hart kernel/trap.c
  24. 24userret switches back to echo's page table kernel/trampoline.S
  25. 25ld sp, then sret: back to user mode kernel/trampoline.S
  26. 26echo carries on user/echo.c

Keys: ← → step · Home start