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 <michael.kubacki@microsoft.com>
This commit is contained in:
Michael Kubacki 2023-09-01 16:54:56 -04:00 коммит произвёл GitHub
Родитель 206a7c50ea
Коммит 69515fe2d4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 750 добавлений и 115 удалений

Просмотреть файл

@ -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"
]
}

Просмотреть файл

@ -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 <Module Name>
```
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=<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 <Optional: Module Name>
```
```cmd
cargo make coverage <Optional: Module Name>
```
- 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).

Просмотреть файл

@ -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
//!
//! <any non-code requirements for this library to work (installations, etc.)>
//!
//! ## Examples and Usage
//!
//! <Short examples of using this library or links to where examples can be found>
//! <can use links [`String`](std::string::String) to other places in the library>
//!
//! ## Features
//!
//! <Add this section if this library defines features that can be enabled / disabled>
//!
//! ## <Custom sections>
//!
//! <Common additional sections are described in the Common Sections section or other custom
//! sections>
//!
//! ## License
//!
//! <Add the license type here>
//!
```
### Module Template
Example [Here](#module-style-guide).
``` rust
//! Summary Line -> what this is
//!
//! Longer description and use of the module.
//!
//! ## <Custom sections>
//!
//! <Common additional sections are described in the Common Sections section or other custom
//! sections>
//!
```
### Type Template
Example [Here](#type-style-guide).
``` rust
/// Summary line -> what this is
///
/// <Optional> longer description and semantics regarding the type. (e.g. how to construct and deconstruct)
///
/// ## <Custom sections>
///
/// <Common additional sections are described in the Common Sections section or other custom
/// sections>
///
/// <for each attribute in the type>
/// A short description of the attribute
///
```
### Function Template
Example [Here](#function-style-guide)
``` rust
/// Summary line -> what this is
///
/// <Optional> longer description of what is returned
///
/// # Errors
///
/// <list of possible raised errors and why. Use doc links>
/// Returns [`NoOptionalHeader`](Pe32Error::NoOptionalHeader) if the optional header is missing
/// in the PE32 image.
///
/// # Examples
///
/// ```
/// <some-rust-code></some-rust-code>
/// ```
///
/// <Common additional sections are described in the Common Sections section or other custom
/// sections>
///
```
## 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 `## <section_name>` 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
///
/// ``` <attribute>
/// <code></code>
/// ```
```
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 <this> happens
/// Returns [ErrorName2](crate::module::ErrorEnum::Error2) when <this> 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<u8> = 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<u8> = 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 (<filename>.efi).
pub filename: Option<String>,
}
```
### 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<u8> = 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<Pe32ImageInfo, Pe32Error> {
...
}
```

Просмотреть файл

@ -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

119
docs/WhatAndWhy/rust.md Normal file
Просмотреть файл

@ -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.