Architecture

Layer stack, workspace structure, crate dependencies, and build pipeline powering the Helix kernel.

Documentation

Layer Stack

Helix follows a strict layered architecture — every layer only depends on layers below it, never above. This is enforced at compile time through Cargo dependency declarations: if crate A depends on crate B, crate B cannot depend on crate A.

Kernel Layer Stack7N · 6E
syscall ABItrait objectsorchestratesHAL traitsfirmware datahardware initUser SpaceELF loader, shell, r…1Module SystemModule trait v1/v2, …2Core FrameworkKernelOrchestrator, …2SubsystemsMemory, Execution, D…2Hardware Abstraction LayerCPU, MMU, interrupts…2Boot ProtocolLimine · Multiboot2 …2Hardwarex86_64 · AArch64 · R…1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

Layer Rules

  1. No upward dependencieshelix-hal never imports helix-core. Subsystems access hardware only through HAL traits.
  2. No circular dependencies — Cargo enforces this at workspace resolution time.
  3. Trait-based abstraction — Each layer boundary is defined by traits: HalImpl, Subsystem, Module, SyscallHandler.
  4. Compile-time target selection — Architecture-specific code is selected via #[cfg(target_arch)], not runtime dispatch.

Workspace Structure

The Cargo workspace at the root defines 16 member crates plus the Lumina graphics sub-workspace and the Magma GPU driver sub-workspace:

CratePathLinesDescription
helix-corecore/~2,800Kernel orchestrator, IPC, syscalls, self-heal
helix-halhal/~51,300Hardware abstraction — x86_64, AArch64, RISC-V
helix-limineboot/limine/~1,200Limine Protocol Rev 2 boot
helix-multiboot2boot/multiboot2/~400Multiboot2 spec boot
helix-uefiboot/uefi/~148,000Full UEFI platform (130+ files, 57 modules)
helix-memorysubsystems/memory/~2,200Physical/virtual memory management
helix-executionsubsystems/execution/~2,500Threads, scheduler, processes
helix-dissubsystems/dis/~11,600Dynamic Intent Scheduling engine
helix-userspacesubsystems/userspace/~3,500ELF loader, shell, syscall ABI
helix-relocationsubsystems/relocation/~2,000ELF relocation + KASLR engine
helix-nexussubsystems/nexus/~90,000+AI/ML intelligence (SYMBIOSIS)
helix-initsubsystems/init/~4,5005-phase initialization framework
helix-modulesmodules/~3,800Module trait, registry, ABI, hot-reload
helix-fsfs/~12,000HelixFS — CoW B-tree filesystem
helix-benchmarksbenchmarks/~500Benchmark suite
helix-minimal-osprofiles/minimal/~1,700Kernel entry point + demos
helix-scheduler-round-robinmodules_impl/schedulers/round_robin/~400Example module: round-robin scheduler

Sub-workspaces

WorkspacePathCratesDescription
Luminagraphics/18 cratesGPU graphics pipeline — SPIR-V, render graph, PBR
Magmadrivers/gpu/magma/52+ cratesGPU driver — PCI HAL, VRAM, Vulkan 1.3, OpenGL 4.6

Workspace Metadata

[workspace.package]
version = "0.4.0"        # codename "Aurora"
edition = "2021"
rust-version = "1.75.0"
license = "MIT"
[workspace]
members = [
    "core", "hal", "boot/limine", "boot/multiboot2", "boot/uefi",
    "subsystems/memory", "subsystems/execution", "subsystems/dis",
    "subsystems/userspace", "subsystems/relocation", "subsystems/nexus",
    "subsystems/init", "modules", "modules_impl/schedulers/round_robin",
    "fs", "benchmarks", "profiles/minimal",
]

Crate Dependency Graph

Below is the full dependency graph showing how every crate connects. Arrows point from dependent to dependency:

Crate Dependency Graph17N · 32E
helix-minimal-osKernel entry point9helix-coreOrchestrator, IPC, s…8helix-halHardware abstraction8helix-memoryPhysical/virtual mem…4helix-executionThreads, scheduler5helix-modulesModule trait, regist…4helix-userspaceELF loader, shell5helix-disDIS scheduler2helix-init5-phase init3helix-fsHelixFS CoW B-tree1helix-relocationELF relocation + KAS…2helix-nexusAI/ML engine 90K+1helix-benchmarksBenchmark suite7helix-limineLimine boot2helix-multiboot2Multiboot2 boot0helix-uefiUEFI platform0helix-sched-rrRound-robin schedule…3
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

Dependency Rules

RuleRationale
Subsystems depend on HAL, never on CoreSubsystems are reusable building blocks
Core depends on HAL and subsystemsCore orchestrates subsystem lifecycle
Modules depend on HAL onlyModules use trait objects, not concrete types
Boot crates are standaloneBoot code runs before anything else exists
helix-fs has zero dependenciesFilesystem logic is pure Rust, fully portable
helix-relocation uses edition 2024Needs latest Rust features for ELF parsing
helix-nexus is self-containedAI engine uses only libm + spin

External Dependencies (workspace-wide)

CrateVersionUsed ByPurpose
spin0.9nexus, uefi, disSpinlock-based mutexes (no_std)
bitflags2.xdis, memory, halType-safe bitfield flags
libm0.2nexusMath functions for AI (no_std)
heapless0.8limineFixed-size collections (no_std)

The entire kernel uses only 4 external crates. Everything else is written from scratch.


Project Metrics

MetricValue
Total workspace crates17 (+ 18 Lumina + 52 Magma)
Total estimated lines350,000+
Rust edition2021 (2024 for relocation)
Nightly featuresabi_x86_interrupt, allocator_api, naked_functions, asm_const, const_mut_refs, inline_const, negative_impls
Target architectures3 (x86_64, AArch64, RISC-V 64)
Lumina sub-crates18 (core, math, shader, IR, SPIR-V, render, pipeline, material, mesh, backend, sync, memory, debug, scene, 3d, ui, tools, inspector)
Magma sub-crates52+ (core, hal, mem, cmd, rpc, gl, vulkan, and sub-components)
NEXUS feature flags96+
UEFI modules57
Boot protocols3 (Limine, Multiboot2, UEFI)
Linker scripts5
Syscalls implemented47 (42 POSIX + 5 Helix-specific)
Shell built-in commands16
Module types8 (Essential, HotReloadable, Userspace, Driver, Filesystem, Scheduler, Allocator, Security)

Design Principles

Helix is designed around five core principles that guide every architectural decision:

1. Compile-Time Safety

Rust's type system and ownership model are used extensively to prevent entire classes of kernel bugs at compile time:

  • No null pointersOption<T> everywhere
  • No data racesSend/Sync bounds enforced on all shared state
  • No buffer overflows — bounds-checked arrays, no raw indexing in safe code
  • No use-after-free — ownership model prevents dangling references
  • panic = "abort" — no unwinding in kernel space, predictable failure mode

2. Trait-Driven Abstraction

Every major subsystem boundary is defined by a trait, enabling pluggable implementations:

core/src/lib.rs
rust
1
// HAL boundary
trait HalImpl: CpuHal + InterruptHal + MmuHal + TimerHal {}
3
4
// Subsystem boundary
2 refs
trait Subsystem: Send + Sync {
2 refs
fn name(&self) -> &'static str;
fn dependencies(&self) -> &[&'static str] { &[] }
2 refs
fn init(&self) -> KernelResult<()>;
fn shutdown(&self) -> KernelResult<()>;
fn is_healthy(&self) -> bool { true }
11
}
12
13
// Module boundary
trait KernelComponent: Send + Sync {
2 refs
fn name(&self) -> &'static str;
2 refs
fn init(&mut self) -> KernelResult<()>;
fn health_check(&self) -> bool { true }
18
}
Index

3. Zero External Dependencies (almost)

The kernel uses only 4 external crates (spin, bitflags, libm, heapless). Everything else — schedulers, allocators, filesystems, graphics, AI — is written from scratch.

4. Hot-Reloadable Modules

The module system supports runtime replacement without downtime:

  1. Save module state via get_state()ModuleState
  2. Unload old module binary
  3. Load new module binary, verify ABI compatibility
  4. Restore state via restore_state(ModuleState)
  5. Resume execution

5. Layered Initialization

The kernel boots through 5 strictly-ordered phases, each unlocking new capabilities:

PhaseIndexCapabilities Unlocked
Boot0Console, serial output
Early1Heap allocator, basic memory
Core2Interrupts, timers, scheduler
Late3Drivers, filesystem, IPC
Runtime4Userspace, modules, networking

Build Profiles

Helix defines six Cargo build profiles tailored for different use cases:

[profile.dev]
opt-level = 0          # No optimization — fastest builds
lto = false
debug = true           # Full debug info
panic = "abort"        # No unwinding in kernel
codegen-units = 256    # Maximum parallelism

[profile.release]
opt-level = 3          # Maximum optimization
lto = "fat"            # Full link-time optimization
debug = false          # No debug info
panic = "abort"
codegen-units = 1      # Best optimization (single CGU)

[profile.release-debug]
inherits = "release"
debug = true           # Release speed + debug symbols

[profile.production]
inherits = "release"   # Alias for CI/CD pipelines

[profile.bench]
opt-level = 3
lto = "thin"           # Faster than fat LTO, still good
panic = "abort"

[profile.test]
opt-level = 1          # Some optimization for realistic tests
debug = true
panic = "abort"

Profile Selection Guide

Use CaseProfileLTODebugOpt
Day-to-day developmentdevNoYes0
Performance testingreleaseFatNo3
Debugging release issuesrelease-debugFatYes3
CI/CD deploymentproductionFatNo3
Benchmark runsbenchThinNo3
Unit test executiontestNoYes1

All profiles use panic = "abort" — stack unwinding is not supported in kernel space.


Toolchain

The project pins a specific nightly via rust-toolchain.toml:

[toolchain]
channel = "nightly"
components = ["rust-src", "rustfmt", "clippy", "llvm-tools-preview"]
targets = ["x86_64-unknown-none"]

Required Components

ComponentPurpose
rust-srcRequired for -Zbuild-std — builds core/alloc from source for no_std targets
rustfmtCode formatting: max_width = 100, tab_spaces = 4, imports_granularity = "Crate"
clippyLint enforcement: -D warnings (all warnings are errors)
llvm-tools-previewllvm-objcopy for binary stripping, llvm-objdump for disassembly

Compile Targets

Target TripleArchitectureUsage
x86_64-unknown-nonex86_64Primary kernel target (bare-metal, no OS)
aarch64-unknown-noneAArch64ARM 64-bit kernel target
riscv64gc-unknown-none-elfRISC-V 64RISC-V kernel target (GC extensions)
x86_64-unknown-linux-gnuLinux hostUnit tests run on host OS

Nightly Features Used

FeatureStabilityWhere Used
abi_x86_interruptUnstableHAL interrupt handlers — x86 calling convention
allocator_apiUnstableCustom allocators — Allocator trait
naked_functionsUnstableContext switch — no prologue/epilogue
asm_constUnstableInline assembly constants
const_mut_refsUnstableCompile-time mutable references
inline_constUnstableInline const expressions in patterns
negative_implsUnstableimpl !Send for Type — safety invariants

Linker Scripts

Helix ships five linker scripts for different boot protocols. All higher-half scripts map the kernel to the top 2 GB of virtual address space.

ScriptProtocolBase AddressKey Feature
profiles/minimal/linker.ldMultiboot20x100000 (1 MB)Flat mapping, .multiboot_header first
profiles/minimal/linker_pie.ldMultiboot2 PIE0xFFFFFFFF80000000KASLR-ready with .dynamic + GOT
profiles/common/linker_base.ldUniversal0xFFFFFFFF80000000RELRO, PLT/GOT, Limine requests section
profiles/limine/linker.ldLimine PIE0xFFFFFFFF80000000.limine_requests section, HHDM support
profiles/uefi/linker.ldUEFI PIE0xFFFFFFFF80000000AT() load addresses, .text.hot/.text.cold

Memory Layout

All higher-half linker scripts produce the following virtual memory layout:

Virtual Memory Layout — 0xFFFFFFFF800000005N · 4E
.textExecutable code1.rodataRead-only data, stri…2.dataInitialized mutable …2.dynamicELF dynamic section …2.bssZero-initialized dat…1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

Exported Symbols

Every linker script exports these symbols for use in Rust code:

__kernel_start, __kernel_end          # Kernel image boundaries
__text_start, __text_end              # Code section
__rodata_start, __rodata_end          # Read-only data
__data_start, __data_end              # Mutable data
__bss_start, __bss_end                # Zero-init section
__got_start, __got_end                # GOT (for KASLR relocation)
__rela_start, __rela_end              # Relocation entries
KERNEL_PHYS_BASE, KERNEL_VIRT_BASE    # Physical/virtual base addresses

These are accessed in Rust via extern "C" blocks and used during early boot to set up paging and perform KASLR relocation.


Boot Sequence

The boot flow from power-on to kernel_main passes through 5 initialization phases managed by helix-init:

Boot Sequence — 7 Phases to kernel_main8N · 7E
handoffjumpreadyFirmwareBIOS / UEFI / Device…1BootloaderLimine / GRUB / UEFI…2Phase 0 — Boot_start / limine_entr…2Phase 1 — EarlyPre-heap initializat…2Phase 2 — CoreCore framework init2Phase 3 — LateDriver & filesystem …2Phase 4 — RuntimeFull system operatio…2kernel_mainEvent loop: tick, di…1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

Init Subsystems

The init framework registers 13 subsystems with dependency ordering:

Init Subsystem Dependencies13N · 18E
BootPhase 0 — Entry2CPUPhase 1 — Priority 1…2DebugPhase 1 — Priority 2…1MemoryPhase 1 — Priority 3…5InterruptsPhase 2 — Priority 4…3TimersPhase 2 — Priority 5…2SchedulerPhase 2 — Priority 6…3IPCPhase 3 — Priority 7…3DriversPhase 3 — Priority 8…4FilesystemPhase 3 — Priority 8…3SecurityPhase 3 — Priority 9…3NetworkPhase 4 — Priority 1…2UserlandPhase 4 — Priority 1…3
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node
SubsystemPhasePriorityDependencies
Boot00None
CPU110Boot
Debug120Boot
Memory130CPU
Interrupts240Memory
Timers250Interrupts
Scheduler260Timers, Memory
IPC370Scheduler
Drivers380Interrupts, Memory
Filesystem385Drivers, Memory
Security390Memory, IPC
Network4100Drivers, IPC
Userland4110Filesystem, Security, Scheduler

KernelState Machine

The kernel transitions through a state machine managed by KernelOrchestrator:

Kernel State Machine6N · 7E
suspendresumefatalfatalBootInitial firmware han…1InitializingRunning init phases3RunningNormal operation4ShuttingDownGraceful shutdown1SuspendedPower-save mode1PanicUnrecoverable error2
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

Each state transition triggers registered LifecycleCallback handlers.


Build Commands

Make Targets

make build           # Release build (opt-level 3, fat LTO)
make build-debug     # Debug build (opt-level 0, full debug info)
make qemu            # Build + launch in QEMU
make qemu-debug      # Build debug + QEMU with GDB server on :1234
make test            # Full test suite (integration + unit)
make test-unit       # Unit tests only (host target)
make clippy          # Lint check (-D warnings)
make fmt             # Format all code (rustfmt)
make fmt-check       # Verify formatting without changes
make docs            # Generate rustdoc (private items)
make iso             # Create bootable ISO image
make clean           # Remove build/ and target/
make pre-commit      # fmt-check + clippy + test (CI gate)
make size            # Show kernel binary size breakdown

Just Recipes

just build           # Release build
just watch           # Rebuild on file changes (cargo-watch)
just doc-serve       # Serve docs on localhost:8000
just audit           # cargo audit + cargo deny check

Docker

docker compose run dev       # Interactive dev shell with all tools
docker compose run build     # One-shot release build
docker compose run test      # Full test suite in container
docker compose run qemu      # QEMU with port forwarding (1234, 5900)

Nix

nix develop          # Enter development shell with all deps
nix build            # Reproducible release build

Data Flow

Understanding how data flows through the kernel helps grasp the architecture:

Syscall Path

Syscall Data Flow6N · 5E
int 0x80validateddispatchResult<usize>returnUser Processint 0x80 / syscall i…1SyscallGatewayhelix_syscall_entry …2SyscallDispatcherHook execution + han…2SyscallHandlerhandle(args) → Resul…2PostDispatchPost-hooks + return2User ProcessResumes execution1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

IPC Path

IPC Channel Flow4N · 3E
send()wake + dequeueOk(msg)Sender Threadchannel.send(message…1Ring BufferLock-free MPSC2Receiver Threadchannel.recv() → Ok(…2Process MessageHandle received data1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

Module Hot-Reload Path

Module Hot-Reload Pipeline7N · 6E
Preparing → SavingSaving → UnloadingUnloading → LoadingLoading → RestoringCompletedTriggerAdmin command / heal…1HotReloadEnginereload(module_id)2Save Statemodule.get_state() →…2Unload BinaryRemove old module fr…2Load New BinaryVerify ABI compatibi…2Restore Statemodule.restore_state…2Module ResumesNew code, same state1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

Security Architecture

Security is embedded at every layer of the kernel:

Capability-Based Access Control

The CapabilityBroker in helix-core manages fine-grained permissions:

subsystems/init/src/security.rs
rust
1
// Linux-compatible capabilities (41 total)
2
#[repr(u32)]
2 refs
pub enum Capability {
4
Chown, DacOverride, DacReadSearch, Fowner, Fsetid,
5
Kill, Setgid, Setuid, Setpcap,
6
NetBindService, NetBroadcast, NetAdmin, NetRaw,
7
IpcLock, IpcOwner, SysModule, SysRawio,
8
SysAdmin, SysBoot, SysNice, SysResource,
9
// ... 20 more (Mknod, AuditWrite, Bpf, Perfmon, etc.)
10
}
11
12
// 64-bit bitmap for O(1) capability checks
2 refs
pub struct CapabilitySet { bits: u64 }
14
2 refs
impl CapabilitySet {
pub fn has(&self, cap: Capability) -> bool {
17
(self.bits & (1 << (cap as u32))) != 0
18
}
19
}
Index

Isolation Levels (DIS)

The Dynamic Intent Scheduling system defines 5 isolation levels:

DIS Isolation Levels5N · 4E
add address spaceadd capabilitiesadd resource limitsadd hardware isolationLevel 0 — NoneNo isolation1Level 1 — BasicSeparate address spa…2Level 2 — StandardCapability-restricte…2Level 3 — StrictResource-limited2Level 4 — MaximumHardware-isolated1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node
LevelNameGuarantees
0NoneNo isolation — kernel threads
1BasicSeparate address space
2StandardCapability-restricted
3StrictResource-limited, syscall-filtered
4MaximumHardware-isolated (future: VT-x)

Protection Keys (Memory)

The memory subsystem supports Intel PKU for per-page protection domains:

  • ProtectionFlags: NONE, READ, WRITE, EXECUTE, RW, RX, RWX
  • ProtectionDomain: Groups pages under a single protection key
  • GuardPage: Unmapped pages surrounding stacks to catch overflows

Error Handling Strategy

Helix uses a consistent error handling pattern across all crates:

Error Handling Flow6N · 6E
return Err(e)propagated upyesnosuccessexhausted retriesError OccursCrate-specific error…1Result<T, E>Propagate with ?2Recoverable?Check severity3SelfHealingManagerAuto-recovery3PanicHandlerKernel halt2Recovered ✓System continues1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node
  1. Each crate defines its own error enumKernelError, MemError, HalError, ModuleError, etc.
  2. All errors are Send + Sync — safe to pass across thread boundaries
  3. No panics in normal pathsResult<T, E> everywhere
  4. Panic = kernel haltpanic = "abort" in all profiles, custom PanicHandler logs context
  5. Self-healing for recoverable failuresSelfHealingManager monitors subsystem health and triggers automatic recovery (max 3 restart attempts)

Panic Handling

core/src/panic.rs
rust
trait PanicHandler: Send + Sync {
fn handle_panic(&self, ctx: &PanicContext) -> PanicAction;
3
}
4
2 refs
enum PanicAction {
6
Halt, // Stop the CPU
7
Reboot, // Full system restart
8
DebugBreak, // Break into debugger
9
Continue, // Try to continue (dangerous)
10
}
Index

The PanicContext captures: message, location (file:line:col), backtrace, CPU state, and the current thread ID.