Unsafe by Design, Safe by Testing: Register Access in Rust
Andreas Wallner, Infineon Technologies Austria AG, Graz, AT
Topic: Test, Safety
Abstract: We present our idea for flexible register access, complete with support for unittesting. We embrace the inherently unsafe nature of accessing hardware with side-effects. Enabling host-unittests for register-accessing code allows us to know that our drivers are correct and safe.
The lowest layer of all embedded firmware is interfacing to the hardware via writing memory-mapped registers. In Rust we have ways to provide usable and safer interfaces which remove many of the error sources we encounter when using C. Examples are the APIs generated by `svd2rust` or `chiptool`.
At Infineon, we want to make our Aurix controller family - among others - available to the Rust community. With our partners we chose to implement an alternative register interface, because
- due to the nature of many hardware modules, ownership semantics of Rust do not work well for the register level, and we think safety should be enforced at the driver layer
- register access must be extendable for niche use-cases like HW with intrinsic read-modify-write support or registers with page select
- a generated crate for registers should not have any dependencies or macros
- unittesting of register accessing firmware should be possible on a PC.
This alternative is `svd2pac` which we recently open-sourced - a generator that builds crates for register access given an industry standard SVD file.
As part of this alternative interface we also want to present `regmock-rs` - a testing framework that allows the user to test code that does register access. Embedded code can be run and be debugged on a normal developer machine.
Different levels of testing can be applied, from simply checking that registers are set to a given value, verifying that the order of operations is correct, up to running the code against a model of the hardware. Apart from fast development cycles, being on the host also allows us to inject simulated hardware errors.
Regmock completes our story as it allows us to achieve test coverage for low-level code can be both: useful and simple to write. Depending on the logic we are testing we can choose how to represent or simulate our hardware. Since our register accessing code is testable we can often flatten our architecture since we don't need logic-less layers that abstract hardware for the sole purpose of testing.