@@ -36,7 +36,8 @@ extern crate uefi;
36
36
37
37
use core:: ffi:: c_void;
38
38
use core:: fmt:: Write ;
39
- use core:: ptr:: NonNull ;
39
+ use core:: ptr:: { self , NonNull } ;
40
+ use core:: sync:: atomic:: { AtomicPtr , Ordering } ;
40
41
41
42
use cfg_if:: cfg_if;
42
43
@@ -50,12 +51,24 @@ use uefi::{Event, Result};
50
51
/// This table is only fully safe to use until UEFI boot services have been exited.
51
52
/// After that, some fields and methods are unsafe to use, see the documentation of
52
53
/// 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 ( ) ) ;
54
55
55
56
/// Global logger object
56
57
#[ cfg( feature = "logger" ) ]
57
58
static mut LOGGER : Option < uefi:: logger:: Logger > = None ;
58
59
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
+
59
72
/// Obtains a pointer to the system table.
60
73
///
61
74
/// This is meant to be used by higher-level libraries,
@@ -66,28 +79,23 @@ static mut LOGGER: Option<uefi::logger::Logger> = None;
66
79
/// The returned pointer is only valid until boot services are exited.
67
80
#[ must_use]
68
81
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" )
75
83
}
76
84
77
85
/// Initialize the UEFI utility library.
78
86
///
79
87
/// This must be called as early as possible,
80
88
/// before trying to use logging or memory allocation capabilities.
81
89
pub fn init ( st : & mut SystemTable < Boot > ) -> Result < Option < Event > > {
82
- unsafe {
90
+ if system_table_opt ( ) . is_some ( ) {
83
91
// 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
+ }
87
94
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 ) ;
90
97
98
+ unsafe {
91
99
// Setup logging and memory allocation
92
100
93
101
#[ cfg( feature = "logger" ) ]
@@ -111,15 +119,10 @@ pub fn init(st: &mut SystemTable<Boot>) -> Result<Option<Event>> {
111
119
// Internal function for print macros.
112
120
#[ doc( hidden) ]
113
121
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" ) ;
123
126
}
124
127
125
128
/// Prints to the standard output.
@@ -185,7 +188,7 @@ unsafe extern "efiapi" fn exit_boot_services(_e: Event, _ctx: Option<NonNull<c_v
185
188
// check that the callback does get called.
186
189
//
187
190
// info!("Shutting down the UEFI utility library");
188
- SYSTEM_TABLE = None ;
191
+ SYSTEM_TABLE . store ( ptr :: null_mut ( ) , Ordering :: Release ) ;
189
192
190
193
#[ cfg( feature = "logger" ) ]
191
194
if let Some ( ref mut logger) = LOGGER {
@@ -201,7 +204,7 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
201
204
println ! ( "[PANIC]: {}" , info) ;
202
205
203
206
// 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 ( ) {
205
208
st. boot_services ( ) . stall ( 10_000_000 ) ;
206
209
} else {
207
210
let mut dummy = 0u64 ;
@@ -222,7 +225,7 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
222
225
qemu_exit_handle. exit_failure( ) ;
223
226
} else {
224
227
// 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 ( ) {
226
229
use uefi:: table:: runtime:: ResetType ;
227
230
st. runtime_services( )
228
231
. reset( ResetType :: SHUTDOWN , uefi:: Status :: ABORTED , None ) ;
0 commit comments