A hacker-style bare-metal playground for learning RISC-V assembly, C, and OS development on QEMU. From simple "Hello World" to a preemptive multitasking kernel!
This repository contains a progressive learning path from basic assembly to a functional mini-kernel with interrupts and scheduling:
- Assembly Basics (
asm/) - Pure RISC-V assembly programs - Bare-Metal C (
c/) - C programs without standard library - Chronos Kernel (
chronos/) - Full-featured mini-kernel with:- ✅ Modular architecture
- ✅ Timer interrupts (CLINT)
- ✅ External interrupts (PLIC)
- ✅ UART driver
- ✅ Preemptive multitasking scheduler
- ✅ Context switching
wirehack/
├── asm/ # Assembly demos
│ └── hello/ # Hello UART in pure assembly
├── c/ # Bare-metal C demos
│ ├── hello/ # Hello World in C
│ └── kernel/ # Early kernel experiments
├── chronos/ # 🌟 Full-featured mini-kernel
│ ├── src/
│ │ ├── asm/ # Boot code and trap handlers
│ │ ├── kernel.c # Main kernel logic
│ │ └── modules/ # Modular kernel subsystems
│ │ ├── clint/ # Timer interrupt driver
│ │ ├── plic/ # Interrupt controller
│ │ ├── uart/ # Serial port driver
│ │ └── sched/ # 🆕 Preemptive scheduler
│ ├── docs/ # Detailed documentation
│ └── Makefile # Modular build system
├── docs/ # Learning guides
│ ├── roadmap.md # Learning roadmap
│ └── clint_vs_plic.md # Interrupt controllers guide
├── include/ # Shared headers
├── scripts/ # Build helpers
└── tools/ # Analysis tools
cd asm/hello
make runcd c/hello
make runcd chronos
make runExpected output:
[CLINT] timer tick, task=0
[CLINT] timer tick, task=1
[CLINT] timer tick, task=0
...
The alternating task IDs show preemptive multitasking in action! 🎉
The Chronos mini-kernel is the crown jewel of this repository, featuring:
- Clean separation of kernel subsystems
- Each module is self-contained with its own directory
- Easy to understand, modify, and extend
- CLINT (Core-Local Interruptor) for timer interrupts
- PLIC (Platform-Level Interrupt Controller) for external interrupts
- Proper trap handling with interrupt routing
- Context switching using RISC-V callee-saved registers
- Cooperative scheduling - tasks can yield voluntarily
- Preemptive scheduling - timer-driven task switches (10ms)
- Round-robin between tasks
- xv6-style implementation
chronos/README.md- Kernel overviewchronos/docs/scheduler.md- Scheduler deep divechronos/docs/IMPLEMENTATION_SUMMARY.md- Implementation details
Follow the roadmap for a structured learning journey:
- Basics - RISC-V ISA, registers, UART I/O
- Assembly - Hello World, loops, string printing
- Bare-Metal C - C without stdlib, linker scripts
- Mini Kernel - Boot code, interrupts, drivers
- Advanced - Multitasking, scheduling, OS concepts
- RISC-V Toolchain:
riscv64-unknown-elf-gcc - QEMU:
qemu-system-riscv64 - Make: Build automation
brew install riscv-gnu-toolchain qemu# Ubuntu/Debian
sudo apt-get install gcc-riscv64-unknown-elf qemu-system-misc
# Arch Linux
sudo pacman -S riscv64-elf-gcc qemu-arch-extra- ✅ RISC-V assembly programming (RV64IMAC)
- ✅ Memory-mapped I/O (UART, CLINT, PLIC)
- ✅ Bare-metal C programming
- ✅ Linker scripts and memory layout
- ✅ Interrupt handling (M-mode)
- ✅ Context switching and task management
- ✅ Preemptive multitasking
- ✅ Modular kernel architecture
- RISC-V Specifications
- QEMU RISC-V Documentation
- xv6-riscv - Educational OS
- RISC-V Assembly Programmer's Manual
This is a personal learning repository, but feel free to:
- Open issues for questions or suggestions
- Submit PRs for improvements or fixes
- Use this as a template for your own RISC-V learning journey
This project is open source and available for educational purposes.
- ✅ Assembly demos working
- ✅ Bare-metal C demos working
- ✅ Chronos kernel with interrupts
- ✅ Modular architecture implemented
- ✅ Preemptive scheduler working
- 🚧 Future: More tasks, priorities, synchronization primitives
Hack, learn, repeat 😎
From "Hello World" to a multitasking kernel - one instruction at a time!