5 Commits

54 changed files with 322 additions and 205 deletions

View File

@@ -48,28 +48,15 @@ jobs:
- name: 'assemble artifacts' - name: 'assemble artifacts'
run: ./hack/assemble.sh run: ./hack/assemble.sh
- name: 'upload sprout-x86_64.efi.zip artifact' - name: 'upload artifacts'
id: upload-sprout-x86_64-efi id: upload
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with: with:
name: sprout-x86_64.efi.zip name: artifacts
path: target/assemble/sprout-x86_64.efi path: target/assemble/*
- name: 'upload sprout-aarch64.efi.zip artifact' - name: 'attest artifacts'
id: upload-sprout-aarch64-efi
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: sprout-aarch64.efi.zip
path: target/assemble/sprout-aarch64.efi
- name: 'attest sprout-x86_64.efi.zip artifact'
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with: with:
subject-name: sprout-x86_64.efi.zip subject-name: artifacts.zip
subject-digest: "sha256:${{ steps.upload-sprout-x86_64-efi.outputs.artifact-digest }}" subject-digest: "sha256:${{ steps.upload.outputs.artifact-digest }}"
- name: 'attest sprout-aarch64.efi.zip artifact'
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
with:
subject-name: sprout-aarch64.efi.zip
subject-digest: "sha256:${{ steps.upload-sprout-aarch64-efi.outputs.artifact-digest }}"

66
Cargo.lock generated
View File

@@ -66,7 +66,7 @@ dependencies = [
[[package]] [[package]]
name = "edera-sprout" name = "edera-sprout"
version = "0.0.20" version = "0.0.21"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags", "bitflags",
@@ -74,6 +74,8 @@ dependencies = [
"hex", "hex",
"log", "log",
"sha2", "sha2",
"shlex",
"spin",
"toml", "toml",
"uefi", "uefi",
"uefi-raw", "uefi-raw",
@@ -81,17 +83,11 @@ dependencies = [
[[package]] [[package]]
name = "edera-sprout-config" name = "edera-sprout-config"
version = "0.0.20" version = "0.0.21"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.9" version = "0.14.9"
@@ -102,34 +98,27 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "hashbrown"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
[[package]] [[package]]
name = "hex" name = "hex"
version = "0.4.3" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "indexmap"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.177" version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.28" version = "0.4.28"
@@ -174,6 +163,12 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.228"
@@ -224,6 +219,21 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "spin"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
dependencies = [
"lock_api",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.108" version = "2.0.108"
@@ -241,12 +251,10 @@ version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8"
dependencies = [ dependencies = [
"indexmap",
"serde_core", "serde_core",
"serde_spanned", "serde_spanned",
"toml_datetime", "toml_datetime",
"toml_parser", "toml_parser",
"toml_writer",
"winnow", "winnow",
] ]
@@ -268,12 +276,6 @@ dependencies = [
"winnow", "winnow",
] ]
[[package]]
name = "toml_writer"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.19.0" version = "1.19.0"

View File

@@ -7,22 +7,45 @@ resolver = "3"
[workspace.package] [workspace.package]
license = "Apache-2.0" license = "Apache-2.0"
version = "0.0.20" version = "0.0.21"
homepage = "https://sprout.edera.dev" homepage = "https://sprout.edera.dev"
repository = "https://github.com/edera-dev/sprout" repository = "https://github.com/edera-dev/sprout"
edition = "2024" edition = "2024"
[workspace.dependencies] [workspace.dependencies]
anyhow = "1.0.100"
bitflags = "2.10.0" bitflags = "2.10.0"
hex = "0.4.3"
log = "0.4.28" log = "0.4.28"
serde = "1.0.228" spin = "0.10.0"
sha2 = "0.10.9"
toml = "0.9.8"
uefi = "0.36.0" uefi = "0.36.0"
uefi-raw = "0.12.0" uefi-raw = "0.12.0"
[workspace.dependencies.anyhow]
version = "1.0.100"
default-features = false
[workspace.dependencies.hex]
version = "0.4.3"
default-features = false
features = ["alloc"]
[workspace.dependencies.serde]
version = "1.0.228"
default-features = false
features = ["alloc", "derive"]
[workspace.dependencies.sha2]
version = "0.10.9"
default-features = false
[workspace.dependencies.shlex]
version = "1.3.0"
default-features = false
[workspace.dependencies.toml]
version = "0.9.8"
default-features = false
features = ["serde", "parse"]
# Common build profiles # Common build profiles
# NOTE: We have to compile everything for opt-level = 2 due to optimization passes # NOTE: We have to compile everything for opt-level = 2 due to optimization passes
# which don't handle the UEFI target properly. # which don't handle the UEFI target properly.

View File

@@ -5,11 +5,7 @@ This guide is a work in progress.
## Development Setup ## Development Setup
You can use any Rust development environment to develop Sprout. You can use any Rust development environment to develop Sprout.
Rustup is recommended as the Rust toolchain manager to manage Rust versions and targets. Rustup is recommended as the Rust toolchain manager to manage Rust versions and targets.
Sprout currently requires Rust nightly to support uefi_std. See [uefi_std](https://doc.rust-lang.org/beta/rustc/platform-support/unknown-uefi.html) for more details.
We currently only support `x86_64-unknown-uefi` and `aarch64-unknown-uefi` targets. We currently only support `x86_64-unknown-uefi` and `aarch64-unknown-uefi` targets.
To test your changes in QEMU, please run `./hack/dev/boot.sh`, you can specify `x86_64` or `aarch64` To test your changes in QEMU, please run `./hack/dev/boot.sh`, you can specify `x86_64` or `aarch64`

View File

@@ -9,7 +9,7 @@ edition.workspace = true
[dependencies.serde] [dependencies.serde]
workspace = true workspace = true
features = ["derive"] default-features = false
[lib] [lib]
name = "edera_sprout_config" name = "edera_sprout_config"

View File

@@ -1,3 +1,5 @@
use alloc::string::String;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// The configuration of the chainload action. /// The configuration of the chainload action.

View File

@@ -1,3 +1,5 @@
use alloc::string::String;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// The configuration of the edera action which boots the Edera hypervisor. /// The configuration of the edera action which boots the Edera hypervisor.

View File

@@ -1,3 +1,4 @@
use alloc::string::String;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// The configuration of the print action. /// The configuration of the print action.

View File

@@ -1,3 +1,4 @@
use alloc::string::String;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Declares a driver configuration. /// Declares a driver configuration.

View File

@@ -1,5 +1,7 @@
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
/// Declares a boot entry to display in the boot menu. /// Declares a boot entry to display in the boot menu.
/// ///

View File

@@ -1,3 +1,4 @@
use alloc::string::String;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// The filesystem device match extractor. /// The filesystem device match extractor.

View File

@@ -1,4 +1,5 @@
use crate::entries::EntryDeclaration; use crate::entries::EntryDeclaration;
use alloc::string::{String, ToString};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// The default path to the BLS directory. /// The default path to the BLS directory.

View File

@@ -1,6 +1,8 @@
use crate::entries::EntryDeclaration; use crate::entries::EntryDeclaration;
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
/// List generator configuration. /// List generator configuration.
/// The list generator produces multiple entries based /// The list generator produces multiple entries based

View File

@@ -1,6 +1,8 @@
use crate::entries::EntryDeclaration; use crate::entries::EntryDeclaration;
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
/// Matrix generator configuration. /// Matrix generator configuration.
/// The matrix generator produces multiple entries based /// The matrix generator produces multiple entries based

View File

@@ -1,5 +1,7 @@
//! Sprout configuration descriptions. //! Sprout configuration descriptions.
//! This crate provides all the configuration structures for Sprout. //! This crate provides all the configuration structures for Sprout.
#![no_std]
extern crate alloc;
use crate::actions::ActionDeclaration; use crate::actions::ActionDeclaration;
use crate::drivers::DriverDeclaration; use crate::drivers::DriverDeclaration;
@@ -7,8 +9,9 @@ use crate::entries::EntryDeclaration;
use crate::extractors::ExtractorDeclaration; use crate::extractors::ExtractorDeclaration;
use crate::generators::GeneratorDeclaration; use crate::generators::GeneratorDeclaration;
use crate::phases::PhasesConfiguration; use crate::phases::PhasesConfiguration;
use alloc::collections::BTreeMap;
use alloc::string::String;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
pub mod actions; pub mod actions;
pub mod drivers; pub mod drivers;

View File

@@ -1,5 +1,7 @@
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
/// Configures the various phases of the boot process. /// Configures the various phases of the boot process.
/// This allows hooking various phases to run actions. /// This allows hooking various phases to run actions.

View File

@@ -13,12 +13,14 @@ bitflags.workspace = true
edera-sprout-config.path = "../config" edera-sprout-config.path = "../config"
hex.workspace = true hex.workspace = true
sha2.workspace = true sha2.workspace = true
shlex.workspace = true
spin.workspace = true
toml.workspace = true toml.workspace = true
log.workspace = true log.workspace = true
[dependencies.uefi] [dependencies.uefi]
workspace = true workspace = true
features = ["alloc", "logger"] features = ["alloc", "global_allocator", "logger", "panic_handler"]
[dependencies.uefi-raw] [dependencies.uefi-raw]
workspace = true workspace = true

View File

@@ -1,6 +1,6 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use alloc::rc::Rc;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use std::rc::Rc;
/// EFI chainloader action. /// EFI chainloader action.
pub mod chainload; pub mod chainload;

View File

@@ -4,10 +4,11 @@ use crate::integrations::shim::{ShimInput, ShimSupport};
use crate::utils; use crate::utils;
use crate::utils::media_loader::MediaLoaderHandle; use crate::utils::media_loader::MediaLoaderHandle;
use crate::utils::media_loader::constants::linux::LINUX_EFI_INITRD_MEDIA_GUID; use crate::utils::media_loader::constants::linux::LINUX_EFI_INITRD_MEDIA_GUID;
use alloc::boxed::Box;
use alloc::rc::Rc;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use edera_sprout_config::actions::chainload::ChainloadConfiguration; use edera_sprout_config::actions::chainload::ChainloadConfiguration;
use log::error; use log::error;
use std::rc::Rc;
use uefi::CString16; use uefi::CString16;
use uefi::proto::loaded_image::LoadedImage; use uefi::proto::loaded_image::LoadedImage;

View File

@@ -1,5 +1,3 @@
use std::rc::Rc;
use crate::{ use crate::{
actions, actions,
context::SproutContext, context::SproutContext,
@@ -13,6 +11,9 @@ use crate::{
}, },
}, },
}; };
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use alloc::{format, vec};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use edera_sprout_config::actions::chainload::ChainloadConfiguration; use edera_sprout_config::actions::chainload::ChainloadConfiguration;
use edera_sprout_config::actions::edera::EderaConfiguration; use edera_sprout_config::actions::edera::EderaConfiguration;

View File

@@ -1,8 +1,8 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use alloc::rc::Rc;
use anyhow::Result; use anyhow::Result;
use edera_sprout_config::actions::print::PrintConfiguration; use edera_sprout_config::actions::print::PrintConfiguration;
use log::info; use log::info;
use std::rc::Rc;
/// Executes the print action with the specified `configuration` inside the provided `context`. /// Executes the print action with the specified `configuration` inside the provided `context`.
pub fn print(context: Rc<SproutContext>, configuration: &PrintConfiguration) -> Result<()> { pub fn print(context: Rc<SproutContext>, configuration: &PrintConfiguration) -> Result<()> {

View File

@@ -1,4 +1,6 @@
use crate::utils; use crate::utils;
use alloc::string::ToString;
use alloc::{format, vec};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use edera_sprout_config::RootConfiguration; use edera_sprout_config::RootConfiguration;
use edera_sprout_config::actions::ActionDeclaration; use edera_sprout_config::actions::ActionDeclaration;

View File

@@ -1,5 +1,9 @@
use crate::utils; use crate::utils;
use crate::utils::vercmp; use crate::utils::vercmp;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use alloc::{format, vec};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use edera_sprout_config::RootConfiguration; use edera_sprout_config::RootConfiguration;
use edera_sprout_config::actions::ActionDeclaration; use edera_sprout_config::actions::ActionDeclaration;
@@ -7,7 +11,6 @@ use edera_sprout_config::actions::chainload::ChainloadConfiguration;
use edera_sprout_config::entries::EntryDeclaration; use edera_sprout_config::entries::EntryDeclaration;
use edera_sprout_config::generators::GeneratorDeclaration; use edera_sprout_config::generators::GeneratorDeclaration;
use edera_sprout_config::generators::list::ListConfiguration; use edera_sprout_config::generators::list::ListConfiguration;
use std::collections::BTreeMap;
use uefi::CString16; use uefi::CString16;
use uefi::fs::{FileSystem, Path, PathBuf}; use uefi::fs::{FileSystem, Path, PathBuf};
use uefi::proto::device_path::DevicePath; use uefi::proto::device_path::DevicePath;

View File

@@ -1,4 +1,6 @@
use crate::utils; use crate::utils;
use alloc::string::ToString;
use alloc::{format, vec};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use edera_sprout_config::RootConfiguration; use edera_sprout_config::RootConfiguration;
use edera_sprout_config::actions::ActionDeclaration; use edera_sprout_config::actions::ActionDeclaration;

View File

@@ -1,10 +1,11 @@
use crate::options::SproutOptions; use crate::options::SproutOptions;
use crate::platform::tpm::PlatformTpm; use crate::platform::tpm::PlatformTpm;
use crate::utils; use crate::utils;
use alloc::vec::Vec;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use core::ops::Deref;
use edera_sprout_config::{RootConfiguration, latest_version}; use edera_sprout_config::{RootConfiguration, latest_version};
use log::info; use log::info;
use std::ops::Deref;
use toml::Value; use toml::Value;
use uefi::proto::device_path::LoadedImageDevicePath; use uefi::proto::device_path::LoadedImageDevicePath;

View File

@@ -1,11 +1,15 @@
use crate::options::SproutOptions; use crate::options::SproutOptions;
use crate::platform::timer::PlatformTimer; use crate::platform::timer::PlatformTimer;
use alloc::boxed::Box;
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::format;
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use anyhow::anyhow; use anyhow::anyhow;
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use core::cmp::Reverse;
use edera_sprout_config::actions::ActionDeclaration; use edera_sprout_config::actions::ActionDeclaration;
use std::cmp::Reverse;
use std::collections::{BTreeMap, BTreeSet};
use std::rc::Rc;
use uefi::proto::device_path::DevicePath; use uefi::proto::device_path::DevicePath;
/// The maximum number of iterations that can be performed in [SproutContext::finalize]. /// The maximum number of iterations that can be performed in [SproutContext::finalize].

View File

@@ -1,11 +1,13 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use crate::integrations::shim::{ShimInput, ShimSupport}; use crate::integrations::shim::{ShimInput, ShimSupport};
use crate::utils; use crate::utils;
use alloc::collections::BTreeMap;
use alloc::format;
use alloc::rc::Rc;
use alloc::string::String;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
pub(crate) use edera_sprout_config::drivers::DriverDeclaration; use edera_sprout_config::drivers::DriverDeclaration;
use log::info; use log::info;
use std::collections::BTreeMap;
use std::rc::Rc;
use uefi::boot::SearchType; use uefi::boot::SearchType;
/// Loads the driver specified by the `driver` declaration. /// Loads the driver specified by the `driver` declaration.

View File

@@ -1,6 +1,7 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use edera_sprout_config::entries::EntryDeclaration; use edera_sprout_config::entries::EntryDeclaration;
use std::rc::Rc;
/// Represents an entry that is stamped and ready to be booted. /// Represents an entry that is stamped and ready to be booted.
#[derive(Clone)] #[derive(Clone)]

View File

@@ -1,7 +1,8 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use alloc::rc::Rc;
use alloc::string::String;
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use edera_sprout_config::extractors::ExtractorDeclaration; use edera_sprout_config::extractors::ExtractorDeclaration;
use std::rc::Rc;
/// The filesystem device match extractor. /// The filesystem device match extractor.
pub mod filesystem_device_match; pub mod filesystem_device_match;

View File

@@ -1,10 +1,11 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use crate::utils; use crate::utils;
use alloc::rc::Rc;
use alloc::string::String;
use anyhow::{Context, Result, anyhow, bail}; use anyhow::{Context, Result, anyhow, bail};
use core::ops::Deref;
use core::str::FromStr;
use edera_sprout_config::extractors::filesystem_device_match::FilesystemDeviceMatchExtractor; use edera_sprout_config::extractors::filesystem_device_match::FilesystemDeviceMatchExtractor;
use std::ops::Deref;
use std::rc::Rc;
use std::str::FromStr;
use uefi::fs::{FileSystem, Path}; use uefi::fs::{FileSystem, Path};
use uefi::proto::device_path::DevicePath; use uefi::proto::device_path::DevicePath;
use uefi::proto::media::file::{File, FileSystemVolumeLabel}; use uefi::proto::media::file::{File, FileSystemVolumeLabel};

View File

@@ -1,9 +1,10 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use crate::entries::BootableEntry; use crate::entries::BootableEntry;
use alloc::rc::Rc;
use alloc::vec::Vec;
use anyhow::Result; use anyhow::Result;
use anyhow::bail; use anyhow::bail;
use edera_sprout_config::generators::GeneratorDeclaration; use edera_sprout_config::generators::GeneratorDeclaration;
use std::rc::Rc;
/// The BLS generator. /// The BLS generator.
pub mod bls; pub mod bls;

View File

@@ -3,11 +3,14 @@ use crate::entries::BootableEntry;
use crate::generators::bls::entry::BlsEntry; use crate::generators::bls::entry::BlsEntry;
use crate::utils; use crate::utils;
use crate::utils::vercmp; use crate::utils::vercmp;
use alloc::format;
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use core::cmp::Ordering;
use core::str::FromStr;
use edera_sprout_config::generators::bls::BlsConfiguration; use edera_sprout_config::generators::bls::BlsConfiguration;
use std::cmp::Ordering;
use std::rc::Rc;
use std::str::FromStr;
use uefi::cstr16; use uefi::cstr16;
use uefi::fs::{FileSystem, PathBuf}; use uefi::fs::{FileSystem, PathBuf};
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly}; use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};

View File

@@ -1,5 +1,6 @@
use alloc::string::{String, ToString};
use anyhow::{Error, Result}; use anyhow::{Error, Result};
use std::str::FromStr; use core::str::FromStr;
/// Represents a parsed BLS entry. /// Represents a parsed BLS entry.
/// Fields unrelated to Sprout are not included. /// Fields unrelated to Sprout are not included.

View File

@@ -1,8 +1,10 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use crate::entries::BootableEntry; use crate::entries::BootableEntry;
use alloc::rc::Rc;
use alloc::string::ToString;
use alloc::vec::Vec;
use anyhow::Result; use anyhow::Result;
use edera_sprout_config::generators::list::ListConfiguration; use edera_sprout_config::generators::list::ListConfiguration;
use std::rc::Rc;
/// Generates a set of entries using the specified `list` configuration in the `context`. /// Generates a set of entries using the specified `list` configuration in the `context`.
pub fn generate( pub fn generate(

View File

@@ -1,11 +1,14 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use crate::entries::BootableEntry; use crate::entries::BootableEntry;
use crate::generators::list; use crate::generators::list;
use alloc::collections::BTreeMap;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
use anyhow::Result; use anyhow::Result;
use edera_sprout_config::generators::list::ListConfiguration; use edera_sprout_config::generators::list::ListConfiguration;
use edera_sprout_config::generators::matrix::MatrixConfiguration; use edera_sprout_config::generators::matrix::MatrixConfiguration;
use std::collections::BTreeMap;
use std::rc::Rc;
/// Builds out multiple generations of `input` based on a matrix style. /// Builds out multiple generations of `input` based on a matrix style.
/// For example, if input is: {"x": ["a", "b"], "y": ["c", "d"]} /// For example, if input is: {"x": ["a", "b"], "y": ["c", "d"]}

View File

@@ -2,6 +2,9 @@ use crate::integrations::bootloader_interface::bitflags::LoaderFeatures;
use crate::platform::timer::PlatformTimer; use crate::platform::timer::PlatformTimer;
use crate::utils::device_path_subpath; use crate::utils::device_path_subpath;
use crate::utils::variables::{VariableClass, VariableController}; use crate::utils::variables::{VariableClass, VariableController};
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use uefi::proto::device_path::DevicePath; use uefi::proto::device_path::DevicePath;
use uefi::{Guid, guid}; use uefi::{Guid, guid};

View File

@@ -3,10 +3,13 @@ use crate::secure::SecureBoot;
use crate::utils; use crate::utils;
use crate::utils::ResolvedPath; use crate::utils::ResolvedPath;
use crate::utils::variables::{VariableClass, VariableController}; use crate::utils::variables::{VariableClass, VariableController};
use alloc::boxed::Box;
use alloc::string::ToString;
use alloc::vec::Vec;
use anyhow::{Context, Result, anyhow, bail}; use anyhow::{Context, Result, anyhow, bail};
use core::ffi::c_void;
use core::pin::Pin;
use log::warn; use log::warn;
use std::ffi::c_void;
use std::pin::Pin;
use uefi::Handle; use uefi::Handle;
use uefi::boot::LoadImageSource; use uefi::boot::LoadImageSource;
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly}; use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};

View File

@@ -1,8 +1,9 @@
use crate::integrations::shim::{ShimInput, ShimSupport, ShimVerificationOutput}; use crate::integrations::shim::{ShimInput, ShimSupport, ShimVerificationOutput};
use crate::utils; use crate::utils;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result};
use core::slice;
use log::warn; use log::warn;
use std::sync::{LazyLock, Mutex}; use spin::{Lazy, Mutex};
use uefi::proto::device_path::FfiDevicePath; use uefi::proto::device_path::FfiDevicePath;
use uefi::proto::unsafe_protocol; use uefi::proto::unsafe_protocol;
use uefi::{Guid, guid}; use uefi::{Guid, guid};
@@ -45,8 +46,7 @@ struct SecurityHookState {
/// Global state for the security hook. /// Global state for the security hook.
/// This is messy, but it is safe given the mutex. /// This is messy, but it is safe given the mutex.
static GLOBAL_HOOK_STATE: LazyLock<Mutex<Option<SecurityHookState>>> = static GLOBAL_HOOK_STATE: Lazy<Mutex<Option<SecurityHookState>>> = Lazy::new(|| Mutex::new(None));
LazyLock::new(|| Mutex::new(None));
/// Security hook helper. /// Security hook helper.
pub struct SecurityHook; pub struct SecurityHook;
@@ -110,9 +110,7 @@ impl SecurityHook {
// Verify the input, if it fails, call the original hook. // Verify the input, if it fails, call the original hook.
if !Self::verify(input) { if !Self::verify(input) {
// Acquire the global hook state to grab the original hook. // Acquire the global hook state to grab the original hook.
let function = match GLOBAL_HOOK_STATE.lock() { let function = match GLOBAL_HOOK_STATE.lock().as_ref() {
// We have acquired the lock, so we can find the original hook.
Ok(state) => match state.as_ref() {
// The hook state is available, so we can acquire the original hook. // The hook state is available, so we can acquire the original hook.
Some(state) => state.original_hook.file_authentication_state, Some(state) => state.original_hook.file_authentication_state,
@@ -121,15 +119,6 @@ impl SecurityHook {
warn!("global hook state is not available, unable to call original hook"); warn!("global hook state is not available, unable to call original hook");
return Status::LOAD_ERROR; return Status::LOAD_ERROR;
} }
},
Err(error) => {
warn!(
"unable to acquire global hook state lock to call original hook: {}",
error,
);
return Status::LOAD_ERROR;
}
}; };
// Call the original hook function to see what it reports. // Call the original hook function to see what it reports.
@@ -161,7 +150,7 @@ impl SecurityHook {
} }
// Construct a slice out of the file buffer and size. // Construct a slice out of the file buffer and size.
let buffer = unsafe { std::slice::from_raw_parts(file_buffer, file_size) }; let buffer = unsafe { slice::from_raw_parts(file_buffer, file_size) };
// Construct a shim input from the path. // Construct a shim input from the path.
let input = ShimInput::SecurityHookBuffer(Some(path), buffer); let input = ShimInput::SecurityHookBuffer(Some(path), buffer);
@@ -169,9 +158,7 @@ impl SecurityHook {
// Verify the input, if it fails, call the original hook. // Verify the input, if it fails, call the original hook.
if !Self::verify(input) { if !Self::verify(input) {
// Acquire the global hook state to grab the original hook. // Acquire the global hook state to grab the original hook.
let function = match GLOBAL_HOOK_STATE.lock() { let function = match GLOBAL_HOOK_STATE.lock().as_ref() {
// We have acquired the lock, so we can find the original hook.
Ok(state) => match state.as_ref() {
// The hook state is available, so we can acquire the original hook. // The hook state is available, so we can acquire the original hook.
Some(state) => state.original_hook2.file_authentication, Some(state) => state.original_hook2.file_authentication,
@@ -180,15 +167,6 @@ impl SecurityHook {
warn!("global hook state is not available, unable to call original hook"); warn!("global hook state is not available, unable to call original hook");
return Status::LOAD_ERROR; return Status::LOAD_ERROR;
} }
},
Err(error) => {
warn!(
"unable to acquire global hook state lock to call original hook: {}",
error
);
return Status::LOAD_ERROR;
}
}; };
// Call the original hook function to see what it reports. // Call the original hook function to see what it reports.
@@ -237,9 +215,7 @@ impl SecurityHook {
}; };
// Acquire the lock to the global state and replace it. // Acquire the lock to the global state and replace it.
let Ok(mut global_state) = GLOBAL_HOOK_STATE.lock() else { let mut global_state = GLOBAL_HOOK_STATE.lock();
bail!("unable to acquire global hook state lock");
};
global_state.replace(state); global_state.replace(state);
// Install the hooks into the UEFI stack. // Install the hooks into the UEFI stack.
@@ -276,9 +252,7 @@ impl SecurityHook {
.context("unable to open security arch2 protocol")?; .context("unable to open security arch2 protocol")?;
// Acquire the lock to the global state. // Acquire the lock to the global state.
let Ok(mut global_state) = GLOBAL_HOOK_STATE.lock() else { let mut global_state = GLOBAL_HOOK_STATE.lock();
bail!("unable to acquire global hook state lock");
};
// Take the state and replace the original functions. // Take the state and replace the original functions.
let Some(state) = global_state.take() else { let Some(state) = global_state.take() else {

View File

@@ -1,8 +1,8 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![feature(uefi_std)] #![no_std]
#![no_main]
/// The delay to wait for when an error occurs in Sprout. extern crate alloc;
const DELAY_ON_ERROR: Duration = Duration::from_secs(10);
use crate::context::{RootContext, SproutContext}; use crate::context::{RootContext, SproutContext};
use crate::entries::BootableEntry; use crate::entries::BootableEntry;
@@ -14,13 +14,18 @@ use crate::platform::timer::PlatformTimer;
use crate::platform::tpm::PlatformTpm; use crate::platform::tpm::PlatformTpm;
use crate::secure::SecureBoot; use crate::secure::SecureBoot;
use crate::utils::PartitionGuidForm; use crate::utils::PartitionGuidForm;
use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::ToString;
use alloc::vec::Vec;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use core::ops::Deref;
use core::time::Duration;
use edera_sprout_config::RootConfiguration; use edera_sprout_config::RootConfiguration;
use log::{error, info, warn}; use log::{error, info, warn};
use std::collections::BTreeMap; use uefi::entry;
use std::ops::Deref;
use std::time::Duration;
use uefi::proto::device_path::LoadedImageDevicePath; use uefi::proto::device_path::LoadedImageDevicePath;
use uefi_raw::Status;
/// actions: Code that can be configured and executed by Sprout. /// actions: Code that can be configured and executed by Sprout.
pub mod actions; pub mod actions;
@@ -73,6 +78,9 @@ pub mod options;
/// utils: Utility functions that are used by other parts of Sprout. /// utils: Utility functions that are used by other parts of Sprout.
pub mod utils; pub mod utils;
/// The delay to wait for when an error occurs in Sprout.
const DELAY_ON_ERROR: Duration = Duration::from_secs(10);
/// Run Sprout, returning an error if one occurs. /// Run Sprout, returning an error if one occurs.
fn run() -> Result<()> { fn run() -> Result<()> {
// For safety reasons, we will note that Secure Boot is in beta on Sprout. // For safety reasons, we will note that Secure Boot is in beta on Sprout.
@@ -373,9 +381,14 @@ fn run() -> Result<()> {
/// The main entrypoint of sprout. /// The main entrypoint of sprout.
/// It is possible this function will not return if actions that are executed /// It is possible this function will not return if actions that are executed
/// exit boot services or do not return control to sprout. /// exit boot services or do not return control to sprout.
fn main() -> Result<()> { #[entry]
fn efi_main() -> Status {
// Initialize the basic UEFI environment. // Initialize the basic UEFI environment.
setup::init()?; // If initialization fails, we will return ABORTED.
if let Err(error) = setup::init() {
error!("unable to initialize environment: {}", error);
return Status::ABORTED;
}
// Run Sprout, then handle the error. // Run Sprout, then handle the error.
let result = run(); let result = run();
@@ -387,9 +400,10 @@ fn main() -> Result<()> {
} }
// Sleep to allow the user to read the error. // Sleep to allow the user to read the error.
uefi::boot::stall(DELAY_ON_ERROR); uefi::boot::stall(DELAY_ON_ERROR);
return Status::ABORTED;
} }
// Sprout doesn't necessarily guarantee anything was booted. // Sprout doesn't necessarily guarantee anything was booted.
// If we reach here, we will exit back to whoever called us. // If we reach here, we will exit back to whoever called us.
Ok(()) Status::SUCCESS
} }

View File

@@ -1,9 +1,10 @@
use crate::entries::BootableEntry; use crate::entries::BootableEntry;
use crate::integrations::bootloader_interface::BootloaderInterface; use crate::integrations::bootloader_interface::BootloaderInterface;
use crate::platform::timer::PlatformTimer; use crate::platform::timer::PlatformTimer;
use alloc::vec;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use core::time::Duration;
use log::{info, warn}; use log::{info, warn};
use std::time::Duration;
use uefi::ResultExt; use uefi::ResultExt;
use uefi::boot::TimerTrigger; use uefi::boot::TimerTrigger;
use uefi::proto::console::text::{Input, Key, ScanCode}; use uefi::proto::console::text::{Input, Key, ScanCode};

View File

@@ -1,6 +1,10 @@
use crate::options::parser::{OptionDescription, OptionForm, OptionsRepresentable}; use crate::options::parser::{OptionDescription, OptionForm, OptionsRepresentable};
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use std::collections::BTreeMap;
/// Acquire arguments from UEFI environment.
pub mod env;
/// The Sprout options parser. /// The Sprout options parser.
pub mod parser; pub mod parser;

View File

@@ -0,0 +1,77 @@
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use anyhow::{Context, Result, bail};
use uefi::proto::loaded_image::{LoadOptionsError, LoadedImage};
/// Loads the command-line arguments passed to Sprout.
pub fn args() -> Result<Vec<String>> {
// Acquire the image handle of Sprout.
let handle = uefi::boot::image_handle();
// Open the LoadedImage protocol for Sprout.
let loaded_image = uefi::boot::open_protocol_exclusive::<LoadedImage>(handle)
.context("unable to open loaded image protocol for sprout")?;
// Load the command-line argument string.
let options = match loaded_image.load_options_as_cstr16() {
// Load options were passed. We will return them for processing.
Ok(options) => options,
// No load options were passed. We will return an empty vector.
Err(LoadOptionsError::NotSet) => {
return Ok(Vec::new());
}
Err(LoadOptionsError::NotAligned) => {
bail!("load options are not properly aligned");
}
Err(LoadOptionsError::InvalidString(error)) => {
bail!("load options are not a valid string: {}", error);
}
};
// Convert the options to a string.
let options = options.to_string();
// Use shlex to parse the options.
// If shlex fails, we will fall back to a simple whitespace split.
let mut args = shlex::split(&options).unwrap_or_else(|| {
options
.split_ascii_whitespace()
.map(|string| string.to_string())
.collect::<Vec<_>>()
});
// If there is a first argument, check if it is not an option.
// If it is not, we will assume it is the path to the executable and remove it.
if let Some(arg) = args.first()
&& !arg.starts_with('-')
{
args.remove(0);
}
// Correct firmware that may add invalid arguments at the start.
// Witnessed this on a Dell Precision 5690 when direct booting.
loop {
// Grab the first argument or break.
let Some(arg) = args.first() else {
break;
};
// Check if the argument is a valid character.
// If it is not, remove it and continue.
let Some(first_character) = arg.chars().next() else {
break;
};
// If the character is not a printable character or a backtick, remove it and continue.
if first_character < 0x1f as char || first_character == '`' {
args.remove(0);
continue;
}
break;
}
Ok(args)
}

View File

@@ -1,6 +1,10 @@
use crate::options::env;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use core::ptr::null_mut;
use log::info; use log::info;
use std::collections::BTreeMap; use uefi_raw::Status;
/// The type of option. This disambiguates different behavior /// The type of option. This disambiguates different behavior
/// of how options are handled. /// of how options are handled.
@@ -47,23 +51,7 @@ pub trait OptionsRepresentable {
// Collect all the arguments to Sprout. // Collect all the arguments to Sprout.
// Skip the first argument, which is the path to our executable. // Skip the first argument, which is the path to our executable.
let mut args = std::env::args().skip(1).collect::<Vec<_>>(); let args = env::args()?;
// Correct firmware that may add invalid arguments at the start.
// Witnessed this on a Dell Precision 5690 when direct booting.
loop {
// Grab the first argument or break.
let Some(arg) = args.first() else {
break;
};
// If the argument starts with a tilde, remove it.
if arg.starts_with("`") {
args.remove(0);
continue;
}
break;
}
// Represent options as key-value pairs. // Represent options as key-value pairs.
let mut options = BTreeMap::new(); let mut options = BTreeMap::new();
@@ -77,7 +65,7 @@ pub trait OptionsRepresentable {
break; break;
}; };
// If the doesn't start with --, that is invalid. // If the option doesn't start with --, that is invalid.
if !option.starts_with("--") { if !option.starts_with("--") {
bail!("invalid option: {option}"); bail!("invalid option: {option}");
} }
@@ -144,7 +132,9 @@ pub trait OptionsRepresentable {
); );
} }
// Exit because the help has been displayed. // Exit because the help has been displayed.
std::process::exit(0); unsafe {
uefi::boot::exit(uefi::boot::image_handle(), Status::SUCCESS, 0, null_mut());
};
} }
// Insert the option and the value into the map. // Insert the option and the value into the map.

View File

@@ -1,8 +1,9 @@
use crate::actions; use crate::actions;
use crate::context::SproutContext; use crate::context::SproutContext;
use alloc::format;
use alloc::rc::Rc;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use edera_sprout_config::phases::PhaseConfiguration; use edera_sprout_config::phases::PhaseConfiguration;
use std::rc::Rc;
/// Executes the specified [phase] of the boot process. /// Executes the specified [phase] of the boot process.
/// The value [phase] should be a reference of a specific phase in the [PhasesConfiguration]. /// The value [phase] should be a reference of a specific phase in the [PhasesConfiguration].

View File

@@ -1,7 +1,7 @@
// Referenced https://github.com/sheroz/tick_counter (MIT license) as a baseline. // Referenced https://github.com/sheroz/tick_counter (MIT license) as a baseline.
// Architecturally modified to support UEFI and remove x86 (32-bit) support. // Architecturally modified to support UEFI and remove x86 (32-bit) support.
use std::time::Duration; use core::time::Duration;
/// Support for aarch64 timers. /// Support for aarch64 timers.
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]

View File

@@ -1,5 +1,5 @@
use crate::platform::timer::TickFrequency; use crate::platform::timer::TickFrequency;
use std::arch::asm; use core::arch::asm;
/// Reads the cntvct_el0 counter and returns the value. /// Reads the cntvct_el0 counter and returns the value.
pub fn ticks() -> u64 { pub fn ticks() -> u64 {

View File

@@ -1,6 +1,6 @@
use crate::platform::timer::TickFrequency; use crate::platform::timer::TickFrequency;
use core::arch::asm; use core::arch::asm;
use std::time::Duration; use core::time::Duration;
/// We will measure the frequency of the timer based on 1000 microseconds. /// We will measure the frequency of the timer based on 1000 microseconds.
/// This will result in a call to BS->Stall(1000) in the end. /// This will result in a call to BS->Stall(1000) in the end.

View File

@@ -1,27 +1,8 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::os::uefi as uefi_std;
/// Initializes the UEFI environment. /// Initializes the UEFI environment.
///
/// This fetches the system table and current image handle from uefi_std and injects
/// them into the uefi crate.
pub fn init() -> Result<()> { pub fn init() -> Result<()> {
// Acquire the system table and image handle from the uefi_std environment. // Initialize the uefi internals.
let system_table = uefi_std::env::system_table();
let image_handle = uefi_std::env::image_handle();
// SAFETY: The UEFI variables above come from the Rust std.
// These variables are not-null and calling the uefi crates with these values is validated
// to be corrected by hand.
unsafe {
// Set the system table and image handle.
uefi::table::set_system_table(system_table.as_ptr().cast());
let handle = uefi::Handle::from_ptr(image_handle.as_ptr().cast())
.context("unable to resolve image handle")?;
uefi::boot::set_image_handle(handle);
}
// Initialize the uefi logger mechanism and other helpers.
uefi::helpers::init().context("unable to initialize uefi")?; uefi::helpers::init().context("unable to initialize uefi")?;
Ok(()) Ok(())
} }

View File

@@ -1,6 +1,10 @@
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use core::ops::Deref;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::ops::Deref;
use uefi::boot::SearchType; use uefi::boot::SearchType;
use uefi::fs::{FileSystem, Path}; use uefi::fs::{FileSystem, Path};
use uefi::proto::device_path::text::{AllowShortcuts, DevicePathFromText, DisplayOnly}; use uefi::proto::device_path::text::{AllowShortcuts, DevicePathFromText, DisplayOnly};

View File

@@ -1,3 +1,5 @@
use alloc::vec;
use alloc::vec::Vec;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use uefi::proto::console::gop::{BltOp, BltPixel, BltRegion, GraphicsOutput}; use uefi::proto::console::gop::{BltOp, BltPixel, BltRegion, GraphicsOutput};

View File

@@ -1,5 +1,8 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use std::ffi::c_void; use core::ffi::c_void;
use core::ptr;
use uefi::proto::device_path::DevicePath; use uefi::proto::device_path::DevicePath;
use uefi::proto::device_path::build::DevicePathBuilder; use uefi::proto::device_path::build::DevicePathBuilder;
use uefi::proto::device_path::build::media::Vendor; use uefi::proto::device_path::build::media::Vendor;
@@ -261,8 +264,7 @@ impl MediaLoaderHandle {
let protocol = Box::from_raw(self.protocol); let protocol = Box::from_raw(self.protocol);
// Retrieve a box for the data we passed in. // Retrieve a box for the data we passed in.
let slice = let slice = ptr::slice_from_raw_parts_mut(protocol.address as *mut u8, protocol.length);
std::ptr::slice_from_raw_parts_mut(protocol.address as *mut u8, protocol.length);
let data = Box::from_raw(slice); let data = Box::from_raw(slice);
// Drop all the allocations explicitly, as we don't want to leak them. // Drop all the allocations explicitly, as we don't want to leak them.

View File

@@ -1,4 +1,7 @@
use crate::utils; use crate::utils;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use log::warn; use log::warn;
use uefi::{CString16, guid}; use uefi::{CString16, guid};

View File

@@ -1,5 +1,5 @@
use std::cmp::Ordering; use core::cmp::Ordering;
use std::iter::Peekable; use core::iter::Peekable;
/// Handles single character advancement and comparison. /// Handles single character advancement and comparison.
macro_rules! handle_single_char { macro_rules! handle_single_char {

View File

@@ -1,4 +1,4 @@
[toolchain] [toolchain]
channel = "nightly" channel = "1.91.0"
components = ["rustfmt", "rust-std", "clippy"] components = ["rustfmt", "clippy"]
targets = ["x86_64-unknown-uefi", "aarch64-unknown-uefi"] targets = ["x86_64-unknown-uefi", "aarch64-unknown-uefi"]