Overview

BOOTMGR (Boot Manager) is the initial boot loader for FreeWorld OS. It consists of two stages:

  • Stage 1 (bootloader_stage1.asm): The MBR bootloader (512 bytes) that loads stage 2
  • Stage 2 (bootloader_ui.asm): The graphical bootloader that displays the boot menu and loads the kernel
Note: Stage 1 runs in 16-bit real mode and must fit within exactly 512 bytes (boot sector size). Stage 2 is larger (~2KB) and is loaded from disk by stage 1.

Boot Sector Structure

The boot sector follows the standard PC boot sector format:

  • Size: 512 bytes
  • Boot Signature: 0xAA55 at bytes 510-511
  • Entry Point: 0x7C00 (standard BIOS load address)

Code Structure

Assembly Directives

bits 16          ; 16-bit real mode
org 0x7C00      ; BIOS loads boot sector at 0x7C00

Entry Point: start

The start label is the entry point executed by the BIOS:

start:
    cli              ; Disable interrupts
    xor ax, ax       ; Clear AX register
    mov ds, ax       ; Set data segment to 0
    mov es, ax       ; Set extra segment to 0
    mov ss, ax       ; Set stack segment to 0
    mov sp, 0x7C00   ; Set stack pointer

Functions

init_serial

Initializes serial port COM1 at 0x3F8 for debugging output:

init_serial:
    ; Set baud rate to 38400 (divisor 0x0003)
    ; Configure: 8 bits, no parity, 1 stop bit
    ; Enable FIFO

Purpose: Enables serial port debugging output alongside video output.

print_serial

Prints a character to the serial port (COM1):

print_serial:
    ; Wait for transmit ready
    ; Send character to COM1 data port

Purpose: Outputs debug information to serial port for QEMU debugging.

print_string

Displays a null-terminated string using BIOS interrupt 0x10 and serial port:

print_string:
    lodsb            ; Load byte from [SI] into AL, increment SI
    or al, al        ; Check if AL is zero (end of string)
    jz done          ; Jump to done if zero
    mov ah, 0x0E     ; BIOS teletype function
    int 0x10         ; BIOS video interrupt
    jmp print_string ; Loop
done:
    ret              ; Return

Disk Read (Stage 1)

Stage 1 loads stage 2 from disk using LBA extended read with CHS fallback:

; Check for LBA extended read support
mov ah, 0x41        ; Check Extensions Present
mov bx, 0x55AA
mov dl, [boot_device]
int 0x13
jc .use_chs         ; Fall back to CHS if not supported

; Use LBA extended read (Disk Address Packet)
mov si, dap         ; DAP structure
mov ah, 0x42        ; Extended Read Sectors
mov dl, [boot_device]
int 0x13
jnc .verify_load    ; Success

.use_chs:
; CHS addressing (required for floppy disks)
mov ah, 0x02        ; Read sectors
mov al, 4           ; Read 4 sectors (stage 2)
mov ch, 0           ; Cylinder 0
mov cl, 3           ; CHS sector 3 (physical sector 2)
mov dh, 0           ; Head 0
mov dl, [boot_device]
xor bx, bx
mov es, bx
mov bx, 0x7E00      ; Load to 0x0000:0x7E00
int 0x13

.verify_load:
; Verify stage 2 signature ('OB' = 0x424F)
cmp byte [es:0x7E00], 'O'
jne .bad_sig
cmp byte [es:0x7E00 + 1], 'B'
jne .bad_sig
jmp 0x0000:0x7E00   ; Jump to stage 2

Purpose: Loads stage 2 bootloader from disk into memory at 0x0000:0x7E00.

Critical: Uses CHS sector 3 (not 2) because CHS sectors are 1-based while physical sectors are 0-based.

Error Handling: Checks for disk read errors and verifies stage 2 signature ('OB') before jumping.

Important: The bootloader was fixed to correctly map physical sectors to CHS sectors:
  • Physical sector 0 = CHS sector 1 (MBR)
  • Physical sector 2 = CHS sector 3 (Stage 2 start)
  • Physical sector 6 = CHS sector 7 (Graphics start)
  • Physical sector 33 = CHS sector 33 (Kernel start)

JMP Instructions

Jump to Kernel

After loading the kernel, BOOTMGR jumps to the kernel entry point:

jmp 0x1000:0x0000  ; Far jump to kernel at segment 0x1000, offset 0x0000

Jump in print_string Loop

Conditional jump used in the string printing loop:

jz done          ; Jump if zero flag is set (end of string)
jmp print_string ; Unconditional jump to continue loop

Variables and Constants

Name Type Value Description
boot_msg String 'FreeWorld Boot Manager v0.1' Boot message displayed on startup
0x7C00 Address 0x7C00 BIOS boot sector load address
0xAA55 Signature 0xAA55 Boot sector signature (bytes 510-511)
0x1000:0x0000 Address Segment:Offset Kernel entry point address

Boot Process Flow

Stage 1 (bootloader_stage1.asm)

  1. BIOS loads boot sector (512 bytes) from disk to memory at 0x7C00
  2. BIOS jumps to 0x7C00 (start label)
  3. Stage 1 initializes segments, stack, and serial port
  4. Stage 1 initializes VGA text mode (80x25)
  5. Stage 1 displays "Loading FreeWorld OS..." message
  6. Stage 1 checks for LBA extended read support
  7. Stage 1 loads stage 2 from CHS sector 3 (physical sector 2) to 0x0000:0x7E00
  8. Stage 1 verifies stage 2 signature ('OB')
  9. Stage 1 passes boot device number to stage 2
  10. Stage 1 jumps to stage 2 at 0x0000:0x7E00

Stage 2 (bootloader_ui.asm)

  1. Stage 2 initializes segments and stack
  2. Stage 2 initializes graphics mode (VESA or VGA)
  3. Stage 2 loads graphics from disk (logo, background, icons)
  4. Stage 2 displays graphical boot menu
  5. Stage 2 waits for user selection
  6. Stage 2 loads kernel from CHS sector 33 (physical sector 33) to 0x1000:0x0000
  7. Stage 2 verifies kernel signature ('FREEWORL')
  8. Stage 2 jumps to kernel entry point (0x1000:0x0000)

Memory Layout

0x0000 - 0x03FF  : Interrupt Vector Table
0x0400 - 0x04FF  : BIOS Data Area
0x0500 - 0x7BFF  : Available
0x7C00 - 0x7DFF  : Stage 1 Bootloader (512 bytes)
0x7E00 - 0x9FFF  : Stage 2 Bootloader (~2KB)
0x8000 - 0x8FFF  : Graphics Index Table
0x9000 - 0x9FFF  : Logo Graphics Buffer
0xA000 - 0xAFFF  : Background Graphics Buffer
0xB000 - 0xB7FF  : Selection Highlight Buffer
0xB800 - 0xBFFF  : Progress Bar Buffer
0xC000 - 0xC1FF  : Error Icon Buffer
0xC200 - 0xC3FF  : Success Icon Buffer
0xA000 - 0xBFFF  : Video Memory (VGA)
0xC000 - 0xFFFF  : BIOS ROM
0x1000:0x0000    : Kernel Entry Point

Disk Layout

The boot disk is organized as follows:

Physical Sector 0  : Stage 1 Bootloader (MBR, 512 bytes)
Physical Sector 1  : Unused
Physical Sector 2  : Stage 2 Bootloader start (CHS sector 3)
Physical Sectors 2-5: Stage 2 Bootloader (4 sectors, ~2KB)
Physical Sector 6  : Graphics start (Logo, CHS sector 7)
Physical Sectors 6-32: Graphics resources
Physical Sector 33 : Kernel start (CHS sector 33)

BIOS Interrupts Used

Interrupt Function AH Register Description
0x10 Video Services 0x00 Set video mode (AL=0x03 for 80x25 text mode)
0x10 Video Services 0x0E Teletype output - prints character in AL register
0x13 Disk Services 0x00 Reset disk system
0x13 Disk Services 0x41 Check if extended disk access functions are available
0x13 Disk Services 0x42 Extended Read Sectors (LBA) - uses Disk Address Packet (DAP)
0x13 Disk Services 0x02 Read Sectors (CHS) - traditional cylinder-head-sector addressing

Build Instructions

To build the bootloader:

# Build Stage 1
cd boot
nasm -f bin bootloader_stage1.asm -o build/bootloader_stage1.bin

# Build Stage 2
make bootloader_ui.bin

# Create boot image
./scripts/fix-boot-layout.sh

The output file bootloader_stage1.bin is exactly 512 bytes and must be written to the first sector (sector 0) of a bootable disk.

The fix-boot-layout.sh script ensures correct placement of all boot components on the disk image.

Integration Points

  • BIOS/UEFI: Loaded by BIOS at 0x7C00
  • Kernel: Loads and transfers control to kernel at 0x1000:0x0000 (linear 0x10000)
  • Serial Port: Outputs debug information to COM1 (0x3F8) for QEMU debugging
  • BCD: May read BCD configuration (future)

Debug Output

Stage 1 outputs messages to both video (BIOS INT 0x10) and serial port (COM1):

  • "S1" - Stage 1 started (serial only)
  • "Loading FreeWorld OS..." - Before loading stage 2
  • "OK" - Disk read successful (serial only)
  • "JMP" - Jumping to stage 2 (serial only)
  • "Disk read failed!" - If disk read fails
  • "Bad signature! Got: XX" - If stage 2 signature doesn't match

Serial port output is particularly useful for debugging in QEMU with -serial stdio or -serial file:serial.log.

Debugging Tip: The bootloader includes extensive serial output for debugging. Use strings serial.log or hexdump -C serial.log to view the output after a QEMU run.

Recent Fixes

The following critical fixes were implemented:

  • CHS Sector Mapping: Fixed incorrect sector calculation - physical sector 2 now correctly maps to CHS sector 3
  • LBA Extended Read: Implemented LBA extended read (INT 0x13, AH=0x42) with automatic fallback to CHS
  • Graphics Loader: Fixed graphics loader to use correct CHS sectors matching disk layout
  • Disk Reset: Added disk reset before reading to ensure reliable disk access
  • Register Preservation: Fixed register preservation during INT 0x13 calls