An operating system manages and abstracts low-level hardware, shares physical resources among multiple programs, and provides controlled ways for programs to interact.
- Kernel: A special privileged program that provides core services to running programs.
- Process: A running program consisting of memory (instructions, data, and a stack) and private state managed by the kernel.
- System Call: A defined entry point in the operating system’s interface that transitions execution from user space to kernel space to perform privileged operations.
- Hardware Protection: The kernel utilizes CPU mechanisms to ensure processes access only their own memory and execute without hardware privileges.
| System call | Description |
|---|---|
fork | Create a process, return child’s PID. |
exit | Terminate the current process; status is reported to wait(). No return. |
wait | Wait for a child to exit; exit status in *status; returns child PID. |
kill | Terminate process PID. Returns 0, or -1 for error. |
getpid | Return the current process’s PID. |
pause | Pause for n clock ticks. |
uptime | Return how many clock ticks have occurred since boot. |
exec | Load a file and execute it with arguments; only returns on error. |
sbrk | Grow process memory by n bytes. Returns start of new memory. |
open | Open a file; flags indicate read/write; returns a file descriptor. |
write | Write n bytes from buf to file descriptor fd; returns n. |
read | Read n bytes into buf; returns number read, or 0 at end of file. |
close | Release open file descriptor fd. |
dup | Return a new file descriptor referring to the same file as fd. |
pipe | Create a pipe, placing read/write file descriptors in p[0] and p[1]. |
chdir | Change the current directory. |
mkdir | Create a new directory. |
mknod | Create a device file. |
fstat | Place info about an open file into *st. |
link | Create another name (file2) for the file file1. |
unlink | Remove a file. |
Processes
The operating system time-shares hardware by transparently switching available CPUs among waiting processes, saving and restoring CPU registers during transitions.
- Process Identifier (PID): A unique integer the kernel associates with each process.
- Process Creation:
fork()creates a new child process by exactly duplicating the parent’s memory contents.fork()returns in the child process and the child’s PID in the parent process.- The parent and child execute independently with different memory spaces and registers; changes in one do not affect the other.
- Process Execution:
exec(file, argv)replaces the calling process’s memory with a new memory image loaded from a file (structured in the ELF format).exec()takes an executable filename and an array of string arguments, starting execution at the binary’s declared entry point without returning to the calling program.
- Process Termination and Synchronization:
exit(status)stops the calling process and releases resources like memory and open files. A status of conventionally indicates success, while indicates failure.wait(*status)pauses the calling process until a child exits, returning the child’s PID and copying its exit status into the provided address.
- Memory Management:
- Most user-space memory is allocated implicitly during
fork()andexec(). sbrk(n)grows a process’s data memory by bytes dynamically at run-time and returns the location of the new memory.
- Most user-space memory is allocated implicitly during
File
A file descriptor is a small integer acting as an index into a per-process table, representing a kernel-managed object such as a file, directory, device, or pipe.
- Standard Conventions: By default, processes read from file descriptor (standard input), write to (standard output), and write errors to (standard error).
- Core I/O Operations:
read(fd, buf, n)reads up to bytes from into , advancing the file offset by the number of bytes read. It returns to indicate the end of the file.write(fd, buf, n)writes bytes from to , advancing the file offset sequentially.close(fd)releases a file descriptor for future reuse. Newly allocated file descriptors always use the lowest-numbered unused integer for the current process.
- I/O Redirection:
fork()copies the parent’s file descriptor table to the child, granting the child the exact same open files.exec()replaces the process memory but completely preserves the file table.- A shell redirects I/O by forking a child, closing standard file descriptors, opening specific files to claim those low-numbered descriptors, and then calling
exec()to run the new program.
- Offset Sharing:
- Underlying file offsets are shared between file descriptors only if they were derived from the same original descriptor via
fork()ordup(). dup(fd)duplicates an existing descriptor, returning a new one that refers to the same underlying I/O object and shares its offset.
- Underlying file offsets are shared between file descriptors only if they were derived from the same original descriptor via
Pipes
A pipe is a small kernel buffer exposed to processes as a pair of file descriptors: one for reading and one for writing.
- Creation:
pipe(p)creates the buffer and records the read descriptor in and the write descriptor in . - Communication Flow:
- Writing data to the write end makes it available for reading at the read end.
- If no data is available, a read operation blocks until data is written or until all file descriptors referring to the write end are closed.
- If all write ends are closed,
read()returns , simulating an end-of-file. This requires processes to rigorously close unused write descriptors to prevent readers from waiting indefinitely.
- Advantages Over Temporary Files:
- Pipes automatically clean themselves up, whereas temporary files require explicit deletion.
- Pipes can pass arbitrarily long streams of data without being constrained by disk space.
- Pipes allow parallel execution of pipeline stages, unlike files which require the first program to finish before the second starts.
- Blocking reads and writes in pipes are significantly more efficient than non-blocking file semantics for inter-process communication.
File system
The file system provides data files (uninterpreted byte arrays) and directories (named references to files and other directories), structured as a tree originating from a root directory.
- Path Resolution:
- Paths beginning with
/are evaluated from the root directory. - Paths not beginning with
/are evaluated relative to the calling process’s current directory, which can be modified usingchdir(dir).
- Paths beginning with
- Inodes and Links:
- Inode: The underlying physical file object that holds file metadata, including type (file, directory, or device), length, disk location, and the number of links.
- Link: An entry in a directory containing a filename and a reference to an inode.
- A single inode can have multiple links (names) pointing to it.
- File System Operations:
mkdir(dir)creates a new directory.open(file, O_CREATE)creates a new data file.mknod(file, major, minor)creates a special device file that diverts I/O system calls directly to a kernel device implementation identified by major and minor numbers.link(file1, file2)creates a new name (file2) referring to the exact same inode as an existing file (file1).unlink(file)removes a name from the file system. The underlying inode and disk space are only freed when the file’s link count drops to and no active file descriptors refer to it.fstat(fd, *st)andstat(file, *st)retrieve inode information into astruct statobject.
User mode, supervisor mode and system calls
- CPUs provide hardware execution modes to establish a hard boundary between application code and the operating system.
- Machine Mode: Starts upon CPU boot, executes with full hardware privilege, and is strictly used for low-level computer configuration.
- Supervisor Mode: Allows execution of privileged instructions necessary for OS operations, such as enabling interrupts or writing to page table registers. Software running in this mode is the kernel, executing in kernel space.
- User Mode: Restricts execution to unprivileged instructions. Applications execute in this mode within user space.
- If a user-mode application attempts a privileged instruction, the CPU suppresses the instruction and forcefully switches to supervisor mode so the kernel can terminate the application.
- Applications invoke kernel services via system calls using specialized instructions (e.g., the RISC-V
ecallinstruction). - System calls switch the CPU to supervisor mode at a strictly kernel-defined entry point, preventing malicious applications from bypassing argument validation or access control checks.
Virtualization
- A process is the fundamental unit of isolation, shielding an application’s memory, CPU state, and file descriptors from interference by other processes.
- A process bundles two foundational architectural illusions:
- Private Address Space: Simulates private physical memory using hardware page tables.
- RISC-V page tables translate virtual addresses utilized by instructions into physical addresses on the RAM chip.
- The layout begins at virtual address zero with instructions, global variables, the stack, and the heap.
- The address space is bounded by hardware translation limits; xv6 uses 38 bits of addressable space, establishing a maximum virtua l address of (
MAXVA). - The top pages of the address space are reserved for a trampoline page (managing user/kernel transitions) and a trapframe page (saving user state).
- Private CPU (Thread): Simulates dedicated processor execution.
- Each process contains a thread of execution that tracks local variables and return addresses on stacks.
- A process actively alternates between two stacks: a user stack for user-space computation, and a kernel stack used exclusively during system calls and interrupts.
- The kernel stack is protected from user-space access to ensure the kernel can execute safely even if the user stack is compromised.
- Private Address Space: Simulates private physical memory using hardware page tables.
- Kernel state for each process is centralized in a
procstructure, containing references to the process’s page table (p->pagetable), kernel stack (p->kstack), and run state (p->state). - During a system call, hardware elevates the privilege level, switches the program counter to the kernel entry point, executes on the kernel stack, and subsequently utilizes the
sretinstruction to lower privileges and resume the user thread.
Layout of a process’s virtual space:

Codebase
The xv6 codebase is organised into four distinct parts:
| Order | Part | Role |
|---|---|---|
| 1 | Makefile | Coordinates the build and launch flow. |
| 2 | kernel/ | Builds the xv6 OS kernel. |
| 3 | user/ | Builds xv6 user programs. |
| 4 | mkfs/ | Builds fs.img using the xv6 user programs. |
| 5 | QEMU | Boots the kernel with fs.img as the disk. |
Kernel Subsystems
The kernel is easier to read by subsystem rather than as one flat list of files.
1 Headers and Utilities
| File | Kind | Purpose |
|---|---|---|
kernel/types.h | Header | Basic integer/type aliases. |
kernel/param.h | Header | Kernel-wide size limits. |
kernel/memlayout.h | Header | Physical/virtual memory map. |
kernel/riscv.h | Header | RISC-V registers, paging, and interrupt helpers. |
kernel/defs.h | Header | Cross-file kernel declarations. |
kernel/kernel.ld | Linker script | Kernel memory layout at link time. |
2 Boot Sequence
| File | Kind | Purpose |
|---|---|---|
kernel/entry.S | Assembly | First code after QEMU jumps to the kernel. |
kernel/start.c | C | Early CPU setup before main. |
kernel/main.c | C | Kernel initialization order. |
3 Memory Subsystem
| File | Kind | Purpose |
|---|---|---|
kernel/kalloc.c | C | Physical page allocator. |
kernel/vm.h | Header | sbrk allocation mode constants. |
kernel/vm.c | C | Page tables and virtual memory. |
kernel/string.c | C | Basic memory/string helpers. |
4 Process Subsystem
| File | Kind | Purpose |
|---|---|---|
kernel/proc.h | Header | Process, CPU, trapframe, and context structures. |
kernel/proc.c | C | Processes, scheduling, sleep/wakeup, and wait/exit. |
kernel/swtch.S | Assembly | Low-level context switch. |
kernel/elf.h | Header | ELF executable file format. |
kernel/exec.c | C | Load and run user programs. |
5 Synchronization Mechanism
| File | Kind | Purpose |
|---|---|---|
kernel/spinlock.h | Header | Spinlock structure. |
kernel/spinlock.c | C | Short critical-section locking. |
kernel/sleeplock.h | Header | Sleeping lock structure. |
kernel/sleeplock.c | C | Locks that sleep while waiting. |
6 Traps
| File | Kind | Purpose |
|---|---|---|
kernel/trampoline.S | Assembly | User/kernel trap transition code. |
kernel/kernelvec.S | Assembly | Kernel-mode trap vector. |
kernel/trap.c | C | Trap, syscall, timer, and interrupt handling. |
7 PLIC
| File | Kind | Purpose |
|---|---|---|
kernel/plic.c | C | External interrupt controller setup and interrupt claiming. |
8 UART Device Driver
| File | Kind | Purpose |
|---|---|---|
kernel/uart.c | C | Low-level serial device driver. |
kernel/console.c | C | Console input/output layer on top of UART. |
kernel/printf.c | C | Kernel printing and panic output. |
9 Virtio Disk Driver
| File | Kind | Purpose |
|---|---|---|
kernel/virtio.h | Header | Virtio disk protocol definitions. |
kernel/virtio_disk.c | C | Virtual disk driver. |
10 Filesystem
| File | Kind | Purpose |
|---|---|---|
kernel/buf.h | Header | Disk buffer structure. |
kernel/bio.c | C | Buffer cache and LRU block reuse. |
kernel/fs.h | Header | On-disk filesystem format. |
kernel/log.c | C | Filesystem transaction log. |
kernel/fs.c | C | Inodes, directories, path lookup, and inode I/O. |
11 File Layer (VFS)
| File | Kind | Purpose |
|---|---|---|
kernel/file.h | Header | In-memory file, inode, pipe, and device structs. |
kernel/file.c | C | Open-file table and file operations. |
kernel/fcntl.h | Header | File open flags. |
kernel/stat.h | Header | File metadata structure. |
kernel/pipe.c | C | Pipes for process communication. |
12 Syscall Connectors and Wrappers
| File | Kind | Purpose |
|---|---|---|
kernel/syscall.h | Header | System call number definitions. |
kernel/syscall.c | C | System call dispatch and argument fetching. |
kernel/sysproc.c | C | Process-related system calls. |
kernel/sysfile.c | C | File-related system calls. |
User-Space Runtime
| Order | File | Kind | Purpose |
|---|---|---|---|
| 1 | user/user.h | Header | User-visible syscall and library declarations. |
| 2 | user/usys.pl | Generator | Generates user syscall stubs. |
| 3 | user/usys.S | Generated assembly | User-side syscall wrappers using ecall. |
| 4 | user/ulib.c | User library | Basic user-space helper functions. |
| 5 | user/printf.c | User library | User-space formatted printing. |
| 6 | user/umalloc.c | User library | Simple user-space memory allocator. |
User Programs
| Order | File | Kind | Purpose |
|---|---|---|---|
| 1 | user/init.c | User program | First user process. |
| 2 | user/sh.c | User program | xv6 shell. |
| 3 | user/ls.c | User program | List directory contents. |
| 4 | user/cat.c | User program | Print file contents. |
| 5 | user/echo.c | User program | Print arguments. |
| 6 | user/grep.c | User program | Search text. |
| 7 | user/wc.c | User program | Count lines, words, bytes. |
| 8 | user/mkdir.c | User program | Create directories. |
| 9 | user/rm.c | User program | Remove files. |
| 10 | user/ln.c | User program | Create hard links. |
| 11 | user/kill.c | User program | Kill a process. |
| 12 | user/stressfs.c | Test program | Stress filesystem behavior. |
| 13 | user/forktest.c | Test program | Stress process creation. |
| 14 | user/grind.c | Test program | Stress processes/filesystem/concurrency. |
| 15 | user/usertests.c | Test program | Broad xv6 test suite. |
mkfs and Filesystem Image
mkfs is a host-side tool that runs on the build machine before xv6 boots. It packs compiled user binaries into fs.img, the virtual disk QEMU presents to xv6.
| Order | File / Artifact | Kind | Purpose |
|---|---|---|---|
| 1 | kernel/fs.h | Shared format header | Defines xv6 on-disk filesystem layout. |
| 2 | mkfs/mkfs.c | Host tool | Creates fs.img using xv6 filesystem format. |
| 3 | user/_init etc. | RISC-V binaries | Compiled user programs inserted into fs.img. |
| 4 | fs.img | Disk image | Virtual disk passed to xv6 by QEMU. |
Full Build-to-Boot Pipeline
| Order | Step | Runs where? | Purpose |
|---|---|---|---|
| 1 | Makefile | Host | Coordinates the build. |
| 2 | Build kernel files | Host cross-compiler | Produces kernel/kernel. |
| 3 | Build user support files | Host cross-compiler | Produces user runtime objects. |
| 4 | Build user programs | Host cross-compiler | Produces user/_init, user/_sh, etc. |
| 5 | Build mkfs/mkfs.c | Host compiler | Produces host executable mkfs/mkfs. |
| 6 | Run mkfs/mkfs | Host | Packs user binaries into fs.img. |
| 7 | Start QEMU | Host | Creates virtual RISC-V machine. |
| 8 | Run kernel/kernel | QEMU/RISC-V | Boots xv6 kernel. |
| 9 | Run /init | xv6 user mode | Starts first user process. |
| 10 | Run /sh | xv6 user mode | Starts shell. |
Runtime flow:
| Order | Part | Role |
|---|---|---|
| 1 | QEMU | Starts the virtual RISC-V machine. |
| 2 | kernel/entry.S | Sets up the first kernel stack. |
| 3 | kernel/start.c | Switches from machine mode to supervisor. |
| 4 | kernel/main.c | Initializes kernel subsystems. |
| 5 | Disk and filesystem init | Makes fs.img available through xv6. |
| 6 | kernel/exec.c loads /init | Loads the first user program. |
| 7 | user/init.c starts /sh | Opens the console and starts the shell. |
| 8 | user/sh.c runs commands | Reads and executes user commands. |
Makefile
The Makefile coordinates three separate builds and then launches QEMU.
Build Pipeline
| Step | Input | Linker Script | Output |
|---|---|---|---|
| Kernel build | kernel/*.c + kernel/*.S | kernel/kernel.ld | kernel/kernel |
| User build | user/*.c + usys.S | user/user.ld | user/_init etc. |
| mkfs (Host) | mkfs/mkfs.c | — | mkfs/mkfs |
| Filesystem image | mkfs/mkfs + user/_init etc. | — | fs.img |
| Boot | kernel/kernel + fs.img | — | QEMU launches xv6 |
Linking all kernel object files with kernel.ld produces three files:
| File | Content |
|---|---|
kernel/kernel | Linked kernel binary loaded by QEMU |
kernel/kernel.asm | Mixed source/disassembly for inspection |
kernel/kernel.sym | Address-to-symbol map for debugging |
Every user program links against a small runtime library:
| Object | Source | Role |
|---|---|---|
ulib.o | ulib.c | String helpers and syscall wrappers |
usys.o | generated usys.S | Syscall stubs (ecall wrappers) |
printf.o | printf.c | User-space printf |
umalloc.o | umalloc.c | User-space malloc/free |
Notes:
usys.Sis generated by runningusys.plthrough Perl where each stub loads the syscall number intoa7and executesecall.- User programs are named with a leading underscore (
user/_init) to avoid clashing with host tools.mkfsstrips it when packing intofs.img. forktestomitsprintf.oandumalloc.oto stay small enough to max out the process table.
These are the compiled user programs packed into fs.img by mkfs:
| Program | Purpose |
|---|---|
_init | First user process started by the kernel |
_sh | xv6 shell |
_ls | List directory contents |
_cat | Print file contents |
_echo | Print arguments |
_grep | Search text |
_wc | Count lines, words, bytes |
_mkdir | Create directories |
_rm | Remove files |
_ln | Create hard links |
_kill | Kill a process |
_zombie | Demonstrate zombie process behavior |
_forktest | Stress process creation |
_stressfs | Stress filesystem writes |
_usertests | Broad xv6 test suite |
_grind | Stress processes, filesystem, and concurrency |
_logstress | Stress filesystem logging |
_forphan / _dorphan | Test orphaned process behavior |
Toolchain
| Tool | Role |
|---|---|
$(CC) | Compiles C and preprocessed .S assembly |
$(LD) | Links object files into binaries |
$(OBJDUMP) | Generates .asm and .sym files for inspection |
gcc (host) | Compiles mkfs/mkfs.c — runs on build machine, not RISC-V |
Compiler Flags
| Flag | Purpose |
|---|---|
-Wall -Werror | Warnings as errors |
-O | Basic optimization |
-ggdb | GDB-friendly debug info |
-gdwarf-2 | DWARF v2 debug format |
-fno-omit-frame-pointer | Keep frame pointers for stack traces |
-march=rv64gc | Target 64-bit RISC-V with standard extensions |
-mcmodel=medany | Addressing for code linked at 0x80000000, not near zero |
-MD | Emit .d dependency files for incremental builds |
-ffreestanding | No hosted C environment assumptions |
-nostdlib | Do not link standard library or startup files |
-fno-common | Catch duplicate global definitions at link time |
-fno-builtin-* | Prevent GCC substituting xv6’s own memcpy, printf etc. with libc versions |
-fno-stack-protector | No stack canary — kernel has no runtime support for it |
-fno-pie -no-pie | Fixed-address binaries; xv6 does not use position-independent code |
-I. | Include headers relative to project root |
Linker Flags
| Flag | Purpose |
|---|---|
-z max-page-size=4096 | Align ELF segments to 4 KiB, matching xv6’s page size. |
QEMU Launch
| Spec | Value |
|---|---|
| Machine | virt (generic RISC-V virtual board) |
| CPU | riscv64 |
| Cores | 3 |
| RAM | 128M |
| Kernel | kernel/kernel |
| Disk | fs.img via virtio-blk |
| Display | None (-nographic, serial console only) |
The Linker Script
The kernel/kernel.ld tells the linker how to lay out the final kernel binary in memory. It defines where code goes, in what order, and what symbols the rest of the kernel can use to find section boundaries.
Memory Layout
The linker arranges the kernel into sections in this order, starting at 0x80000000:
| Section | Contents | Notes |
|---|---|---|
.text | Kernel code | _entry placed first, then all other code |
.rodata | Read-only data | Constants, string literals, aligned to 16 bytes |
.data | Initialized globals | Non-zero globals, stored in the binary |
.bss | Zero-initialized globals | Not stored in binary; kernel zeroes at startup |
.text:
- Executable code only, read and execute permissions.
_entrylands at exactly0x80000000.- Trampoline is carved out at the end, aligned to a 4 KiB page boundary
- user-kernel transitions and must be mapped at the same virtual address in every page table.
trampoline.Sdeclares.section trampsec, which the linker places here.
.rodata:
- Read-only.
- Aligned to 16 bytes.
- Contains string literals and constant arrays that must not be modified at runtime.
- Separate from
.dataso the OS can enforce read-only page permissions.
.data:
- Read-write.
- Aligned to 16 bytes.
- Holds initialized globals with non-zero starting values, embedded in the binary and copied into RAM at load time.
.bss:
- Read-write.
- Aligned to 16 bytes.
- Holds zero-initialized globals.
- Not stored in the binary: the linker records only the size and the kernel zeroes the region at startup.

Note:
The 16-byte alignment across data sections ensures efficient memory access. On a 64-bit RISCV system, 16 bytes covers two 64-bit registers, which compilers exploit for multi-word loads and stores. Unaligned access can cause hardware exceptions or significant slowdowns on some architectures.
Symbols
The linker script exports two symbols the kernel uses at runtime:
| Symbol | Meaning |
|---|---|
etext | Address of the end of the text section |
end | Address of the end of the entire kernel image |
_trampoline | Start address of the trampoline page |
The .rodata
Size: 2,080 bytes.
Contents:
- Lock debug names: passed to
initlock()andinitsleeplock()at startup. - Panic and error messages: invariant violation and error detection strings across the kernel.
- Boot messages: printed during initialization and secondary hart startup.
- Format strings: used in trap handling and process dumps.
- Path strings:
"/"and"/init"used during first process setup. - Compiler-promoted immutable tables: digit lookup, process state names, syscall dispatch table.
Note: No const globals exist in xv6 everything here was placed by the compiler.
Permissions: xv6 maps this range as PTE_R | PTE_W in the kernel page table, so read-only is by convention only.
The .data
Size: 24 bytes almost nothing.
Contents:
- The
nextpid = 1inproc.cis the only meaningful non-zero global. - A static local
firstinkalloc.cto detect the firstkfreecall.
Why so small: most kernel state is zero-initialized and lives in .bss; string data lives in .rodata.
The .bss
Size: 103,224 bytes the bulk of xv6’s kernel state.
Contents: all global structs declared without explicit initializers. Not stored in the binary; the kernel zeroes this region at startup.
| Symbol | Size | First used by | Purpose |
|---|---|---|---|
stack0 | 32 KiB | entry.S / start.c | Boot stack for all CPUs before main |
cons | 168 B | consoleinit() | Console input buffer and lock |
tx_lock | 24 B | consoleinit() | UART transmit spinlock |
tx_chan | 4 B | consoleinit() | UART transmit sleep channel |
tx_busy | 4 B | consoleinit() | UART transmit busy flag |
pr | 24 B | printfinit() | printf serialization lock |
panicked | 4 B | printfinit() | Flag set when kernel has panicked |
panicking | 4 B | printfinit() | Flag set while panic is in progress |
kmem | 32 B | kinit() | Physical page free list and its lock |
kernel_pagetable | 8 B | kvminit() | Pointer to the kernel page table |
proc | 23 KiB | procinit() | Process table 64 process slots |
wait_lock | 24 B | procinit() | Condition lock for parent/child wait coordination |
pid_lock | 24 B | procinit() | Protects nextpid counter |
tickslock | 24 B | trapinit() | Serializes access to the ticks counter |
ticks | 4 B | trapinit() | Wall-clock tick counter incremented by timer interrupts |
bcache | 34 KiB | binit() | Buffer cache 30 LRU disk block buffers |
itable | 6.7 KiB | iinit() | In-memory inode table |
ftable | 4 KiB | fileinit() | Open file table shared across all processes |
devsw | 160 B | fileinit() | Device switch table mapping major numbers to read/write handlers |
disk | 320 B | virtio_disk_init() | Virtio disk driver state and descriptor ring |
initproc | 8 B | userinit() | Pointer to the init process |
sb | 32 B | fsinit() | Superblock filesystem geometry and metadata |
log | 168 B | initlog() | Filesystem transaction log state |
cpus | 1 KiB | scheduler() | Per-CPU state current process, scheduler context, lock depth |
started | 4 B | After CPU 0 init | Signals secondary CPUs that CPU 0 has finished initialization |
The Free Memory
Starts at end (linker symbol at the end of .bss) and extends to PHYSTOP (0x88000000).
- Not part of the kernel binary — raw physical RAM managed at runtime.
kalloc.ctracks it as a free list of 4 KiB pages.kinit()walks fromendtoPHYSTOPand adds each page to the free list.kalloc()pops a page from the free list;kfree()pushes one back.
| Allocation | kalloc() site | kfree() site | Pages | What gets a page |
|---|---|---|---|---|
| Kernel page table | kvmmake() | Never | 102 | 1 root + 3 L1 + 98 L0 nodes for the Sv39 tree |
| Kernel stacks | proc_mapstacks() | Never | 64 | One per process slot, called inside kvmmake() |
| Virtio rings | virtio_disk_init() | Never | 3 | Descriptor ring, available ring, used ring for disk DMA |
| Trapframe | allocproc() | freeproc() | 1 per process | Per-process trap register save area |
| User page table | proc_pagetable() | proc_freepagetable() | 1 per process | Root page table, called inside allocproc() |
| User memory | uvmalloc() | uvmdealloc() / uvmfree() | varies | User process address space pages during exec and sbrk |
| Intermediate page table nodes | walk() with alloc=1 | freewalk() | varies | L1 and L0 pages as user page tables are built |
| Fork copy | uvmcopy() | uvmfree() on child exit | 1 per mapped page | Physical page copies for child during fork |
| Page fault | vmfault() | uvmfree() on process exit | 1 per fault | On-demand page on fault |
| Pipe buffer | pipealloc() | pipeclose() | 1 per pipe | Pipe kernel buffer |
| exec argv | sys_exec() | After copy / on error | varies | Temporary argument string pages during exec |