Skip to content

Multiboot

Multiboot is a specification defining how a bootloader hands control to a kernel: a standardized contract covering how the kernel identifies itself as Multiboot-compliant, what state the CPU is guaranteed to be in on entry, and how the bootloader passes information (a memory map, command-line arguments, module locations) back to the kernel. Its main practical benefit is decoupling a kernel from any one specific bootloader’s internal details: a Multiboot-compliant kernel works with any bootloader that implements the same specification, most commonly GRUB, without either side needing to know anything else about the other.

A kernel declares itself Multiboot-compliant by embedding a specific structure within the first 8 KB of its binary, identified by a fixed magic number the bootloader scans for. Multiboot 1 uses magic number 0x1BADB002; Multiboot 2, a later, more extensible revision, uses 0xE85250D6 and a somewhat more elaborate tagged structure rather than a single fixed-size header.

// Multiboot 1 header
struct multiboot_header {
uint32_t magic; // 0x1BADB002
uint32_t flags;
uint32_t checksum; // magic + flags + checksum == 0
};
__attribute__((section(".multiboot")))
struct multiboot_header mb_header = {
.magic = 0x1BADB002,
.flags = 0,
.checksum = -(0x1BADB002 + 0),
};

The checksum field exists purely so a bootloader can validate the header wasn’t corrupted or misidentified by coincidence: the three fields are defined to sum to zero, mod 2³², and a bootloader rejects a header where they don’t. Correctly placing this structure within the required first 8 KB depends on the kernel’s linker script; a header buried later in the binary by an unlucky choice of section ordering will never be found, and the bootloader falls back to treating the kernel as non-Multiboot, generally failing to load it at all.

A Multiboot bootloader guarantees a specific, documented CPU state on jumping into the kernel: 32-bit protected mode already active, paging disabled, interrupts disabled, and a defined pair of registers: EAX holding a magic value (0x2BADB002 for Multiboot 1) confirming a Multiboot-compliant loader was actually used, and EBX holding a pointer to the Multiboot information structure, the bootloader’s response containing the memory map, boot command line, and locations of any loaded modules. A kernel’s earliest entry code conventionally checks the EAX magic value before trusting anything else it was handed, since a kernel accidentally loaded by a non-Multiboot-aware path would leave both registers holding unrelated, meaningless values.

Notably, this guaranteed state stops at 32-bit protected mode: a kernel targeting long mode still has to perform the protected-to-long-mode transition itself after Multiboot hands off control, since Multiboot predates x86-64 and makes no guarantees about 64-bit state at all.

The structure EBX points to is itself a tagged (Multiboot 2) or flag-driven (Multiboot 1) collection of optional pieces of information, only some of which a bootloader is required to actually populate. The physical memory map is the piece nearly every kernel consumes immediately, since it removes the need to query BIOS or UEFI directly; boot module locations (used for loading an initial ramdisk, for instance) and the kernel’s command-line string are also commonly present and consumed early.

Multiboot 2 restructures the fixed-flags header into a series of typed, length-prefixed tags, letting the specification add new optional information without breaking every existing implementation’s fixed-offset assumptions the way extending Multiboot 1’s flags field would. Multiboot 2 also formally supports being loaded directly in 64-bit mode on capable hardware, though GRUB’s actual handoff behavior in practice still commonly lands a kernel in 32-bit protected mode regardless of version, leaving the long-mode transition to the kernel either way. A new kernel with no legacy compatibility requirement generally targets Multiboot 2 for its more extensible tag structure, though Multiboot 1 remains simpler to implement correctly for a minimal first boot.

The linker script requirement (placing the Multiboot header within the binary’s first 8 KB) is a common early source of a kernel that GRUB simply refuses to recognize at all, with no error message beyond GRUB’s own generic “unrecognized” failure, since the bootloader has no way to distinguish “not a kernel” from “a kernel whose header is present but not where it’s looking.” Explicitly placing the header in its own linker section, positioned first in the output binary’s layout, avoids this regardless of how the compiler happens to order other code and data.

  1. ^ GNU, Multiboot2 Specification: the formal specification this article summarizes.
  • Bootloaders: GRUB and other Multiboot-compliant loaders that implement this handoff.
  • The Boot Process: where the Multiboot handoff fits into the larger boot sequence.
  • initrd: what a boot module commonly loads, and why.