Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
- The documentation for UEFI protocols has been streamlined and improved.
- Fixed memory safety bug in `SimpleNetwork::read_nv_data`. The `buffer`
parameter is now mutable.
- Removed all internal usages including public APIs using the unstable
`allocator_api` feature. It may be reintroduced if it will have a chance of
getting stabilized in stable Rust.
- Removed `File::get_boxed_info_in`
- Removed `Directory::read_entry_boxed_in`

# uefi - 0.35.0 (2025-05-04)

Expand Down
7 changes: 2 additions & 5 deletions uefi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,8 @@
//! - `log-debugcon`: Whether the logger set up by `logger` should also log
//! to the debugcon device (available in QEMU or Cloud Hypervisor on x86).
//! - `panic_handler`: Add a default panic handler that logs to `stdout`.
//! - `unstable`: Enable functionality that depends on [unstable
//! features] in the nightly compiler.
//! As example, in conjunction with the `alloc`-feature, this gate allows
//! the `allocator_api` on certain functions.
//! - `unstable`: Enable functionality that depends on [unstable features] in
//! the Rust compiler (nightly version).
//! - `qemu`: Enable some code paths to adapt their execution when executed
//! in QEMU, such as using the special `qemu-exit` device when the panic
//! handler is called.
Expand Down Expand Up @@ -229,7 +227,6 @@
//! [uefi-std-tr-issue]: https://github.com/rust-lang/rust/issues/100499
//! [unstable features]: https://doc.rust-lang.org/unstable-book/

#![cfg_attr(all(feature = "unstable", feature = "alloc"), feature(allocator_api))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![no_std]
#![deny(
Expand Down
57 changes: 5 additions & 52 deletions uefi/src/mem/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@

use crate::data_types::Align;
use crate::{Error, Result, ResultExt, Status};
use ::alloc::alloc::{alloc, dealloc};
use ::alloc::boxed::Box;
use core::alloc::Layout;
use core::fmt::Debug;
use core::slice;

#[cfg(not(feature = "unstable"))]
use ::alloc::alloc::{alloc, dealloc};

#[cfg(feature = "unstable")]
use {core::alloc::Allocator, core::ptr::NonNull};

/// Helper to return owned versions of certain UEFI data structures on the heap in a [`Box`]. This
/// function is intended to wrap low-level UEFI functions of this crate that
/// - can consume an empty buffer without a panic to get the required buffer size in the errors
Expand All @@ -23,31 +18,14 @@ use {core::alloc::Allocator, core::ptr::NonNull};
/// buffer size is sufficient, and
/// - return a mutable typed reference that points to the same memory as the input buffer on
/// success.
///
/// # Feature `unstable` / `allocator_api`
/// By default, this function works with the allocator that is set as
/// `#[global_allocator]`. This might be UEFI allocator but depends on your
/// use case and how you set up the environment.
///
/// If you activate the `unstable`-feature, all allocations uses the provided
/// allocator (via `allocator_api`) instead. In that case, the function takes an
/// additional parameter describing the specific [`Allocator`]. You can use
/// [`alloc::alloc::Global`] which defaults to the `#[global_allocator]`.
///
/// [`Allocator`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html
/// [`alloc::alloc::Global`]: https://doc.rust-lang.org/alloc/alloc/struct.Global.html
pub(crate) fn make_boxed<
'a,
// The UEFI data structure.
Data: Align + ?Sized + Debug + 'a,
F: FnMut(&'a mut [u8]) -> Result<&'a mut Data, Option<usize>>,
#[cfg(feature = "unstable")] A: Allocator,
>(
// A function to read the UEFI data structure into a provided buffer.
mut fetch_data_fn: F,
#[cfg(feature = "unstable")]
// Allocator of the `allocator_api` feature. You can use `Global` as default.
allocator: A,
) -> Result<Box<Data>> {
let required_size = match fetch_data_fn(&mut []).map_err(Error::split) {
// This is the expected case: the empty buffer passed in is too
Expand All @@ -70,21 +48,13 @@ pub(crate) fn make_boxed<

// Allocate the buffer on the heap.
let heap_buf: *mut u8 = {
#[cfg(not(feature = "unstable"))]
{
let ptr = unsafe { alloc(layout) };
if ptr.is_null() {
return Err(Status::OUT_OF_RESOURCES.into());
}
ptr
}

#[cfg(feature = "unstable")]
allocator
.allocate(layout)
.map_err(|_| <Status as Into<Error>>::into(Status::OUT_OF_RESOURCES))?
.as_ptr()
.cast::<u8>()
};

// Read the data into the provided buffer.
Expand All @@ -97,29 +67,19 @@ pub(crate) fn make_boxed<
let data: &mut Data = match data {
Ok(data) => data,
Err(err) => {
#[cfg(not(feature = "unstable"))]
unsafe {
dealloc(heap_buf, layout)
};
#[cfg(feature = "unstable")]
unsafe {
allocator.deallocate(NonNull::new(heap_buf).unwrap(), layout)
}
unsafe { dealloc(heap_buf, layout) };
return Err(err);
}
};

let data = unsafe { Box::from_raw(data) };

Ok(data)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{ResultExt, StatusExt};
#[cfg(feature = "unstable")]
use alloc::alloc::Global;

/// Some simple dummy type to test [`make_boxed`].
#[derive(Debug)]
Expand Down Expand Up @@ -212,27 +172,20 @@ mod tests {
assert_eq!(&data.0.0, &[1, 2, 3, 4]);
}

/// This unit tests checks the [`make_boxed`] utility. The test has different code and behavior
/// depending on whether the "unstable" feature is active or not.
/// This unit tests checks the [`make_boxed`] utility.
///
/// This test is especially useful when run by miri.
#[test]
fn test_make_boxed_utility() {
let fetch_data_fn = |buf| uefi_function_stub_read(buf);

#[cfg(not(feature = "unstable"))]
let data: Box<SomeData> = make_boxed(fetch_data_fn).unwrap();

#[cfg(feature = "unstable")]
let data: Box<SomeData> = make_boxed(fetch_data_fn, Global).unwrap();
assert_eq!(&data.0, &[1, 2, 3, 4]);

let fetch_data_fn = |buf| uefi_function_stub_read(buf);

#[cfg(not(feature = "unstable"))]
let data: Box<SomeDataAlign16> = make_boxed(fetch_data_fn).unwrap();

#[cfg(feature = "unstable")]
let data: Box<SomeDataAlign16> = make_boxed(fetch_data_fn, Global).unwrap();

assert_eq!(&data.0.0, &[1, 2, 3, 4]);
}
}
4 changes: 0 additions & 4 deletions uefi/src/proto/hii/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,8 @@ impl HiiDatabase {
}
}

#[cfg(not(feature = "unstable"))]
let buf = make_boxed::<[u8], _>(|buf| fetch_data_fn(self, buf))?;

#[cfg(feature = "unstable")]
let buf = make_boxed::<[u8], _, _>(|buf| fetch_data_fn(self, buf), alloc::alloc::Global)?;

Ok(buf)
}
}
37 changes: 0 additions & 37 deletions uefi/src/proto/media/file/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ use crate::data_types::Align;
use core::ffi::c_void;
#[cfg(feature = "alloc")]
use {crate::mem::make_boxed, alloc::boxed::Box};
#[cfg(all(feature = "unstable", feature = "alloc"))]
use {alloc::alloc::Global, core::alloc::Allocator};

/// A `FileHandle` that is also a directory.
///
Expand Down Expand Up @@ -80,42 +78,7 @@ impl Directory {
maybe_info.expect("Should have more entries")
})
};

#[cfg(not(feature = "unstable"))]
let file_info = make_boxed::<FileInfo, _>(fetch_data_fn)?;

#[cfg(feature = "unstable")]
let file_info = make_boxed::<FileInfo, _, _>(fetch_data_fn, Global)?;

Ok(Some(file_info))
}

/// Wrapper around [`Self::read_entry`] that returns an owned copy of the data. It has the same
/// implications and requirements. On failure, the payload of `Err` is `()´.
///
/// It allows to use a custom allocator via the `allocator_api` feature.
#[cfg(all(feature = "unstable", feature = "alloc"))]
pub fn read_entry_boxed_in<A: Allocator>(
&mut self,
allocator: A,
) -> Result<Option<Box<FileInfo>>> {
let read_entry_res = self.read_entry(&mut []);

// If no more entries are available, return early.
if read_entry_res == Ok(None) {
return Ok(None);
}

let fetch_data_fn = |buf| {
self.read_entry(buf)
// this is safe, as above, we checked that there are more entries
.map(|maybe_info: Option<&mut FileInfo>| {
maybe_info.expect("Should have more entries")
})
};

let file_info = make_boxed::<FileInfo, _, A>(fetch_data_fn, allocator)?;

Ok(Some(file_info))
}

Expand Down
17 changes: 0 additions & 17 deletions uefi/src/proto/media/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ use core::fmt::Debug;
use core::{mem, ptr};
use uefi_raw::protocol::file_system::FileProtocolV1;

#[cfg(all(feature = "unstable", feature = "alloc"))]
use {alloc::alloc::Global, core::alloc::Allocator};

#[cfg(feature = "alloc")]
use {crate::mem::make_boxed, alloc::boxed::Box};

Expand Down Expand Up @@ -198,21 +195,7 @@ pub trait File: Sized {
#[cfg(feature = "alloc")]
fn get_boxed_info<Info: FileProtocolInfo + ?Sized + Debug>(&mut self) -> Result<Box<Info>> {
let fetch_data_fn = |buf| self.get_info::<Info>(buf);
#[cfg(not(feature = "unstable"))]
let file_info = make_boxed::<Info, _>(fetch_data_fn)?;
#[cfg(feature = "unstable")]
let file_info = make_boxed::<Info, _, _>(fetch_data_fn, Global)?;
Ok(file_info)
}

/// Read the dynamically allocated info for a file.
#[cfg(all(feature = "unstable", feature = "alloc"))]
fn get_boxed_info_in<Info: FileProtocolInfo + ?Sized + Debug, A: Allocator>(
&mut self,
allocator: A,
) -> Result<Box<Info>> {
let fetch_data_fn = |buf| self.get_info::<Info>(buf);
let file_info = make_boxed::<Info, _, A>(fetch_data_fn, allocator)?;
Ok(file_info)
}

Expand Down
11 changes: 0 additions & 11 deletions uefi/src/proto/media/load_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#[cfg(doc)]
use crate::Status;
use crate::proto::unsafe_protocol;
#[cfg(all(feature = "alloc", feature = "unstable"))]
use alloc::alloc::Global;
use uefi_raw::protocol::media::{LoadFile2Protocol, LoadFileProtocol};
#[cfg(feature = "alloc")]
use {
Expand Down Expand Up @@ -90,12 +88,7 @@ impl LoadFile {
status.to_result_with_err(|_| Some(size)).map(|_| buf)
};

#[cfg(not(feature = "unstable"))]
let file: Box<[u8]> = make_boxed::<[u8], _>(fetch_data_fn)?;

#[cfg(feature = "unstable")]
let file = make_boxed::<[u8], _, _>(fetch_data_fn, Global)?;

Ok(file)
}
}
Expand Down Expand Up @@ -158,12 +151,8 @@ impl LoadFile2 {
status.to_result_with_err(|_| Some(size)).map(|_| buf)
};

#[cfg(not(feature = "unstable"))]
let file: Box<[u8]> = make_boxed::<[u8], _>(fetch_data_fn)?;

#[cfg(feature = "unstable")]
let file = make_boxed::<[u8], _, _>(fetch_data_fn, Global)?;

Ok(file)
}
}
15 changes: 1 addition & 14 deletions uefi/src/proto/tcg/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ use uefi_raw::protocol::tcg::v1::{TcgBootServiceCapability, TcgProtocol};
#[cfg(feature = "alloc")]
use {crate::mem::make_boxed, alloc::boxed::Box};

#[cfg(all(feature = "unstable", feature = "alloc"))]
use alloc::alloc::Global;

pub use uefi_raw::protocol::tcg::v1::TcgVersion as Version;

/// 20-byte SHA-1 digest.
Expand Down Expand Up @@ -157,17 +154,7 @@ impl PcrEvent {
digest: Sha1Digest,
event_data: &[u8],
) -> Result<Box<Self>> {
#[cfg(not(feature = "unstable"))]
{
make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, digest, event_data))
}
#[cfg(feature = "unstable")]
{
make_boxed(
|buf| Self::new_in_buffer(buf, pcr_index, event_type, digest, event_data),
Global,
)
}
make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, digest, event_data))
}

/// PCR index for the event.
Expand Down
15 changes: 1 addition & 14 deletions uefi/src/proto/tcg/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ use uefi_raw::protocol::tcg::v2::{Tcg2EventHeader as EventHeader, Tcg2Protocol};
#[cfg(feature = "alloc")]
use {crate::mem::make_boxed, alloc::boxed::Box};

#[cfg(all(feature = "unstable", feature = "alloc"))]
use alloc::alloc::Global;

pub use uefi_raw::protocol::tcg::v2::{
Tcg2EventLogFormat as EventLogFormat, Tcg2HashAlgorithmBitmap,
Tcg2HashLogExtendEventFlags as HashLogExtendEventFlags, Tcg2Version as Version,
Expand Down Expand Up @@ -183,17 +180,7 @@ impl PcrEventInputs {
event_type: EventType,
event_data: &[u8],
) -> Result<Box<Self>> {
#[cfg(not(feature = "unstable"))]
{
make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data))
}
#[cfg(feature = "unstable")]
{
make_boxed(
|buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data),
Global,
)
}
make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data))
}
}

Expand Down
12 changes: 1 addition & 11 deletions uefi/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ use {
alloc::{vec, vec::Vec},
};

#[cfg(all(feature = "unstable", feature = "alloc"))]
use alloc::alloc::Global;

pub use uefi_raw::capsule::{CapsuleBlockDescriptor, CapsuleFlags, CapsuleHeader};
pub use uefi_raw::table::runtime::{
ResetType, TimeCapabilities, VariableAttributes, VariableVendor,
Expand Down Expand Up @@ -187,14 +184,7 @@ pub fn get_variable_boxed(
val
})
};
#[cfg(not(feature = "unstable"))]
{
make_boxed(get_var).map(|val| (val, out_attr))
}
#[cfg(feature = "unstable")]
{
make_boxed(get_var, Global).map(|val| (val, out_attr))
}
make_boxed(get_var).map(|val| (val, out_attr))
}

/// Gets each variable key (name and vendor) one at a time.
Expand Down
7 changes: 2 additions & 5 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,10 @@ fn run_host_tests(test_opt: &TestOpt) -> Result<()> {
packages.push(Package::UefiMacros);
}

// Run uefi-rs and uefi-macros tests.
// Run uefi-rs and uefi-macros tests with `unstable` feature.
let cargo = Cargo {
action: CargoAction::Test,
// At least one unit test, for make_boxed() currently, has different behaviour dependent on
// the unstable feature. Because of this, we need to allow to test both variants. Runtime
// features is set to no as it is not possible as as soon a #[global_allocator] is
// registered, the Rust runtime executing the tests uses it as well.
// Some tests may behave differently depending on the unstable feature.
features: Feature::more_code(*test_opt.unstable, false),
packages,
release: false,
Expand Down