From Power On to Main(): How an OS Boots
When you press the power button, magic happens. But it’s not magic - it’s legacy engineering layered on newer standards.
Before your beautiful React app loads, your CPU has to wake up in a mode that resembles a 40-year-old Intel 8086 chip.
1. The Firmware Phase (BIOS or UEFI)
The PSU stabilizes power. The CPU wakes up and jumps to a reset vector. Firmware code runs on a flash chip.
BIOS path (legacy):
- Runs POST (Power-On Self-Test).
- Scans for a bootable device.
- Reads the first 512 bytes (Sector 0) into memory at
0x7C00and jumps there.
UEFI path (modern):
- Loads a boot manager from the EFI System Partition (ESP).
- Boots a
.efiexecutable (like GRUB or systemd-boot). - Passes control with a richer API and memory map.
2. The Bootloader
Legacy BIOS gives you only 512 bytes of stage-1 bootloader space. That’s why modern bootloaders are multi-stage:
- Stage 1: Tiny loader in the MBR.
- Stage 2: Understands filesystems and loads the kernel image.
Bootloaders also pass critical data to the kernel: memory maps, CPU features, and boot arguments.
3. CPU Mode Switch
The CPU starts in Real Mode (16-bit). It can address only 1MB of RAM. A real OS needs Protected Mode (32-bit) or Long Mode (64-bit).
; Switch to Protected Mode (simplified)
cli ; Disable interrupts
lgdt [gdt_descriptor] ; Load Global Descriptor Table
mov eax, cr0
or eax, 1 ; Set the PE (Protection Enable) bit
mov cr0, eax
jmp 08h:clear_pipe ; Far jump to flush CPU pipeline
In 64-bit mode, you also enable paging and load a 64-bit GDT.
4. Kernel Entry
The bootloader jumps to the kernel entry point (often a C function like kmain()), but the kernel still needs to set up basics:
- Stack: Allocate a safe stack for C code.
- IDT/GDT: Interrupt and descriptor tables.
- Paging: Virtual memory and page tables.
- Device drivers: Keyboard, screen, disk, timers.
There is no printf. There is no malloc. You have to build them yourself.
5. Userspace Init
Once the kernel is stable, it launches the first user process:
- Linux:
initorsystemd - BSD:
init
That process starts services, networking, and finally your login manager or shell.
That is the joy of systems programming: an entire world built from nothing but a few bytes of boot code.