NovOS, a bare metal x86 operating system kernel by Abdulhamid SonaikeNovOS, a bare metal x86 operating system kernel by Abdulhamid Sonaike

NovOS, a bare metal x86 operating system kernel

Abdulhamid Sonaike

Abdulhamid Sonaike

NovOS is a bare metal operating system kernel for i686 protected mode, written in C and x86 assembly with no standard library underneath it. GRUB loads it, it brings up its own interrupts, memory and drivers, and it ends at an interactive shell.

Why I built it

Most of what I build sits high up the stack. Web apps, APIs, model calls. I wanted to know what all of that is actually standing on, and the only honest way to find out is to write the layer yourself, with nothing underneath you to fall back on.

What happens when it boots

BIOS loads GRUB from the ISO. GRUB finds the multiboot entry, loads the kernel into memory at 1 MiB and jumps to the assembly entry point, which sets up a 16 KiB stack and calls into C with the multiboot magic and info pointer. From there the init sequence runs in a fixed order: GDT, IDT, PIC, PIT, keyboard, physical memory manager, paging, then the RAM filesystem. Hardware interrupts are switched on and the shell takes over.

What is actually implemented

The GDT carries five descriptors: null, kernel code, kernel data, user code and user data. The IDT covers all 32 CPU exceptions plus 16 hardware IRQs, with NASM stubs that save registers before dispatching into the C handlers. The 8259A PIC is remapped to vectors 32 to 47, so hardware interrupts stop landing on the same vectors as CPU exceptions, which is the first bug everyone writing a kernel runs into.
Memory is handled by a bitmap physical frame allocator that covers up to 512 MiB, with the bitmap itself living in BSS. Paging is enabled rather than skipped: the page directory and tables are statically allocated and 4 KiB aligned, the first 8 MiB is identity mapped, and CR0.PG is set, so after paging init the physical and virtual addresses of all kernel data are identical.
Drivers are a VGA text mode driver at 80 by 25 with 16 colours, scrolling and a blinking cursor; a PS/2 keyboard on IRQ1 handling scancode set 1 with Shift, CapsLock and the arrow keys; and the PIT on channel 0 at 1000 Hz, which gives a millisecond accurate wait. On top of those sits a shell with nine built in commands, 32 entries of history on the up and down keys, and a read only in-memory RAMFS holding five files that ls and cat can read.

There is no standard library

Every string and memory routine, and the formatted print used for all kernel output, is written from scratch in the kernel's own util file. That constraint is the point of the project. When a print goes wrong you cannot blame libc, and when a page fault fires the only handler that exists is the one you wrote.

Building and running it

The kernel has to be compiled with an i686-elf cross compiler rather than host GCC, assembled with NASM, linked at 1 MiB by a custom linker script, and packaged into a bootable ISO with grub-mkrescue. It boots under qemu-system-i386. The Makefile runs the whole chain in one command.

What it demonstrates

Systems level C and x86 assembly, comfort working directly against hardware and interrupt controllers, and the discipline of an environment with no runtime, no allocator and no error message except the ones you print yourself. It is the reason I am careful about memory, ordering and failure modes in the higher level work I do now.
The init sequence, in the order it actually runs.
The init sequence, in the order it actually runs.
Each subsystem, and what is actually implemented in it.
Each subsystem, and what is actually implemented in it.
Why a kernel is on an AI engineer's profile.
Why a kernel is on an AI engineer's profile.
Like this project

Posted Sep 15, 2026

An i686 kernel in C and x86 assembly with no standard library: GDT, IDT, remapped PIC, paging, VGA and PS/2 drivers, a RAMFS and a working shell.