12
12
//! Failure to do so will turn subsequent allocation into undefined behaviour.
13
13
14
14
use core:: alloc:: { GlobalAlloc , Layout } ;
15
- use core:: ptr:: { self , NonNull } ;
16
- use core:: sync:: atomic:: { AtomicU32 , Ordering } ;
15
+ use core:: ffi:: c_void;
16
+ use core:: ptr;
17
+ use core:: sync:: atomic:: { AtomicPtr , AtomicU32 , Ordering } ;
17
18
18
19
use crate :: proto:: loaded_image:: LoadedImage ;
19
20
use crate :: table:: boot:: { BootServices , MemoryType } ;
21
+ use crate :: table:: { Boot , SystemTable } ;
20
22
21
- /// 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.
22
25
///
23
- /// 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
24
27
/// exited by the host application yet.
25
- static mut BOOT_SERVICES : Option < NonNull < BootServices > > = None ;
28
+ static SYSTEM_TABLE : AtomicPtr < c_void > = AtomicPtr :: new ( ptr :: null_mut ( ) ) ;
26
29
27
30
/// The memory type used for pool memory allocations.
28
- /// TODO: Use OnceCell when stablilized.
29
31
static MEMORY_TYPE : AtomicU32 = AtomicU32 :: new ( MemoryType :: LOADER_DATA . 0 ) ;
30
32
31
33
/// Initializes the allocator.
@@ -34,9 +36,10 @@ static MEMORY_TYPE: AtomicU32 = AtomicU32::new(MemoryType::LOADER_DATA.0);
34
36
///
35
37
/// This function is unsafe because you _must_ make sure that exit_boot_services
36
38
/// will be called when UEFI boot services will be exited.
37
- pub unsafe fn init ( boot_services : & BootServices ) {
38
- 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 ) ;
39
41
42
+ let boot_services = system_table. boot_services ( ) ;
40
43
if let Ok ( loaded_image) =
41
44
boot_services. open_protocol_exclusive :: < LoadedImage > ( boot_services. image_handle ( ) )
42
45
{
@@ -45,17 +48,18 @@ pub unsafe fn init(boot_services: &BootServices) {
45
48
}
46
49
47
50
/// Access the boot services
48
- fn boot_services ( ) -> NonNull < BootServices > {
49
- 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 ( )
50
56
}
51
57
52
58
/// Notify the allocator library that boot services are not safe to call anymore
53
59
///
54
60
/// You must arrange for this function to be called on exit from UEFI boot services
55
61
pub fn exit_boot_services ( ) {
56
- unsafe {
57
- BOOT_SERVICES = None ;
58
- }
62
+ SYSTEM_TABLE . store ( ptr:: null_mut ( ) , Ordering :: Release ) ;
59
63
}
60
64
61
65
/// Allocator which uses the UEFI pool allocation functions.
@@ -73,19 +77,19 @@ unsafe impl GlobalAlloc for Allocator {
73
77
let align = layout. align ( ) ;
74
78
let memory_type = MemoryType ( MEMORY_TYPE . load ( Ordering :: Acquire ) ) ;
75
79
80
+ let boot_services = & * boot_services ( ) ;
81
+
76
82
if align > 8 {
77
83
// The requested alignment is greater than 8, but `allocate_pool` is
78
84
// only guaranteed to provide eight-byte alignment. Allocate extra
79
85
// space so that we can return an appropriately-aligned pointer
80
86
// within the allocation.
81
- let full_alloc_ptr = if let Ok ( ptr) = boot_services ( )
82
- . as_ref ( )
83
- . allocate_pool ( memory_type, size + align)
84
- {
85
- ptr
86
- } else {
87
- return ptr:: null_mut ( ) ;
88
- } ;
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
+ } ;
89
93
90
94
// Calculate the offset needed to get an aligned pointer within the
91
95
// full allocation. If that offset is zero, increase it to `align`
@@ -110,8 +114,7 @@ unsafe impl GlobalAlloc for Allocator {
110
114
// The requested alignment is less than or equal to eight, and
111
115
// `allocate_pool` always provides eight-byte alignment, so we can
112
116
// use `allocate_pool` directly.
113
- boot_services ( )
114
- . as_ref ( )
117
+ boot_services
115
118
. allocate_pool ( memory_type, size)
116
119
. unwrap_or ( ptr:: null_mut ( ) )
117
120
}
@@ -124,7 +127,7 @@ unsafe impl GlobalAlloc for Allocator {
124
127
// before the aligned allocation in `alloc`.
125
128
ptr = ( ptr as * const * mut u8 ) . sub ( 1 ) . read ( ) ;
126
129
}
127
- boot_services ( ) . as_ref ( ) . free_pool ( ptr) . unwrap ( ) ;
130
+ ( * boot_services ( ) ) . free_pool ( ptr) . unwrap ( ) ;
128
131
}
129
132
}
130
133
0 commit comments