Configuration & Build

helix.toml schema, linker scripts, build commands, cargo workspace, and toolchain setup.

Profile Reference

Configuration & Build

Every Helix kernel profile is configured through a helix.toml file, linked with architecture-specific linker scripts, and built with a 12-step LFS-inspired build system. This section covers the real configuration schema, linker scripts, and build commands — all taken directly from the codebase.


helix.toml Schema

The only profile with a helix.toml today is profiles/minimal/. This is the actual file from the repository:

profiles/minimal/helix.toml
toml
1
[profile]
2
name = "minimal"
3
version = "1.0.0"
4
description = "Minimal OS for embedded systems"
5
target = "embedded"
6
7
[profile.arch]
8
primary = "x86_64"
9
supported = ["x86_64", "aarch64", "riscv64"]
10
11
[profile.features]
12
multicore = false
13
hot_reload = false
14
userspace = false
15
networking = false
16
filesystem = false
17
graphics = false
18
19
[memory]
20
min_ram_mb = 4
21
max_ram_mb = 64
22
heap_size_kb = 256
23
stack_size_kb = 16
24
virtual_memory = false
25
26
[scheduler]
27
module = "round_robin"
28
time_slice_ms = 10
29
priority_levels = 8
30
load_balancing = false
31
32
[console]
33
backend = "serial"
34
baud_rate = 115200
35
early_console = true
36
37
[modules]
38
static = ["helix-scheduler-round-robin"]
39
dynamic = []
40
41
[boot]
42
entry = "kernel_main"
43
early_init = ["console", "memory", "interrupts"]
44
late_init = ["scheduler"]
45
cmdline = "quiet loglevel=3"
46
47
[debug]
48
level = "minimal"
49
symbols = false
50
stack_traces = true
51
panic_behavior = "halt"
52
53
[build]
54
opt_level = "s"
55
lto = true
56
panic = "abort"
57
strip = true

Configuration Options Reference

SectionKeyTypeDefaultDescription
profilenameStringProfile identifier
profiletargetString"embedded"Target use-case
profile.archprimaryString"x86_64"Primary target architecture
profile.archsupportedArray["x86_64"]All supported architectures
profile.featuresmulticoreBoolfalseEnable SMP support
profile.featureshot_reloadBoolfalseEnable runtime module swap
profile.featuresuserspaceBoolfalseEnable ring-3 transition
memoryheap_size_kbInteger256Kernel heap in KB
memorystack_size_kbInteger16Per-thread stack in KB
memoryvirtual_memoryBoolfalseEnable paging
schedulermoduleString"round_robin"Scheduler implementation
schedulertime_slice_msInteger10Default time quantum
consolebackendString"serial"Output backend
consolebaud_rateInteger115200Serial baud rate
bootentryString"kernel_main"Kernel entry function name
debugpanic_behaviorString"halt""halt" · "reboot" · "dump"
buildopt_levelString"s""0" · "1" · "2" · "3" · "s" · "z"
buildltoBooltrueLink-Time Optimization
buildstripBooltrueStrip debug symbols

Profiles Directory

There are 4 profile directories in the repository:

DirectoryPurposeContents
profiles/minimal/The only runnable kernel profilehelix.toml, linker.ld, linker_pie.ld, src/ (main.rs, boot.rs, framebuffer.rs, filesystem.rs, nexus.rs)
profiles/limine/Limine-specific linker scriptlinker.ld (352 lines, PIE + KASLR + HHDM)
profiles/uefi/UEFI-specific linker scriptlinker.ld (339 lines, PIE + RELRO)
profiles/common/Shared base linker scriptlinker_base.ld (350 lines, included by others)

Linker Scripts

Minimal — Multiboot2 (flat physical, 1 MB load)

profiles/minimal/linker.ld
ld
1
ENTRY(_start)
2
3
SECTIONS
4
{
5
. = 1M;
6
7
.multiboot_header : ALIGN(8) {
8
KEEP(*(.multiboot_header))
9
}
10
11
.boot : ALIGN(4K) { *(.boot) }
12
.text : ALIGN(4K) { *(.text .text.*) }
13
.rodata : ALIGN(4K) { *(.rodata .rodata.*) }
14
.data : ALIGN(4K) { *(.data .data.*) }
15
16
.bss : ALIGN(4K) {
17
__bss_start = .;
18
*(.bss .bss.*) *(COMMON)
19
__bss_end = .;
20
}
21
22
_kernel_end = .;
23
}

Minimal — PIE variant (higher-half, KASLR-ready)

profiles/minimal/linker_pie.ld
ld
1
KERNEL_VIRT_BASE = 0xFFFFFFFF80000000; /* -2GB higher-half */
2
KERNEL_PHYS_BASE = 0x100000; /* 1MB physical */
3
4
PHDRS {
5
boot PT_LOAD FLAGS(5); /* R-X: Multiboot + early boot */
6
text PT_LOAD FLAGS(5); /* R-X: Executable code */
7
rodata PT_LOAD FLAGS(4); /* R--: Read-only data */
8
data PT_LOAD FLAGS(6); /* RW-: Read-write data */
9
dynamic PT_DYNAMIC FLAGS(6); /* RW-: Relocation info */
10
}
11
12
/* Multiboot2 header in first 32KB, then .text, .rodata, .data,
13
.bss, .rela.dyn, .dynamic, .got — full PIE layout */

Limine — PIE with HHDM

profiles/limine/linker.ld
ld
1
KERNEL_VMA = 0xFFFFFFFF80000000;
2
3
PHDRS {
4
limine PT_LOAD FLAGS(4); /* R--: Limine requests */
5
text PT_LOAD FLAGS(5); /* R-X: Code */
6
rodata PT_LOAD FLAGS(4); /* R--: Read-only data */
7
data PT_LOAD FLAGS(6); /* RW-: Data */
8
bss PT_LOAD FLAGS(6); /* RW-: Zero-init */
9
dynamic PT_DYNAMIC FLAGS(6); /* RW-: Relocations */
10
relro PT_GNU_RELRO FLAGS(4); /* R--: RELRO */
11
gnu_stack PT_GNU_STACK FLAGS(6); /* Non-executable stack */
12
}
13
14
/* .limine_requests first, then .text (with .text.boot, .text.hot),
15
.rodata, .data, .bss, .rela.dyn, .dynamic, .got — full KASLR */

Common — Universal base (included by others)

profiles/common/linker_base.ld
ld
1
__KERNEL_VMA_BASE = 0xFFFFFFFF80000000; /* -2 GiB virtual */
2
__KERNEL_LMA_BASE = 0x0000000000200000; /* 2 MiB physical */
3
__PAGE_SIZE = 0x1000;
4
__HUGE_PAGE_SIZE = 0x200000;
5
6
PHDRS {
7
text PT_LOAD FLAGS(5);
8
rodata PT_LOAD FLAGS(4);
9
data PT_LOAD FLAGS(6);
10
bss PT_LOAD FLAGS(6);
11
dynamic PT_DYNAMIC FLAGS(6);
12
relro PT_GNU_RELRO FLAGS(4);
13
gnu_stack PT_GNU_STACK FLAGS(6);
14
}
15
16
/* Sections: .boot.entry → .multiboot → .limine_reqs → .text → .plt
17
→ .rodata → .eh_frame_hdr → .data → .got → .dynamic → .bss
18
Includes RELRO support and non-executable stack */

Exported Linker Symbols

SymbolScriptDescription
_startAllEntry point — 32-bit trampoline to long mode
__bss_start / __bss_endAllZero-initialized data — cleared to 0 during boot
_kernel_endminimalEnd of all kernel sections
__kernel_start / __kernel_endlimine, uefi, commonKernel image boundaries
__text_start / __text_endlimine, uefi, commonCode segment — R-X
__rodata_start / __rodata_endlimine, uefi, commonRead-only data — R--
__data_start / __data_endlimine, uefi, commonMutable data — RW-
__rela_start / __rela_endPIE scriptsRelocation entries for KASLR
__got_start / __got_endPIE scriptsGlobal Offset Table

Build Commands

The build system uses a 12-step LFS-inspired pipeline orchestrated by scripts/build.sh.

terminal
bash
1
# Build the kernel (release, 12-step pipeline)
2
./scripts/build.sh
3
4
# Build with debug symbols (DWARF info)
5
./scripts/build.sh --debug
6
7
# Create bootable ISO
8
./scripts/build.sh --iso
9
10
# Run in QEMU (builds first)
11
./scripts/run_qemu.sh
12
13
# Run with GDB debug server
14
./scripts/run_qemu.sh --debug
15
16
# Run all tests
17
./scripts/test.sh
18
19
# Unit tests only (host target)
20
cargo test --target x86_64-unknown-linux-gnu --lib
21
22
# Format + lint
23
cargo fmt --all
24
cargo clippy --all-targets --all-features -- -D warnings
25
26
# Generate documentation
27
cargo doc --no-deps --document-private-items
28
29
# Show kernel binary size
30
size build/output/helix-kernel

The 12 build steps:

StepNameDescription
0Prepare EnvironmentValidate toolchain, create build dirs
1Build BootloaderCompile boot protocol crate
2Build Kernel CoreCompile helix-core
3Build Memory SubsystemCompile helix-memory
4Build SchedulerCompile helix-execution + DIS
5Build I/O SubsystemCompile drivers and I/O
6Build Module SystemCompile helix-modules
7Build Communication LayerCompile IPC + syscalls
8Build System InterfaceCompile helix-userspace
9Build Userland FrameworkCompile userspace tools + shell
10Test AllRun cargo test on host target
11Package KernelLink final ELF, strip, create ISO

Cargo Workspace

The root Cargo.toml defines the workspace with 14 member crates:

Cargo.toml (workspace root)
toml
1
[workspace]
2
resolver = "2"
3
4
members = [
5
# Boot Infrastructure
6
"boot/multiboot2",
7
"boot/limine",
8
"boot/uefi",
9
10
# Hardware Abstraction Layer
11
"hal",
12
13
# Kernel Core
14
"core",
15
16
# Subsystems
17
"subsystems/execution",
18
"subsystems/memory",
19
"subsystems/dis",
20
"subsystems/userspace",
21
"subsystems/relocation",
22
"subsystems/nexus",
23
24
# Module System
25
"modules",
26
27
# Module Implementations
28
"modules_impl/schedulers/round_robin",
29
30
# Benchmarks
31
"benchmarks",
32
33
# Filesystem
34
"fs",
35
36
# OS Profiles (only minimal is runnable)
37
"profiles/minimal",
38
]
39
40
[workspace.dependencies]
41
helix-hal = { path = "hal" }
42
helix-core = { path = "core" }
43
helix-execution = { path = "subsystems/execution" }
44
helix-memory = { path = "subsystems/memory" }
45
helix-userspace = { path = "subsystems/userspace" }
46
helix-modules = { path = "modules" }
47
helix-benchmarks = { path = "benchmarks" }
48
spin = "0.9"
49
bitflags = "2.4"
50
log = "0.4"
51
hashbrown = "0.14"
52
static_assertions = "1.1"
53
cfg-if = "1.0"
54
55
[workspace.package]
56
version = "0.1.0"
57
authors = ["Helix OS Contributors"]
58
edition = "2021"
59
license = "MIT OR Apache-2.0"
60
repository = "https://github.com/helix-os/helix"

Cargo Build Profiles

Cargo.toml (build profiles)
toml
1
[profile.dev]
2
panic = "abort"
3
opt-level = 0
4
debug = true
5
lto = false
6
codegen-units = 256
7
8
[profile.release]
9
panic = "abort"
10
opt-level = 3
11
lto = "fat"
12
codegen-units = 1
13
strip = "symbols"
14
15
[profile.release-with-debug]
16
inherits = "release"
17
debug = true
18
strip = "none"
19
20
[profile.production]
21
inherits = "release"
22
lto = "fat"
23
codegen-units = 1

Toolchain

rust-toolchain.toml
toml
1
[toolchain]
2
channel = "nightly-2025-01-15"
3
4
components = [
5
"rust-src", # Required for -Zbuild-std
6
"rustfmt", # Code formatting
7
"clippy", # Linting
8
"llvm-tools-preview", # objcopy, objdump, size
9
]
10
11
targets = [
12
"x86_64-unknown-none", # Primary: x86_64 bare metal
13
"aarch64-unknown-none", # Future: ARM64
14
"riscv64gc-unknown-none-elf", # Future: RISC-V
15
"x86_64-unknown-linux-gnu", # Host: tests & tools
16
]

To create a new profile, create a directory under profiles/ with at minimum a Cargo.toml, a linker.ld, and a src/main.rs. Add it to the workspace members array in the root Cargo.toml, configure a helix.toml for your target settings, and build with ./scripts/build.sh.