Ferrous Systems Rust Exercises

repository·main·Indexed 18 days ago

https://github.com/ferrous-systems/rust-exercises

A collection of self-contained Rust exercises and lessons ranging from beginner to advanced levels. Includes materials for embedded Rust targeting nRF52840 DK and USB Dongle, STM32 TrustZone on NUCLEO-U5A5ZJ-Q, UART drivers using Ferrocene or upstream Rust, and advanced guides for building Linux kernel drivers in Rust within a Debian VM environment.

Tokens
109.4K
Snippets
398
Records
550
Agent score
63%

What's inside rust-exercises

  1. Overview of the STM32 TrustZone Exercise

    main

    This exercise focuses on implementing and interacting with Arm TrustZone-M (Cortex-M Security Extensions) on an STM32U5A5ZJ-Q microcontroller. You will develop two concurrent applications on a NUCLEO-U5A5ZJ-Q board to practice the following concepts:

    • Arm TrustZone-M (CMSE): Understanding the security architecture.
    • Security Attribution Unit (SAU): Managing memory security attributes.
    • STM32U5 Global Trust Zone Controller: Configuring the hardware-specific security controller.
    • State Transitions: Starting a Nonsecure State binary from a Secure State.
    • Secure APIs: Calling Secure State APIs from a Nonsecure State.
    • Dual Debugging: Using semihosting and defmt over RTT simultaneously for debug output from two different programs.
  2. Overview of STM32 TrustZone exercises

    main

    This repository contains exercises for working with STM32 TrustZone, specifically designed for the ST Micro NUCLEO-U5A5ZJ-Q board (featuring an STM32U5A5ZJ microcontroller).

    The exercises demonstrate a Secure/Nonsecure execution model where a secure-loader (running in Secure State) initializes hardware and then boots a nonsecure-app (running in Nonsecure State). The nonsecure-app can interact with services exported by the secure-loader.

  3. Explore the Rust Exercises curriculum

    main

    The rust-exercises repository is organized into several learning tracks, ranging from fundamental syntax to specialized embedded systems development. You can navigate the curriculum through the following categories:

    • Rust Fundamentals: Basic concepts like Fizzbuzz, Iterators, and SimpleDB.
    • Applied Rust: Practical applications including TCP servers and mailbox implementations.
    • Self-check Project: A dedicated project for self-assessment.
    • Advanced Rust: Complex topics like Async TCP Chat Servers, formal verification with Kani, and Linux Kernel Drivers.
    • Rust for Microcontrollers: Deep dives into nRF52 (Radio, HAL, USB) and STM32 (TrustZone).
    • Rust for Real-Time Systems: Working without std and bare-metal firmware on Cortex-R52.
  4. Learning objectives of the nRF52 USB Exercise

    main

    This exercise focuses on building a toy USB device application that runs in a fully event-driven fashion (only performing work when requested by the host). By completing this exercise, you will learn how to:

    • Work with registers and peripherals from Rust.
    • Handle external events in embedded Rust applications using RTIC (Real-Time Interrupt-driven Concurrency).
    • Debug event-driven applications.
    • Test no_std code.
  5. Understand the nRF52 code organization

    main

    The nRF52 target firmware is located in the ./nrf52-code directory. The project is organized into Board Support Packages (BSPs), application crates (templates and solutions), and shared libraries.

    Key Directories:

    • boards/dk: BSP for the nRF52840 Developer Kit.
    • boards/dk-solution: BSP for the nRF52840 Developer Kit including the BSP exercise solution.
    • boards/dongle: BSP for the nRF52840 USB Dongle (not used in these exercises).
    • boards/dongle-fw: Contains pre-compiled firmware for the nRF52 USB Dongle (available in GitHub releases; empty in the Git repo).
    • consts: Shared constants (e.g., USB Vendor IDs) used across multiple crates.
    • hal-app: Template and solution binary crates for the nRF BSP exercise.
    • dongle-fw: Source code for the USB Dongle firmware used in the radio exercise.
    • radio-app: Template and solution binary crates for the nRF Radio exercise.
    • usb-app: Template binary crates for the nRF USB exercise.
    • usb-app-solutions: Solution binary crates for the nRF USB exercise.
    • usb-lib: Template library crate for the nRF USB exercise (used for parsing USB descriptor information).
    • usb-lib-solutions/: Contains specific solution library crates: get-descriptor-config, get-device, and set-config.
  6. Use the `dongle` Board Support Package (BSP)

    main

    The dongle crate provides a Board Support Package (BSP) specifically for the nRF52840 USB Dongle. Use this package when developing Rust applications targeting this specific hardware platform.

    For hardware specifications and details, refer to the official Nordic Semiconductor product page: https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle

  7. What is a Tuple in Rust

    main

    A tuple is a collection of values of different types. Tuples are constructed using parentheses () and each tuple is a value with a type signature (T1, T2, ...) where T1, T2, etc., are the types of its members. Tuples can hold any number of values and are useful for returning multiple values from a function or grouping related state for pattern matching.

    // A tuple with a bunch of different types.
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                          -1i8, -2i16, -3i32, -4i64,
                          0.1f32, 0.2f64,
                          'a', true);
  8. What is TrustZone and how it works on STM32U5A5ZJ-Q

    main

    TrustZone is an Arm security extension that provides two execution states:

    • Secure State: Has higher permissions and can affect the Nonsecure state.
    • Nonsecure State: Cannot affect the Secure state.

    On the STM32U5A5ZJ-Q (Cortex-M33), state transitions are managed via:

    • Non-volatile Option Bytes (e.g., the TZEN bit) to control the boot state.
    • Special branch instructions for Secure-to-Nonsecure or Nonsecure-to-Secure calls (the latter requiring a Secure Gateway marker).

    This architecture allows sensitive data, like encryption keys, to be isolated in the Secure state even if the Nonsecure state code is compromised.

  9. Use the turbofish syntax `::<>` to disambiguate types

    main

    When the Rust compiler cannot infer the specific type required by an iterator method, use the turbofish operator ::<> to provide explicit type hints. This is common with methods like .parse(), which can return different types (e.g., i32 vs f64) depending on the target type.

    let numbers: Vec<_> = ["1", "2", "3"]
        .iter()
        .map(|s| s.parse::<i32>().unwrap())
        .map(|n| n + 1)
        .collect();