- Atul for Marketing
- Posts
- Writing a 512-Byte Boot Sector OS in x86 Assembly from Scratch
Writing a 512-Byte Boot Sector OS in x86 Assembly from Scratch
In Week 12 of Project52, I challenged myself to build an operating system from the most fundamental entry point possible: the boot sector. This 512-byte region at the start of a disk is the first code executed by the CPU after power-on, loaded directly into memory by the BIOS. Without relying on GRUB, Linux, or even a file system, I wrote hand-crafted x86 Assembly that runs in 16-bit real mode, interacts with BIOS interrupts, and produces output directly to the screen. This project was an exercise in minimalism, precision, and understanding the bare-metal mechanics of how all modern computing systems begin.
In Week 12 of Project52, I stepped away from frontend development, application code, and high-level abstractions. Instead, I went back to the roots of computing. This week, I built a minimalist operating system that runs without the support of any existing OS or bootloader.
This project was about writing the bare-metal boot sector code that the BIOS itself reads and executes. What follows is a deep technical breakdown of what was built, why it's significant, and how it works under the hood.
A boot sector is a 512-byte region at the very beginning of a disk, and that’s all the BIOS reads when the system first powers on.
BIOS stands for Basic Input/Output System.
It’s the very first software that runs when a computer is powered on.
It’s stored on a chip on your motherboard and is completely independent of any operating system.
In most real systems:
The boot sector just loads a larger OS (e.g., via GRUB or a kernel).
The OS itself lives elsewhere (higher on the disk, in memory, or filesystems).
But in my project:
There is no handoff.
The entire OS is the boot sector.
Your “OS” is the boot code — it prints a message, controls CPU flow, and halts.
While simple, it:
Directly controls the CPU
Interfaces with the screen via BIOS interrupts
Executes logic without any OS below it
Runs instead of macOS, Linux, or GRUB
Owns the full instruction cycle from power-on to halt
So it’s a minimalist operating system that happens to be implemented entirely in the boot sector — hence the term.
What Actually Booted?
A custom-written 512-byte boot sector, compiled from hand-written x86 Assembly, which prints a message to the screen using BIOS interrupts and halts the system.
x86 refers to a family of instruction set architectures (ISAs) developed by Intel, starting with the Intel 8086 CPU in 1978.
It’s called “x86” because early CPUs in the family ended in “86”:
8086
80186
80286
80386
80486
→ After that, it just became known as x86.
When your PC or QEMU boots, the BIOS expects the boot sector to contain 16-bit x86 machine code. Every modern Intel/AMD CPU still supports x86’s 16-bit Real Mode — for backward compatibility.
The project does not rely on GRUB, Linux, or any OS. It does not even include a file system. This is raw hardware control.
The final artifact: mini_os.img
, a virtual floppy disk image loaded and executed by QEMU.
What Happens When a Real Machine Boots
When a PC powers on, it goes through this sequence:
BIOS (Basic Input/Output System) runs from firmware.
It performs POST (Power-On Self Test).
It scans connected devices to find a bootable disk (candidate disks).
For each disk, BIOS reads the first 512 bytes into memory address
0x7C00
.It checks for a signature: the last two bytes of that 512-byte block must be
0xAA55
.If found, it assumes the disk is bootable and jumps to
0x7C00
, executing your code.
0xAA55
is the mandatory boot sector signature.
It’s the last 2 bytes of the 512-byte boot sector, at offset 510 and 511.
When BIOS loads a disk, it checks those last two bytes:
if (memory[0x7DFE] == 0x55 && memory[0x7DFF] == 0xAA) {
// Valid boot sector — let's jump to 0x7C00
}
else {
// Invalid — skip this device
}
If the signature isn’t exactly 0xAA55
, BIOS won’t consider the disk bootable.
What I Wrote in Assembly
Code (boot.s):
[bits 16]
[org 0x7C00]
start:
mov si, message
print_loop:
lodsb
or al, al
jz halt
mov ah, 0x0E
int 0x10
jmp print_loop
halt:
cli
hlt
message:
db "Hello from Project52 OS Boot Sector!", 0
times 510-($-$$) db 0
dw 0xAA55
Explanation:
bits 16
&org 0x7C00
: We tell the assembler this code runs in 16-bit real mode and starts at 0x7C00.mov si, message
: Points to the string to print.lodsb
: Loads a byte from the string into AL.int 0x10
: BIOS interrupt for teletype output (prints characters to the screen).cli
+hlt
: Disables interrupts and halts the CPU.dw 0xAA55
: The required BIOS boot signature.
What Makes It Bootable?
1. First 512 Bytes Only
BIOS only reads the first sector of a disk.
2. Boot Signature 0xAA55
Located at byte 510 and 511
Required by BIOS to recognize it as a boot sector
Stored in little endian:
0x55
first, then0xAA
3. No File System
Nothing is loaded from a file — BIOS just dumps the raw bytes from the disk.
Makefile for Building the Boot Sector
AS = nasm
BOOT_SRC = src/boot.s
BOOT_BIN = boot.bin
BOOT_IMG = mini_os.img
all: $(BOOT_IMG)
$(BOOT_BIN): $(BOOT_SRC)
$(AS) -f bin $(BOOT_SRC) -o $(BOOT_BIN)
$(BOOT_IMG): $(BOOT_BIN)
cp $(BOOT_BIN) $(BOOT_IMG)
run: $(BOOT_IMG)
qemu-system-x86_64 -drive format=raw,file=$(BOOT_IMG)
clean:
rm -f $(BOOT_BIN) $(BOOT_IMG)
Final Output
When I run make run
, QEMU starts and simulates a PC. It loads mini_os.img
, sees the boot signature, and executes the boot sector. I see:

No OS, no bootloader, no drivers. Just my code. It’s the closest you can get to talking directly to the CPU.
What This Unlocks
This project laid the foundation for truly low-level system programming. Next steps include:
Switching to 32-bit Protected Mode
Writing a real kernel in C
Implementing keyboard input via PS/2 controller
Managing screen output without BIOS (VGA memory directly)
Building a custom file system
Why It Matters
You learn how a real PC boots
You interact with CPU architecture directly
You understand that an "OS" is just code that happens to get run early enough
You build trust with the machine — you know every instruction it’s executing
This project made it clear: all abstractions are built on top of something terrifyingly simple — 512 bytes of raw, bootable logic.
This week’s project wasn’t just about building an operating system — it was about understanding where computing begins. By stepping into the 16-bit world of real mode and BIOS interrupts, I now understand how the first sparks of execution flow into what we later call “an operating system.”
Writing a complete system in 512 bytes forces a level of precision and intentionality that’s rare in modern development. Every byte matters. Every instruction counts. And every assumption about what’s “provided” by the system is shattered — because you are the system.
This is the essence of bootstrapping: no safety nets, no libraries, no OS. Just code and silicon. And from here, the only way is up — into protected mode, memory management, device drivers, multitasking, and beyond.
-Atul Verma
Creator, Project52🚀