xv6, line by line
lab 17
Lab 1717 Direct user access with sstatus.SUM

Lab 17 · reveal · 18 steps · 7 commits

Direct user access with sstatus.SUM: the reference solution

Every time a system call reads or writes user memory, this tree’s copyin and copyout translate the user’s address in software: walkaddr walks the process’s page table, finds the physical page, and the kernel copies through its own direct map of RAM. The user pointer itself is never dereferenced. Real kernels (Linux on RISC-V among them) do the opposite: they load and store through the user’s virtual address directly, and let the hardware translate it. In this lab you make xv6 do that.

RISC-V has a bit for exactly this purpose, SUM in the sstatus register. Setting it turns out to be the easy part. Which page table is in satp while a system call runs, and what does it map at a user address? If you put the user’s pages into it, what is already there? What becomes of a user pointer that points at the kernel, at a device, or at a page that does not exist yet, now that the hardware, not your code, does the lookup? A page fault inside the kernel has always meant panic in this tree: what must it mean now? And is the result actually faster? The think section asks these in the order a designer meets them, and the measure section answers the last one with numbers that may surprise you.

The reference solution is seven commits. usertests -q passes on 3 harts at every one of them, and a new test, sumtest, checks direct copies with good and bad pointers.

Each step shows one change on the branch ext/17-sum, the code around it, and the state of the machine when that code runs.

The route
  1. 1A cap on user memory kernel/memlayout.h
  2. 2Two usertests that asked for a gigabyte user/usertests.c
  3. 3A kernel page table that shares almost everything kernel/vm.c
  4. 4Freeing exactly what is private kernel/vm.c
  5. 5The scheduler installs the process's page table kernel/proc.c
  6. 6And switches back before letting go kernel/proc.c
  7. 7Mirroring the user's pages kernel/vm.c
  8. 8sbrk in both directions kernel/proc.c
  9. 9fork mirrors the child's whole image kernel/proc.c
  10. 10exec swaps both page tables at once kernel/exec.c
  11. 11A lazy fault fills both tables kernel/vm.c
  12. 12The copy loop, with SUM set for exactly its duration kernel/uaccess.S
  13. 13Strings, and where a failed copy resumes kernel/uaccess.S
  14. 14kerneltrap learns to forgive one kind of fault kernel/trap.c
  15. 15A fault nobody can fix kernel/trap.c
  16. 16copyout uses the user's address kernel/vm.c
  17. 17copyin and copyinstr have only one path kernel/vm.c
  18. 18sumtest's bad pointers user/sumtest.c

Keys: ← → step · Home start