A minimal bare-metal kernel written entirely in Zig (zero assembly files). It boots on an x86 (i386) machine via the Multiboot 1 protocol and prints a coloured greeting to the VGA text-mode display, then halts the CPU.
The project is designed to be cross-compiled from any host (including Apple Silicon Macs) and tested instantly with QEMU — no ISO image, no GRUB installation, no bootloader binaries required.
- QEMU loads the ELF binary using its built-in Multiboot 1 support.
- The CPU starts in 32-bit protected mode at the
_startentry point. _startsets up a 16 KiB stack and jumps tokmain.kmainclears the VGA text buffer and writes a message to the screen.- The CPU enters an infinite
hltloop.
| Tool | Version | Install |
|---|---|---|
| Zig | 0.14.0+ | ziglang.org/download or brew install zig |
| QEMU | any recent | brew install qemu / nix-env -iA nixpkgs.qemu |
No other dependencies. Zig bundles its own LLVM back-end and linker, so
cross-compilation to x86-freestanding-none works out of the box on any host
OS and architecture (macOS ARM, Linux x86_64, etc.).
# Build the kernel (produces zig-out/bin/kernel) zig build # Boot it in QEMU (opens a graphical VGA window) zig build run # Or use the helper script (curses mode, auto-kills after a few seconds) chmod +x run.sh ./run.sh
To run QEMU manually with custom flags:
qemu-system-i386 -kernel zig-out/bin/kernel
You should see this:
zig-kernel/
├── build.zig Zig build script (target, linker, QEMU run step)
├── build.zig.zon Package manifest
├── linker.ld Linker script (section layout, entry point)
├── run.sh Quick-test shell script
└── src/
└── main.zig Entire kernel: Multiboot header, VGA driver, kmain
HOST (macOS ARM / any OS) EMULATED x86 MACHINE (QEMU)
───────────────────────── ──────────────────────────────
┌──────────────┐ zig build ┌────────────────────┐
│ src/main.zig│───────────────▶│ zig-out/bin/kernel│ (i386 ELF binary)
│ linker.ld │ cross-compile │ Multiboot 1 magic │
│ build.zig │ x86-free- │ at offset 0 │
└──────────────┘ standing-none └─────────┬──────────┘
│
qemu-system-i386 -kernel
│
▼
┌──────────────────────┐
│ QEMU / TCG │
│ (x86 CPU emulation) │
└─────────┬────────────┘
│
┌─────────────────────┼───────────────────────┐
│ Emulated i386 hardware │
│ │ │
│ 1. Multiboot │ │
│ loader reads ▼ │
│ ELF, puts ┌───────────┐ │
│ CPU in │ _start │ 32-bit │
│ protected │ (naked) │ protected │
│ mode └────┬──────┘ mode │
│ │ │
│ set up │ stack │
│ ▼ │
│ ┌──────────┐ │
│ │ kmain │ │
│ └────┬─────┘ │
│ │ │
│ ┌───────────┼───────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ clearScreen() print(...) hlt loop │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ VGA Text Buffer at 0xB8000 │ │
│ │ 80×25 grid, 16-bit per cell │ │
│ │ (ASCII byte + colour attribute) │ │
│ └──────────────────────────────────┘ │
│ │ │
└─────────────────────┼───────────────────────┘
│
▼
┌──────────────────────┐
│ QEMU VGA Window │
│ │
│ ════════════════ │
│ Hello from the │
│ Zig Kernel! │
│ ════════════════ │
│ │
└──────────────────────┘
- Target:
x86-freestanding-none— 32-bit, no OS, no libc - Boot protocol: Multiboot 1 — a 12-byte header (magic
0x1BADB002, flags, checksum) placed in the first 8 KiB of the ELF - VGA output: Direct memory-mapped I/O to
0xB8000using Zig'svolatilepointer semantics — no drivers, no BIOS calls - Red zone: Disabled — the System V ABI red zone would be corrupted by hardware interrupts
- SSE/AVX: Disabled — avoids the need to save/restore FPU state
- No assembly files: The Multiboot header is a Zig
extern structexported to a linker section; the entry point uses inlineasm volatile