Hardware Abstraction Layer

Unified HAL trait, CPU abstraction, MMU page tables, interrupt controller, and firmware interface.

Profile Reference

Hardware Abstraction Layer

The HAL (helix-hal) is the only crate that touches hardware directly. Every other crate in Helix accesses hardware through HAL traits. This means adding support for a new architecture (ARM, RISC-V) requires implementing just the HAL traits — zero changes to core, modules, or any subsystem.

The HAL defines four core abstractions: CPU, MMU, Interrupt Controller, and Firmware Interface.

Main HAL Trait

This is the top-level trait that ties all hardware abstractions together. Each architecture provides a single struct that implements HardwareAbstractionLayer with its four associated types.

HAL Trait Composition5N · 4E
type Cputype Mmutype IntCtrltype FwHardwareAbstractionLayerMain HAL trait4CpuAbstractionCPU control & contex…1MmuAbstractionPage tables & memory1InterruptControllerIRQ management1FirmwareInterfaceACPI, device tree, U…1
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node
hal/src/lib.rs
rust
pub trait HardwareAbstractionLayer: Send + Sync + 'static {
2
type Cpu: CpuAbstraction;
3
type Mmu: MmuAbstraction;
4
type InterruptController: InterruptController;
5
type Firmware: FirmwareInterface;
6
fn cpu(&self) -> &Self::Cpu;
fn mmu(&self) -> &Self::Mmu;
fn interrupt_controller(&self) -> &Self::InterruptController;
fn firmware(&self) -> &Self::Firmware;
11
fn arch_name(&self) -> &'static str; // "x86_64", "aarch64", etc.
fn arch_version(&self) -> &'static str;
14
fn early_init(&mut self) -> HalResult<()>; // Very early boot
fn init(&mut self) -> HalResult<()>; // Full hardware init
fn halt(&self) -> !;
fn reboot(&self) -> !;
fn shutdown(&self) -> !;
20
}
Index

Address Types

Helix uses newtype wrappers for physical and virtual addresses. This prevents accidentally passing a physical address where a virtual one is expected — a common source of bugs in kernel code.

hal/src/lib.rs
rust
1
#[repr(transparent)]
2 refs
pub struct PhysAddr(u64); // Private inner field
3
4
#[repr(transparent)]
2 refs
pub struct VirtAddr(u64);
6
2 refs
impl PhysAddr {
8
pub const fn new(addr: u64) -> Self { Self(addr) }
9
pub const fn as_u64(self) -> u64 { self.0 }
10
pub const fn is_aligned(self, align: u64) -> bool { self.0 % align == 0 }
11
pub const fn align_up(self, align: u64) -> Self {
12
Self((self.0 + align - 1) & !(align - 1))
13
}
14
pub const fn align_down(self, align: u64) -> Self {
15
Self(self.0 & !(align - 1))
16
}
17
}
18
19
// VirtAddr has the same interface plus as_ptr<T>() / as_mut_ptr<T>()
Index

CPU Abstraction

The CPU trait exposes processor features, context management, and low-level operations. It's the bridge between Helix's architecture-independent scheduling and the actual hardware register manipulation.

hal/src/cpu.rs
rust
pub trait CpuAbstraction: Send + Sync {
2
type Context: CpuContext; // Saved CPU state (trait, not struct!)
3
type CpuId: Copy + Eq + Debug;
4
fn current_cpu_id(&self) -> Self::CpuId;
fn cpu_count(&self) -> usize;
fn is_bsp(&self) -> bool; // Bootstrap processor?
8
unsafe fn enable_interrupts(&self); // Safety: system must be ready
unsafe fn disable_interrupts(&self);
fn interrupts_enabled(&self) -> bool;
fn without_interrupts<F, R>(&self, f: F) -> R where F: FnOnce() -> R;
13
fn halt(&self); // HLT — wait for interrupt
fn pause(&self); // PAUSE — spinlock hint
fn memory_barrier(&self); // Full fence
2 refs
fn stack_pointer(&self) -> VirtAddr;
2 refs
fn instruction_pointer(&self) -> VirtAddr;
19
}
20
21
// CpuContext is a TRAIT (not a struct) — architecture provides the concrete type
3 refs
pub trait CpuContext: Clone + Send + Sync + Default {
fn new_kernel(entry: VirtAddr, stack: VirtAddr) -> Self;
fn new_user(entry: VirtAddr, stack: VirtAddr) -> Self;
2 refs
fn instruction_pointer(&self) -> VirtAddr;
2 refs
fn stack_pointer(&self) -> VirtAddr;
fn return_value(&self) -> u64;
fn syscall_arg(&self, index: usize) -> u64;
29
}
Index

The CPU feature and topology structures let higher-level code make decisions without knowing the architecture:

Feature FieldTypeDescription
has_fpuboolFloating point support
has_simdboolSIMD support (SSE/NEON/etc.)
has_advanced_simdboolAdvanced SIMD (AVX/SVE/etc.)
has_virtualizationboolHardware virtualization
has_memory_protection_keysboolMemory protection keys
has_transactional_memoryboolTransactional memory support
has_cryptoboolCryptographic extensions
has_atomicsboolAtomic instructions
Topology FieldTypeDescription
physical_coresusizeNumber of physical CPU cores
logical_coresusizeNumber of hardware threads (with SMT)
numa_nodesusizeNumber of NUMA memory domains
l1d_cache_sizeusizeL1 data cache size in bytes

MMU & Page Tables

The MMU abstraction provides virtual memory mapping, unmapping, and flag management. The PageFlags bitflags type provides type-safe, readable permission control.

hal/src/mmu.rs
rust
1
bitflags! {
5 refs
pub struct PageFlags: u64 {
3
const PRESENT = 1 << 0;
4
const WRITABLE = 1 << 1;
5
const USER = 1 << 2;
6
const WRITE_THROUGH = 1 << 3;
7
const NO_CACHE = 1 << 4;
8
const ACCESSED = 1 << 5;
9
const DIRTY = 1 << 6;
10
const HUGE_PAGE = 1 << 7; // 2MB pages
11
const GLOBAL = 1 << 8; // Survives TLB flush
12
const NO_EXECUTE = 1 << 63; // NX bit
13
}
14
}
15
5 refs
impl PageFlags {
17
pub const fn kernel_code() -> Self; // PRESENT | GLOBAL
18
pub const fn kernel_data() -> Self; // PRESENT | WRITABLE | NO_EXECUTE | GLOBAL
19
pub const fn kernel_rodata() -> Self; // PRESENT | NO_EXECUTE | GLOBAL
20
pub const fn user_code() -> Self; // PRESENT | USER
21
pub const fn user_data() -> Self; // PRESENT | WRITABLE | USER | NO_EXECUTE
22
pub const fn user_rodata() -> Self; // PRESENT | USER | NO_EXECUTE
23
}
24
pub trait MmuAbstraction: Send + Sync {
26
type PageTable: PageTable;
27
type Asid: Copy + Eq + Debug; // Address Space ID
28
fn supported_page_sizes(&self) -> &[PageSize];
fn create_page_table(&self) -> HalResult<Self::PageTable>;
fn kernel_page_table(&self) -> &Self::PageTable;
unsafe fn switch_page_table(&self, table: &Self::PageTable, asid: Self::Asid);
fn translate(&self, table: &Self::PageTable, virt: VirtAddr) -> Option<PhysAddr>;
fn invalidate_tlb(&self, virt: VirtAddr);
fn invalidate_tlb_all(&self);
36
}
37
6 refs
pub trait PageTable: Send + Sync {
unsafe fn map(&mut self, virt: VirtAddr, phys: PhysAddr,
40
size: PageSize, flags: PageFlags) -> HalResult<()>;
fn unmap(&mut self, virt: VirtAddr, size: PageSize) -> HalResult<PhysAddr>;
fn query(&self, virt: VirtAddr) -> Option<(PhysAddr, PageSize, PageFlags)>;
fn update_flags(&mut self, virt: VirtAddr, size: PageSize,
44
flags: PageFlags) -> HalResult<()>;
fn root_physical_address(&self) -> PhysAddr;
46
}
Index

Interrupt Controller

The interrupt controller trait abstracts hardware interrupt management — registering handlers, enabling/disabling IRQs, and acknowledging interrupts after handling.

hal/src/interrupts.rs
rust
8 refs
pub type InterruptVector = u8;
2 refs
pub type InterruptPriority = u8;
3
pub trait InterruptController: Send + Sync {
fn init(&mut self) -> HalResult<()>;
fn enable(&mut self);
fn disable(&mut self);
fn interrupt_count(&self) -> usize;
9
fn enable_interrupt(&mut self, vector: InterruptVector) -> HalResult<()>;
fn disable_interrupt(&mut self, vector: InterruptVector) -> HalResult<()>;
fn is_interrupt_enabled(&self, vector: InterruptVector) -> bool;
13
fn set_priority(&mut self, vector: InterruptVector,
15
priority: InterruptPriority) -> HalResult<()>;
fn acknowledge(&mut self, vector: InterruptVector);
fn send_ipi(&mut self, target: IpiTarget, vector: InterruptVector)
18
-> HalResult<()>;
fn pending_interrupt(&self) -> Option<InterruptVector>;
20
}
21
2 refs
pub enum IpiTarget { Current, Cpu(usize), All, AllExceptSelf }
Index

Firmware Interface

The firmware trait provides access to platform-specific firmware services — ACPI tables, timers, power management, and framebuffer setup.

hal/src/firmware.rs
rust
pub trait FirmwareInterface: Send + Sync {
fn firmware_type(&self) -> FirmwareType;
fn firmware_version(&self) -> Option<&str>;
fn memory_map(&self) -> Vec<MemoryRegion>;
fn acpi_rsdp(&self) -> Option<PhysAddr>; // ACPI root pointer
fn device_tree_blob(&self) -> Option<&[u8]>;
fn command_line(&self) -> Option<&str>;
fn framebuffer(&self) -> Option<FramebufferInfo>;
fn request_reboot(&self) -> HalResult<()>;
fn request_shutdown(&self) -> HalResult<()>;
11
}
12
2 refs
pub enum FirmwareType { Bios, Uefi, DeviceTree, OpenFirmware, Unknown }
14
2 refs
pub struct FramebufferInfo {
16
pub address: PhysAddr,
17
pub width: u32,
18
pub height: u32,
19
pub pitch: u32, // Bytes per row (may include padding)
20
pub bpp: u8, // Bits per pixel (typically 32)
21
pub format: PixelFormat,
22
}
23
2 refs
pub enum PixelFormat { Rgb, Bgr, Rgba, Bgra, Unknown }
Index

To port Helix to a new architecture, implement these four traits: CpuAbstraction, MmuAbstraction + PageTable, InterruptController, and FirmwareInterface. Bundle them into a struct implementing HardwareAbstractionLayer, and the entire kernel runs on your new hardware.