Boot System

Multi-stage boot pipeline — from firmware hand-off to kernel_main entry.

Profile Reference

Boot System

The boot process in Helix is an 8-stage pipeline that takes the kernel from raw firmware handoff to a fully operational system. Each stage has a specific responsibility, and the pipeline is designed so that failures at any point produce a clear diagnostic rather than a silent hang.

Helix supports three boot protocols out of the box: Limine (modern, recommended), Multiboot2 (GRUB-compatible), and UEFI (direct firmware boot). The protocol is selected in your profile's helix.toml.

Boot Stages

The kernel progresses through these stages in strict order. Each stage depends on the previous one completing successfully.

8-Stage Boot Pipeline8N · 7E
Stage 0 — Firmware HandoffBootloader passes co…1Stage 1 — BSS & StackZero .bss, set up ke…2Stage 2 — Serial ConsoleInit UART for debug …2Stage 3 — Physical MemoryParse map, init fram…2Stage 4 — Virtual MemoryPage tables, enable …2Stage 5 — InterruptsIDT/GDT, exception h…2Stage 6 — HeapKernel heap allocato…2Stage 7 — SubsystemsStart all subsystems1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node
StageNameWhat Happens
0Firmware HandoffBootloader passes control — memory map, framebuffer, ACPI tables
1BSS Clear & StackZero .bss section, set up the initial kernel stack
2Serial ConsoleInitialize UART for early debug output before framebuffer
3Physical MemoryParse the memory map, initialize the physical frame allocator
4Virtual MemorySet up page tables, enable paging, map the kernel higher-half
5InterruptsConfigure IDT/GDT, set up exception handlers and IRQs
6HeapInitialize the kernel heap allocator (switch from bump to buddy)
7SubsystemsStart all registered subsystems in dependency order

BootConfig

The BootConfig struct holds the parsed configuration from your profile's helix.toml. It's built once during early boot and passed immutably to every subsystem that needs it.

boot/src/config.rs
rust
pub struct BootConfig {
2
pub memory: MemoryConfig,
3
pub scheduler: SchedulerConfig,
4
pub console: ConsoleConfig,
5
pub modules: ModulesConfig,
6
pub boot: BootProtocolConfig,
7
pub debug: DebugConfig,
8
pub build: BuildConfig,
9
}
10
2 refs
pub struct MemoryConfig {
12
pub heap_size: usize, // e.g. 4 * 1024 * 1024 (4MB)
13
pub stack_size: usize, // e.g. 64 * 1024 (64KB)
14
pub page_size: usize, // 4096
15
pub physical_allocator: &'static str, // "buddy" | "bitmap" | "bump"
16
pub kaslr: bool,
17
}
18
2 refs
pub struct ConsoleConfig {
20
pub serial: bool,
21
pub serial_port: &'static str, // "COM1"
22
pub serial_baud: u32, // 115200
23
pub framebuffer: bool,
24
pub log_level: &'static str, // "info"
25
}
Index

BootInfo Builder

The BootInfo struct is populated by the bootloader protocol handler and passed to kernel_main. It contains everything the kernel needs to know about the hardware environment — memory map, framebuffer dimensions, ACPI root, and command line.

boot/src/info.rs
rust
3 refs
pub struct BootInfo {
2
pub memory_map: Vec<MemoryRegion>,
3
pub framebuffer: Option<FramebufferInfo>,
4
pub acpi_rsdp: Option<PhysAddr>,
5
pub command_line: Option<String>,
6
pub boot_protocol: BootProtocol,
7
pub physical_memory_offset: u64,
8
}
9
3 refs
impl BootInfo {
11
// Builder pattern for clean construction
pub fn builder() -> BootInfoBuilder;
13
}
14
2 refs
impl BootInfoBuilder {
2 refs
pub fn memory_map(self, regions: Vec<MemoryRegion>) -> Self;
2 refs
pub fn framebuffer(self, fb: FramebufferInfo) -> Self;
2 refs
pub fn acpi_rsdp(self, addr: PhysAddr) -> Self;
2 refs
pub fn command_line(self, cmd: &str) -> Self;
pub fn build(self) -> BootInfo;
21
}
22
3 refs
pub struct MemoryRegion {
24
pub base: PhysAddr,
25
pub length: u64,
26
pub region_type: MemoryRegionType,
27
}
28
2 refs
pub enum MemoryRegionType {
30
Usable, Reserved, AcpiReclaimable, AcpiNvs,
31
BadMemory, BootloaderReclaimable, Kernel, Framebuffer,
32
}
Index

Kernel Entry Point

This is where execution begins after the bootloader hands off. The entry point parses boot info, runs the 8-stage pipeline, and then enters the main kernel loop.

boot/src/main.rs
rust
1
#[no_mangle]
2
pub extern "C" fn kernel_main(boot_info: &'static BootInfo) -> ! {
3
// Stage 0-1: BSS already cleared by bootloader/asm stub
4
5
// Stage 2: Early serial console
6
serial::init(boot_info);
7
log::info!("Helix kernel starting...");
8
9
// Stage 3: Physical memory
10
let allocator = memory::init_physical(boot_info);
11
12
// Stage 4: Virtual memory + paging
13
memory::init_virtual(boot_info, &allocator);
14
15
// Stage 5: Interrupts
16
interrupts::init();
17
18
// Stage 6: Kernel heap
19
heap::init(boot_info.config.memory.heap_size);
20
21
// Stage 7: Subsystems
22
init::start_all_subsystems(boot_info);
23
24
log::info!("All subsystems started — entering main loop");
25
kernel_loop()
26
}

Limine Boot Entry

Limine is the recommended boot protocol for Helix. It provides a modern, feature-rich interface with higher-half direct mapping, framebuffer setup, and SMP initialization out of the box.

boot/limine/src/main.rs
rust
1
// Limine requests — the bootloader reads these at load time
2 refs
static MEMORY_MAP: limine::MemoryMapRequest = limine::MemoryMapRequest::new();
2 refs
static FRAMEBUFFER: limine::FramebufferRequest = limine::FramebufferRequest::new();
2 refs
static HHDM: limine::HhdmRequest = limine::HhdmRequest::new();
2 refs
static RSDP: limine::RsdpRequest = limine::RsdpRequest::new();
6
7
#[no_mangle]
8
extern "C" fn limine_entry() -> ! {
9
let mmap = MEMORY_MAP.get_response().expect("No memory map");
10
let fb = FRAMEBUFFER.get_response().ok();
11
let hhdm = HHDM.get_response().expect("No HHDM");
12
13
let boot_info = BootInfo::builder()
14
.memory_map(parse_limine_mmap(mmap))
15
.framebuffer(fb.map(convert_fb))
16
.acpi_rsdp(RSDP.get_response().map(|r| PhysAddr(r.address)))
17
.build();
18
19
kernel_main(&boot_info)
20
}
Index

The BootInfo builder pattern ensures you can't forget a required field. If you're porting Helix to a new boot protocol, implement the conversion from your protocol's structures to BootInfo and everything downstream works unchanged.