Skip to content

About

Crafting a bootloader from scratch

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Craft a Bootloader

This is a simple bootloader for x86_64 arch, for learning purposes.

Prerequisites (Arch Linux)

Install the following packages:

sudo pacman -S nasm qemu-system-x86 tigervnc
Package Purpose Minimum Version
nasm x86 assembler for boot.s 2.16+
qemu-system-x86 QEMU emulator (provides qemu-system-x86_64) 8.0+
tigervnc Provides vncviewer for graphical QEMU output 1.14+

Build & Run

Build bootloader.bin

make

Launch in QEMU with VNC output (opens vncviewer automatically and closes QEMU on exit)

make run

Clean build artifacts

make clean

Learning Material

Notes

The code enters 16-bit Real mode, which is the simplest x86 CPU operating mode, active at startup (reset). It uses 16-bit registers, a 20-bit address bus (limiting accessible memory to 1 MB), and addresses memory via segment:offset pairs. There's no memory protection, no privilege levels, and no virtual memory — any code can access any memory or I/O port. Real mode is what DOS and legacy BIOS bootloaders run in.

We need to start with 0x07C0 as this address is the starting point for The last 2 bytes of the 512 bytes sector are 0xAA55, which represent the boot signature.

In x86 Real mode the following registers are used:

Category Register(s) Purpose
General-purpose AX Accumulator, commonly used for arithmetic and I/O.
General-purpose BX Base register, often used for memory addressing.
General-purpose CX Count register, used in loops and shifts.
General-purpose DX Data register, used with AX in some operations and I/O.
General-purpose SI Source index, used in string and memory operations.
General-purpose DI Destination index, used in string and memory operations.
General-purpose BP Base pointer, typically used to access stack-based data.
General-purpose SP Stack pointer, points to the top of the stack.
Segment CS Code segment, used with IP to locate instructions.
Segment DS Data segment, default segment for many data accesses.
Segment ES Extra segment, often used in string instructions.
Segment SS Stack segment, used with SP/BP.
Segment FS Extra segment register on later x86 CPUs.
Segment GS Extra segment register on later x86 CPUs.
Instruction pointer IP Offset of the next instruction within CS.
Flags FLAGS Status and control bits for CPU operations.
8-bit subregisters AH / AL High and low 8-bit parts of AX.
8-bit subregisters BH / BL High and low 8-bit parts of BX.
8-bit subregisters CH / CL High and low 8-bit parts of CX.
8-bit subregisters DH / DL High and low 8-bit parts of DX.

Notes on nasm assembly:

Instruction / Directive What it does
bits 16 Tells NASM to assemble 16-bit code (Real mode).
mov dest, src Copies src into dest. Can move between registers, memory, and immediates.
call label Pushes the return address onto the stack and jumps to label.
ret Pops the return address from the stack and jumps back after a call.
push val Decrements SP and stores val on the stack.
pop reg Loads a value from the stack into reg and increments SP.
pusha Pushes all 16-bit general-purpose registers (AX, CX, DX, BX, SP, BP, SI, DI) onto the stack.
popa Restores all registers saved by pusha (in reverse order).
add dest, src Adds src to dest and stores the result in dest. Used here to clean arguments off the stack (add sp, 2).
cli Clears the interrupt flag — CPU ignores maskable hardware interrupts.
hlt Stops the CPU until the next external interrupt (or reset).
int n Triggers software interrupt number n. BIOS provides services via int 0x10 (video), int 0x13 (disk), etc.
or dest, src Performs a bitwise OR. Used here as or al, 0 to set the zero flag without changing the value (tests for zero).
je label Jumps to label if the zero flag is set (i.e. if the previous operation resulted in zero).
jmp label Unconditionally jumps to label.
db val Defines a byte (or bytes) of data. msg: db "Hello", 0 stores the string followed by a null terminator.
dw val Defines a word (2 bytes) of data. dw 0xAA55 places the boot signature at the end of the sector.
times count directive Repeats directive count times. times 510-($-$$) db 0 fills the rest of the 512-byte sector with zeros.

About

Crafting a bootloader from scratch

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages