Skip to content

Commit 954a359

Browse files
josephlrGabrielMajeri
authored andcommitted
Add allocating get_info helper function (#89)
* Add allocating get_info helper function * Properly handle alignment math
1 parent e429a37 commit 954a359

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

src/data_types/mod.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ pub trait Align {
2323

2424
/// Assert that some storage is correctly aligned for this type
2525
fn assert_aligned(storage: &mut [u8]) {
26-
assert_eq!(
27-
(storage.as_ptr() as usize) % Self::alignment(),
28-
0,
29-
"The provided storage is not correctly aligned for this type"
30-
)
26+
if !storage.is_empty() {
27+
assert_eq!(
28+
(storage.as_ptr() as usize) % Self::alignment(),
29+
0,
30+
"The provided storage is not correctly aligned for this type"
31+
)
32+
}
3133
}
3234
}
3335

uefi-exts/src/file.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use alloc::{alloc::alloc, boxed::Box};
2+
use core::{alloc::Layout, mem, slice};
3+
use uefi::prelude::*;
4+
use uefi::proto::media::file::{File, FileProtocolInfo};
5+
use uefi::Result;
6+
7+
/// Utility functions for dealing with file data
8+
pub trait FileExt: File {
9+
/// Get the dynamically allocated info for a file
10+
fn get_boxed_info<Info: FileProtocolInfo + ?Sized>(&mut self) -> Result<Box<Info>> {
11+
// Initially try get_info with an empty array, this should always fail
12+
// as all Info types at least need room for a null-terminator.
13+
let size = match self
14+
.get_info::<Info>(&mut [])
15+
.expect_error("zero sized get_info unexpectedly succeeded")
16+
.split()
17+
{
18+
(s, None) => return Err(s.into()),
19+
(_, Some(size)) => size,
20+
};
21+
22+
// These unsafe alloc APIs make sure our buffer is correctly aligned. We
23+
// round up a size must always be a multiple of alignment. We turn the
24+
// pointer into a Box<[u8]>, so it's always freed on error.
25+
let layout = Layout::from_size_align(size, Info::alignment())
26+
.unwrap()
27+
.pad_to_align()
28+
.unwrap();
29+
let buffer_start = unsafe { alloc(layout) };
30+
let mut buffer = unsafe { Box::from_raw(slice::from_raw_parts_mut(buffer_start, size)) };
31+
32+
let info = self
33+
.get_info(&mut buffer)
34+
.discard_errdata()?
35+
.map(|info_ref| {
36+
// This operation is safe because info uses the exact memory
37+
// of the provied buffer (so no memory is leaked), and the box
38+
// is created if and only if buffer is leaked (so no memory can
39+
// ever be freed twice).
40+
41+
assert_eq!(mem::size_of_val(info_ref), layout.size());
42+
assert_eq!(info_ref as *const Info as *const u8, buffer_start);
43+
unsafe { Box::from_raw(info_ref as *mut _) }
44+
});
45+
mem::forget(buffer);
46+
47+
Ok(info)
48+
}
49+
}
50+
51+
impl<T: File> FileExt for T {}

uefi-exts/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
//! which add utility functions to various UEFI objects.
55
66
#![no_std]
7-
#![feature(alloc)]
7+
#![feature(alloc, alloc_layout_extra)]
88

99
extern crate alloc;
1010

1111
mod boot;
12+
mod file;
13+
1214
pub use self::boot::BootServicesExt;
15+
pub use self::file::FileExt;

0 commit comments

Comments
 (0)