The problem
An operating system project has to make every hidden assumption explicit. Before there is a runtime, filesystem, or standard library, the bootloader must load code, establish a machine state, and transfer control reliably.
The approach
I kept the system deliberately small: roughly 11KB of x86 assembly split between the bootloader and kernel. The bootloader sets up the Global Descriptor Table, switches the CPU into 32-bit protected mode, and jumps into the kernel.
The kernel then writes to the VGA text buffer, handles PS/2 keyboard input, and turns those inputs into a small interactive command shell. QEMU made the feedback loop cheap: assemble an image, boot it, and inspect the result without risking the host system.
How I actually built this
- First pass: I got the boot sector loading a kernel image before adding terminal output or input.
- Setback: the protected-mode handoff failed when the segment configuration did not match the GDT, leaving the kernel unreachable after the mode switch.
- Recovery: I verified the transition in small steps, then added keyboard handling, scrolling, and shell commands once the boot path was dependable.
What I learned
Low-level progress is easier to trust when each boundary has a visible proof: the bootloader loads, protected mode is active, the kernel prints, and input arrives. The current shell is only an early milestone, but it gives future memory management, filesystems, and executable loading somewhere concrete to land.