Preemptive Multithreading System on ARM64 using Rust

Bahaa Tantaoui

Bahaa Tantaoui

Preemptive Threads — Bare-Metal Multithreading in Rust

Designing and implementing a preemptive multithreading system on bare-metal ARM64, without an operating system.

Overview

Preemptive Threads is a low-level systems project exploring how preemptive multitasking can be implemented from first principles on bare metal hardware using Rust. The target platform is the Raspberry Pi Zero 2 W (ARM64), running with no OS, no standard library, and full control over interrupts, scheduling, and context switching.
The goal was not to build a toy scheduler, but to understand and implement the core mechanics behind real operating systems: timer interrupts, thread context management, and safe preemption under tight constraints.

The Challenge

Implementing preemptive multitasking on bare metal introduces several non-trivial problems:
No operating system abstractions to rely on
No standard library (#![no_std])
Interrupt handlers must safely switch execution contexts
ARM64 exception return (eret) restores CPU state automatically, making naïve context switching incorrect
Debugging happens close to the hardware, often through UART and QEMU
A particularly tricky issue was that ARM64 IRQ returns overwrite register state, which means switching stacks alone does not work. Context switching had to be designed with full awareness of the CPU exception model.

What I Built

Core Scheduling & Context Switching

Implemented preemptive context switching driven by timer interrupts (1ms tick)
Designed thread context structures to explicitly store and restore register state
Switched execution by loading thread contexts directly rather than relying on the IRQ stack
Built a priority-based scheduler with round-robin scheduling for equal priorities

Architecture-Specific Work

Wrote ARM64-specific interrupt and exception handling logic
Implemented vector tables and IRQ handlers for AArch64
Added support for both QEMU virt and real Raspberry Pi Zero 2 W hardware
Built custom linker scripts to control memory layout precisely

Tooling, Safety & Testing

Added fuzzing infrastructure for threading primitives
Built benchmarks to validate scheduler behavior
Created examples demonstrating multiple threads running concurrently on bare metal
Maintained strict separation between architecture-independent scheduling logic and architecture-specific code

Current Capabilities

Working
Preemptive multitasking
Timer-based scheduling (1ms resolution)
Priority scheduling with round-robin fairness
UART output for debugging
QEMU and real-hardware execution
Not Implemented (by design, yet)
Multi-core scheduling (currently single-core)
Memory protection
Thread join / exit semantics

Outcome

This project resulted in a fully functioning bare-metal preemptive scheduler running real concurrent threads on ARM64 hardware, written entirely in Rust without an operating system.
Beyond the implementation itself, it deepened my understanding of:
CPU exception models and interrupt mechanics
Low-level concurrency and scheduling
Systems design under extreme constraints
Writing safe, structured Rust in no_std environments
This project serves as a foundation for more advanced kernel-level work and demonstrates hands-on systems engineering beyond application-level development.

Tech Stack

Rust (#![no_std], nightly)
ARM64 (AArch64)
Raspberry Pi Zero 2 W
QEMU
Custom linker scripts & bare-metal tooling
Like this project

Posted Dec 15, 2025

Implemented a preemptive scheduler on ARM64 in Rust without an OS.