1212//! Failure to do so will turn subsequent allocation into undefined behaviour.
1313
1414use 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 } ;
1718
1819use crate :: proto:: loaded_image:: LoadedImage ;
1920use crate :: table:: boot:: { BootServices , MemoryType } ;
21+ use crate :: table:: { Boot , SystemTable } ;
2022
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.
2225///
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
2427/// 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 ( ) ) ;
2629
2730/// The memory type used for pool memory allocations.
28- /// TODO: Use OnceCell when stablilized.
2931static MEMORY_TYPE : AtomicU32 = AtomicU32 :: new ( MemoryType :: LOADER_DATA . 0 ) ;
3032
3133/// Initializes the allocator.
@@ -34,9 +36,10 @@ static MEMORY_TYPE: AtomicU32 = AtomicU32::new(MemoryType::LOADER_DATA.0);
3436///
3537/// This function is unsafe because you _must_ make sure that exit_boot_services
3638/// 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 ) ;
3941
42+ let boot_services = system_table. boot_services ( ) ;
4043 if let Ok ( loaded_image) =
4144 boot_services. open_protocol_exclusive :: < LoadedImage > ( boot_services. image_handle ( ) )
4245 {
@@ -45,17 +48,18 @@ pub unsafe fn init(boot_services: &BootServices) {
4548}
4649
4750/// 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 ( )
5056}
5157
5258/// Notify the allocator library that boot services are not safe to call anymore
5359///
5460/// You must arrange for this function to be called on exit from UEFI boot services
5561pub fn exit_boot_services ( ) {
56- unsafe {
57- BOOT_SERVICES = None ;
58- }
62+ SYSTEM_TABLE . store ( ptr:: null_mut ( ) , Ordering :: Release ) ;
5963}
6064
6165/// Allocator which uses the UEFI pool allocation functions.
@@ -73,19 +77,19 @@ unsafe impl GlobalAlloc for Allocator {
7377 let align = layout. align ( ) ;
7478 let memory_type = MemoryType ( MEMORY_TYPE . load ( Ordering :: Acquire ) ) ;
7579
80+ let boot_services = & * boot_services ( ) ;
81+
7682 if align > 8 {
7783 // The requested alignment is greater than 8, but `allocate_pool` is
7884 // only guaranteed to provide eight-byte alignment. Allocate extra
7985 // space so that we can return an appropriately-aligned pointer
8086 // 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+ } ;
8993
9094 // Calculate the offset needed to get an aligned pointer within the
9195 // full allocation. If that offset is zero, increase it to `align`
@@ -110,8 +114,7 @@ unsafe impl GlobalAlloc for Allocator {
110114 // The requested alignment is less than or equal to eight, and
111115 // `allocate_pool` always provides eight-byte alignment, so we can
112116 // use `allocate_pool` directly.
113- boot_services ( )
114- . as_ref ( )
117+ boot_services
115118 . allocate_pool ( memory_type, size)
116119 . unwrap_or ( ptr:: null_mut ( ) )
117120 }
@@ -124,7 +127,7 @@ unsafe impl GlobalAlloc for Allocator {
124127 // before the aligned allocation in `alloc`.
125128 ptr = ( ptr as * const * mut u8 ) . sub ( 1 ) . read ( ) ;
126129 }
127- boot_services ( ) . as_ref ( ) . free_pool ( ptr) . unwrap ( ) ;
130+ ( * boot_services ( ) ) . free_pool ( ptr) . unwrap ( ) ;
128131 }
129132}
130133
0 commit comments