Skip to content

Commit 39fee66

Browse files
uefi: Improve clarity of global_allocator
Add more comments and rename some variables.
1 parent 438be09 commit 39fee66

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

uefi/src/global_allocator.rs

+35-13
Original file line numberDiff line numberDiff line change
@@ -52,38 +52,60 @@ pub fn exit_boot_services() {
5252
pub struct Allocator;
5353

5454
unsafe impl GlobalAlloc for Allocator {
55+
/// Allocate memory using [`BootServices::allocate_pool`]. The allocation is
56+
/// of type [`MemoryType::LOADER_DATA`].
5557
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
5658
let mem_ty = MemoryType::LOADER_DATA;
5759
let size = layout.size();
5860
let align = layout.align();
5961

6062
if align > 8 {
61-
// allocate more space for alignment
62-
let ptr = if let Ok(ptr) = boot_services().as_ref().allocate_pool(mem_ty, size + align)
63-
{
64-
ptr
65-
} else {
66-
return ptr::null_mut();
67-
};
68-
// calculate align offset
69-
let mut offset = ptr.align_offset(align);
63+
// The requested alignment is greater than 8, but `allocate_pool` is
64+
// only guaranteed to provide eight-byte alignment. Allocate extra
65+
// space so that we can return an appropriately-aligned pointer
66+
// within the allocation.
67+
let full_alloc_ptr =
68+
if let Ok(ptr) = boot_services().as_ref().allocate_pool(mem_ty, size + align) {
69+
ptr
70+
} else {
71+
return ptr::null_mut();
72+
};
73+
74+
// Calculate the offset needed to get an aligned pointer within the
75+
// full allocation. If that offset is zero, increase it to `align`
76+
// so that we still have space to store the extra pointer described
77+
// below.
78+
let mut offset = full_alloc_ptr.align_offset(align);
7079
if offset == 0 {
7180
offset = align;
7281
}
73-
let return_ptr = ptr.add(offset);
74-
// store allocated pointer before the struct
75-
(return_ptr.cast::<*mut u8>()).sub(1).write(ptr);
76-
return_ptr
82+
83+
// Before returning the aligned allocation, store a pointer to the
84+
// full unaligned allocation in the bytes just before the aligned
85+
// allocation. We know we have at least eight bytes there due to
86+
// adding `align` to the memory allocation size. We also know the
87+
// write is appropriately aligned for a `*mut u8` pointer because
88+
// `align_ptr` is aligned, and alignments are always powers of two
89+
// (as enforced by the `Layout` type).
90+
let aligned_ptr = full_alloc_ptr.add(offset);
91+
(aligned_ptr.cast::<*mut u8>()).sub(1).write(full_alloc_ptr);
92+
aligned_ptr
7793
} else {
94+
// The requested alignment is less than or equal to eight, and
95+
// `allocate_pool` always provides eight-byte alignment, so we can
96+
// use `allocate_pool` directly.
7897
boot_services()
7998
.as_ref()
8099
.allocate_pool(mem_ty, size)
81100
.unwrap_or(ptr::null_mut())
82101
}
83102
}
84103

104+
/// Deallocate memory using [`BootServices::free_pool`].
85105
unsafe fn dealloc(&self, mut ptr: *mut u8, layout: Layout) {
86106
if layout.align() > 8 {
107+
// Retrieve the pointer to the full allocation that was packed right
108+
// before the aligned allocation in `alloc`.
87109
ptr = (ptr as *const *mut u8).sub(1).read();
88110
}
89111
boot_services().as_ref().free_pool(ptr).unwrap();

0 commit comments

Comments
 (0)