In this article
An operating system does not begin with a taskbar. First, code must reliably take control from a bootloader, understand information about the machine and manage memory. BoringOS demonstrates this path through its experimental independent x86_64 system and its own BoringKernel.
The BoringOS project page presents the larger current state. This article explains the foundations for readers who have never written a kernel. BoringOS uses mainly C with small assembly components and is not a Linux distribution. Our starting point is an emulator, without modifying a physical boot drive.
Firmware, bootloader and kernel have distinct roles
Firmware starts the machine and selects a boot path. A bootloader loads the kernel and provides defined information. BoringOS uses Limine for this step. The kernel then takes responsibility for its own system work.
| Layer | Role in the simplified introduction |
|---|---|
| Firmware | Hardware startup and boot selection |
| Limine | Load the kernel and deliver boot information |
| BoringKernel | Memory, exceptions, processes and system functions |
| Userspace | Native services and applications |
Limine is an external project rather than a self-developed part of BoringKernel. Keeping this boundary clear shows what the kernel owns and which assumptions still come from the bootloader.
Why a kernel differs from a normal C program
An ordinary application starts inside an existing operating system and can use its processes, files and libraries. An early kernel must supply that environment first.
Freestanding describes this difference in the C build. A compiled C program is not automatically a bootable kernel: entry point, linker layout, architecture and boot protocol must agree. A normal printf is not simply available during early startup.
Serial output is therefore a useful first observation channel. It can report progress before a full graphics stack or filesystem exists. An emulator makes that output conveniently visible on the host.
Read the real BoringKernel entry point
kernel/core/entry.c contains boring_kernel_entry. A short real excerpt is:
serial_init();
serial_write_string("BoringOS booting...\n");
serial_write_string("BoringKernel 0.0.62-dev\n");
These lines belong inside the existing entry function; they are not a complete bootable file. Queries and checks for several system areas follow. The current implementation is substantially beyond a “Hello World” kernel.
Order matters when reading it: observation needs an output channel before memory-initialization failures can be reported clearly. The code checks results and halts deliberately after fundamental failures rather than continue with invalid prerequisites.
Separate physical and virtual memory
The physical memory manager, or PMM, tracks usable RAM regions and frames. It must distinguish available memory from areas reserved for the kernel or hardware.
The virtual memory manager, VMM, handles address mappings through page tables. A program address is consequently not necessarily the same as a physical RAM address. Bootloader information includes the memory map and details of existing mappings.
BoringOS tests these foundations deliberately: allocated frames should be aligned, unique and correctly accounted for when released. Passing one test establishes a particular condition, rather than the correctness of an entire desktop.
Older repository documents describe earlier milestones. For current work, the precise revision, present entry code and documented acceptance checkpoints matter more than an isolated old bootstrap description.
Understand a small halting example
This original C example illustrates only a controlled waiting loop in an x86_64 kernel context:
void tutorial_halt(void) {
for (;;) {
__asm__ volatile ("cli; hlt");
}
}
cli disables maskable interrupts; hlt halts the CPU until an appropriate event. The loop does not return into an unknown calling environment. These privileged instructions belong in kernel context. Do not execute the example as an ordinary Linux application.
It intentionally omits the boot protocol, linker script, output and device initialization. For an actual boot, use the complete project rather than infer bootability from this small excerpt.
Explore the project in an emulator
Prerequisites include a suitable x86_64 GCC/binutils toolchain, Make, QEMU, xorriso and the project's documented download tools. Check the current build instructions and use a new checkout:
git clone https://github.com/dennishilk/BoringOS.git
Enter it:
cd BoringOS
Build the standard configuration:
make
Start the standard emulator test:
make run
The current Makefile uses QEMU with serial output and no graphical window. This is a bootstrap/test route, rather than automatically the full graphical BoringWM demo. The observed state also depends on test mode. End this foreground QEMU test with Ctrl + C; its stdio connection enables terminal signals by default.
Follow the path to a native desktop
A desktop additionally needs a scheduler, Ring 3 processes, native system calls, a VFS and BoringFS, plus display and input services. BoringWM, terminal, editor and file management build on those foundations.
The project documents physical tests on Cthulhu, including USB/HID and a 1920×1080 desktop. Such claims belong to particular accepted revisions. A later optimization passing automated tests is not automatically the same physically verified version.
QEMU supports reproducible development but does not test every USB topology or physical graphics device. It remains the appropriate first setting for beginners: observe startup, read one function and follow a single checked prerequisite.
References and next steps
- BoringOS on GitHub.
- Checked kernel entry and Makefile.
- Current project state and physical references.
- Limine boot protocol and QEMU documentation.
Sources checked on 8 October 2026. For a closer look at display addressing, continue with the framebuffer article.