From 69515fe2d4fa9cdef8f1f699bdc4e113a3ad8f7c Mon Sep 17 00:00:00 2001 From: Michael Kubacki Date: Fri, 1 Sep 2023 16:54:56 -0400 Subject: [PATCH] Add Rust documentation (#175) Adds documents that explain: - How to build with Rust in Project Mu - Documentation conventions for Rust code in Project Mu - Motivation to adopt Rust in Project Mu Signed-off-by: Michael Kubacki --- cspell.json | 243 ++++++++------- docs/DeveloperDocs/rust_build.md | 152 +++++++++ docs/How/rust_documentation_conventions.md | 347 +++++++++++++++++++++ docs/WhatAndWhy/features.md | 4 + docs/WhatAndWhy/rust.md | 119 +++++++ 5 files changed, 750 insertions(+), 115 deletions(-) create mode 100644 docs/DeveloperDocs/rust_build.md create mode 100644 docs/How/rust_documentation_conventions.md create mode 100644 docs/WhatAndWhy/rust.md diff --git a/cspell.json b/cspell.json index 3c40a2d6f..b7d63f46d 100644 --- a/cspell.json +++ b/cspell.json @@ -16,137 +16,150 @@ ], // words - list of words to be always considered correct - use dictionary for all words "words": [ - "uefi", - "tiano", - "ibv", - "ibvs", - "oem", - "oems", + "AARCH", "ACPI", - "MSRC", - "tianocore", + "acpica", + "afile", + "asl", + "ASLR", + "azurepipelines", + "backported", + "basecore", + "basetools", + "bootable", + "bootstrapper", + "brotli", + "buildid", + "buildreport", + "buildreporting", + "buildsha", + "buildtime", + "buildtools", + "certfile", + "certreq", + "cleanonly", + "cmocka", + "codebases", + "commitlink", + "componentization", + "corebuild", + "customizations", + "datacenter", + "debuggability", + "depex", + "DFCI", + "Donath", "doxygen", - "nvme", - "esrt", - "Infineon", - "pbkdf", - "EdkII", "Edk2", - "pkcs", - "guids", - "guid", - "uuid", - "uuids", + "EdkII", + "efiapi", "eku", "ekus", - "memmap", - "whitepaper", - "pcr", - "pcrs", - "pcd", - "pcds", - "DFCI", - "linaro", - "nuget", - "iasl", - "asl", - "brotli", - "nasm", - "acpica", - "VSTS", - "commitlink", - "efiapi", - "inf", - "infs", - "openssl", - "redfish", - "muchange", - "guidgen", - "certreq", - "datacenter", - "bootable", - "mkdir", - "newcerts", - "keyfile", - "privkey", - "keyid", - "genrsa", - "outform", - "inkey", - "smime", - "certfile", - "afile", - "OVERRIDELOG", - "buildid", - "buildreporting", - "buildreport", + "emojione", + "enablement", + "esrt", + "extdep", "fdsizereport", - "ndisasm", - "basetools", - "overrider", - "buildsha", - "corebuild", - "lzturbo", - "depex", - "skippostbuild", - "cleanonly", - "skipbuild", - "skipprebuild", - "mathlib", - "norestart", - "nocache", - "buildtools", - "bootstrapper", - "mkdocs", + "flake8", + "Franceschetti", + "genrsa", + "gitattributes", "gitignore", "gitmodules", - "gitattributes", - "pymdown", - "repo", - "repos", - "basecore", - "submodules", - "submodule", + "guid", + "guidgen", + "guids", "howto", - "mscore", - "signtool", - "emojione", - "opencode", - "buildtime", - "componentization", - "customizations", - "enablement", - "pluggable", - "upstreams", - "upstream", - "projectmu", + "iasl", + "ibv", + "ibvs", + "inf", + "Infineon", + "infs", + "inkey", "jinja", + "keyfile", + "keyid", + "linaro", "lzturbo", - "rebased", - "backported", - "pytest", - "pip", - "flake8", - "workspaces", - "venv", + "lzturbo", + "markdownlint", + "mathlib", + "memmap", + "microcontrollers", + "mkdir", + "mkdocs", + "mscore", + "MSRC", + "msvc", + "muchange", + "nasm", + "ndisasm", + "newcerts", + "nocache", + "norestart", + "nuget", + "nvme", + "oem", + "oems", "omnicache", - "roadmap", - "roadmaps", - "wdksetup", - "cmocka", - "toolchains", - "toolchain", + "opencode", + "openssl", + "outform", + "OVERRIDELOG", + "overrider", "ovmf", + "pbkdf", + "pcd", + "pcds", + "pcr", + "pcrs", + "pip", + "pkcs", + "pluggable", + "privkey", + "projectmu", + "pymdown", + "pytest", "pytool", "pytools", + "rebased", + "redfish", + "repo", + "repos", + "rlib", + "roadmap", + "roadmaps", + "rustfmt", + "rustup", + "signtool", + "skipbuild", + "skippostbuild", + "skipprebuild", + "smime", + "staticlib", + "struct", + "structs", + "submodule", + "submodules", "superfences", - "markdownlint", + "TCMORPH", + "tiano", + "tianocore", + "timeframe", + "toolchain", + "toolchains", + "uefi", "UINTN", - "azurepipelines", - // Names and Attributions - "Franceschetti", - "Donath", - "extdep", - "TCMORPH" + "upstream", + "upstreams", + "usize", + "uuid", + "uuids", + "venv", + "VSTS", + "wdksetup", + "whitepaper", + "workspaces" ] } diff --git a/docs/DeveloperDocs/rust_build.md b/docs/DeveloperDocs/rust_build.md new file mode 100644 index 000000000..747a57dda --- /dev/null +++ b/docs/DeveloperDocs/rust_build.md @@ -0,0 +1,152 @@ +# Rust Build + +Project Mu has integrated support to build Rust modules in the normal firmware build process. + +[Cargo make](https://crates.io/crates/cargo-make/) is used as a build runner to allow users to build Rust packages +individually and simply on the command line similar to the way they are built during the firmware build process. It +is a CLI tool that helps abstract away many of the CLI arguments necessary to build a Rust module so that developers +can easily check, test, and build individual Rust packages without the need to copy and/or memorize a long list of +arguments. + +Based on changes in: [edk2-staging/edkii-rust](https://github.com/tianocore/edk2-staging/tree/edkii-rust) + +## Generally Getting Started with Rust + +It is recommended to: + +1. Update the repo to ensure it includes the changes needed for Rust build support. + +2. Download and install `Rust` and `cargo` from [Getting Started - Rust Programming Language (rust-lang.org)](https://www.rust-lang.org/learn/get-started) + +3. Verify `cargo` is working: + + \>`cargo --version` + +4. Install the desired Rust tool chain + + - Example: `1.68.2 x86_64 toolchain` + + - Windows: + + \>`rustup toolchain install 1.68.2-x86_64-pc-windows-msvc` + + \>`rustup component add rust-src --toolchain 1.68.2-x86_64-pc-windows-msvc` + + - Linux: + + \>`rustup toolchain install 1.68.2-x86_64-unknown-linux-gnu` + + \>`rustup component add rust-src --toolchain 1.68.2-x86_64-unknown-linux-gnu` + +5. Install `cargo make` + + \>`cargo install --force cargo-make` + +At this point, the essential Rust applications are installed, and a repo can begin to add and build Rust code. + +## Important Build and Config Files + +Currently, two files are provided in Project Mu repos that play an important role in the building and formatting of +Rust code in Project Mu based repositories. + +- `Makefile.toml` - Defines the tasks and environment settings use within the Project Mu build system to bui;d and + test code. + +- `rustfmt.toml` - Defines Rust formatting options used. + +Project Mu repos have common files automatically synced from a common source in the [Mu DevOps](https://github.com/microsoft/mu_devops) +repo. Projects downstream to Project Mu are recommended to "extend" the `Makefile.toml` in [Mu Basecore](https://github.com/microsoft/mu_basecore) +by following the instructions in the "Default Tasks and Extending" section of the +[cargo make documentation](https://sagiegurari.github.io/cargo-make/). + +Note that the file path to the Mu Basecore file will be relative to the project's own makefile. + +The `rustfmt.toml` file synced across Project Mu repos defines the common formatting options expected for Rust code in +other Project Mu based repositories. + +## Dev Container (with Rust) + +A container that includes Rust and Project Mu tools for a simple "out of box" development experience is available +in the [container registry in Mu DevOps](https://github.com/microsoft/mu_devops/pkgs/container/mu_devops%2Fubuntu-22-dev). + +## Build Variations + +First, the simplest case is a new user approaching a package that supports Rust modules. In that case, just build the +package like "normal" (e.g., stuart build) and the "normal" build output (i.e., EFI drivers and firmware volumes) will +be produced. + +### Build an Individual Module + + ```cmd + cargo make build + ``` + +The following command line options are available: + +1. `-p PROFILE [development|release]`. `DEFAULT` = `development (debug)` +2. `-e ARCH=[IA32|X64|AARCH64|LOCAL]`. `DEFAULT` = `X64` +3. `-e TARGET_TRIPLE=[triple]`. + +- `ARCH=LOCAL` is used to build any locally executable tools associated with a Rust library package (e.g., a + dual-purpose executable and library). + +- `TARGET_TRIPLE=` is used to cross-compile locally executable tools associated with a Rust library package. + +- Note: A Rust package must be specified. +- The output location is: + - `target/[x86_64-unknown-uefi|i686-unknown-uefi]/[debug|release]/module_name.[efi|rlib]` + +### Test an Individual Module + +```cmd +cargo make test +``` + +```cmd +cargo make coverage +``` + +- Note: If a package is not specified, all packages will be tested. Multiple packages can be provided, comma separated. +- cargo make coverage to generate coverage results on top of testing. + +### Supported Build Combinations + +1. C source + Rust source mixed in INF (Library or Module) + - Rust source code is supported by build rule – `Rust-To-Lib-File` (`.rs` => `.lib`) + + - Limitation: Rust code cannot have external dependencies. + +2. Pure Rust Module only. + + - A `Cargo.toml` file is added to the INF file `[Sources]` section. + + - Rust Module build is supported by build rule – `Toml-File.RUST_MODULE` (`Toml` => `.efi`) + + - Limitation: Runtime might be a problem, such as virtual address translation for Rust code internal global + variables. + +3. Pure Rust Module + Pure Rust Library with Cargo Dependency. + + - Cargo dependency means the Rust lib dependency declared in `Cargo.toml`. + +4. Pure Rust Module + C Library with EDK II Dependency. + + - Rust Module build is supported by build rule – `Toml-File` (`Toml` => `.lib`) + + - The EDK II dependency means the EDK II lib dependency declared in INF. + + - If a Rust module is built with C, the cargo must use `staticlib`. Otherwise, `rlib` is used. + - A simple example that specifies `staticlib` in the package `Cargo.toml` file using `crate-type = ["staticlib"]` + in the `[lib]` section is shown below. + + ```toml + [lib] + crate-type = ["staticlib"] + ``` + +5. C Module + Pure Rust Library with EDK II Dependency. + + - Rust library build is supported by build rule – `Toml-File`. (`Toml` => `.lib`) + +6. Pure Rust Module + Pure Rust Library with EDK II Dependency. + - Same as (4) + (5). diff --git a/docs/How/rust_documentation_conventions.md b/docs/How/rust_documentation_conventions.md new file mode 100644 index 000000000..88b737da1 --- /dev/null +++ b/docs/How/rust_documentation_conventions.md @@ -0,0 +1,347 @@ +# Rust Documentation Conventions + +This document lays out the standards of practice for inline rust documentation for generating rust +docs. It also provides templates that should be followed when creating documentation for these +items. The templates will be immediately provided, however if this is your first time seeing this +document, please read it in it's entirety. + +## Table of Contents + +- [Rust Documentation Conventions](#rust-documentation-conventions) + - [Table of Contents](#table-of-contents) + - [Templates](#templates) + - [Crate Template](#crate-template) + - [Module Template](#module-template) + - [Type Template](#type-template) + - [Function Template](#function-template) + - [Quick Reference](#quick-reference) + - [Common Sections](#common-sections) + - [Examples](#examples) + - [Errors](#errors) + - [Safety](#safety) + - [Panics](#panics) + - [Lifetimes](#lifetimes) + - [Style Guides](#style-guides) + - [Crate Style Guide](#crate-style-guide) + - [Module Style Guide](#module-style-guide) + - [Type Style Guide](#type-style-guide) + - [Function Style Guide](#function-style-guide) + +## Templates + +### Crate Template + +Example [Here](#crate-style-guide). + +``` rust +//! Summary Line -> what this is +//! +//! Longer description and use of the crate +//! +//! ## Getting Started +//! +//! +//! +//! ## Examples and Usage +//! +//! +//! +//! +//! ## Features +//! +//! +//! +//! ## +//! +//! +//! +//! ## License +//! +//! +//! +``` + +### Module Template + +Example [Here](#module-style-guide). + +``` rust +//! Summary Line -> what this is +//! +//! Longer description and use of the module. +//! +//! ## +//! +//! +//! +``` + +### Type Template + +Example [Here](#type-style-guide). + +``` rust +/// Summary line -> what this is +/// +/// longer description and semantics regarding the type. (e.g. how to construct and deconstruct) +/// +/// ## +/// +/// +/// +/// +/// A short description of the attribute +/// +``` + +### Function Template + +Example [Here](#function-style-guide) + +``` rust +/// Summary line -> what this is +/// +/// longer description of what is returned +/// +/// # Errors +/// +/// +/// Returns [`NoOptionalHeader`](Pe32Error::NoOptionalHeader) if the optional header is missing +/// in the PE32 image. +/// +/// # Examples +/// +/// ``` +/// +/// ``` +/// +/// +/// +``` + +## Quick Reference + +- `///` Documents the item following the comment whereas `//!` documents the parent item. +- `#[doc(html_playground_url = "https://playground.example.com/")]` to add a Run button to examples + - Warning: Be cognizant of using the playground run button with confidential code. +- `#[doc(hidden)]` to hide items +- `#[doc(alias = "alias")]` to make items easier to find via the search index +- `[Bar]`, `[bar](Bar)`, is supported for linking items (i.e. `[String](std::string::String)`) +- markdown is supported including sections (`#`), footnotes (`[^note]`), tables, tasks, punctuation +- Keep documentation lines to 100 characters +- codeblock attributes (\`\`\`[attribute]) options: `should_panic`, `no_run`, `compile_fail` + +## Common Sections + +All sections are described as `## ` inside the doc comments. + +### Examples + +Examples can optionally contain descriptions of each example, but must contain code blocks. +Code blocks can contain one of the following attributes: `ignore`, `should_panic`, `no_run`, or +`compile_fail`. + +``` rust +/// # Examples +/// +/// optional description +/// +/// ``` +/// +/// ``` +``` + +Code snippets should show how to use what is being documented. + +Including `#[doc(html_playground_url = "https://playground.example.com/")]` will allow examples to be runnable in the documentation. + +### Errors + +Errors can optionally contain an overall description, but should contain the error type as a +linked reference and the reason why the error would be returned + +``` rust +/// # Errors +/// +/// Returns [ErrorName1](crate::module::ErrorEnum::Error1) when happens +/// Returns [ErrorName2](crate::module::ErrorEnum::Error2) when happens +/// +``` + +### Safety + +Provide general description and comments on unsafe calls, what makes the call unsafe, and any +undefined behavior that may happen. If being used at the module or crate level, use a general +description and then use a reference link to the function. The function should contain a detailed +Safety section. + +### Panics + +Provide general description and comments on any functions that use `.unwrap()`, `debug_assert!`, +etc. that would result in a panic. Typically only used when describing functions. + +### Lifetimes + +Provide a general description and comments on any types that have lifetimes more complex than a +single lifetime (explicit or implicit). Assume that the developer understands lifetimes; focus on +why the lifetime was modeled a certain way rather than describing why it was needed to make the +compiler happy! Typically only used when describing types. + +## Style Guides + +The goal is to create documentation that provides developers with a clear and concise description +on how to use a crate, module, type, or function while keeping it clean when auto-generating +documentation with `cargo doc`. As alluded to, it is the responsibility of the developer to ensure +that each library crate, public module, public type, and public function is well documented. Below +are the expectations for each. + +If a common section is not applicable to the documented item, do not include it. + +### Crate Style Guide + +Crate documentation should be located at the top of the lib.rs or main.rs file. The intent is to +describe the purpose of the crate, providing any setup instructions and examples. This is also the +place to describe any common misconceptions or "gotchas". Doc comments here use `//!` specifying +we are documenting the *parent* item (the crate). + +``` rust +//! PE32 Management +//! +//! This library provides high-level functionality for operating on and representing PE32 images. +//! +//! ## Examples and Usage +//! +//! ``` +//! let file: File = File::open(test_collateral!("test_image.pe32")) +//! .expect("failed to open test file."); +//! +//! let mut buffer: Vec = Vec::new(); +//! file.read_to_end(&mut buffer).expect("Failed to read test file"); +//! +//! let image_info: Pe32ImageInfo = pe32_get_image_info(buffer).unwrap(); +//! +//! let mut loaded_image: Vec = vec![0; image_info.size_of_image as usize]; +//! pe32_load_image(&image, &mut loaded_image).unwrap(); +//! ``` +//! +//! ## License +//! +//! Copyright (C) Microsoft Corporation. All rights reserved. +//! +//! SPDX-License-Identifier: BSD-2-Clause-Patent +//! +``` + +### Module Style Guide + +Module documentation should be placed at the top of a module, whether that be a mod.rs file or the +module itself if contained to a single file. If a crate only consists of a single module, the crate +style guide should be used.Submodules should be avoided if possible, as they cause confusion. The +goal is to describe the types found in this module and their interactions with the rest of the +crate. Doc comments here use `//!` specifying we are documenting the *parent* item (the module). + +``` rust +//! PE32 Management +//! +//! This module provides high-level functionality for operating on and representing PE32 images. +//! +//! ## License +//! +//! Copyright (C) Microsoft Corporation. All rights reserved. +//! +//! SPDX-License-Identifier: BSD-2-Clause-Patent +//! +``` + +### Type Style Guide + +Type documentation should be available for all public public types such as enums, structs, etc. The +focus should be on the construction of the type (when / how), Destruction of the type if a custom +Drop trait is implemented, and any performance concerns. Doc comments here use `///` specifying we +are documenting the item directly below it (the type or member of the type). + +**Document traits, not trait implementations!** + +``` rust +/// Type for describing errors that result from working with PE32 images. +#[derive(Debug)] +pub enum Pe32Error { + /// Goblin failed to parse the PE32 image. + /// + /// See the enclosed goblin error for a reason why the parsing failed. + ParseError(goblin::error::Error), + /// The parsed PE32 image does not contain an Optional Header. + NoOptionalHeader, + /// Failed to load the PE32 image into the provided memory buffer. + LoadError, + /// Failed to relocate the loaded image to the destination. + RelocationError, +} + +/// Type containing information about a PE32 image. +#[derive(PartialEq, Debug)] +pub struct Pe32ImageInfo { + /// The offset of the entry point relative to the start address of the PE32 image. + pub entry_point_offset: usize, + /// The subsystem type (IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER [0xB], etc.). + pub image_type: u16, + /// The total length of the image. + pub size_of_image: u32, + /// The size of an individual section in a power of 2 (4K [0x1000], etc.). + pub section_alignment: u32, + /// The ascii string representation of a file (.efi). + pub filename: Option, +} +``` + +### Function Style Guide + +Function documentation should be available for functions of a public type (associated functions), +and any public functions. At least one example is required for each function in addition to the +other sections mentioned below. + +Do not provide an arguments section, the name and type of the argument should make it self-evident + +Do not provide a Returns section, this should be captured in the longer description and the return +type makes the possible return value self-evident. + +``` rust + +/// Attempts to parse a PE32 image and return information about the image. +/// +/// Parses the bytes buffer containing a PE32 image and generates a [Pe32ImageInfo] struct +/// containing general information about the image otherwise an error. +/// +/// ## Errors +/// +/// Returns [`ParseError`](Pe32Error::ParseError) if parsing the PE32 image failed. Contains the +/// exact parsing [`Error`](goblin::error::Error). +/// +/// Returns [`NoOptionalHeader`](Pe32Error::NoOptionalHeader) if the parsed PE32 image does not +/// contain the OptionalHeader necessary to provide information about the image. +/// +/// ## Examples +/// +/// ``` +/// extern crate std; +/// +/// use std::{fs::File, io::Read}; +/// use uefi_pe32_lib::pe32_get_image_info; +/// +/// let mut file: File = File::open(concat!(env!("CARGO_MANIFEST_DIR"), "/resources/test/","test_image.pe32")) +/// .expect("failed to open test file."); +/// +/// let mut buffer: Vec = Vec::new(); +/// file.read_to_end(&mut buffer).expect("Failed to read test file"); +/// +/// let image_info = pe32_get_image_info(&buffer).unwrap(); +/// ``` +/// +pub fn pe32_get_image_info(image: &[u8]) -> Result { + ... +} +``` diff --git a/docs/WhatAndWhy/features.md b/docs/WhatAndWhy/features.md index 8fcdb1bd4..1bbe3f5a3 100644 --- a/docs/WhatAndWhy/features.md +++ b/docs/WhatAndWhy/features.md @@ -21,6 +21,10 @@ What major features does Project Mu bring to the table above/beyond EDK2? * Up-to-date Visual Studio compiler support * Base64 encode for binary objects * XML Support Package +* Rust support + * [Rust build documentation](../DeveloperDocs/rust_build.md) + * [Rust convention documentation](../How/rust_documentation_conventions.md) + * [Rust motivation documentation:](../WhatAndWhy/rust.md) ### Features Coming Soon diff --git a/docs/WhatAndWhy/rust.md b/docs/WhatAndWhy/rust.md new file mode 100644 index 000000000..f9afe7a37 --- /dev/null +++ b/docs/WhatAndWhy/rust.md @@ -0,0 +1,119 @@ +# Project Mu and Rust + +## Overview + +Firmware and UEFI firmware in particular has long been written in C. Firmware operates in a unique environment to other +system software. It is written to bootstrap a system often at the host CPU reset vector and as part of a chain of +trust established by a hardware rooted immutable root of trust. Modern PC firmware is extraordinarily complex with +little room for error. + +From a functional perspective, firmware must initialize the operating environment of a device. To do so involves +integrating vendor code for dedicated microcontrollers, security engines, individual peripherals, SOC initialization, +and so on. Individual firmware blobs may be located on a number of non-volatile media with very limited capacity. The +firmware must perform its functional tasks successfully or risk difficult to diagnose errors in higher levels of the +software stack that may impede overall device usability and debuggability. + +From a security perspective, firmware is an important component in the overall system Trusted Computing Base (TCB). +Fundamental security features taken for granted in later system software such as kernels and hypervisors are often +based on secure establishment in a lower layer of firmware. At the root is a concept of "trust". + +While operating systems are attractive targets due to their ubiquity across devices and scale, attackers are +beginning to shift more focus to firmware as an attack surface in response to increasingly effective security measures +being applied in modern operating systems. Securing the early boot process revolves around key inflection points and +protections applied between those points. The earliest point is the device "root of trust", where the system needs to +ensure it begins operating in a trusted state. This is often performed by code in immutable ROMs located in a SOC. +Since size is extremely limited, this logic typically hands off quickly to code of larger size on some mutable storage +such as SPI flash that is first verified by a key stored in the SOC. In general, this handoff process continues +throughout the boot process as hardware capabilities come online enabling larger and more complex code to be loaded +forming what is referred to as a "chain of trust". Eventually some code must execute on the host CPU, that code is +often UEFI based firmware. While significant research has been devoted across the entire boot process, UEFI firmware +on the host CPU presents a unique opportunity to gain more visibility into early code execution details and intercept +the boot process before essential activities take place such as application of important security register locks, +cache/memory/DMA protections, isolated memory regions, etc. The result is code executed in this timeframe must carry +forward proper verification and measurement of future code while also ensuring it does not introduce a vulnerability +in its own execution. + +From a performance perspective, firmware code is often expected to execute exceedingly fast. The ultimate goal is for +an end user to not even be aware such code is present. In a consumer device scenario, a user expects to press a power +button and immediately receive confirmation their system is working properly. At the minimum, a logo is often shown to +assure the user something happened and they will be able to interact with the system soon. In a server scenario, +fleet uptime is paramount. Poorly written firmware can lead to long boot times that impact virtual machine +responsiveness and workload scaling or, even worse, Denial of Service if the system fails to boot entirely. In an +embedded scenario, government regulations may require firmware to execute fast enough to show a backup camera within a +fixed amount of time. + +All of this is to illustrate that firmware must perform important work in a diverse set of hardware states with code +that is as small as possible and do so quickly and securely. In order to transition implementation spanning millions of +lines of code written in a language developed over 50 years ago requires a unique and compelling alternative. + +## Rust and Firmware + +As previously stated, modern PC firmware necessitates a powerful language that can support low-level programming with +maximum performance, reliability, and safety. While C has provided the flexibility needed to implement relatively +efficient firmware code, it has failed to prevent recurring problems around memory safety. + +Common pitfalls in C such as null pointer dereferences, buffer and stack overflows, and pointer mismanagement continue +to be at the root of high impact firmware vulnerabilities. These issues are especially impactful if they compromise +the system TCB. Rust is compelling for UEFI firmware development because it is designed around strong memory safety +without the usual overhead of a garbage collector. In addition, it enforces stringent type safety and concurrency rules +that prevent the types of issues that often lead to subtle bugs in low-level software development. + +Languages aside, UEFI firmware has greatly fallen behind other system software in its adoption of basic memory +vulnerability mitigation techniques. For example, data execution protection, heap and stack guards, stack cookies, +and null pointer dereference detection is not present in the vast majority of UEFI firmware today. More advanced +(but long time) techniques such as Address Space Layout Randomization (ASLR), forward-edge control flow integrity +technologies such as x86 Control Flow Enforcement (CET) Indirect Branch Tracking (IBT) or Arm Branch Target +Identification (BTI) instructions, structured exception handling, and similar technologies are completely absent in +most UEFI firmware today. This of course exacerbates errors commonly made as a result of poor language safety. + +Given firmware code also runs in contexts with high privilege level such as System Management Mode (SMM) in x86, +implementation errors can be elevated by attackers to gain further control over the system and subvert other +protections. + +However, the Rust ecosystem brings more than just safety. As a modern language firmware development can now participate +in concepts and communities typically closed to firmware developers. For example: + +- Higher level multi-paradigm programming concepts such as those borrowed from functional programming in addition to + productive polymorphism features such as generics and traits. + +- Safety guarantees that prevent errors and reduce the need for a myriad of static analysis tools with flexibility to + still work around restrictions when needed in an organized and well understood way (unsafe code). + +- An official package management system with useful tools such as first-class formatters and linters that reduce + project-specific implementations and focus discussion on functional code changes. + +- High quality reusable bundles of code in the form of crates that increase development velocity and engagement with + other domain experts. + +- Useful compilation messages and excellent documentation that can assist during code development. + +Rust's interoperability with C code is also useful. This enables a phased adoption pathway where codebases can start +incorporating Rust while still relying upon its extensive pre-existing code. At the same time, Rust has been conscious +of low-level needs and can precisely structure data for C compatibility. + +## Rust and Project Mu + +At this time, Project Mu has started its Rust journey by including support for Rust code within the build system used +for firmware code. This allows Rust code to naturally be included in the compilation and firmware packaging process. +More details about build support in particular is covered in the +[Project Mu Rust Build](https://github.com/microsoft/mu_basecore/blob/HEAD/Docs/rust_build.md) readme. + +Setting up a fully functional pre-Rust firmware development environment can be tedious. The Rust toolchain is another +dependency that must be accounted for now. To ease the setup process, everything needed to get started has been +integrated into a [container](https://github.com/microsoft/mu_devops/pkgs/container/mu_devops%2Fubuntu-22-dev) in the +[Project Mu developer operations repo](https://github.com/microsoft/mu_devops). As Rust code is being rolled out to +Project Mu repos, they are being hooked into the common Rust infrastructure defined in the Mu DevOps repo. + +Project Mu plans to participate within the open Rust development community by leveraging and contributing back to +popular crates and publishing new crates that may be useful to other projects. A general design strategy is to solve +common problems in a generic crate that can be shared and then integrate it back into firmware. In particular, UEFI +specific crates such as [r-efi](https://docs.rs/r-efi/latest/r_efi/) have already been helpful during early +development. + +[QEMU](https://www.qemu.org/) is an open-source virtual machine emulator. Project Mu implements open-source firmware +for the [QEMU Q35 platform](https://wiki.qemu.org/Features/Q35) in its [Mu Tiano Platforms repository](https://github.com/microsoft/mu_tiano_platforms). +This open virtual platform is used as an easily accessible demonstration vehicle for Project Mu features. In this case, +UEFI (DXE) modules are already included in the platform firmware to demonstrate their functionality (and test it in CI). + +Looking forward, we're continuing to expand the coverage of our firmware code written in Rust. We are excited to +continue learning more about Rust in collaboration with the community and our partners.