RepoPilotOpen in app →

rust-embedded/rust-raspberrypi-OS-tutorials

:books: Learn to write an embedded OS in Rust :crab:

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 12 active contributors
  • Apache-2.0 licensed
  • CI configured
Show all 6 evidence items →
  • Tests present
  • Stale — last commit 2y ago
  • Concentrated ownership — top contributor handles 75% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/rust-embedded/rust-raspberrypi-os-tutorials)](https://repopilot.app/r/rust-embedded/rust-raspberrypi-os-tutorials)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/rust-embedded/rust-raspberrypi-os-tutorials on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: rust-embedded/rust-raspberrypi-OS-tutorials

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/rust-embedded/rust-raspberrypi-OS-tutorials shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • 12 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ Concentrated ownership — top contributor handles 75% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live rust-embedded/rust-raspberrypi-OS-tutorials repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/rust-embedded/rust-raspberrypi-OS-tutorials.

What it runs against: a local clone of rust-embedded/rust-raspberrypi-OS-tutorials — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in rust-embedded/rust-raspberrypi-OS-tutorials | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 848 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>rust-embedded/rust-raspberrypi-OS-tutorials</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of rust-embedded/rust-raspberrypi-OS-tutorials. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials.git
#   cd rust-raspberrypi-OS-tutorials
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of rust-embedded/rust-raspberrypi-OS-tutorials and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "rust-embedded/rust-raspberrypi-OS-tutorials(\\.git)?\\b" \\
  && ok "origin remote is rust-embedded/rust-raspberrypi-OS-tutorials" \\
  || miss "origin remote is not rust-embedded/rust-raspberrypi-OS-tutorials (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "01_wait_forever/src/main.rs" \\
  && ok "01_wait_forever/src/main.rs" \\
  || miss "missing critical file: 01_wait_forever/src/main.rs"
test -f "01_wait_forever/src/_arch/aarch64/cpu/boot.s" \\
  && ok "01_wait_forever/src/_arch/aarch64/cpu/boot.s" \\
  || miss "missing critical file: 01_wait_forever/src/_arch/aarch64/cpu/boot.s"
test -f "01_wait_forever/src/bsp/raspberrypi/kernel.ld" \\
  && ok "01_wait_forever/src/bsp/raspberrypi/kernel.ld" \\
  || miss "missing critical file: 01_wait_forever/src/bsp/raspberrypi/kernel.ld"
test -f "01_wait_forever/Cargo.toml" \\
  && ok "01_wait_forever/Cargo.toml" \\
  || miss "missing critical file: 01_wait_forever/Cargo.toml"
test -f "01_wait_forever/build.rs" \\
  && ok "01_wait_forever/build.rs" \\
  || miss "missing critical file: 01_wait_forever/build.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 848 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~818d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/rust-embedded/rust-raspberrypi-OS-tutorials"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

A progressive tutorial series teaching bare-metal ARMv8-A OS kernel development in Rust on Raspberry Pi 3/4 hardware. Starting from bootloader-level code (tutorial 01_wait_forever) and advancing through memory management, UART drivers, and exception handling, each tutorial builds a functional monolithic kernel that runs on real hardware or QEMU with no std library dependency. Linear progression structure: 00_before_we_start through 15+ tutorials, each in numbered directories (01_wait_forever/, 02_runtime_init/, etc.) with independent Cargo.toml and Makefile. Architecture split: src/_arch/aarch64/ contains CPU-specific assembly/low-level code; src/bsp/raspberrypi/ contains board-specific linker scripts (kernel.ld) and peripheral definitions. Each tutorial is self-contained bootable kernel binary built via Makefile targets.

👥Who it's for

Embedded systems enthusiasts and hobby OS developers learning systems programming; specifically those targeting ARM 64-bit platforms who want hands-on experience writing memory-unsafe code with Rust's safety guarantees. Educational use case: students and self-taught developers building from scratch rather than using existing kernels.

🌱Maturity & risk

Actively maintained educational project with solid CI/CD infrastructure (separate workflows for RPi3/RPi4, unit/integration/xtra tests in .github/workflows/). Code is production-grade in structure but explicitly tutorial-focused; demonstrates maturity through multi-language support (README files in .CN, .ES variants) and comprehensive test coverage. Last observable structure suggests active ongoing development.

Low risk for educational use; minimal external dependencies (intentional for learning), single-maintainer (Andre Richter) but well-established community adoption. Risk factors: highly hardware-specific (RPi3/4 only in .github/workflows), architectural changes between tutorials could break learner comprehension mid-series, bare-metal code requires intimate hardware knowledge to modify safely.

Active areas of work

Tutorial series is actively maintained with per-architecture CI pipelines (build_rpi3.yml, build_rpi4.yml validate each tutorial). Git hooks (.githooks/pre-commit) enforce code quality. The progression appears to advance through architectural abstractions and driver implementations based on directory naming (pattern suggests tutorials covering GPIO/UART drivers, memory management, exception handling).

🚀Get running

Clone and enter a specific tutorial: git clone https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials && cd 01_wait_forever. Run make (uses Makefile in each tutorial directory). To test in QEMU: make qemu (inferred from CI workflows). Requires Rust toolchain with aarch64-unknown-none target and QEMU aarch64 emulator.

Daily commands: Navigate to a tutorial directory (e.g., cd 01_wait_forever) and run: make (build), make qemu (emulate in QEMU), make qemu-release (optimized build). Check each tutorial's Makefile for target-specific commands (RPi3 vs RPi4 differ in QEMU args). The Makefile contains all orchestration; no separate npm/cargo CLI needed.

🗺️Map of the codebase

  • 01_wait_forever/src/main.rs — Entry point for the first tutorial; demonstrates bare-metal Rust kernel initialization and the panic handler setup.
  • 01_wait_forever/src/_arch/aarch64/cpu/boot.s — ARMv8-A assembly bootstrap code; essential for understanding CPU initialization and entry into Rust code.
  • 01_wait_forever/src/bsp/raspberrypi/kernel.ld — Linker script defining memory layout for Raspberry Pi; critical for correct kernel placement and symbol resolution.
  • 01_wait_forever/Cargo.toml — Workspace and crate configuration; defines feature flags for RPi3/RPi4 BSP selection and build profile settings.
  • 01_wait_forever/build.rs — Build script that compiles assembly and manages architecture-specific compilation; foundational for the build pipeline.
  • 03_hacky_hello_world/src/bsp/raspberrypi/console.rs — UART console driver implementation; demonstrates hardware abstraction and I/O for serial communication.
  • 03_hacky_hello_world/src/print.rs — Macro-based printing infrastructure; shows how to bridge Rust formatting with low-level hardware output.

🛠️How to make changes

Add a new BSP (Board Support Package) for a different ARM board

  1. Create a new directory under src/bsp/newboard/ parallel to raspberrypi/ (src/bsp/newboard/mod.rs)
  2. Implement board-specific CPU initialization by copying and modifying src/bsp/raspberrypi/cpu.rs with your board's memory map and device addresses (src/bsp/newboard/cpu.rs)
  3. Create a new linker script for your board's memory layout, based on src/bsp/raspberrypi/kernel.ld (src/bsp/newboard/kernel.ld)
  4. Add a feature flag in Cargo.toml for your board (e.g., bsp_newboard) and conditionally compile the module in src/bsp.rs (Cargo.toml)
  5. Implement any hardware-specific drivers (e.g., console/UART) by creating src/bsp/newboard/console.rs and abstracting via src/console.rs (src/bsp/newboard/console.rs)

Add a new CPU architecture (e.g., ARMv7, RISC-V)

  1. Create a new architecture directory src/_arch/newarch/ with subdirectory cpu/ (src/_arch/newarch/cpu/mod.rs)
  2. Implement bootstrap assembly in src/_arch/newarch/cpu/boot.s following the pattern of src/_arch/aarch64/cpu/boot.s (src/_arch/newarch/cpu/boot.s)
  3. Create Rust CPU abstraction in src/_arch/newarch/cpu/boot.rs that mirrors src/_arch/aarch64/cpu/boot.rs (src/_arch/newarch/cpu/boot.rs)
  4. Update build.rs to conditionally compile your new architecture's assembly based on target triple (build.rs)
  5. Create a conditional module in src/_arch/mod.rs that exports your architecture when targeted (src/_arch/mod.rs)

Add a new console driver (e.g., for a different UART or display interface)

  1. Create a new driver file in the BSP directory, e.g., src/bsp/raspberrypi/newdriver.rs, following the pattern of src/bsp/raspberrypi/console.rs (src/bsp/raspberrypi/newdriver.rs)
  2. Implement the Write trait or a custom output trait for your driver (src/bsp/raspberrypi/newdriver.rs)
  3. Register your driver in the BSP initialization code within src/bsp/raspberrypi.rs (src/bsp/raspberrypi.rs)
  4. Update the console abstraction in src/console.rs to support your new driver or add conditional compilation (src/console.rs)

🔧Why these technologies

  • Rust — Provides memory safety without garbage collection, ideal for bare-metal embedded systems where safety and performance are critical.
  • ARMv8-A assembly (aarch64) — Required for low-level CPU initialization (stack setup, BSS clearing, entry point) that cannot be expressed in Rust before runtime initialization.
  • Linker scripts (kernel.ld) — Defines precise memory layout for kernel sections, ensuring code/data placement matches hardware memory map and bootloader expectations.
  • Cargo with feature flags — Enables conditional compilation for multiple Raspberry Pi models (RPi3 vs RPi4) from a single codebase.

⚖️Trade-offs already made

  • Monolithic kernel architecture (not microkernel)

    • Why: Simpler to teach and implement; matches traditional OS design; lower overhead.
    • Consequence: All kernel subsystems run in privileged mode; a bug in one subsystem can crash the entire OS.
  • Tutorial-driven progression (multiple numbered directories)

    • Why: Each tutorial builds incrementally on previous concepts (wait_forever → runtime_init → hello_world → safe_globals), allowing learners to follow step-by-step.
    • Consequence: Code duplication across tutorial directories; not a production codebase meant for version control or code reuse.
  • Minimal dependencies (no external crates in early tutorials)

    • Why: Maximizes learning by implementing core functionality from scratch; reduces abstraction layers.
    • Consequence: More boilerplate; slower development iteration in later tutorials when features expand.
  • Direct hardware register access in drivers (e.g., UART in console.rs)

    • Why: Transparent and educational; no HAL abstraction layer to obscure low-level I/O mechanics.
    • Consequence: Code is specific to Raspberry Pi hardware; not portable to other platforms without driver rewrite.

🚫Non-goals (don't propose these)

  • Production-ready OS kernel: this is educational software for learning, not suitable for real-world deployment.
  • Multi-core support: tutorials focus on single-core ARMv8-A; multi-core synchronization is out of scope.
  • Networking stack: no TCP/IP or ethernet drivers implemented.
  • File system: no block device or filesystem layer (not even a ramdisk).
  • Memory protection: no MMU setup or process isolation in early tutorials; security is not a goal.
  • Device-agnostic HAL: hardware abstraction is specific to Raspberry Pi; other ARM boards require new BSP.
  • Preemptive multitas

🪤Traps & gotchas

Toolchain version: Requires rustc nightly or stable with explicit aarch64-unknown-none target installed (rustup target add aarch64-unknown-none). Linker script path: kernel.ld path is hardcoded in build.rs relative to crate root; moving files breaks linking. QEMU requirement: .github/workflows/ assumes qemu-system-aarch64 installed; no fallback. Feature flags matter: Cargo features bsp_rpi3 vs bsp_rpi4 select at compile time; building without feature flag may select wrong defaults. Makefile assumptions: Relies on shell commands (objdump, objcopy) being in PATH; Windows developers need MSYS2 or WSL. No Cargo.lock for kernel crate: minimal dependencies by design means lock file is small but reproducibility depends on exact rustc version.

🏗️Architecture

💡Concepts to learn

  • torvalds/linux — Production ARMv8 kernel reference; useful for understanding real-world exception handling, memory management, and device tree parsing once basics are mastered
  • rust-lang/rust — Rust compiler and standard library source; essential for understanding no_std constraints, inline assembly syntax, and panic behavior in embedded contexts
  • riscv-software-src/riscv-pk — RISC-V bootloader and proxy kernel; demonstrates similar bare-metal Rust patterns for an alternative ISA (inspiration for potential RISC-V port mentioned in README)
  • raspberry-pi/linux — Official Raspberry Pi Linux kernel fork; reference for RPi3/4 hardware register definitions, device tree bindings, and real driver implementations
  • jamesmunns/knurling-rs — Rust embedded tooling ecosystem (defmt, probe-run); complementary debugging and logging infrastructure for extending this kernel with better observability

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for BSP-specific kernel linking and memory layout

The repo has multiple BSP variants (rpi3, rpi4) with architecture-specific linker scripts (src/bsp/raspberrypi/kernel.ld) and boot sequences (src/_arch/aarch64/cpu/boot.s). Currently, test_integration.yml exists but there are no specific tests verifying that kernels built with different BSP features produce valid ELF binaries with correct memory layouts. This would catch regressions in linker script changes and ensure both RPi3 and RPi4 builds are bootable.

  • [ ] Create tests/integration_bsp_linking.rs to verify kernel ELF format and section addresses for both bsp_rpi3 and bsp_rpi4 features
  • [ ] Add test assertions checking that .text, .rodata, and .data sections are at expected memory addresses matching src/bsp/raspberrypi/kernel.ld definitions
  • [ ] Update .github/workflows/test_integration.yml to run these new tests for both BSP configurations
  • [ ] Document expected memory layout in a new tests/README.md for future contributors

Add architecture-specific unit tests for aarch64 CPU operations in src/_arch/aarch64/cpu/

The bootstrap code (src/_arch/aarch64/cpu/boot.rs and boot.s) performs critical CPU initialization tasks, but there are no unit tests validating Rust CPU operations. The existing test_unit.yml workflow suggests unit test infrastructure exists. Adding tests for CPU features like barrier operations, exception handling setup, and register configurations would prevent subtle architectural bugs.

  • [ ] Create tests/unit_aarch64_cpu.rs with tests for CPU barrier instructions (isb, dsb, dmb) if wrapped in Rust functions
  • [ ] Add tests validating any CPU feature detection or CPUID-like operations in src/_arch/aarch64/cpu/boot.rs
  • [ ] If CPU state initialization is testable, add unit tests verifying correct EL (Exception Level) or system register configurations
  • [ ] Update Makefile targets to include these tests in the standard test suite

Add pre-commit hook validation for kernel.ld syntax and linker script consistency across BSPs

The repo already has .githooks/pre-commit in place, indicating a pre-commit infrastructure. Both src/bsp/raspberrypi/kernel.ld files (in different tutorials) define memory layouts but there's no validation that they're syntactically correct or that symbol definitions match between tutorials/BSP variants. A linker script linter would catch typos before CI runs and ensure consistency.

  • [ ] Enhance .githooks/pre-commit to validate all kernel.ld files using a Rust-based linker script parser or a simple regex check for common syntax errors
  • [ ] Add a script (tools/validate_linker_scripts.sh) that checks: MEMORY block definitions are present, section placements are within defined regions, and no conflicting symbol definitions exist
  • [ ] Document linker script conventions in a new doc/LINKER_SCRIPT_GUIDE.md explaining the structure of kernel.ld for contributors modifying BSP definitions
  • [ ] Test the pre-commit hook on intentionally broken linker scripts to verify it catches errors

🌿Good first issues

  • Add unit tests for BSP memory layout validation: Create a test module in src/bsp.rs that validates kernel.ld memory regions match Rust code assumptions (e.g., boot stack size matches linker script). Currently no tests verify the contract between Makefile linking and runtime memory access.
  • Document the boot sequence flow diagram in README: Add a visual ASCII diagram or Mermaid chart to 01_wait_forever/README.md showing the exact flow: firmware → boot.s → boot.rs → main.rs → panic_wait. Tutorial text is scattered; learners need a single reference showing how files connect.
  • Extract CPU frequency detection code into reusable module: A later tutorial likely reads CPU frequency from hardware; instead of duplicating in each tutorial, create src/_arch/aarch64/cpu/frequency.rs with hardware register parsing. Currently no central place for such utilities across tutorials.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 644474c — fix:simplify self assignment and use Ruby to simplify syntax (#211) (Jzow)
  • 42a1f7a — Fix pdf reference page for errors #200 (#202) (Jzow)
  • 8856331 — Modify outdated translations (#201) (Jzow)
  • 98147b7 — Use https in links. (eldruin)
  • 53074bb — fix depracated link to the rust-toolchain.toml file (#199) (nmpluta)
  • 93e108f — Translation Chapter 08 (#190) (Jzow)
  • 502935c — Translation Chapter 10 (#192) (Jzow)
  • aa7413f — Translation Chapter 09 (#191) (Jzow)
  • 2dfb9e7 — Translation Chapter 7 (#189) (Jzow)
  • 9fd529f — Translation Chapter 6 (#186) (Jzow)

🔒Security observations

This is an embedded OS tutorial project with a strong security posture. The codebase has minimal external dependencies (reducing attack surface), no hardcoded credentials detected, and no obvious injection vulnerabilities. Main concerns are around low-severity items: lack of dependency version pinning guidance, assembly code requiring specialized review, and absence of automated security scanning in CI/CD. The educational nature and bare-metal scope limit exposure to common web/application vulnerabilities.

  • Low · No Explicit Dependency Pinning in Cargo.toml — Cargo.toml. The Cargo.toml file shows an empty [dependencies] section. While this is appropriate for a bare-metal OS tutorial project with minimal external dependencies, any future dependencies should be carefully vetted and pinned to specific versions to prevent supply chain attacks. Fix: When adding dependencies, use exact version pinning (e.g., '0.1.2' instead of '0.1') and regularly audit dependencies using 'cargo audit' in CI/CD pipelines.
  • Low · LTO Enabled Without Additional Security Hardening — Cargo.toml [profile.release]. The release profile enables Link Time Optimization (LTO) which is good for performance, but there are no explicit security hardening flags configured (e.g., overflow-checks, debug assertions for embedded systems). Fix: Consider adding security-focused compiler flags in the release profile such as 'overflow-checks = true' or review the use of 'debug-assertions' for embedded security contexts.
  • Low · Potential Unsafe Code in Assembly Files — src/_arch/aarch64/cpu/boot.s (and similar files across tutorials). The project contains multiple assembly files (*.s files in _arch/aarch64/cpu/) which are inherently unsafe and difficult to audit. These are critical for boot sequences and require careful security review. Fix: Ensure all assembly code is peer-reviewed, well-documented with security considerations, and validated against ARM ARMv8-A specification. Consider adding MISRA-C compliance checks if applicable.
  • Low · Limited Security Testing in CI/CD — .github/workflows/. While the repository includes GitHub Actions workflows for building and testing, there is no explicit security scanning (e.g., cargo-audit, SAST tools) visible in the CI configuration. Fix: Add 'cargo audit' step to CI/CD pipelines (build_rpi3.yml, build_rpi4.yml, test_*.yml) to detect known vulnerabilities in dependencies.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · rust-embedded/rust-raspberrypi-OS-tutorials — RepoPilot