Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Appendix G · Reading xv6 Alongside This Book

An appendix in this book is a reference, not a chapter: no argument, no narrative, and everything in it either cites a primary source or comes from a stamped result under bench/results/.

Everything below was read out of the submodule at its pinned commit rather than recalled, so it describes the code you have checked out. Appendix D says what else is in that tree.

The two books ask different questions

The kernel this book uses has its own commentary Cox et al. (n.d.), written by the people who wrote the kernel, distributed free by MIT. It is the best available explanation of what that code does and you should read it.

It is not a competitor and this book does not summarise it. They ask different questions of the same source:

The xv6 commentaryWhat does this code do, and why is it arranged this way?
This bookWhat does it cost, and how would I know?

That difference decides almost everything about how the two are organised. The commentary follows the kernel’s own structure, because it is explaining a program. This book follows a question, which is why its Part IV takes the kernel apart mechanism by mechanism and its Part V then asks the price of each — and why a mechanism that is one section there may be a chapter here, or the reverse.

Read them in either order. A reader who has the commentary open will find this book’s chapters supply the measurements it does not attempt; a reader who starts here will find the commentary supplies the surrounding code that a chapter about one mechanism does not show.

Where the coverage meets

Mapped by topic rather than by chapter number, deliberately: the commentary’s numbering shifts between revisions and its topics do not.

When the commentary is onThis book is inAnd the price is in
Operating system interfaces — processes, fork, exec, filesch04 for the memory model it implies; the trace below—
Operating system organization, isolation, privilegech16ch29
Page tables and Sv39ch17ch25 address translation, ch29 faults
Traps, system calls, and the trap pathch16ch29
Page faults and what can be built on themch18ch29
Interrupts and device driversch19—
Lockingch20ch28
Scheduling and context switchingch21ch29
File system, logging, buffer cachech22—
Concurrency revisited, memory orderingch20ch28

Two of the blank rows share a reason: the cost of an interrupt, a file system and a driver on this machine is the cost of this machine’s devices, and the reference board’s storage is an SD card behind a bridge rather than anything a chapter could generalise from. ch19 and ch22 say so in their own limitations sections. The third blank, operating-system interfaces, has no single price: the trace below pays it a layer at a time.

One call through every layer: fork

fork is the worked example of how to use the table above, because it is the one call in the kernel that touches almost every mechanism this book takes apart separately. Reading it is the fastest way to see that the chapters are describing one system rather than six.

In the pinned tree the function is kfork in kernel/proc.c — sys_fork in kernel/sysproc.c is a one-line wrapper. Older revisions of the commentary call it fork.

What it doesWhich layerWhere that is explained
allocproc() finds an unused slot in the fixed process tableallocation without a heapch04
…and returns 0 when there is none, which becomes -1failure that returns rather than raisesch04’s problem 4.2
uvmcopy() walks the parent’s page table and copies every pageaddress translationch17
…with a kalloc() per page, which can also failthe physical allocatorch18
*(np->trapframe) = *(p->trapframe) copies the saved user registerswhat a trap savesch16
np->trapframe->a0 = 0the calling conventionch14, ch16
filedup() over the open files, and idup() on the working directoryreference countingch22
np->state = RUNNABLE makes it eligible to be chosenschedulingch21

Nothing returns twice. The row that sets a0 to zero is where that illusion comes from. The child is a copy of the parent — including the saved register set the trap path will restore on the way out — with a single word changed: the register the calling convention uses for a return value. Both processes then resume at the instruction after the ecall, each reading its own a0. ch16 is where that saved register set is counted.

uvmcopy copies eagerly, and the pinned tree is explicit about it: a kalloc and a memmove of a whole page, per page, with no sharing. That is a deliberate simplification, and it lets ch18 add copy-on-write rather than merely explain it — the mechanism is absent here, so the chapter has somewhere to put it. A production kernel shares the pages and marks them read-only, and ch29 is where the difference in cost is measured.

The failure paths are where ch04’s second problem lives, in the source. kfork can fail in two places — no free slot, or no free page — and both return -1 after undoing what they had done. A caller that does not look at the result has written the bug ch04 is about.

What this cannot tell you

What the commentary says. This page is a map, not a summary, and it deliberately does not restate a word of it. Where the two books cover the same mechanism they do it differently and both are worth reading; where this page sends you to a chapter, the chapter is about the cost.

Anything about a different revision. The tree here is pinned, and in it the function is kfork and allocproc returns 0. Both have been spelled otherwise. The conditions line under Appendix D’s tables names the commit; git -C xv6/xv6-riscv log -1 is the check.

Whether the commentary’s version and this one agree. They are different documents at different revisions, and where they differ the tree wins — the tree is what boots.

References
  1. Cox, R., Kaashoek, M. F., & Morris, R. (n.d.). xv6: a simple, Unix-like teaching operating system. MIT. https://pdos.csail.mit.edu/6.1810/