Skip to content

Commit 47635fe

Browse files
authored
Merge pull request #977 from nicholasbishop/bishop-atomic-system-table
uefi-services: Change SYSTEM_TABLE to an atomic pointer
2 parents 166716f + df454f9 commit 47635fe

File tree

3 files changed

+36
-26
lines changed

3 files changed

+36
-26
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Added
66
- Implemented `Index`, `IndexMut`, `get`, and `get_mut` on `MemoryMap`.
7+
- Added `SystemTable::as_ptr`.
78

89
### Changed
910
- We fixed a memory leak in `GraphicsOutput::query_mode`. As a consequence, we

uefi-services/src/lib.rs

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ extern crate uefi;
3636

3737
use core::ffi::c_void;
3838
use core::fmt::Write;
39-
use core::ptr::NonNull;
39+
use core::ptr::{self, NonNull};
40+
use core::sync::atomic::{AtomicPtr, Ordering};
4041

4142
use cfg_if::cfg_if;
4243

@@ -50,12 +51,24 @@ use uefi::{Event, Result};
5051
/// This table is only fully safe to use until UEFI boot services have been exited.
5152
/// After that, some fields and methods are unsafe to use, see the documentation of
5253
/// UEFI's ExitBootServices entry point for more details.
53-
static mut SYSTEM_TABLE: Option<SystemTable<Boot>> = None;
54+
static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
5455

5556
/// Global logger object
5657
#[cfg(feature = "logger")]
5758
static mut LOGGER: Option<uefi::logger::Logger> = None;
5859

60+
#[must_use]
61+
fn system_table_opt() -> Option<SystemTable<Boot>> {
62+
let ptr = SYSTEM_TABLE.load(Ordering::Acquire);
63+
// Safety: the `SYSTEM_TABLE` pointer either be null or a valid system
64+
// table.
65+
//
66+
// Null is the initial value, as well as the value set when exiting boot
67+
// services. Otherwise, the value is set by the call to `init`, which
68+
// requires a valid system table reference as input.
69+
unsafe { SystemTable::from_ptr(ptr) }
70+
}
71+
5972
/// Obtains a pointer to the system table.
6073
///
6174
/// This is meant to be used by higher-level libraries,
@@ -66,28 +79,23 @@ static mut LOGGER: Option<uefi::logger::Logger> = None;
6679
/// The returned pointer is only valid until boot services are exited.
6780
#[must_use]
6881
pub fn system_table() -> SystemTable<Boot> {
69-
unsafe {
70-
let table_ref = SYSTEM_TABLE
71-
.as_ref()
72-
.expect("The system table handle is not available");
73-
table_ref.unsafe_clone()
74-
}
82+
system_table_opt().expect("The system table handle is not available")
7583
}
7684

7785
/// Initialize the UEFI utility library.
7886
///
7987
/// This must be called as early as possible,
8088
/// before trying to use logging or memory allocation capabilities.
8189
pub fn init(st: &mut SystemTable<Boot>) -> Result<Option<Event>> {
82-
unsafe {
90+
if system_table_opt().is_some() {
8391
// Avoid double initialization.
84-
if SYSTEM_TABLE.is_some() {
85-
return Status::SUCCESS.to_result_with_val(|| None);
86-
}
92+
return Status::SUCCESS.to_result_with_val(|| None);
93+
}
8794

88-
// Setup the system table singleton
89-
SYSTEM_TABLE = Some(st.unsafe_clone());
95+
// Setup the system table singleton
96+
SYSTEM_TABLE.store(st.as_ptr().cast_mut(), Ordering::Release);
9097

98+
unsafe {
9199
// Setup logging and memory allocation
92100

93101
#[cfg(feature = "logger")]
@@ -111,15 +119,10 @@ pub fn init(st: &mut SystemTable<Boot>) -> Result<Option<Event>> {
111119
// Internal function for print macros.
112120
#[doc(hidden)]
113121
pub fn _print(args: core::fmt::Arguments) {
114-
unsafe {
115-
let st = SYSTEM_TABLE
116-
.as_mut()
117-
.expect("The system table handle is not available");
118-
119-
st.stdout()
120-
.write_fmt(args)
121-
.expect("Failed to write to stdout");
122-
}
122+
system_table()
123+
.stdout()
124+
.write_fmt(args)
125+
.expect("Failed to write to stdout");
123126
}
124127

125128
/// Prints to the standard output.
@@ -185,7 +188,7 @@ unsafe extern "efiapi" fn exit_boot_services(_e: Event, _ctx: Option<NonNull<c_v
185188
// check that the callback does get called.
186189
//
187190
// info!("Shutting down the UEFI utility library");
188-
SYSTEM_TABLE = None;
191+
SYSTEM_TABLE.store(ptr::null_mut(), Ordering::Release);
189192

190193
#[cfg(feature = "logger")]
191194
if let Some(ref mut logger) = LOGGER {
@@ -201,7 +204,7 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
201204
println!("[PANIC]: {}", info);
202205

203206
// Give the user some time to read the message
204-
if let Some(st) = unsafe { SYSTEM_TABLE.as_ref() } {
207+
if let Some(st) = system_table_opt() {
205208
st.boot_services().stall(10_000_000);
206209
} else {
207210
let mut dummy = 0u64;
@@ -222,7 +225,7 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
222225
qemu_exit_handle.exit_failure();
223226
} else {
224227
// If the system table is available, use UEFI's standard shutdown mechanism
225-
if let Some(st) = unsafe { SYSTEM_TABLE.as_ref() } {
228+
if let Some(st) = system_table_opt() {
226229
use uefi::table::runtime::ResetType;
227230
st.runtime_services()
228231
.reset(ResetType::SHUTDOWN, uefi::Status::ABORTED, None);

uefi/src/table/system.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ impl<View: SystemTableView> SystemTable<View> {
113113
_marker: PhantomData,
114114
})
115115
}
116+
117+
/// Get the underlying raw pointer.
118+
#[must_use]
119+
pub fn as_ptr(&self) -> *const c_void {
120+
self.table.cast()
121+
}
116122
}
117123

118124
// These parts of the UEFI System Table interface may only be used until boot

0 commit comments

Comments
 (0)