Precursor: Renode for developing advanced products with embedded GUIs
Topics: Open security / safety, Open ISA, Open FPGA IP, Open toolchains
Our open source Renode simulator has been helping our customers develop products using ARM, RISC-V and - recently - Xtensa-based SoCs, providing hardware-software co-development and CI-driven testing capabilities for a variety of real product development projects. One of such projects, previously described on our blog, is Betrusted’s Precursor, an FPGA-based, fully open source, transparent and secure communication device based (among other things) on two interconnected RISC-V CPUs.
In this long running collaboration, Renode has become an important tool for testing and debugging Precursor’s firmware based on their original microkernel OS, Xous, providing SW-HW co-simulation and continuous integration capabilities. The Betrusted team has been gradually adopting the wide array of advanced debugging and testing features of Renode, and this use case is a perfect example of how our simulation framework can be used to rapidly develop and improve advanced, multi-node products with embedded GUIs, harnessing features such as multi-node simulation and host-guest networking.
Ensuring security with Renode’s advanced debugging features
Security-oriented projects like Precursor want to guarantee their users the highest level of confidence in their operations, leaving no room for unexpected behavior - that’s why the use of simulation which provides full control and inspectability is so important in their context.
Renode provides many introspection features, such as:
- logging of accesses to memory-mapped peripherals,
- inspection of signals, like GPIOs and interrupts,
- execution tracing of guest binaries with various level of detail: function calls, PC values or full disassembly,
- metrics of execution,
- detection of access to unexpected addresses.
The last feature especially, as reported by the Betrusted team, has been very useful for spotting several errors in their code.
All of the above is not feasible on physical systems - you would either need to instrument your code to generate data (and be able to retrieve it afterwards) or use complex external tracing mechanisms - if they are even available on your hardware.
You can even use Python programming to react to various events, making the simulation environment not only inspectable, but also reactive to certain situations, also very interesting from the security corner-case testing perspective.
And while being able to interactively inspect your software is extremely useful, the real power of a virtual setup presents itself in the context of Continuous Integration, similar to the one we created for Precursor, verifying each and every commit of your software against a set of rules, in all imaginable conditions and circumstances. Below we will walk you through some of the advanced features of Renode that are being used, and also developed, in the context of Betrusted’s Precursor project’s CI and daily development environment.
Rapid development with ad-hoc compilation capabilities
Renode is very much oriented towards adaptability and composability of features and models - the supported boards, defined in human-readable text files, are assembled from independent building blocks, allowing you to precisely model your platform.
While Renode comes bundled with a broad range of different IP models, Precursor, based on two FPGAs programmed with VexRiscv and a soft SoC generated with LiteX, uses many custom-designed peripherals, understandably not yet available in upstream Renode.
The Betrusted team approached this head-on - they implemented the required models themselves and even created a tutorial on how to write Precursor peripheral models for Renode. With our help, they also implemented a custom communication mechanism based on SPI which allowed them to have two parts of Precursor - the main SoC and the Embedded Controller, work together in simulation.
Since Precursor’s peripherals are still under development and the models change often, upstreaming them is not an option for the moment (for other customer use cases, pre-release confidentiality might impose a similar limitation). However, working on a fork would deprive Betrusted of the ability to track new developments in upstream Renode. Fortunately Renode offers an easy way to work with out-of-tree peripherals, by shipping with a C# compiler included which allows you to compile your models in runtime. These peripherals are as capable as the built-in ones: they can be used in the Renode platform (
.repl) files, access the internal Renode infrastructure as well as the bundled blocks.
Loading a C# model in Renode is as easy as can be - you just need to add it with the
(monitor) include @path/to/your/model.cs (monitor) EnsureTypeIsLoaded “Full.Class.Name”
One of the recent additions to Renode, resulting from another customer project but also helpful for the Precursor use case, is ad-hoc compiler cache support, allowing you to speed up loading of your script if you reuse a file that was already compiled by Renode - this is especially useful if you run a set of automated tests loading your platforms over and over again.
Multi-node simulation capabilities
As we mentioned, Precursor consists of two parts, the secure domain SoC and the Embedded Controller, or EC, responsible for handling the untrusted part of the system, like the WiFi stack.
While they are coupled in a single device, from the development perspective they are independent entities. This complexity of the design results in a quite challenging debugging setup.
Renode allows you to contain complicated, heterogeneous setups within a single simulation, with blocks connected over various types of connections, like Ethernet, Bluetooth and other wireless networks, UARTs, SPI and other means. This capability comes with a range of features unavailable when working with the real hardware.
Most importantly, each and every part of the simulation is governed by a central virtual time controller. This has a profound impact on the debugging process - Renode can be configured to provide a transparent multi-node debugging experience, with all nodes patiently waiting while you step over your code - without communication timeouts or additional message passing. Debugging on real hardware, if possible, is fundamentally different - other nodes are not aware that you are currently trying to debug your communication stack and will assume your stopped node is just not responding, which will result in all sorts of unwanted behavior. Renode also allows you to record and replay events, simulate faults and lossy transmissions, all very helpful for full-system debugging.
As mentioned, the Betrusted team created their own means of communication and modeled it in Renode. Both the EC and the SoC are simulated in a single environment. This allows us to run and test the whole software flow, starting with the user input, through the untrusted stack and communication with the external world to the graphical display.
GUI development with testing capabilities
One of the problems that are notoriously difficult to solve when testing hardware systems is the verification of graphical output. While in physical testing serial ports and test pins can be connected to an automated rig, automated testing of integrated displays requires very customized and sophisticated setups. As the main way Precursor communicates with its users is via the display, properly verifying this functionality is of key importance.
Renode provides an API to test all kinds of interfaces: serial connections, networks, LEDs and more. For display testing, it includes a FramebufferTester - an easy to use mechanism to look for specific frames produced by the simulated board.
The Precursor display is fairly complex - after booting up the user is presented with a main work area with history of commands and their results, an input area, a status bar including information on current time and battery status, occasional modal pop-ups and even randomized blur over the background. All of these elements add to the complexity of display testing, but Renode offers a range of features that can help address them (some of which we developed with the Precursor use case in mind):
- strictly controlled time flow
- external sensors (like battery gauge) that are easy to model or mock
- region-of-interest testing for the framebuffer, allowing us to ignore certain parts of the display
- internal Random Number Generator, that can be controlled and deterministic even in multi-node setup, allowing us to stabilize the background blur
These and other features are used in the GitHub Actions workflow we prepared to test Xous on Precursor in Renode. The workflow builds Xous and runs tests on a virtual platform using our dedicated Renode GitHub Action, allowing users to run Renode tests in a few lines of code.
Xous and Precursor are not the only recent use-case for Renode-aided testing of embedded UIs - not long ago Microsoft’s Benjamin Cabé shared his experience on running Azure RTOS ThreadX UI in Renode.
While the graphical display allows the user to talk to Precursor, one of its important tasks is to talk to the rest of the world via the Internet. Precursor sports a SiLabs WF200 WiFi chip for that purpose (which we are excited to push towards our upstream as the first supported WiFi chip!), and Renode allows the simulated setup to access the external world just as well.
Among many host-guest integration options available in Renode, Precursor makes extensive use of host-guest networking.
Using the TAP interface on the host system, Renode is able to communicate with network applications running on your PC.
This in turn provides a pathway to integrate with other simulated environments or even the cloud. This opens an opportunity to test IoT devices on every level of detail - from the drivers fetching sensor data, through software life-cycle and data processing, to large scale integrations with cloud services - all within the fully controlled environment of Renode.
Host guest networking is currently available for Linux and macOS, with support for Windows coming soon to upstream Renode.
Boosting hardware development with Renode
Antmicro continues to support the Betrusted team and many other partners and customers in developing their products with Renode, providing the tools necessary to create truly secure and thoroughly tested solutions. We offer comprehensive services for pre-silicon development of hardware-software systems, enabling hardware modeling even before it is fully defined, as well as reliable debugging and verification. If you are interested in improving your workflow with open source tools and software-driven hardware development approach, reach out to us at email@example.com and learn how Renode can be employed into your use case.