opensource.google.com

Menu
Showing posts with label microcontrollers. Show all posts
Showing posts with label microcontrollers. Show all posts

Secure-by-design firmware development with Wasefire

Tuesday, November 18, 2025

Improving firmware development

Building firmware for embedded devices—like microcontrollers and IoT hardware—is hard. It's often complex, it requires deep expertise, and most importantly it is prone to security bugs. One of the key challenges is the limited resources available on these devices, such as constrained processing power, memory, and storage capacity. These constraints make implementing robust security measures at odds with performance and functionality. Unsafe IoT devices are then recruited by cyber criminals into botnets, to perform DDoS attacks, steal information, and act as proxies to evade detection (e.g. the Mirai botnet).

Today, we introduce a new framework that makes it easier to build and maintain safer embedded systems: Wasefire.

Wasefire simplifies the development process and incorporates security best practices by default. This enables developers to create secure firmware without requiring extensive security expertise and only focusing on the business logic they want to implement. To this end, Wasefire provides for each supported device, a platform on which device-agnostic sandboxed applets can run. Wasefire currently supports nRF52840 DK, nRF52840 Dongle, nRF52840 MDK Dongle, and OpenTitan Earlgrey. There is also a Host platform for testing without embedded devices.

A Wasefire platform abstracts the hardware so Wasefire applets are portable

The platform is written in Rust for its performance and built-in memory safety. Embedded devices are one of the four target domains of the Rust 2018 roadmap. So today, it is quite simple to write embedded code in Rust, or even integrate Rust in existing embedded code.

The platform expects the applets to be written in—or more realistically, compiled to—WebAssembly for its simplicity, portability, and security. WebAssembly is a binary instruction format for a stack-based virtual machine. It is designed for high-performance applications on the web (hence its name) but it also supports non-web environments. Fun fact: Wasefire uses WebAssembly in both environments: the main usage is non-web for the virtual machine to run applets, but the web interface of the Host platform also relies on WebAssembly.

Incidentally, WebAssembly is another one of the four target domains of the Rust 2018 roadmap. This means that writing applets in Rust and compiling them to WebAssembly is very simple. For this reason, Rust is the primary language to write applets for Wasefire. Starting a new project is as simple as the following steps:

WebAssembly on microcontrollers

Running WebAssembly on microcontrollers may seem like overkill if it were only for sandboxing. But using a virtual machine also provides binary-level portability like Java Cards. In particular, the same WebAssembly applet can be distributed in binary form and run on multiple platforms.

On a microcontroller, every byte matters. To cater to a variety of needs, Wasefire provides multiple alternatives to balance between security, performance, footprint, and portability:

  • WebAssembly applets: Platforms may embed the Wasefire interpreter. This is a custom in-place interpreter for WebAssembly in the style of "A fast in-place interpreter for WebAssembly" with a very small footprint. The main drawback is that it doesn't support computation heavy applets.
  • Pulley applets: Platforms may embed Wasmtime and its Pulley interpreter. WebAssembly was not designed for interpretation, but for compilation. So WebAssembly interpreters will experience some form of challenge (either performance or footprint). On the contrary, Pulley was designed for fast interpretation and can be compiled from WebAssembly. The main drawback is the larger footprint of this solution and the need for applets to be signed (which is not yet implemented) since Pulley cannot be validated like WebAssembly.
  • Native applets: Platforms may link with an applet compiled as a static library for the target architecture. This solution is only provided as a last resort when no other existing alternative works. The main drawback is that almost all security benefits are nullified and binary-level portability is lost.
  • CHERI applets: This alternative is planned (but not yet started) and would provide the performance and footprint advantage of Native applets while retaining the sandboxing advantage of WebAssembly and Pulley applets. The main drawback is that the target device needs to support CHERI and binary-level portability is lost.

To illustrate this tradeoff, let's look at a few examples from the Wasefire repository:

  • The first example is a button-controlled blinking LED. This applet can run as a WebAssembly applet without problem.
  • The second example is a FIDO2 security key implemented using the OpenSK library. This applet reaches the limits of the WebAssembly in-place interpreter in terms of performance at the moment. By using a Pulley applet instead, performance can be improved by degrading applet size and memory footprint.
  • The third example is a BLE sniffer. Performance is a critical aspect of this applet. The in-place interpreter is too slow and many packets are dropped. Compiling this applet to Pulley doesn't drop any packet in a noisy BLE environment.

We can summarize the tradeoff in the table below. The platform size differs between examples because the second and third examples need optional drivers disabled by default. The platform is the nRF52840 DK. For the security key, applet performance is measured as the time between a FIDO2 GetInfo request and the last packet of its response. For the BLE sniffer, applet performance is measured as the number of processed packets per second. This metric saturates for Pulley and Native applets, so we only get a lower bound of performance in those cases.

Blinking LED WebAssembly Pulley Native
Platform size (KiB) 98 299 49
Applet size (KiB) 3.3 12 5.6
Platform memory (KiB) 10 80 5
Security key WebAssembly Pulley Native
Platform size (KiB) 133 334 80
Applet size (KiB) 125 247 73
Platform memory (KiB) 20 104 9
Applet performance (ms) 1191 60 23
BLE sniffer WebAssembly Pulley Native
Platform size (KiB) 102 303 53
Applet size (KiB) 7.2 18 7.6
Platform memory (KiB) 16 82 8.8
Applet performance (packet/s) = 55 (dropping packets) > 195 (not dropping) > 195 (not dropping)

Looking forward

Wasefire is still an experimental project. Many features are missing (including security features) and many improvements are planned. For example, the platform currently runs a single applet and provides all the resources this applet asks for. Ultimately, applets would come with a manifest describing which resources they are permitted to use, and those resources would be isolated to that single applet. It would also be possible to run multiple applets concurrently.

The project is open source, so bug reports, feature requests, and pull requests are welcome. The project is licensed under Apache-2.0, so commercial use is permitted.

Feel free to give it a try (no hardware needed) and share the word!

Introducing the Pigweed SDK: A modern embedded development suite

Thursday, August 8, 2024

Back in 2020, Google announced Pigweed, an open-source collection of embedded libraries to enable a faster and more reliable development experience for 32-bit microcontrollers. Since then, Pigweed’s extensive collection of middleware libraries has continuously evolved and now includes RTOS abstractions and a powerful RPC interface. These components have shipped in millions of devices, including Google’s own Pixel suite of devices, Nest thermostats, DeepMind robots, as well as satellites and autonomous aerial drones.

Today, we introduce the first developer preview of the Pigweed SDK, making it even easier to leverage Pigweed’s libraries to develop, debug, test, and deploy embedded C++ applications. Using the included sample applications and comprehensive tutorial, you can easily get started prototyping simple programs and build up to more complex applications that leverage advanced Pigweed functionalities. Pigweed’s modern and modular approach makes it easy to design applications with significantly reduced debugging and maintenance overhead, thus making it a perfect choice for medium to large product teams.

We are also thrilled to contribute to the Raspberry Pi Pico 2 and RP2350 launch, providing official support in Pigweed for RP2350 and its predecessor, the RP2040. Building on the success of the Pico 1 and RP2040, the Pico 2 introduces the RP2350 microcontroller, bringing more performance and an exciting set of new capabilities in a much lower power profile. We’ve worked closely with the Raspberry Pi team to not only provide a great experience on Pigweed, but also upstreamed a new Bazel-based build system for Raspberry Pi’s own Pico SDK.

Raspberry Pi Pico 2 (RP2350) with Enviro+ pack hat.
Raspberry Pi Pico 2 (RP2350) with Enviro+ pack hat.

What's in the SDK

The Pigweed SDK aims to be the best way to develop for the Pico family of devices. The SDK includes the Sense showcase project, which demonstrates a lot of our vision for the future of sustainable, robust, and rapid embedded system development, such as:

  • Hermetic building, flashing, testing, and cross-platform toolchain integration through Bazel.
  • Fully open-source Clang/LLVM toolchain for embedded that includes a compiler, linker, and C/C++ libraries with modern performance, features, and standards compliance
  • Efficient and robust device communication over RPC
  • An interactive REPL for viewing device logs and sending commands via command-line and web interfaces
  • Visual Studio Code integration with full C++ code intelligence
  • GitHub Actions support for continuous building and testing
  • Access to pico-sdk APIs when you need to drop down to hardware-specific functionality
Moving image of the Pigweed CLI console engaging with the device through interactive Remote Procedure Calls (RPCs).
Utilize the Pigweed CLI console to communicate with your device through interactive Remote Procedure Calls (RPCs).

By building your project with the Pigweed SDK (using the Sense showcase as your guide), you can start on readily available hardware like the Pico 1 or 2 today. Then when you’re ready to start prototyping your own custom hardware, you can target your Pigweed SDK project to your custom hardware without the need for a major rewrite.

Try Sense now

Bazel for embedded

Pigweed is all-in on Bazel for embedded development. We believe Bazel has great potential to improve the productivity (and mental wellbeing) of embedded development teams. We made the "all-in" decision last September and the Raspberry Pi collaboration was a great motivator to really flesh out our Bazel strategy:

  • We contributed to an entirely new Bazel-based build for the Pico SDK to make it easy for the RP2 ecosystem to use Bazel and demonstrate how Bazel takes care of complex toolchains and dependencies for you.
  • The new Sense showcase demonstrates Bazel-based building, testing, and flashing.
  • Our GitHub Actions guide shows you how to build and test your Bazel-based repo when pull requests are opened, updated, or merged.

Head over to Bazel's launch blog post to learn more about the benefits of Bazel for embedded.


Clang/LLVM for embedded

Pigweed SDK fully leverages the modern Clang/LLVM toolchain. We are especially excited to include LLVM libc, a fully compliant libc implementation that can easily be decomposed and scaled down for smaller systems. The team spent many months developing and contributing patches to the upstream project. Their collaboration with teams across Google and the upstream LLVM team was instrumental in making this new version of libc available for embedded use cases.

The sample applications, Pigweed modules, host-side unit tests, and showcase examples already use Clang, LLD, LLVM libc and libc++. Thus, developers can take advantage of Clang’s diagnostics and large tooling ecosystem, LLD’s fast linking times, and modern C and C++ standard library implementations which support features such as Thread Safety Analysis and Hardening.


IDE integration

With full Visual Studio Code support through pw_ide, you can build and test the Sense showcase from the comfort of a modern IDE and extend the IDE integration to meet your needs. Full target-aware code intelligence makes the experience smooth even for complicated embedded products. Automatic linting, formatting, and code quality analysis integrations are coming soon.


Parallel on-device testing with PicoPico

As you would expect from a team with the mission to make embedded development more sustainable, robust, and rapid for large teams, we are of course obsessed with testing. We have hundreds of on-device unit tests running all the time on Picos. The existing options were a bit slow so we whipped up PicoPico in a week (literally) to make it easier to run all these tests in parallel.

A “PicoPico” node
One “PicoPico” node for running parallel on-device tests

RP2 support

The goal behind our extensive catalog of modules is to make it easy to fully leverage C++ in your embedded system codebases. We aim to provide sensible, reusable, hardware-agnostic abstractions that you can build entire systems on top of. Most of our modules work with any hardware, and we have RP2 drivers for I2C, SPI, GPIO, exception handling, and chrono. When Pigweed's modules don't meet your needs, you can still fallback to using pico-sdk APIs directly.


Get started

Clone our Sense showcase repo and follow along with our tutorial. The showcase is a suitable starting point for learning what a fully featured embedded system built on top of the Pigweed SDK looks like.


What’s next

The Pigweed team will continue to have regular and on-going preview releases, with new features, bug fixes, and improvements based on your feedback. The team is working on a comms stack for all your end-to-end networking needs, factory-at-your-desk scripting, and much, much more. Stay tuned on the Pigweed blog for updates!


Learn more

Questions? Feedback? Talk to us on Discord or email us at [email protected].

We have a Pigweed Live session scheduled on August 26th, 13:00 PST where the Pigweed team will talk more about the Pigweed SDK and answer any questions you have. Join [email protected] to get an invite to the meetings.


Acknowledgements

We are profoundly grateful for our passionate community of customers, partners, and contributors. We honor all the time and energy you've given us over the years. Thank you!

By Amit Uttamchandani – Product Manager, Keir Mierle – Software Engineer, and the Pigweed team.

Pigweed: A collection of embedded libraries

Thursday, March 19, 2020


We’re excited to announce Pigweed, an open source collection of embedded-targeted libraries, or as we like to call them, modules. Pigweed modules are built to enable faster and more reliable development on 32-bit microcontrollers.

Pigweed is in early development and is not suitable for production use at this time.


Getting Started with Pigweed

As of today, the source is available for everyone at pigweed.googlesource.com under an Apache 2.0 license. Instructions on getting up and running can be found in the README.


See Pigweed in action

Pigweed offers modules that address a wide range of embedded developer needs. These highlight how Pigweed can accelerate embedded development across the entire lifecycle:

  • Setup: Get started faster with simplified setup via a virtual environment with all required tools
  • Development: Accelerated edit-compile-flash-test cycles with watchers and distributed testing
  • Code Submission: Pre-configured code formatting and integrated presubmit checks

Setup

A classic challenge in the embedded space is reducing the time from running git clone to having a binary executing on a device. Oftentimes, an entire suite of tools is needed for non-trivial production embedded projects. For example, your project likely needs:

  • A C++ compiler for your target device, and also for your host
  • A build system (or three); for example, GN, Ninja, CMake, Bazel
  • A code formatting program like clang-format
  • A debugger like OpenOCD to flash and debug your embedded device
  • A known Python version with known modules installed for scripting
  • … and so on

Below is a system with Python 2.7, clang-format, and no ARM compiler. The bootstrap script in Pigweed’s pw_env_setup module, sets up the current shell to have access to a standardized set of tools—Python 3.8, clang-format, and an ARM compiler among them. All of this is done in a virtual environment so the system’s default environment remains unmodified.

Moving image showing a system with Python 2.7, clang-format, and no ARM compiler running the bootstrap script in Pigweed’s `pw_env_setup module`

Development

In typical embedded development, adding even a small change involves the following additional manual steps:

  • Re-building the image
  • Flashing the image to a device
  • Ensuring that the change works as expected
  • Verifying that existing tests continue to pass

This is a huge disparity from web development workflows where file watchers are prevalent—you save a file and instantly see the results of the change.

Pigweed’s pw_watch module solves this inefficiency directly, providing a watcher that automatically invokes a build when a file is saved, and also runs the specific tests affected by the code changes. This drastically reduces the edit-compile-flash-test cycle for changes.

Moving image of Pigweed's pw_watch-build demo

In the demo above, the pw_watch module (on the right) does the following:

  • Detects source file changes
  • Builds the affected libraries, tests, and binaries
  • Flashes the tests to the device (in this case a STM32F429i Discovery board)
  • Runs the specific unit tests

There’s no need to leave your code editor—all of this is done automatically. You can save additional time by using the pw_target_runner module to run tests in parallel across multiple devices.


Code submission

When developing code as a part of a team, consistent code is an important part of a healthy codebase. However, setting up linters, configuring code formatting, and adding automated presubmit checks is work that often gets delayed indefinitely.

Pigweed’s pw_presubmit module provides an off-the-shelf integrated suite of linters, based on tools that you’ve probably already used, that are pre-configured for immediate use for microcontroller developers. This means that your project can have linting and automatic formatting presubmit checks from its inception.

Moving image of Pigweed's pw-presubmit demo

Other modules

There are many modules in addition to the ones highlighted above:

  • pw_tokenizer – A module that converts strings to binary tokens at compile time. This enables logging with dramatically less overhead in flash, RAM, and CPU usage.
  • pw_string – Provides the flexibility, ease-of-use, and safety of C++-style string manipulation, but with no dynamic memory allocation and a much smaller binary size impact. Using pw_string in place of the standard C functions eliminates issues related to buffer overflow or missing null terminators.
  • pw_bloat – A module to generate memory reports for output binaries empowering developers with information regarding the memory impact of any change.
  • pw_unit_test – Unit testing is important and Pigweed offers a portable library that’s broadly compatible with Google Test. Unlike Google Test, pw_unit_test is built on top of embedded friendly primitives; for example, it does not use dynamic memory allocation. Additionally, it is to port to new target platforms by implementing the test event handler interface.
  • pw_kvs – A key-value-store implementation for flash-backed persistent storage with integrated wear levelling. This is a lightweight alternative to a file system for embedded devices.
  • pw_cpu_exception_armv7m – Robust low level hardware fault handler for ARM Cortex-M; the handler even has unit tests written in assembly to verify nested-hardware-fault handling!
  • pw_protobuf – An early preview of our wire-format-oriented protocol buffer implementation. This protobuf compiler makes a different set of implementation tradeoffs than the most popular protocol buffer library in this space, nanopb.

Why name the project Pigweed?

Pigweed, also known as amaranth, is a nutritious grain and leafy salad green that is also a rapidly growing weed. When developing the project that eventually became Pigweed, we wanted to find a name that was fun, playful, and reflective of how we saw Pigweed growing. Teams would start out using one module that catches their eye, and after that goes well, they’d quickly start using more.

So far, so good 😁


What’s next?

We’re continuing to evolve the collection and add new modules. It’s our hope that others in the embedded community find these modules helpful for their projects.

By Keir Mierle and Mohammed Habibulla, on behalf of the Pigweed team

.