Skip to content

Commit 9d64e76

Browse files
committed
uefi: allocate_pool() now returns NonNull<[u8]>
This aligns the signature with the Rust allocator API.
1 parent c5d594e commit 9d64e76

File tree

6 files changed

+74
-20
lines changed

6 files changed

+74
-20
lines changed

uefi-test-runner/src/boot/memory.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,17 @@ fn test_allocate_pages() {
4343
}
4444

4545
fn test_allocate_pool() {
46-
let ptr = boot::allocate_pool(MemoryType::LOADER_DATA, 10).unwrap();
46+
let mut ptr = boot::allocate_pool(MemoryType::LOADER_DATA, 10).unwrap();
47+
let buffer = unsafe { ptr.as_mut() };
4748

4849
// Verify the allocation can be written to.
4950
{
50-
let ptr = ptr.as_ptr();
51-
unsafe { ptr.write_volatile(0xff) };
52-
unsafe { ptr.add(9).write_volatile(0xff) };
51+
buffer[0] = 0xff;
52+
buffer[9] = 0xff;
53+
assert_eq!(buffer[0], 0xff);
54+
assert_eq!(buffer[9], 0xff);
5355
}
54-
unsafe { boot::free_pool(ptr) }.unwrap();
56+
unsafe { boot::free_pool(ptr.cast()) }.unwrap();
5557
}
5658

5759
// Simple test to ensure our custom allocator works with the `alloc` crate.

uefi-test-runner/src/boot/misc.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,14 @@ fn test_install_configuration_table() {
222222
let initial_table_count = system::with_config_table(|t| t.len());
223223

224224
// Create the entry data.
225-
let config: NonNull<u8> = boot::allocate_pool(MemoryType::RUNTIME_SERVICES_DATA, 1).unwrap();
226-
unsafe { config.write(123u8) };
225+
let mut config_ptr = boot::allocate_pool(MemoryType::RUNTIME_SERVICES_DATA, 1).unwrap();
226+
let buffer = unsafe { config_ptr.as_mut() };
227+
buffer[0] = 123;
227228

228229
// Install the table.
229230
const TABLE_GUID: Guid = guid!("4bec53c4-5fc1-48a1-ab12-df214907d29f");
230231
unsafe {
231-
boot::install_configuration_table(&TABLE_GUID, config.as_ptr().cast()).unwrap();
232+
boot::install_configuration_table(&TABLE_GUID, config_ptr.as_ptr().cast()).unwrap();
232233
}
233234

234235
// Verify the installation.
@@ -244,6 +245,6 @@ fn test_install_configuration_table() {
244245
// Uninstall the table and free the memory.
245246
unsafe {
246247
boot::install_configuration_table(&TABLE_GUID, ptr::null()).unwrap();
247-
boot::free_pool(config).unwrap();
248+
boot::free_pool(config_ptr.cast()).unwrap();
248249
}
249250
}

uefi/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
- **Breaking**: `allocate_pages` now returns `NonNull<[u8]>` to align it with
2929
the Rust allocator API. There is an example in the documentation of that
3030
function.
31+
- **Breaking**: `allocate_pool` now returns `NonNull<[u8]>` to align it with
32+
the Rust allocator API. There is an example in the documentation of that
33+
function.
3134
- `boot::memory_map()` will never return `Status::BUFFER_TOO_SMALL` from now on,
3235
as this is considered a hard internal error where users can't do anything
3336
about it anyway. It will panic instead.

uefi/src/allocator.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@ unsafe impl GlobalAlloc for Allocator {
6868
// only guaranteed to provide eight-byte alignment. Allocate extra
6969
// space so that we can return an appropriately-aligned pointer
7070
// within the allocation.
71-
let full_alloc_ptr = if let Ok(ptr) = boot::allocate_pool(memory_type, size + align) {
72-
ptr.as_ptr()
73-
} else {
74-
return ptr::null_mut();
71+
let full_alloc_ptr = match boot::allocate_pool(memory_type, size + align) {
72+
Ok(ptr) => ptr.cast::<u8>().as_ptr(),
73+
Err(e) => {
74+
log::error!("Failed to allocate pool: {:?}", e);
75+
return ptr::null_mut();
76+
}
7577
};
7678

7779
// Calculate the offset needed to get an aligned pointer within the
@@ -100,7 +102,8 @@ unsafe impl GlobalAlloc for Allocator {
100102
// `allocate_pool` always provides eight-byte alignment, so we can
101103
// use `allocate_pool` directly.
102104
boot::allocate_pool(memory_type, size)
103-
.map(|ptr| ptr.as_ptr())
105+
.map(|mut ptr: NonNull<[u8]>| unsafe { ptr.as_mut() })
106+
.map(|ptr: &mut [u8]| ptr.as_mut_ptr())
104107
.unwrap_or(ptr::null_mut())
105108
}
106109
}

uefi/src/boot.rs

+50-5
Original file line numberDiff line numberDiff line change
@@ -231,22 +231,67 @@ pub unsafe fn free_pages(ptr: NonNull<u8>, count: usize) -> Result {
231231
unsafe { (bt.free_pages)(addr, count) }.to_result()
232232
}
233233

234-
/// Allocates from a memory pool. The pointer will be 8-byte aligned.
234+
/// Allocates a consecutive region of bytes using the UEFI allocator. The buffer
235+
/// will be 8-byte aligned.
236+
///
237+
/// The caller is responsible to free the memory using [`free_pool`].
238+
///
239+
/// # Arguments
240+
/// - `memory_type`: The [`MemoryType`] used to persist the allocation in the
241+
/// UEFI memory map. Typically, UEFI OS loaders should allocate memory of
242+
/// type [`MemoryType::LOADER_DATA`].
243+
///- `size`: Amount of bytes to allocate.
244+
///
245+
/// # Example
246+
///```rust,no_run
247+
/// use uefi::boot::{self, AllocateType};
248+
/// use uefi_raw::table::boot::MemoryType;
249+
///
250+
/// let mut ptr = boot::allocate_pool(
251+
/// MemoryType::LOADER_DATA,
252+
/// 42
253+
/// ).unwrap();
254+
///
255+
/// // ⚠️ Creating the reference is safe, but reading the uninitialized memory
256+
/// // causes Undefined Behavior (UB)! Please make sure to initialize the memory
257+
/// // first by:
258+
/// // - using `core::ptr::write`,
259+
/// // - directly writing to slice indices,
260+
/// // - zeroing the memory,
261+
/// // - using `.copy_from_slice()`,
262+
/// // - or a similar operation.
263+
/// let buffer: &mut [u8] = unsafe { ptr.as_mut() };
264+
/// // Now initialize the content of the buffer, cast it, etc.
265+
/// // Please follow Rust guidelines on safety and UB! ⚠️
266+
///
267+
/// // free the allocation
268+
/// unsafe { boot::free_pool(ptr.cast()) }.unwrap();
269+
/// ```
270+
///
271+
/// # Safety
272+
/// Using this function is safe but reading on initialized memory is not.
273+
/// Please look into the example code.
274+
///
235275
///
236276
/// # Errors
237277
///
238278
/// * [`Status::OUT_OF_RESOURCES`]: allocation failed.
239279
/// * [`Status::INVALID_PARAMETER`]: `mem_ty` is [`MemoryType::PERSISTENT_MEMORY`],
240280
/// [`MemoryType::UNACCEPTED`], or in the range [`MemoryType::MAX`]`..=0x6fff_ffff`.
241-
pub fn allocate_pool(mem_ty: MemoryType, size: usize) -> Result<NonNull<u8>> {
281+
pub fn allocate_pool(memory_type: MemoryType, size: usize) -> Result<NonNull<[u8]>> {
242282
let bt = boot_services_raw_panicking();
243283
let bt = unsafe { bt.as_ref() };
244284

245285
let mut buffer = ptr::null_mut();
246-
let ptr =
247-
unsafe { (bt.allocate_pool)(mem_ty, size, &mut buffer) }.to_result_with_val(|| buffer)?;
286+
let ptr = unsafe { (bt.allocate_pool)(memory_type, size, &mut buffer) }
287+
.to_result_with_val(|| buffer)?;
248288

249-
Ok(NonNull::new(ptr).expect("allocate_pool must not return a null pointer if successful"))
289+
if let Some(ptr) = NonNull::new(ptr) {
290+
let slice = NonNull::slice_from_raw_parts(ptr, size);
291+
Ok(slice)
292+
} else {
293+
Err(Status::OUT_OF_RESOURCES.into())
294+
}
250295
}
251296

252297
/// Frees memory allocated by [`allocate_pool`].

uefi/src/mem/memory_map/impl_.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ impl MemoryMapBackingMemory {
281281
pub(crate) fn new(memory_type: MemoryType) -> crate::Result<Self> {
282282
let memory_map_meta = boot::memory_map_size();
283283
let len = Self::safe_allocation_size_hint(memory_map_meta);
284-
let ptr = boot::allocate_pool(memory_type, len)?.as_ptr();
284+
let ptr = boot::allocate_pool(memory_type, len)?.cast::<u8>().as_ptr();
285285

286286
// Should be fine as UEFI always has allocations with a guaranteed
287287
// alignment of 8 bytes.

0 commit comments

Comments
 (0)