2
2
3
3
#![ unstable( feature = "uefi_std" , issue = "100499" ) ]
4
4
5
- use crate :: { cell:: Cell , ffi:: c_void, ptr:: NonNull } ;
5
+ use crate :: sync:: atomic:: { AtomicBool , AtomicPtr , Ordering } ;
6
+ use crate :: { ffi:: c_void, ptr:: NonNull } ;
6
7
7
- // Since UEFI is single-threaded, making the global variables thread local should be safe.
8
- thread_local ! {
9
- // Flag to check if BootServices are still valid.
10
- // Start with assuming that they are not available
11
- static BOOT_SERVICES_FLAG : Cell <bool > = Cell :: new( false ) ;
12
- // Position 0 = SystemTable
13
- // Position 1 = ImageHandle
14
- static GLOBALS : Cell <Option <( NonNull <c_void>, NonNull <c_void>) >> = Cell :: new( None ) ;
15
- }
8
+ static SYSTEM_TABLE : AtomicPtr < c_void > = AtomicPtr :: new ( crate :: ptr:: null_mut ( ) ) ;
9
+ static IMAGE_HANDLE : AtomicPtr < c_void > = AtomicPtr :: new ( crate :: ptr:: null_mut ( ) ) ;
10
+ // Flag to check if BootServices are still valid.
11
+ // Start with assuming that they are not available
12
+ static BOOT_SERVICES_FLAG : AtomicBool = AtomicBool :: new ( false ) ;
16
13
17
14
/// Initializes the global System Table and Image Handle pointers.
18
15
///
19
16
/// The standard library requires access to the UEFI System Table and the Application Image Handle
20
17
/// to operate. Those are provided to UEFI Applications via their application entry point. By
21
18
/// calling `init_globals()`, those pointers are retained by the standard library for future use.
19
+ /// Thus this function must be called before any of the standard library services are used.
20
+ ///
22
21
/// The pointers are never exposed to any entity outside of this application and it is guaranteed
23
22
/// that, once the application exited, these pointers are never dereferenced again.
24
23
///
25
24
/// Callers are required to ensure the pointers are valid for the entire lifetime of this
26
25
/// application. In particular, UEFI Boot Services must not be exited while an application with the
27
26
/// standard library is loaded.
28
27
///
29
- /// This function must not be called more than once.
30
- pub unsafe fn init_globals ( handle : NonNull < c_void > , system_table : NonNull < c_void > ) {
31
- GLOBALS . set ( Some ( ( system_table, handle) ) ) ;
28
+ /// # SAFETY
29
+ /// Calling this function more than once will panic
30
+ pub ( crate ) unsafe fn init_globals ( handle : NonNull < c_void > , system_table : NonNull < c_void > ) {
31
+ IMAGE_HANDLE
32
+ . compare_exchange (
33
+ crate :: ptr:: null_mut ( ) ,
34
+ handle. as_ptr ( ) ,
35
+ Ordering :: Release ,
36
+ Ordering :: Acquire ,
37
+ )
38
+ . unwrap ( ) ;
39
+ SYSTEM_TABLE
40
+ . compare_exchange (
41
+ crate :: ptr:: null_mut ( ) ,
42
+ system_table. as_ptr ( ) ,
43
+ Ordering :: Release ,
44
+ Ordering :: Acquire ,
45
+ )
46
+ . unwrap ( ) ;
47
+ BOOT_SERVICES_FLAG . store ( true , Ordering :: Release )
32
48
}
33
49
34
50
/// Get the SystemTable Pointer.
@@ -50,7 +66,7 @@ pub fn image_handle() -> NonNull<c_void> {
50
66
/// Get the BootServices Pointer.
51
67
/// This function also checks if `ExitBootServices` has already been called.
52
68
pub fn boot_services ( ) -> Option < NonNull < c_void > > {
53
- if BOOT_SERVICES_FLAG . get ( ) {
69
+ if BOOT_SERVICES_FLAG . load ( Ordering :: Acquire ) {
54
70
let system_table: NonNull < r_efi:: efi:: SystemTable > = try_system_table ( ) ?. cast ( ) ;
55
71
let boot_services = unsafe { ( * system_table. as_ptr ( ) ) . boot_services } ;
56
72
NonNull :: new ( boot_services) . map ( |x| x. cast ( ) )
@@ -62,19 +78,15 @@ pub fn boot_services() -> Option<NonNull<c_void>> {
62
78
/// Get the SystemTable Pointer.
63
79
/// This function is mostly intended for places where panic is not an option
64
80
pub ( crate ) fn try_system_table ( ) -> Option < NonNull < c_void > > {
65
- GLOBALS . get ( ) . map ( |x| x . 0 )
81
+ NonNull :: new ( SYSTEM_TABLE . load ( Ordering :: Acquire ) )
66
82
}
67
83
68
84
/// Get the SystemHandle Pointer.
69
85
/// This function is mostly intended for places where panicking is not an option
70
86
pub ( crate ) fn try_image_handle ( ) -> Option < NonNull < c_void > > {
71
- GLOBALS . get ( ) . map ( |x| x. 1 )
72
- }
73
-
74
- pub ( crate ) fn enable_boot_services ( ) {
75
- BOOT_SERVICES_FLAG . set ( true ) ;
87
+ NonNull :: new ( IMAGE_HANDLE . load ( Ordering :: Acquire ) )
76
88
}
77
89
78
90
pub ( crate ) fn disable_boot_services ( ) {
79
- BOOT_SERVICES_FLAG . set ( false ) ;
91
+ BOOT_SERVICES_FLAG . store ( false , Ordering :: Release )
80
92
}
0 commit comments