Skip to content

Commit 9d803ea

Browse files
committed
xxx
The idea is to enable a more convenient builder experience: - in buffer - on uefi heap - in rust heap
1 parent 4bba239 commit 9d803ea

File tree

8 files changed

+79
-67
lines changed

8 files changed

+79
-67
lines changed

uefi-test-runner/src/bin/shell_launcher.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn get_shell_app_device_path(storage: &mut Vec<u8>) -> &DevicePath {
2929
boot::open_protocol_exclusive::<LoadedImageDevicePath>(boot::image_handle())
3030
.expect("failed to open LoadedImageDevicePath protocol");
3131

32-
let mut builder = DevicePathBuilder::with_vec(storage);
32+
let mut builder = DevicePathBuilder::with_rust_heap(storage);
3333
for node in loaded_image_device_path.node_iter() {
3434
if node.full_type() == (DeviceType::MEDIA, DeviceSubType::MEDIA_FILE_PATH) {
3535
break;

uefi-test-runner/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ fn reconnect_serial_to_console(serial_handle: Handle) {
141141
} else {
142142
Vendor::VT_UTF8
143143
};
144-
let terminal_device_path = DevicePathBuilder::with_vec(&mut storage)
144+
let terminal_device_path = DevicePathBuilder::with_rust_heap(&mut storage)
145145
.push(&build::messaging::Vendor {
146146
vendor_guid: terminal_guid,
147147
vendor_defined_data: &[],

uefi-test-runner/src/proto/device_path.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub fn test() {
4848

4949
fn create_test_device_path() -> Box<DevicePath> {
5050
let mut v = Vec::new();
51-
DevicePathBuilder::with_vec(&mut v)
51+
DevicePathBuilder::with_rust_heap(&mut v)
5252
// Add an ATAPI node because edk2 displays it differently depending on
5353
// the value of `DisplayOnly`.
5454
.push(&build::messaging::Atapi {

uefi-test-runner/src/proto/load.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ pub fn test() {
9898
}
9999

100100
let mut dvp_vec = Vec::new();
101-
let dummy_dvp = DevicePathBuilder::with_vec(&mut dvp_vec);
101+
let dummy_dvp = DevicePathBuilder::with_rust_heap(&mut dvp_vec);
102102
let dummy_dvp = dummy_dvp.finalize().unwrap();
103103

104104
let mut load_file_protocol = boot::open_protocol_exclusive::<LoadFile>(image).unwrap();

uefi-test-runner/src/proto/mod.rs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,7 @@ use uefi::{Identify, proto};
77
pub fn test() {
88
info!("Testing various protocols");
99

10-
console::test();
11-
12-
find_protocol();
13-
test_protocols_per_handle();
14-
test_test_protocol();
15-
16-
debug::test();
17-
device_path::test();
18-
driver::test();
19-
load::test();
20-
loaded_image::test();
21-
media::test();
22-
network::test();
23-
pci::test();
24-
pi::test();
25-
rng::test();
26-
shell_params::test();
27-
string::test();
28-
usb::test();
29-
misc::test();
30-
31-
// disable the ATA test on aarch64 for now. The aarch64 UEFI Firmware does not yet seem
32-
// to support SATA controllers (and providing an AtaPassThru protocol instance for them).
33-
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
34-
ata::test();
35-
scsi::test();
36-
nvme::test();
37-
38-
#[cfg(any(
39-
target_arch = "x86",
40-
target_arch = "x86_64",
41-
target_arch = "arm",
42-
target_arch = "aarch64"
43-
))]
44-
shim::test();
4510
shell::test();
46-
tcg::test();
4711
}
4812

4913
fn find_protocol() {

uefi/src/boot.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ pub unsafe fn free_pages(ptr: NonNull<u8>, count: usize) -> Result {
230230
/// * [`Status::OUT_OF_RESOURCES`]: allocation failed.
231231
/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT_MEMORY`],
232232
/// [`MemoryType::UNACCEPTED`], or in the range <code>[MemoryType::MAX]..=0x6fff_ffff</code>.
233+
// TODO should we return PoolAllocation here?
233234
pub fn allocate_pool(memory_type: MemoryType, size: usize) -> Result<NonNull<u8>> {
234235
let bt = boot_services_raw_panicking();
235236
let bt = unsafe { bt.as_ref() };

uefi/src/mem/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ pub use aligned_buffer::{AlignedBuffer, AlignmentError};
2525
pub(crate) struct PoolAllocation(NonNull<u8>);
2626

2727
impl PoolAllocation {
28+
/// This creates a new [`PoolAllocation`] from a `ptr` that represents
29+
/// the allocation.
30+
///
31+
/// This function doesn't allocate.
2832
pub(crate) const fn new(ptr: NonNull<u8>) -> Self {
2933
Self(ptr)
3034
}

uefi/src/proto/device_path/build.rs

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
//! containing types for building each type of device path node.
77
//!
88
//! [`DevicePaths`]: DevicePath
9-
109
pub use crate::proto::device_path::device_path_gen::build::*;
10+
use alloc::boxed::Box;
11+
use alloc::vec;
1112

1213
use crate::polyfill::{maybe_uninit_slice_as_mut_ptr, maybe_uninit_slice_assume_init_ref};
1314
use crate::proto::device_path::{DevicePath, DevicePathNode};
@@ -16,11 +17,20 @@ use core::mem::MaybeUninit;
1617

1718
#[cfg(feature = "alloc")]
1819
use alloc::vec::Vec;
20+
use core::mem;
21+
use uefi::boot;
22+
use uefi::mem::PoolAllocation;
23+
use uefi::proto::device_path::PoolDevicePath;
24+
use uefi_raw::table::boot::MemoryType;
1925

2026
/// A builder for [`DevicePaths`].
2127
///
22-
/// The builder can be constructed with either a fixed-length buffer or
23-
/// (if the `alloc` feature is enabled) a `Vec`.
28+
/// The builder has multiple constructors affecting the ownership of the
29+
/// resulting device path:
30+
///
31+
/// - [`DevicePathBuilder::with_buf`]
32+
/// - [`DevicePathBuilder::with_uefi_heap`]
33+
/// - [`DevicePathBuilder::with_rust_heap`]
2434
///
2535
/// Nodes are added via the [`push`] method. To construct a node, use one
2636
/// of the structs in these submodules:
@@ -78,21 +88,27 @@ pub struct DevicePathBuilder<'a> {
7888
}
7989

8090
impl<'a> DevicePathBuilder<'a> {
81-
/// Create a builder backed by a statically-sized buffer.
91+
/// Create a builder that will return [`BuiltDevicePath::Buf`].
8292
pub const fn with_buf(buf: &'a mut [MaybeUninit<u8>]) -> Self {
8393
Self {
8494
storage: BuilderStorage::Buf { buf, offset: 0 },
8595
}
8696
}
8797

88-
/// Create a builder backed by a `Vec`.
89-
///
90-
/// The `Vec` is cleared before use.
98+
/// Create a builder that will return [`BuiltDevicePath::UefiHeap`].
99+
pub fn with_uefi_heap() -> Self {
100+
// TODO propagate result?
101+
let ptr = { boot::allocate_pool(MemoryType::LOADER_DATA, 1).unwrap() };
102+
Self {
103+
storage: BuilderStorage::UefiHeap(PoolAllocation::new(ptr)),
104+
}
105+
}
106+
107+
/// Create a builder that will return [`BuiltDevicePath::Boxed`].
91108
#[cfg(feature = "alloc")]
92-
pub fn with_vec(v: &'a mut Vec<u8>) -> Self {
93-
v.clear();
109+
pub const fn with_rust_heap() -> Self {
94110
Self {
95-
storage: BuilderStorage::Vec(v),
111+
storage: BuilderStorage::Boxed(vec::Vec::new()),
96112
}
97113
}
98114

@@ -114,8 +130,11 @@ impl<'a> DevicePathBuilder<'a> {
114130
);
115131
*offset += node_size;
116132
}
133+
BuiltDevicePath::UefiHeap(_pool) => {
134+
todo!()
135+
}
117136
#[cfg(feature = "alloc")]
118-
BuilderStorage::Vec(vec) => {
137+
BuilderStorage::Boxed(vec) => {
119138
let old_size = vec.len();
120139
vec.reserve(node_size);
121140
let buf = &mut vec.spare_capacity_mut()[..node_size];
@@ -129,24 +148,33 @@ impl<'a> DevicePathBuilder<'a> {
129148
Ok(self)
130149
}
131150

132-
/// Add an [`END_ENTIRE`] node and return the resulting [`DevicePath`].
151+
// todo extend method (multiple push)
152+
153+
/// Add an [`END_ENTIRE`] node and return [`BuiltDevicePath`], depending
154+
/// on the chosen builder strategy.
133155
///
134156
/// This method consumes the builder.
135157
///
136158
/// [`END_ENTIRE`]: uefi::proto::device_path::DeviceSubType::END_ENTIRE
137-
pub fn finalize(self) -> Result<&'a DevicePath, BuildError> {
159+
pub fn finalize(self) -> Result<BuiltDevicePath<'a>, BuildError> {
138160
let this = self.push(&end::Entire)?;
139161

140-
let data: &[u8] = match &this.storage {
162+
match this.storage {
141163
BuilderStorage::Buf { buf, offset } => unsafe {
142-
maybe_uninit_slice_assume_init_ref(&buf[..*offset])
164+
let data = maybe_uninit_slice_assume_init_ref(&buf[..offset]);
165+
let ptr: *const () = data.as_ptr().cast();
166+
let path = &*ptr_meta::from_raw_parts(ptr, data.len());
167+
Ok(BuiltDevicePath::Buf(path))
143168
},
169+
BuilderStorage::UefiHeap(pool) => Ok(BuiltDevicePath::UefiHeap(PoolDevicePath(pool))),
144170
#[cfg(feature = "alloc")]
145-
BuilderStorage::Vec(vec) => vec,
146-
};
147-
148-
let ptr: *const () = data.as_ptr().cast();
149-
Ok(unsafe { &*ptr_meta::from_raw_parts(ptr, data.len()) })
171+
BuilderStorage::Boxed(vec) => {
172+
let data = vec.into_boxed_slice();
173+
// SAFETY: Same layout, trivially safe.
174+
let device_path = unsafe { mem::transmute(data) };
175+
Ok(BuiltDevicePath::Boxed(device_path))
176+
}
177+
}
150178
}
151179
}
152180

@@ -158,8 +186,23 @@ enum BuilderStorage<'a> {
158186
offset: usize,
159187
},
160188

189+
UefiHeap(PoolAllocation),
190+
191+
#[cfg(feature = "alloc")]
192+
Boxed(Vec<u8>),
193+
}
194+
195+
/// The device path that is build by [`DevicePathBuilder`].
196+
///
197+
/// This directly depends on [`BuilderStorage`].
198+
pub enum BuiltDevicePath<'a> {
199+
/// Returns a reference to the provided buffer ([`BuilderStorage::Boxed`]).
200+
Buf(&'a DevicePath),
201+
/// Owned value on the UEFI heap.
202+
UefiHeap(PoolDevicePath),
161203
#[cfg(feature = "alloc")]
162-
Vec(&'a mut Vec<u8>),
204+
/// Boxed value on the Rust heap a reference to the provided buffer ([`BuilderStorage::Boxed`]).
205+
Boxed(Box<DevicePath>),
163206
}
164207

165208
/// Error type used by [`DevicePathBuilder`].
@@ -254,7 +297,7 @@ mod tests {
254297
assert!(acpi::AdrSlice::new(&[]).is_none());
255298

256299
let mut v = Vec::new();
257-
let path = DevicePathBuilder::with_vec(&mut v)
300+
let path = DevicePathBuilder::with_rust_heap(&mut v)
258301
.push(&acpi::Adr {
259302
adr: acpi::AdrSlice::new(&[1, 2]).unwrap(),
260303
})?
@@ -282,7 +325,7 @@ mod tests {
282325
#[test]
283326
fn test_acpi_expanded() -> Result<(), BuildError> {
284327
let mut v = Vec::new();
285-
let path = DevicePathBuilder::with_vec(&mut v)
328+
let path = DevicePathBuilder::with_rust_heap(&mut v)
286329
.push(&acpi::Expanded {
287330
hid: 1,
288331
uid: 2,
@@ -334,7 +377,7 @@ mod tests {
334377
fn test_messaging_rest_service() -> Result<(), BuildError> {
335378
let mut v = Vec::new();
336379
let vendor_guid = guid!("a1005a90-6591-4596-9bab-1c4249a6d4ff");
337-
let path = DevicePathBuilder::with_vec(&mut v)
380+
let path = DevicePathBuilder::with_rust_heap(&mut v)
338381
.push(&messaging::RestService {
339382
service_type: RestServiceType::REDFISH,
340383
access_mode: RestServiceAccessMode::IN_BAND,
@@ -390,7 +433,7 @@ mod tests {
390433
fn test_build_with_packed_node() -> Result<(), BuildError> {
391434
// Build a path with both a statically-sized and DST nodes.
392435
let mut v = Vec::new();
393-
let path1 = DevicePathBuilder::with_vec(&mut v)
436+
let path1 = DevicePathBuilder::with_rust_heap(&mut v)
394437
.push(&acpi::Acpi {
395438
hid: 0x41d0_0a03,
396439
uid: 0x0000_0000,
@@ -404,7 +447,7 @@ mod tests {
404447
// Create a second path by copying in the packed nodes from the
405448
// first path.
406449
let mut v = Vec::new();
407-
let mut builder = DevicePathBuilder::with_vec(&mut v);
450+
let mut builder = DevicePathBuilder::with_rust_heap(&mut v);
408451
for node in path1.node_iter() {
409452
builder = builder.push(&node)?;
410453
}
@@ -492,7 +535,7 @@ mod tests {
492535
#[test]
493536
fn test_ipv4_configuration_example() -> Result<(), BuildError> {
494537
let mut v = Vec::new();
495-
let path = DevicePathBuilder::with_vec(&mut v)
538+
let path = DevicePathBuilder::with_rust_heap(&mut v)
496539
.push(&acpi::Acpi {
497540
hid: 0x41d0_0a03,
498541
uid: 0x0000_0000,

0 commit comments

Comments
 (0)