An investigation into compile-time safety invariants and zero-cost modularity for mechatronic systems.
Current industry-standard RTOS architectures (typically C-based) lack the ability to enforce memory safety and hardware-state invariants at compile-time, resulting in runtime failures that are difficult to detect and debug. This thesis seeks to prove that a modular RTOS developed in Rust, utilising static dispatch and the typestate pattern, can eliminate these failure modes at the compilation stage without incurring a noticeable performance penalty compared to a C-based equivalent.
Build (required for compiling):
- Rust β Install via rustup. The target triple (e.g.
thumbv7m-none-eabi) is set in.cargo/config.toml; install it withrustup target add <target>before building (see Building). - Python 3.11+
Flashing and debugging (optional; only if you flash or attach GDB to hardware):
- OpenOCD β Talks to the board over a compatible probe (e.g. ST-Link). Configure
[scripting]in.cargo/config.tomlwithopenocd_interfaceandopenocd_targetfor your board. - A GDB Install β For
scripts/debug.py(attach, load, breakpoints).
sudo dnf install openocd stlink gdbRust Tooling:
rustup component add llvm-tools-preview
cargo install cargo-binutils
cargo install cargo-generate
rustup target add thumbv7m-none-eabi**
- sudo dnf install openocd stlink gdb-multiarch
- rustup target add thumbv7m-none-eabi
Build
- cd /path/to/no_rtos_no_config
- cargo build
Flash
- openocd -f /usr/share/openocd/scripts/interface/stlink.cfg
-f /usr/share/openocd/scripts/target/stm32l1.cfg
-c "add_script_search_dir /usr/share/openocd/scripts/target"
-c "program /path/to/no_rtos_no_config/target/thumbv7m-none-eabi/debug/no_rtos_no_config verify reset exit"
Debug (GDB)
- Terminal 1: run openocd without
exit(keep it alive) - Terminal 2: gdb-multiarch /path/to/no_rtos_no_config/target/thumbv7m-none-eabi/debug/no_rtos_no_config
- In GDB: target extended-remote :3333 monitor reset halt load break main continue
To ensure the academic validity of the thesis, the following boundaries are established:
- Core Infrastructure: Use the appropriate architecture runtime crates for the target (e.g.
cortex-m-rtfor ARM) for vector table and startup logic. - Hardware Access: Use Peripheral Access Crates (PAC) for raw register definitions only.
- Peripheral drivers: Manual implementation. High-level Hardware Abstraction Layers (HALs) are forbidden. All typestate logic and trait implementations must be original work to validate the safety claims of the thesis.
- Kernel Layer: Hardware-blind and generic-first. No architecture-specific code allowed in the
kernel/crate.
The system is organised as a Cargo Workspace to enforce strict compile-time boundaries between the hardware-independent kernel and the target-specific hardware ports.
/
βββ Cargo.toml # Workspace manifest (links all crates)
βββ docs/ # PLANNING: Design specs & architectural diagrams
βββ kernel/ # THE CORE: Hardware-independent scheduling logic
βββ specs/ # THE CONTRACTS: Traits for modules to implement
βββ arch/ # THE PORTS: CPU-specific assembly, linker layout, context logic
βββ mcu/ # DEVICE: Per-MCU crates (startup, memory.x, device link surface)
βββ bsp/ # BOARD: BSP crates that wire an MCU crate to a physical board
βββ macros/ # PROC MACROS: Attributes such as `#[entry]`
βββ scripts/ # TOOLING: Build, flash, and debug helpers
βββ examples/ # PROOF: Sample applications for validation
The phased development plan, gatekeepers, and milestones are defined in docs/roadmap.md.
Authoritative module boundaries are defined in docs/roadmap.md under Architecture Boundaries.
Phase 2 (Gatekeeper 2) β hardware validation: build, flash, GDB, and pass/fail checks are in docs/runbooks/phase2_gatekeeper.md.
Phase 3 (minimal kernel & scheduler): implementation guide is docs/phase3/phase3_minimal_kernel.md (Gatekeeper 3 runbook to follow).
Prerequisites: Install the Rust toolchain (e.g. via rustup). For embedded targets, install the required target before building (the target is set in .cargo/config.toml). For example, for ARM Cortex-M3:
rustup target add thumbv7m-none-eabiBuild commands:
cargo buildβ Builds the crates listed indefault-membersin the rootCargo.toml(see that file for the current set; RTOS pieces such askernel/,specs/,mcu/, andbsp/are added there as they come online). Add each new library crate to bothmembersanddefault-membersas the project grows.cargo build --workspaceβ Builds every crate in the workspace, including all examples. This uses the fullmemberslist in the rootCargo.toml. Ensurememberslists every crate (libs and examples); add each new example or lib there.cargo test -p kernel --target aarch64-apple-darwinβ Runs kernel host tests on a desktop target (required because the default project target is embedded and cannot run test harnesses).
ThetOS is designed for Declarative Configuration. To minimise "Silent Failures" the developer is shielded from the internal complexity of the arch/ and kernel/ crates. Configuration is centralised into two specific files:
Role: Defines "Where" the code is going.
This file contains the hardware metadata: the target triple for the chosen MCU and the path to the linker script (memory map). Once set for a given board, this file remains static.
Role: Defines "What" the hardware is capable of.
The developer interacts exclusively with the root Cargo.toml to toggle system-wide capabilities. Using Rust's Feature Bubbling, selecting a feature at the root (e.g. a capability flag) automatically triggers the corresponding code paths in the arch/ layer.
Key Advantage: The developer never modifies the RTOS source code to suit their hardware. By declaring the hardware features in the manifest, the compiler automatically reconfigures the context-switching logic and peripheral drivers at build-time.
Defines the Traits (interfaces) that serve as the "law" for the system.
- Purpose: Formalises contracts by concern (
arch,mcu,kernel,bsp, andcommon) so hardware capabilities, kernel orchestration, and board-facing APIs remain cleanly separated. - Thesis Relevance: Demonstrates Interface Segregation, ensuring the kernel remains hardware-agnostic.
The hardware-independent kernel logic.
- Purpose: Manages task scheduling (Ready-lists), synchronisation primitives, and lifecycle management.
- Thesis Relevance: Central site for proving that scheduling logic can be safely decoupled from register-level manipulation.
Low-level implementations for supported CPU instruction sets.
- Purpose: Manages stack frame initialisation, register saving/restoring, and atomic operations.
- Thesis Relevance: Isolates the "unsafe" code required for context switching from the safe modular kernel.
Per-microcontroller packages: reset vector, RAM/flash map (memory.x), and other bring-up that is specific to a die or family (not a full development board).
- Purpose: Owns the device side of linking and startup so examples and BSP crates can depend on one MCU crate rather than duplicating linker and reset logic.
- Thesis Relevance: Keeps PAC-level and vendor-specific details out of the generic kernel while remaining explicit about which silicon is targeted.
Board-level crates (e.g. a Nucleo board) that depend on an mcu/ crate and expose the wiring and dependencies applications use.
- Purpose: Maps a concrete board to the MCU crate and pulls the right artefacts into the link (pins, optional probes, feature flags).
- Thesis Relevance: Proves system composition by letting the same kernel and
specs/contracts target different boards via different BSP crates.
Centralised repository for design documents used to support the final thesis report (e.g. roadmap, architecture, safety invariants, benchmarking methodology).
To ensure deterministic execution, the RTOS avoids dynamic dispatch (dyn Trait) and virtual tables. Utilising Monomorphisation, the compiler inlines implementations at the call site, matching the performance of hand-optimised C.
By encoding hardware states into the type system (Typestates), the RTOS transforms common runtime logic errors into build-time failures. This ensures that the system is "Correct by Construction".
The project will be empirically validated against the following criteria:
- Safety Robustness: Comparison of error-catching capabilities against a C-based equivalent (FreeRTOS).
- Context-Switch Latency: Cycle-accurate measurement of scheduling overhead.
- Binary Footprint: Analysis of binary bloat vs performance gains in a resource-constrained environment.