-
Notifications
You must be signed in to change notification settings - Fork 63
Bootloader
The first code executed when MentOS starts.
The bootloader is responsible for:
- Minimal CPU setup - Establish a stack and enter C code
- Multiboot Handling - Use the Multiboot header/info provided by GRUB/QEMU
- Kernel Relocation & Paging - Map low memory and relocate the embedded kernel ELF
-
Kernel Transfer - Jump to the kernel entry point (
kmain())
boot/
├── src/
│ ├── boot.S ← Assembly entry point
│ ├── boot.c ← Main bootloader logic
│ └── multiboot.c ← Multiboot spec handling
└── linker/
├── boot.lds ← Bootloader linker script
└── kernel.lds ← Kernel linker script- BIOS or GRUB loads
bootloader.bininto memory - Execution begins at
boot_entry(defined inboot.S)
; boot/src/boot.S
section .text
global boot_entry
boot_entry:
; Disable interrupts
cli
; Set up stack
mov esp, stack_top
; Pass arguments to boot_main(magic, header, esp)
push esp ; initial stack pointer
push ebx ; multiboot info structure
push eax ; multiboot magic number
; Call C code
call boot_main
; Halt if boot_main returns
cli
.hang:
hlt
jmp .hangActions:
- Disables interrupts
- Sets up stack pointer
- Pushes boot parameters (magic, header, initial stack)
- Calls
boot_main()
In boot/src/boot.c, boot_main() performs the boot-time setup needed to transfer control to the kernel:
- Builds a
boot_info_tstructure (kernel bounds, modules end, memory layout) - Sets up temporary paging mappings (identity-maps low memory and maps the kernel at its virtual base)
- Relocates the embedded kernel ELF to its virtual addresses
- Calls
boot_kernel(stack, entry, &boot_info)to jump to the kernel
Note: GDT/IDT setup happens later inside the kernel (see kernel/src/descriptor_tables/).
// In boot.S: boot_kernel(stack, entry, boot_info)
// Sets ESP, pushes boot_info, and calls kernel entryMentOS uses the Multiboot specification to be compatible with GRUB and other bootloaders.
// boot/src/boot.S
.section .multiboot_header
.align 4
multiboot_header:
.long MULTIBOOT_HEADER_MAGIC
.long MULTIBOOT_HEADER_FLAGS
.long MULTIBOOT_CHECKSUMConstants:
-
MULTIBOOT_HEADER_MAGIC: 0x1BADB002 -
MULTIBOOT_HEADER_FLAGS: Requested features (page align + memory info) -
MULTIBOOT_CHECKSUM: -(MAGIC + FLAGS)
The bootloader receives a multiboot_info_t from GRUB (see kernel/inc/multiboot.h):
typedef struct multiboot_info {
uint32_t flags; // Available info
uint32_t mem_lower; // Lower memory (KB)
uint32_t mem_upper; // Upper memory (KB)
uint32_t boot_device; // Boot device
uint32_t cmdline; // Kernel command line
uint32_t mods_count; // Number of modules
uint32_t mods_addr; // Modules address
// ... more fields
} multiboot_info_t;Information Provided:
- Memory map (physical RAM available)
- Boot device
- Kernel command line
- Loaded modules (if any)
- Framebuffer information
The bootloader builds temporary page tables that:
- Identity-map low memory (so the bootloader can keep running)
- Map the kernel's virtual address range to its physical location
This setup happens in boot/src/boot.c via __setup_boot_paging() and is enabled before jumping to the kernel.
Use the CMake targets:
cd build
make bootloader.binbuild/mentos/bootloader.bin contains:
- Bootloader code
- Embedded
kernel.bin(as a linked binary blob)
Key excerpts (see boot/linker/boot.lds for full script):
ENTRY(boot_entry)
. = 0x00100000;
_bootloader_start = .;
.multiboot : {
*(.multiboot_header)
}
.text : { *(.text) }
.rodata : { *(.rodata*) }
.data : { *(.data) }
.bss : { *(.bss*) }
_bootloader_end = .;Links the standalone kernel.bin (used by kernel compilation).
Main bootloader entry point from assembly.
Parameters:
-
magic: Multiboot bootloader magic (0x2BADB002 expected) -
header: Pointer to multiboot information structure -
esp: Initial stack pointer
Actions:
- Build
boot_info_t(kernel bounds, modules end, memory layout) - Set up boot-time paging
- Relocate the kernel ELF image
- Call
boot_kernel()
Creates the temporary page tables used during early boot.
Copies the ELF segments of the embedded kernel image to their virtual addresses.
Assembly helper that switches the stack pointer and calls the kernel entry.
# Terminal 1
make qemu-gdb
# Terminal 2 (from build/)
gdb --quiet --command=gdb.runAdd debug prints (serial console):
// In boot.c
__debug_puts("[bootloader] Start...\n");objdump -d build/mentos/bootloader.bin | less- GRUB didn't load properly
- Multiboot header is missing or incorrect
- Check
.multiboot_headersection in assembly
- Kernel binary wasn't embedded correctly
- Check linker script
- Verify kernel.bin.o creation
- Paging setup incorrect
- Identity mapping missing
- Check page table entries
- CPU exception during boot
- Usually GDT or paging issue
- Use
make qemu-gdbto catch early
- Kernel - What happens after the bootloader
- Architecture - Overall system structure
- Scheduling - How the kernel runs processes
Previous: Architecture | Next: Kernel →