Rust is the future of systems programming.

Google recently announced that Android now supports the Rust programming language. In this article, we would like to show how the Rust language is becoming popular in Linux kernel development and microcontroller programming. Why is Rust necessary and its benefits for the entire embedded systems industry? This article will cover the technical aspects of the Rust language for Embedded with a few simple examples.

Rust is a systems programming language designed for security, speed, and concurrency. Rust has many compile-time and safety features to avoid data crashes and standard errors, all with minimal overhead. The language is focused on safe memory management, provides automatic memory management, and provides a means to achieve high parallelism of job execution while avoiding a garbage collector and runtime. Rust’s automated memory management frees the developer from manipulating pointers and protects against problems arising from low-level memory handling, such as accessing a region of memory after it is released, dereferencing null pointers, exceeding buffer boundaries. To distribute libraries, provide assembly and manage project dependencies, the Cargo package manager is being developed, which allows you to get the libraries you need for a program in one click. Cargo is a tool that lets you specify the required dependencies for your Rust projects and make sure you get reproducible builds.

Rust has many advantages:

  • Excellent static typing;
  • Lack of a garbage collector and the ability to control the location of data in memory;
  • Excellent built-in static code analyzer to avoid errors related to memory management and multithreading;
  • Easy-to-understand syntax;
  • The compiler from Rust developers with a built-in manager and package collector, a test system, and a documentation generator;
  • Secure memory management;
  • Ability to apply abstractions;
  • Corrections are provided for many compile-time errors;
  • Pointers can only be used in unsafe code; in safe code, only references to guaranteed existing objects are used;
  • Very strict code compiler;
  • Predictable memory allocation and deallocation;
  • Closures;
  • Pattern matching;
  • Algebraic data types, etc.

Rust for microcontroller programming

Already today, the Rust language at ShuraCore is a favorite programming language among developers. More and more clients would like to see Rust as their base application development language. Embedded is no exception. Here are a few points why Rust is already an equal competitor to C/C++ in Embedded.

  1. Powerful static analysis. Enforce pin and peripheral configuration at compile time. Guarantee that resources won’t be used by unintended parts of your application.
  2. Flexible memory. Dynamic memory allocation is optional. Use a global allocator and dynamic data structures. Or leave out the heap altogether and statically allocate everything.
  3. Portability. Write a library or driver once, and use it with a variety of systems, ranging from very small microcontrollers to powerful SBCs.
  4. Fearless concurrency. Rust makes it impossible to accidentally share state between threads. Use any concurrency approach you like, and you’ll still get Rust’s strong guarantees.
  5. Interoperability. Integrate Rust into your existing C codebase or leverage an existing SDK to write a Rust application.
  6. Community driven.As part of the Rust open source project, support for embedded systems is driven by a best-in-class open source community, with support from commercial partners.

We have prepared a small example of LED blinking on the STM32f429i-disco debug board.

cargo-features = ["default-run"]

[package]
authors = ["ShuraCore info@shuracore.com"]
categories = ["embedded", "no-std"]
name = "stm32f429i_disco"
version = "0.1.0"
edition = "2018"

[dependencies]
cortex-m = "0.6.2"
cortex-m-rt = "0.6.12"
panic-halt = "0.2.0"

[dependencies.stm32f4]
version = "0.10.0"
features = ["stm32f429", "rt"]

[dependencies.stm32f4xx-hal]
version = "0.7"
features = ["rt", "stm32f429"]

#![deny(unsafe_code)]
#![no_main]
#![no_std]

// Halt on panic
#[allow(unused_extern_crates)] 
extern crate panic_halt; // panic handler

use cortex_m;
use cortex_m_rt::entry;
use stm32f4xx_hal as hal;

use crate::hal::{prelude::*, stm32};

#[entry]
fn main() -> ! {
    if let (Some(dp), Some(cp)) = (
        stm32::Peripherals::take(),
        cortex_m::peripheral::Peripherals::take(),
    ) {
        // Set up the LEDs. On the stm32f429i-disco they are connected to pin PG13 and PG14.
        let gpiog = dp.GPIOG.split();
        let mut led3 = gpiog.pg13.into_push_pull_output();
        let mut led4 = gpiog.pg14.into_push_pull_output();

        // Set up the system clock. We want to run at 180MHz for this one.
        let rcc = dp.RCC.constrain();
        let clocks = rcc.cfgr.sysclk(180.mhz()).freeze();

        // Create a delay abstraction based on SysTick
        let mut delay = hal::delay::Delay::new(cp.SYST, clocks);

        loop {
            // On for 1s, off for 1s.
            led3.set_high().unwrap();
            led4.set_low().unwrap();
            delay.delay_ms(1000_u32);
            
            led3.set_low().unwrap();
            led4.set_high().unwrap();
            delay.delay_ms(1000_u32);
        }
    }

    loop {}
}

Rust for Linux driver development

In 2020, the developers of the Linux kernel proposed using Rust to develop new code. In March 2021, this idea was partially implemented — the Linux-next branch, on which Linux 5.13 is based, included an initial set of components for developing device drivers on Rust. Google has already announced its intention to participate in the initiative to promote Rust support in the Linux kernel. The company gave examples of the feasibility of implementing Rust to combat problems that arise due to errors when working with memory. The company’s representatives also believe that Rust is ready to join C, becoming another language for developing Linux kernel components.

Here is an example of a driver for Linux in the Rust language.

[package]
name = "test_example"
version = "0.1.0"
authors = ["ShuraCore <info@shuracore.com>"]
edition = "2018"

[lib]
crate-type = ["staticlib"]

[dependencies]
linux-kernel-module = { path = ".." }

[profile.release]
panic = "abort"
lto = true

[profile.dev]
panic = "abort"

#![no_std]
#![feature(alloc)]

extern crate alloc;
use crate::alloc::string::{String, ToString};
use linux_kernel_module::c_types;
use linux_kernel_module::println;

struct ShuraCoreModule {
    message: String,
}

impl linux_kernel_module::KernelModule for ShuraCoreModule {
    fn init() -> linux_kernel_module::KernelResult {
        println!("Hello from ShuraCore!");
        Ok(ShuraCoreModule {
            message: "Hello ShuraCore!".to_string(),
        })
    }
}

impl Drop for ShuraCoreModule {
    fn drop(&mut self) {
        println!("Goodbye from ShuraCore!");
    }
}

static mut MODULE: Option = None;

#[no_mangle]
pub extern "C" fn init_module() -> c_types::c_int {
    match ::init() {
        Ok(m) => {
            unsafe {
                MODULE = Some(m);
            }
            return 0;
        }
        Err(_e) => {
            return 1;
        }
    }
}

#[no_mangle]
pub extern "C" fn cleanup_module() {
    unsafe {
        MODULE = None;
    }
}

#[link_section = ".modinfo"]
pub static MODINFO: [u8; 12] = *b"license=GPL\0";

Statistics

In Google trends, you can see how Rust search results are growing from year to year, all because Rust has a popular love.

When it comes to popularity, Rust comes first. Since 2015, Rust has been recognized by developers as the most favorite programming language in the Stack Overflow developer survey for five consecutive years (2016, 2017, 2018, 2019, 2020):

More and more corporations and companies are using Rust in commercial development. Here is a small part of them: Dropbox, Coursera, Figma, npm, Microsoft, Cloudflare, Facebook, Amazon, Discord, and other significant players. According to official statistics, more than 300 companies worldwide are already using Rust in commercial development.

In total, Rust is a systems programming language that combines the assurances of the compile-time software generation process’s reliability and correctness with high performance. It enhances the ideas of other system languages, such as C/C++, while providing guaranteed memory safety (no crashes, no data jumps) and complete control over the memory lifecycle. Rust’s goal is to show that software is highly productive in specific areas of use. Our team of professionals uses Rust as a programming language to create next-level systems software with tomorrow’s vision. ShuraCore engineers develop software for the following applications:

[contact-form-7 id="1477" title="shuracore_contact_form_en"]