This repository is a Zig-based project for building a small RISC-V OS, inspired by the article Build an OS in 1,000 Lines and its companion repository nuta/operating-system-in-1000-lines.
The current repository includes the following pieces:
- Zig build configuration for a freestanding RISC-V 32-bit target
- A kernel that boots on OpenSBI + QEMU
- Minimal implementations for console output, traps, and process switching
- Disk access via VirtIO Block
- A simple tar-based file system for reading and writing files
- A minimal user-mode shell
- A Docker- and GitHub Actions-based development and CI workflow
This repository focuses on a minimal OS implementation for learning purposes.
- The target platform is RISC-V 32-bit on the QEMU
virtmachine - The implementation prioritizes small size and readability
- Complete OS feature coverage and broad portability are out of scope
- The development workflow assumes Docker as the primary path
For normal use, you need:
- Docker
- Docker with Compose v2 (
docker compose) make
If you want to develop directly on the host without Docker, you need at least:
- Zig 0.15.2
- QEMU (
qemu-system-riscv32) - LLVM tools (
llvm-objcopy,llvm-readelf,llvm-nm,llvm-objdump) clang,lld,dtc,tar,bash,python3shellcheck,shfmt,yamllinttimeout(for example from GNU coreutils)
The recommended path is to use Docker.
First, build the development image.
make imageThen use the following main targets:
make format- Format Zig, shell, and VSCode JSON filesmake lint- Run format checks, shellcheck, and yamllintmake build- Build the kernel and user shellmake run- Boot the OS in QEMUmake ci- Runlint→build→runas one flow
make ci performs a QEMU smoke run and times out after 3 seconds by default.
Normal boot:
make runCI-style check:
make ciIf you want to feed input into QEMU, you can use QEMU_INPUT.
QEMU_INPUT=$'hello\rexit\r' make runQEMU output is saved to qemu.log.
The user shell currently provides these minimal commands:
hello- Print a messagereadfile- Readhello.txtwritefile- Updatehello.txtexit- Exit the shell
The source files for the disk image live under disk/.
.
├── .github/ # GitHub Actions workflow definitions
├── .vscode/ # Workspace settings and editor task configuration
├── assets/ # Static assets used by the repository documentation
├── disk/ # Files packed into the virtual disk image used by the OS
├── scripts/ # Helper scripts for repository formatting and linting
├── src/ # Main Zig source tree for kernel and user-space code
│ ├── kernel/ # Kernel implementation for boot, memory, traps, and devices
│ ├── user/ # User-space startup code and the minimal shell program
│ └── common.zig # Shared utilities used by both kernel and user-space code
├── build.zig # Zig build script that defines kernel and user artifacts
├── compose.yml # Docker Compose configuration for the development environment
├── Dockerfile # Container image definition for local development and CI
├── kernel.ld # Linker script that places kernel sections in memory
├── LICENSE # MIT license for this repository
├── Makefile # Top-level commands for format, lint, build, and run
├── README.md # Project overview, setup guide, and repository structure
├── run.sh # QEMU launcher and disk image packaging helper
├── user.ld # Linker script for user-space programs
├── zig-out/ # Generated build outputs produced by Zig (created after builds)
└── qemu.log # Optional QEMU serial log written by `make run` and `make ci`
- Reference article: Build an OS in 1,000 Lines
- Reference repository: nuta/operating-system-in-1000-lines
MIT License - see LICENSE.
