Skip to content

Commit 23a9f1b

Browse files
authored
Merge pull request rust-osdev#979 from nicholasbishop/bishop-atomic-allocator
uefi: Use atomics instead of `static mut` in allocator
2 parents 6e3b06c + ab8109e commit 23a9f1b

File tree

3 files changed

+35
-28
lines changed

3 files changed

+35
-28
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
- `Logger` no longer requires exterior mutability. `Logger::new` is now `const`,
1515
takes no arguments, and creates the logger in a disabled state. Call
1616
`Logger::set_output` to enable it.
17+
- `uefi::allocator::init` now takes a `&mut SystemTable<Boot>` instead of
18+
`&BootServices`.
1719

1820
## uefi-macros - [Unreleased]
1921

uefi-services/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ pub fn init(st: &mut SystemTable<Boot>) -> Result<Option<Event>> {
101101
#[cfg(feature = "logger")]
102102
init_logger(st);
103103

104-
let boot_services = st.boot_services();
105-
uefi::allocator::init(boot_services);
104+
uefi::allocator::init(st);
106105

107106
// Schedule these tools to be disabled on exit from UEFI boot services
107+
let boot_services = st.boot_services();
108108
boot_services
109109
.create_event(
110110
EventType::SIGNAL_EXIT_BOOT_SERVICES,

uefi/src/allocator.rs

+31-26
Original file line numberDiff line numberDiff line change
@@ -12,49 +12,54 @@
1212
//! Failure to do so will turn subsequent allocation into undefined behaviour.
1313
1414
use core::alloc::{GlobalAlloc, Layout};
15-
use core::ptr::{self, NonNull};
15+
use core::ffi::c_void;
16+
use core::ptr;
17+
use core::sync::atomic::{AtomicPtr, AtomicU32, Ordering};
1618

1719
use crate::proto::loaded_image::LoadedImage;
1820
use crate::table::boot::{BootServices, MemoryType};
21+
use crate::table::{Boot, SystemTable};
1922

20-
/// Reference to the boot services table, used to call the pool memory allocation functions.
23+
/// Reference to the system table, used to call the boot services pool memory
24+
/// allocation functions.
2125
///
22-
/// The inner pointer is only safe to dereference if UEFI boot services have not been
26+
/// The pointer is only safe to dereference if UEFI boot services have not been
2327
/// exited by the host application yet.
24-
static mut BOOT_SERVICES: Option<NonNull<BootServices>> = None;
28+
static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
2529

2630
/// The memory type used for pool memory allocations.
27-
/// TODO: Use OnceCell when stablilized.
28-
static mut MEMORY_TYPE: MemoryType = MemoryType::LOADER_DATA;
31+
static MEMORY_TYPE: AtomicU32 = AtomicU32::new(MemoryType::LOADER_DATA.0);
2932

3033
/// Initializes the allocator.
3134
///
3235
/// # Safety
3336
///
3437
/// This function is unsafe because you _must_ make sure that exit_boot_services
3538
/// will be called when UEFI boot services will be exited.
36-
pub unsafe fn init(boot_services: &BootServices) {
37-
BOOT_SERVICES = NonNull::new(boot_services as *const _ as *mut _);
39+
pub unsafe fn init(system_table: &mut SystemTable<Boot>) {
40+
SYSTEM_TABLE.store(system_table.as_ptr().cast_mut(), Ordering::Release);
3841

42+
let boot_services = system_table.boot_services();
3943
if let Ok(loaded_image) =
4044
boot_services.open_protocol_exclusive::<LoadedImage>(boot_services.image_handle())
4145
{
42-
MEMORY_TYPE = loaded_image.data_type()
46+
MEMORY_TYPE.store(loaded_image.data_type().0, Ordering::Release);
4347
}
4448
}
4549

4650
/// Access the boot services
47-
fn boot_services() -> NonNull<BootServices> {
48-
unsafe { BOOT_SERVICES.expect("Boot services are unavailable or have been exited") }
51+
fn boot_services() -> *const BootServices {
52+
let ptr = SYSTEM_TABLE.load(Ordering::Acquire);
53+
let system_table =
54+
unsafe { SystemTable::from_ptr(ptr) }.expect("The system table handle is not available");
55+
system_table.boot_services()
4956
}
5057

5158
/// Notify the allocator library that boot services are not safe to call anymore
5259
///
5360
/// You must arrange for this function to be called on exit from UEFI boot services
5461
pub fn exit_boot_services() {
55-
unsafe {
56-
BOOT_SERVICES = None;
57-
}
62+
SYSTEM_TABLE.store(ptr::null_mut(), Ordering::Release);
5863
}
5964

6065
/// Allocator which uses the UEFI pool allocation functions.
@@ -70,20 +75,21 @@ unsafe impl GlobalAlloc for Allocator {
7075
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
7176
let size = layout.size();
7277
let align = layout.align();
78+
let memory_type = MemoryType(MEMORY_TYPE.load(Ordering::Acquire));
79+
80+
let boot_services = &*boot_services();
7381

7482
if align > 8 {
7583
// The requested alignment is greater than 8, but `allocate_pool` is
7684
// only guaranteed to provide eight-byte alignment. Allocate extra
7785
// space so that we can return an appropriately-aligned pointer
7886
// within the allocation.
79-
let full_alloc_ptr = if let Ok(ptr) = boot_services()
80-
.as_ref()
81-
.allocate_pool(MEMORY_TYPE, size + align)
82-
{
83-
ptr
84-
} else {
85-
return ptr::null_mut();
86-
};
87+
let full_alloc_ptr =
88+
if let Ok(ptr) = boot_services.allocate_pool(memory_type, size + align) {
89+
ptr
90+
} else {
91+
return ptr::null_mut();
92+
};
8793

8894
// Calculate the offset needed to get an aligned pointer within the
8995
// full allocation. If that offset is zero, increase it to `align`
@@ -108,9 +114,8 @@ unsafe impl GlobalAlloc for Allocator {
108114
// The requested alignment is less than or equal to eight, and
109115
// `allocate_pool` always provides eight-byte alignment, so we can
110116
// use `allocate_pool` directly.
111-
boot_services()
112-
.as_ref()
113-
.allocate_pool(MEMORY_TYPE, size)
117+
boot_services
118+
.allocate_pool(memory_type, size)
114119
.unwrap_or(ptr::null_mut())
115120
}
116121
}
@@ -122,7 +127,7 @@ unsafe impl GlobalAlloc for Allocator {
122127
// before the aligned allocation in `alloc`.
123128
ptr = (ptr as *const *mut u8).sub(1).read();
124129
}
125-
boot_services().as_ref().free_pool(ptr).unwrap();
130+
(*boot_services()).free_pool(ptr).unwrap();
126131
}
127132
}
128133

0 commit comments

Comments
 (0)