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:

  1. BIOS (Basic Input/Output System) runs from firmware.

  2. It performs POST (Power-On Self Test).

  3. It scans connected devices to find a bootable disk (candidate disks).

  4. For each disk, BIOS reads the first 512 bytes into memory address 0x7C00.

  5. It checks for a signature: the last two bytes of that 512-byte block must be 0xAA55.

  6. 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, then 0xAA

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🚀