Skip to content

Introduction

This tutorial builds a small RISC-V kernel for QEMU’s virt machine.

The goal is not to hide the machine. The goal is to make each layer small enough that you can read it, run it, break it, and understand what changed.

By the end, the kernel will:

  • boot once as a tiny machine-mode image without OpenSBI
  • move under OpenSBI as a supervisor-mode kernel
  • allocate physical memory
  • enable Sv39 paging
  • enter user mode
  • handle traps and syscalls
  • schedule multiple user processes
  • deliver synchronous endpoint IPC
  • set up the path toward capabilities

Each chapter should end at a runnable checkpoint. Early chapters favor direct code over abstraction. Later chapters refactor once the reason for the abstraction is visible.

QEMU -bios none
-> raw _start at 0x80000000
-> direct UART output
-> OpenSBI takes M-mode
-> supervisor-mode Rust kernel
-> physical memory
-> kernel page table
-> user address spaces
-> trap trampoline
-> scheduler
-> endpoint IPC

This is not a production kernel. It intentionally starts with simple choices: embedded user programs, a small syscall table, direct console output, and raw endpoint IDs. Those choices make the first working system easy to inspect before we move toward stronger microkernel patterns.

The major architectural step after endpoint IPC is a capability system.