зеркало из https://github.com/microsoft/mu.git
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 <michael.kubacki@microsoft.com>
This commit is contained in:
Родитель
206a7c50ea
Коммит
69515fe2d4
243
cspell.json
243
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"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
Загрузка…
Ссылка в новой задаче