Skip to content

Add allocating get_info helper function #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 5, 2019
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
12 changes: 7 additions & 5 deletions src/data_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ pub trait Align {

/// Assert that some storage is correctly aligned for this type
fn assert_aligned(storage: &mut [u8]) {
assert_eq!(
(storage.as_ptr() as usize) % Self::alignment(),
0,
"The provided storage is not correctly aligned for this type"
)
if !storage.is_empty() {
assert_eq!(
(storage.as_ptr() as usize) % Self::alignment(),
0,
"The provided storage is not correctly aligned for this type"
)
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/result/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ impl<Data: Debug> Error<Data> {
pub fn data(&self) -> &Data {
&self.data
}

/// Split this error into its inner status and error data
pub fn split(self) -> (Status, Data) {
(self.status, self.data)
}
}

// Errors without payloads can be autogenerated from statuses
Expand Down
7 changes: 7 additions & 0 deletions src/result/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub trait ResultExt<Output, ErrData: Debug> {
/// Expect success without warnings, panic with provided message otherwise
fn expect_success(self, msg: &str) -> Output;

/// Expect error, panic with provided message otherwise, discarding output
fn expect_error(self, msg: &str) -> Error<ErrData>;

/// Transform the inner output, if any
fn map_inner<Mapped>(self, f: impl FnOnce(Output) -> Mapped) -> Result<Mapped, ErrData>;

Expand Down Expand Up @@ -75,6 +78,10 @@ impl<Output, ErrData: Debug> ResultExt<Output, ErrData> for Result<Output, ErrDa
self.expect(msg).expect(msg)
}

fn expect_error(self, msg: &str) -> Error<ErrData> {
self.map(|completion| completion.status()).expect_err(msg)
}

fn map_inner<Mapped>(self, f: impl FnOnce(Output) -> Mapped) -> Result<Mapped, ErrData> {
self.map(|completion| completion.map(f))
}
Expand Down
51 changes: 51 additions & 0 deletions uefi-exts/src/file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use alloc::{alloc::alloc, boxed::Box};
use core::{alloc::Layout, mem, slice};
use uefi::prelude::*;
use uefi::proto::media::file::{File, FileProtocolInfo};
use uefi::Result;

/// Utility functions for dealing with file data
pub trait FileExt: File {
/// Get the dynamically allocated info for a file
fn get_boxed_info<Info: FileProtocolInfo + ?Sized>(&mut self) -> Result<Box<Info>> {
// Initially try get_info with an empty array, this should always fail
// as all Info types at least need room for a null-terminator.
let size = match self
.get_info::<Info>(&mut [])
.expect_error("zero sized get_info unexpectedly succeeded")
.split()
{
(s, None) => return Err(s.into()),
(_, Some(size)) => size,
};

// These unsafe alloc APIs make sure our buffer is correctly aligned. We
// round up a size must always be a multiple of alignment. We turn the
// pointer into a Box<[u8]>, so it's always freed on error.
let layout = Layout::from_size_align(size, Info::alignment())
.unwrap()
.pad_to_align()
.unwrap();
let buffer_start = unsafe { alloc(layout) };
let mut buffer = unsafe { Box::from_raw(slice::from_raw_parts_mut(buffer_start, size)) };

let info = self
.get_info(&mut buffer)
.discard_errdata()?
.map(|info_ref| {
// This operation is safe because info uses the exact memory
// of the provied buffer (so no memory is leaked), and the box
// is created if and only if buffer is leaked (so no memory can
// ever be freed twice).

assert_eq!(mem::size_of_val(info_ref), layout.size());
assert_eq!(info_ref as *const Info as *const u8, buffer_start);
unsafe { Box::from_raw(info_ref as *mut _) }
});
mem::forget(buffer);

Ok(info)
}
}

impl<T: File> FileExt for T {}
5 changes: 4 additions & 1 deletion uefi-exts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
//! which add utility functions to various UEFI objects.

#![no_std]
#![feature(alloc)]
#![feature(alloc, alloc_layout_extra)]

extern crate alloc;

mod boot;
mod file;

pub use self::boot::BootServicesExt;
pub use self::file::FileExt;