kernel/defs.h
Included by 22 files
kernel/bio.c, kernel/console.c, kernel/exec.c, kernel/file.c, kernel/fs.c, kernel/kalloc.c, kernel/log.c, kernel/main.c, kernel/pipe.c, kernel/plic.c, kernel/printk.c, kernel/proc.c, kernel/sleeplock.c, kernel/spinlock.c, kernel/start.c, kernel/syscall.c, kernel/sysfile.c, kernel/sysproc.c, kernel/trap.c, kernel/uart.c, kernel/virtio_disk.c, kernel/vm.cAbout this file
One header that declares (almost) every kernel function that is called from a file other
than the one defining it. Nearly every kernel .c file includes it, so any kernel code
can call, say, kalloc or acquire without including a header per subsystem.
It is organized as one section per source file, each headed by a comment naming the file,
which makes it a handy index of the kernel: to find where a function lives, find its
section here. The sections are in rough alphabetical order, with plic.c and
virtio_disk.c added at the end.
defs.h has no include guard and includes nothing itself. It uses types defined
elsewhere (uint and uint64 from kernel/types.h, pagetable_t and pte_t from
kernel/riscv.h), so every file includes those headers before defs.h.
Not everything is here. Functions used only inside their own file are usually static
and absent; the sys_* handlers are declared in kernel/syscall.c, their only user;
and a few cross-file names are declared where they are used (for example forkret
refers to userret with its own extern).
Read alongside: any kernel .c file.
Struct names used in the prototypes
These lines declare struct tags without their contents (incomplete types). That is
all a prototype needs to mention a pointer such as struct buf*: the compiler does
not need to know a struct’s size or fields to pass a pointer to it. Each full
definition lives in its own header (kernel/buf.h, kernel/proc.h,
kernel/file.h, …), which only the files that look inside the struct include.
Without these lines, a tag first seen inside a prototype’s parameter list would be
a different, local type in each prototype, and calls would not type-check.
struct cpu is not in the list but is used on line 92. That one is safe because it
appears in a return type at file scope, which declares the tag for the whole file.
Line 1, // clang-format off, tells the code formatter not to re-flow the aligned
columns below. There is no matching clang-format on; it stays off to the end of
the file.
Disable automatic formatting for the rest of this file, to keep the columns aligned.
bio.c: the buffer cache
kernel/bio.c keeps in-memory copies of disk blocks, the buffer cache.
bread returns a locked buffer holding a block’s contents, bwrite writes it to
disk, and brelse releases it. bpin and bunpin keep a buffer in the cache
while the log needs it. binit runs once at boot.
console.c: the console device
kernel/console.c turns the UART into the console: consoleintr receives
each typed character from uartintr and does line editing (cooked input); consputc
outputs one character for printk. consoleinit is called from main.
exec.c: load a program
kexec replaces the current process’s memory with a program loaded from a file
(exec). The kernel versions carry a k prefix (kexec, kexit,
kfork, kwait, kkill), which keeps them apart from the user-level
functions of the same name.
file.c: open files
kernel/file.c manages the table of open files, the objects that
file descriptors refer to. filealloc, filedup and
fileclose manage their reference counts;
fileread, filewrite and filestat dispatch to pipes, devices or inodes.
Their uint64 arguments are user addresses, as passed to the system call.
fs.c: inodes and directories
kernel/fs.c is the file system proper: inodes (ialloc,
ilock, iput, readi, writei…), directories
(dirlookup, dirlink) and path name lookup (namei,
nameiparent). fsinit reads the superblock and recovers the log; it is
called by the first process (forkret), not by main, because it may sleep.
iinit() with empty parentheses is an old-style declaration
(it does not say “no parameters”); iinit in fact takes none.
kalloc.c: physical pages
kernel/kalloc.c is the page allocator: kalloc returns one free
4096-byte page of physical memory (or 0), and kfree gives one back. kinit
fills the free list at boot.
log.c: crash-safe transactions
kernel/log.c implements the write-ahead log. File system code brackets each
operation with begin_op and end_op, and writes modified blocks with
log_write instead of bwrite, so that an operation either happens completely
or not at all, even if the machine crashes. initlog runs from fsinit.
pipe.c: pipes
kernel/pipe.c implements pipes: pipealloc creates a pipe and the
two open files for its ends; piperead and pipewrite move data, sleeping
when the pipe is empty or full.
printk.c: kernel printing
printk is the kernel’s printf, writing to the console; panic prints a
message and stops the kernel; printkinit sets up the lock that keeps lines from
different harts apart. Both prototypes carry an attribute; see
the line notes.
format(printf, 1, 2) tells GCC that argument 1 is a printf-style
format string and the values start at argument 2, so the compiler checks every
printk call’s arguments against its format, like it does for printf. The ...
makes it a variadic function.
noreturn promises that panic never returns. The compiler can then omit code
after a call to it, and does not warn about a missing return value in a function that
ends with panic.
proc.c: processes and scheduling
kernel/proc.c owns the process table. The groups:
- identity:
cpuid,mycpu,myproc; - the process life cycle behind system calls:
kfork,kexit,kwait,kkill,killed,setkilled,growproc; - page tables for a process:
proc_pagetable,proc_freepagetable, andproc_mapstacksfor the kernel stacks; - scheduling:
scheduler,sched,yield, and the sleep and wakeup functionssleep_prepare,sleepandwakeup; - boot:
procinitanduserinit; - helpers for code that may copy to either user or kernel memory
(
either_copyout,either_copyin), andprocdumpfor debugging (Ctrl-P).
Note the split sleep: in this version a sleeper calls sleep_prepare(chan) while
holding its own lock, releases that lock, and then calls sleep(), as in
sys_pause. Older xv6 versions had a single sleep(chan, lock).
Another old-style declaration with (); myproc takes no arguments.
scheduler never returns either; every hart enters it at the end of main.
The user_dst/user_src flag says whether the other address is a user virtual
address (copy through the process’s page table) or a kernel address (plain
memmove). Used by code that serves both kinds of caller: the console
(kernel/console.c) and readi/writei in kernel/fs.c.
swtch.S: the context switch
swtch saves the current kernel thread’s callee-saved registers into one
struct context and loads another, switching between a process’s kernel thread
and the scheduler (context switch). It is written in assembly in
kernel/swtch.S; this prototype lets C code call it.
spinlock.c: spinlocks
Spinlocks: acquire waits in a loop until the lock is free,
release frees it, holding checks whether this CPU holds it.
push_off and pop_off disable and re-enable interrupts in a nested way;
acquire and release use them so that an interrupt handler on the same CPU can
never wait for a lock its own CPU holds.
sleeplock.c: sleep locks
Sleep locks can be held for a long time, such as across a disk read, because a process waiting for one sleeps instead of spinning. Used for inodes and buffers.
string.c: memory and string helpers
The kernel has no C library, so kernel/string.c supplies the few functions it
needs. safestrcpy is xv6’s own: unlike strncpy, it always NUL-terminates
the destination. The size parameters are uint or int rather than the standard
size_t.
syscall.c: argument fetching and dispatch
The helpers that read system call arguments (argint, argaddr,
argstr) and copy from user addresses (fetchaddr, fetchstr), used by
the sys_* functions in kernel/sysproc.c and kernel/sysfile.c; and
syscall itself, called by usertrap. Note that argint and argaddr
return void: they cannot fail.
syscall(): old-style empty parentheses again.
trap.c: the clock and trap setup
Two variables and three functions. ticks and tickslock are shared with
kernel/sysproc.c (sys_pause, sys_uptime). trapinit and
trapinithart are called from main; prepare_return is called from
forkret in kernel/proc.c as well as from usertrap.
usertrap, kerneltrap and devintr are not declared here: they are only
called from assembly or from trap.c itself.
extern declares the variable without defining it; the definition, uint ticks;,
is in kernel/trap.c:10.
Likewise for tickslock, defined at kernel/trap.c:9.
Declared here because forkret in kernel/proc.c calls it.
uart.c: the serial port
The UART driver in kernel/uart.c: uartinit configures the chip,
uartintr handles its interrupts (called from devintr), uartwrite sends a
buffer of characters (sleeping while the UART is busy), and uartputc_sync sends
one character by busy-waiting, which works even with interrupts off; consputc
uses it, so printk and panic can always print.
vm.c: page tables
kernel/vm.c manages page tables:
- the kernel’s:
kvminit,kvminithart,kvmmap; - building and walking any page table:
mappages,walk,walkaddr,ismapped; - a process’s user memory:
uvmcreate,uvmalloc,uvmdealloc,uvmcopy(forfork),uvmfree,uvmunmap,uvmclear(for the stack guard page); - copying between kernel and user memory:
copyout,copyin,copyinstr; vmfault, which maps a lazily allocated page on first use.
In this version the copy functions take an extra uint64 after the page table: the
process size p->sz, which they pass to vmfault so it can tell valid lazy
addresses from bad ones.
walk returns a pointer to the PTE (page-table entry) for a virtual address, allocating
page-table pages if the last argument is non-zero.
plic.c: the interrupt controller
The PLIC driver in kernel/plic.c: plicinit and plicinithart
at boot, plic_claim and plic_complete around each device interrupt in
devintr.
virtio_disk.c: the disk
The virtio disk driver in kernel/virtio_disk.c: virtio_disk_init at
boot, virtio_disk_rw to read or write one buffer (called by the buffer cache;
it sleeps until the disk finishes), and virtio_disk_intr, called from
devintr when the disk signals completion.
Number of elements in an array
NELEM gives the number of elements of an array: its total size in bytes divided
by the size of one element. It is evaluated at compile time. It only works on a real
array, not on a pointer: for a pointer, sizeof(x) is 8, the size of the pointer.
syscall uses it to bounds-check the system call number, and sys_exec to
bound the argv array.
The outer parentheses and the ones around x keep the macro correct when its
argument or its use is part of a larger expression.