1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2023, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker
15*5225e6b1SAndroid Build Coastguard Worker use crate::{EfiEntry, RuntimeServices};
16*5225e6b1SAndroid Build Coastguard Worker use efi_types::EFI_MEMORY_TYPE_LOADER_DATA;
17*5225e6b1SAndroid Build Coastguard Worker
18*5225e6b1SAndroid Build Coastguard Worker use core::mem::size_of_val;
19*5225e6b1SAndroid Build Coastguard Worker use core::ptr::null_mut;
20*5225e6b1SAndroid Build Coastguard Worker use core::{
21*5225e6b1SAndroid Build Coastguard Worker alloc::{GlobalAlloc, Layout},
22*5225e6b1SAndroid Build Coastguard Worker fmt::Write,
23*5225e6b1SAndroid Build Coastguard Worker };
24*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result};
25*5225e6b1SAndroid Build Coastguard Worker use safemath::SafeNum;
26*5225e6b1SAndroid Build Coastguard Worker
27*5225e6b1SAndroid Build Coastguard Worker /// Implements a global allocator using `EFI_BOOT_SERVICES.AllocatePool()/FreePool()`
28*5225e6b1SAndroid Build Coastguard Worker ///
29*5225e6b1SAndroid Build Coastguard Worker /// To use, add this exact declaration to the application code:
30*5225e6b1SAndroid Build Coastguard Worker ///
31*5225e6b1SAndroid Build Coastguard Worker /// ```
32*5225e6b1SAndroid Build Coastguard Worker /// #[no_mangle]
33*5225e6b1SAndroid Build Coastguard Worker /// #[global_allocator]
34*5225e6b1SAndroid Build Coastguard Worker /// static mut EFI_GLOBAL_ALLOCATOR: EfiAllocator = EfiState::new();
35*5225e6b1SAndroid Build Coastguard Worker /// ```
36*5225e6b1SAndroid Build Coastguard Worker ///
37*5225e6b1SAndroid Build Coastguard Worker /// This is only useful for real UEFI applications; attempting to install the `EFI_GLOBAL_ALLOCATOR`
38*5225e6b1SAndroid Build Coastguard Worker /// for host-side unit tests will cause the test to panic immediately.
39*5225e6b1SAndroid Build Coastguard Worker pub struct EfiAllocator {
40*5225e6b1SAndroid Build Coastguard Worker state: EfiState,
41*5225e6b1SAndroid Build Coastguard Worker runtime_services: Option<RuntimeServices>,
42*5225e6b1SAndroid Build Coastguard Worker }
43*5225e6b1SAndroid Build Coastguard Worker
44*5225e6b1SAndroid Build Coastguard Worker /// Represents the global EFI state.
45*5225e6b1SAndroid Build Coastguard Worker enum EfiState {
46*5225e6b1SAndroid Build Coastguard Worker /// Initial state, no UEFI entry point has been set, global hooks will not work.
47*5225e6b1SAndroid Build Coastguard Worker Uninitialized,
48*5225e6b1SAndroid Build Coastguard Worker /// [EfiEntry] is registered, global hooks are active.
49*5225e6b1SAndroid Build Coastguard Worker Initialized(EfiEntry),
50*5225e6b1SAndroid Build Coastguard Worker /// ExitBootServices has been called, global hooks will not work.
51*5225e6b1SAndroid Build Coastguard Worker Exited,
52*5225e6b1SAndroid Build Coastguard Worker }
53*5225e6b1SAndroid Build Coastguard Worker
54*5225e6b1SAndroid Build Coastguard Worker impl EfiState {
55*5225e6b1SAndroid Build Coastguard Worker /// Returns a reference to the EfiEntry.
efi_entry(&self) -> Option<&EfiEntry>56*5225e6b1SAndroid Build Coastguard Worker fn efi_entry(&self) -> Option<&EfiEntry> {
57*5225e6b1SAndroid Build Coastguard Worker match self {
58*5225e6b1SAndroid Build Coastguard Worker EfiState::Initialized(ref entry) => Some(entry),
59*5225e6b1SAndroid Build Coastguard Worker _ => None,
60*5225e6b1SAndroid Build Coastguard Worker }
61*5225e6b1SAndroid Build Coastguard Worker }
62*5225e6b1SAndroid Build Coastguard Worker }
63*5225e6b1SAndroid Build Coastguard Worker
64*5225e6b1SAndroid Build Coastguard Worker // This is a bit ugly, but we only expect this library to be used by our EFI application so it
65*5225e6b1SAndroid Build Coastguard Worker // doesn't need to be super clean or scalable. The user has to declare the global variable
66*5225e6b1SAndroid Build Coastguard Worker // exactly as written in the [EfiAllocator] docs for this to link properly.
67*5225e6b1SAndroid Build Coastguard Worker extern "Rust" {
68*5225e6b1SAndroid Build Coastguard Worker static mut EFI_GLOBAL_ALLOCATOR: EfiAllocator;
69*5225e6b1SAndroid Build Coastguard Worker }
70*5225e6b1SAndroid Build Coastguard Worker
71*5225e6b1SAndroid Build Coastguard Worker /// An internal API to obtain library internal global EfiEntry and RuntimeServices.
internal_efi_entry_and_rt( ) -> (Option<&'static EfiEntry>, Option<&'static RuntimeServices>)72*5225e6b1SAndroid Build Coastguard Worker pub(crate) fn internal_efi_entry_and_rt(
73*5225e6b1SAndroid Build Coastguard Worker ) -> (Option<&'static EfiEntry>, Option<&'static RuntimeServices>) {
74*5225e6b1SAndroid Build Coastguard Worker // SAFETY:
75*5225e6b1SAndroid Build Coastguard Worker // EFI_GLOBAL_ALLOCATOR is only read by `internal_efi_entry_and_rt()` and modified by
76*5225e6b1SAndroid Build Coastguard Worker // `init_efi_global_alloc()` and `exit_efi_global_alloc()`. The safety requirements of
77*5225e6b1SAndroid Build Coastguard Worker // `init_efi_global_alloc()` and `exit_efi_global_alloc()` mandate that there can be no EFI
78*5225e6b1SAndroid Build Coastguard Worker // event/notification/interrupt that can be triggered when they are called. This suggests that
79*5225e6b1SAndroid Build Coastguard Worker // there cannot be concurrent read and modification on `EFI_GLOBAL_ALLOCATOR` possible. Thus its
80*5225e6b1SAndroid Build Coastguard Worker // access is safe from race condition.
81*5225e6b1SAndroid Build Coastguard Worker unsafe { EFI_GLOBAL_ALLOCATOR.get_efi_entry_and_rt() }
82*5225e6b1SAndroid Build Coastguard Worker }
83*5225e6b1SAndroid Build Coastguard Worker
84*5225e6b1SAndroid Build Coastguard Worker /// Try to print via `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL` in `EFI_SYSTEM_TABLE.ConOut`.
85*5225e6b1SAndroid Build Coastguard Worker ///
86*5225e6b1SAndroid Build Coastguard Worker /// Errors are ignored.
87*5225e6b1SAndroid Build Coastguard Worker #[macro_export]
88*5225e6b1SAndroid Build Coastguard Worker macro_rules! efi_try_print {
89*5225e6b1SAndroid Build Coastguard Worker ($( $x:expr ),* $(,)? ) => {
90*5225e6b1SAndroid Build Coastguard Worker {
91*5225e6b1SAndroid Build Coastguard Worker let _ = (|| -> Result<()> {
92*5225e6b1SAndroid Build Coastguard Worker if let Some(entry) = crate::allocation::internal_efi_entry_and_rt().0 {
93*5225e6b1SAndroid Build Coastguard Worker write!(entry.system_table_checked()?.con_out()?, $($x,)*)?;
94*5225e6b1SAndroid Build Coastguard Worker }
95*5225e6b1SAndroid Build Coastguard Worker Ok(())
96*5225e6b1SAndroid Build Coastguard Worker })();
97*5225e6b1SAndroid Build Coastguard Worker }
98*5225e6b1SAndroid Build Coastguard Worker };
99*5225e6b1SAndroid Build Coastguard Worker }
100*5225e6b1SAndroid Build Coastguard Worker
101*5225e6b1SAndroid Build Coastguard Worker /// Initializes global allocator.
102*5225e6b1SAndroid Build Coastguard Worker ///
103*5225e6b1SAndroid Build Coastguard Worker /// # Safety
104*5225e6b1SAndroid Build Coastguard Worker ///
105*5225e6b1SAndroid Build Coastguard Worker /// This function modifies global variable `EFI_GLOBAL_ALLOCATOR`. It should only be called when
106*5225e6b1SAndroid Build Coastguard Worker /// there is no event/notification function that can be triggered or modify it. Otherwise there
107*5225e6b1SAndroid Build Coastguard Worker /// is a risk of race condition.
init_efi_global_alloc(efi_entry: EfiEntry) -> Result<()>108*5225e6b1SAndroid Build Coastguard Worker pub(crate) unsafe fn init_efi_global_alloc(efi_entry: EfiEntry) -> Result<()> {
109*5225e6b1SAndroid Build Coastguard Worker // SAFETY: See SAFETY of `internal_efi_entry_and_rt()`
110*5225e6b1SAndroid Build Coastguard Worker unsafe {
111*5225e6b1SAndroid Build Coastguard Worker EFI_GLOBAL_ALLOCATOR.runtime_services =
112*5225e6b1SAndroid Build Coastguard Worker efi_entry.system_table_checked().and_then(|v| v.runtime_services_checked()).ok();
113*5225e6b1SAndroid Build Coastguard Worker match EFI_GLOBAL_ALLOCATOR.state {
114*5225e6b1SAndroid Build Coastguard Worker EfiState::Uninitialized => {
115*5225e6b1SAndroid Build Coastguard Worker EFI_GLOBAL_ALLOCATOR.state = EfiState::Initialized(efi_entry);
116*5225e6b1SAndroid Build Coastguard Worker Ok(())
117*5225e6b1SAndroid Build Coastguard Worker }
118*5225e6b1SAndroid Build Coastguard Worker _ => Err(Error::AlreadyStarted),
119*5225e6b1SAndroid Build Coastguard Worker }
120*5225e6b1SAndroid Build Coastguard Worker }
121*5225e6b1SAndroid Build Coastguard Worker }
122*5225e6b1SAndroid Build Coastguard Worker
123*5225e6b1SAndroid Build Coastguard Worker /// Internal API to invalidate global allocator after ExitBootService().
124*5225e6b1SAndroid Build Coastguard Worker ///
125*5225e6b1SAndroid Build Coastguard Worker /// # Safety
126*5225e6b1SAndroid Build Coastguard Worker ///
127*5225e6b1SAndroid Build Coastguard Worker /// This function modifies global variable `EFI_GLOBAL_ALLOCATOR`. It should only be called when
128*5225e6b1SAndroid Build Coastguard Worker /// there is no event/notification function that can be triggered or modify it. Otherwise there
129*5225e6b1SAndroid Build Coastguard Worker /// is a risk of race condition.
exit_efi_global_alloc()130*5225e6b1SAndroid Build Coastguard Worker pub(crate) unsafe fn exit_efi_global_alloc() {
131*5225e6b1SAndroid Build Coastguard Worker // SAFETY: See SAFETY of `internal_efi_entry_and_rt()`
132*5225e6b1SAndroid Build Coastguard Worker unsafe {
133*5225e6b1SAndroid Build Coastguard Worker EFI_GLOBAL_ALLOCATOR.state = EfiState::Exited;
134*5225e6b1SAndroid Build Coastguard Worker }
135*5225e6b1SAndroid Build Coastguard Worker }
136*5225e6b1SAndroid Build Coastguard Worker
137*5225e6b1SAndroid Build Coastguard Worker impl EfiAllocator {
138*5225e6b1SAndroid Build Coastguard Worker /// Creates a new instance.
new() -> Self139*5225e6b1SAndroid Build Coastguard Worker pub const fn new() -> Self {
140*5225e6b1SAndroid Build Coastguard Worker Self { state: EfiState::Uninitialized, runtime_services: None }
141*5225e6b1SAndroid Build Coastguard Worker }
142*5225e6b1SAndroid Build Coastguard Worker
143*5225e6b1SAndroid Build Coastguard Worker /// Gets EfiEntry and RuntimeServices
get_efi_entry_and_rt(&self) -> (Option<&EfiEntry>, Option<&RuntimeServices>)144*5225e6b1SAndroid Build Coastguard Worker fn get_efi_entry_and_rt(&self) -> (Option<&EfiEntry>, Option<&RuntimeServices>) {
145*5225e6b1SAndroid Build Coastguard Worker (self.state.efi_entry(), self.runtime_services.as_ref())
146*5225e6b1SAndroid Build Coastguard Worker }
147*5225e6b1SAndroid Build Coastguard Worker
148*5225e6b1SAndroid Build Coastguard Worker /// Allocate memory via EFI_BOOT_SERVICES.
allocate(&self, size: usize) -> *mut u8149*5225e6b1SAndroid Build Coastguard Worker fn allocate(&self, size: usize) -> *mut u8 {
150*5225e6b1SAndroid Build Coastguard Worker self.state
151*5225e6b1SAndroid Build Coastguard Worker .efi_entry()
152*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::InvalidState)
153*5225e6b1SAndroid Build Coastguard Worker .and_then(|v| v.system_table_checked())
154*5225e6b1SAndroid Build Coastguard Worker .and_then(|v| v.boot_services_checked())
155*5225e6b1SAndroid Build Coastguard Worker .and_then(|v| v.allocate_pool(EFI_MEMORY_TYPE_LOADER_DATA, size))
156*5225e6b1SAndroid Build Coastguard Worker .inspect_err(|e| efi_try_print!("failed to allocate: {e}"))
157*5225e6b1SAndroid Build Coastguard Worker .unwrap_or(null_mut()) as _
158*5225e6b1SAndroid Build Coastguard Worker }
159*5225e6b1SAndroid Build Coastguard Worker
160*5225e6b1SAndroid Build Coastguard Worker /// Deallocate memory previously allocated by `Self::allocate()`.
161*5225e6b1SAndroid Build Coastguard Worker ///
162*5225e6b1SAndroid Build Coastguard Worker /// Errors are logged but ignored.
deallocate(&self, ptr: *mut u8)163*5225e6b1SAndroid Build Coastguard Worker fn deallocate(&self, ptr: *mut u8) {
164*5225e6b1SAndroid Build Coastguard Worker match self.state.efi_entry() {
165*5225e6b1SAndroid Build Coastguard Worker Some(ref entry) => {
166*5225e6b1SAndroid Build Coastguard Worker let _ = entry
167*5225e6b1SAndroid Build Coastguard Worker .system_table_checked()
168*5225e6b1SAndroid Build Coastguard Worker .and_then(|v| v.boot_services_checked())
169*5225e6b1SAndroid Build Coastguard Worker .and_then(|v| v.free_pool(ptr as *mut _))
170*5225e6b1SAndroid Build Coastguard Worker .inspect_err(|e| efi_try_print!("failed to deallocate: {e}"));
171*5225e6b1SAndroid Build Coastguard Worker }
172*5225e6b1SAndroid Build Coastguard Worker // After EFI_BOOT_SERVICES.ExitBootServices(), all allocated memory is considered
173*5225e6b1SAndroid Build Coastguard Worker // leaked and under full ownership of subsequent OS loader code.
174*5225e6b1SAndroid Build Coastguard Worker _ => {}
175*5225e6b1SAndroid Build Coastguard Worker }
176*5225e6b1SAndroid Build Coastguard Worker }
177*5225e6b1SAndroid Build Coastguard Worker }
178*5225e6b1SAndroid Build Coastguard Worker
179*5225e6b1SAndroid Build Coastguard Worker // Alignment guaranteed by EFI AllocatePoll()
180*5225e6b1SAndroid Build Coastguard Worker const EFI_ALLOCATE_POOL_ALIGNMENT: usize = 8;
181*5225e6b1SAndroid Build Coastguard Worker
182*5225e6b1SAndroid Build Coastguard Worker unsafe impl GlobalAlloc for EfiAllocator {
alloc(&self, layout: Layout) -> *mut u8183*5225e6b1SAndroid Build Coastguard Worker unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
184*5225e6b1SAndroid Build Coastguard Worker (|| -> Result<*mut u8> {
185*5225e6b1SAndroid Build Coastguard Worker let align = layout.align();
186*5225e6b1SAndroid Build Coastguard Worker
187*5225e6b1SAndroid Build Coastguard Worker // EFI AllocatePoll() must be at 8-bytes aligned so we can just use returned pointer.
188*5225e6b1SAndroid Build Coastguard Worker if align <= EFI_ALLOCATE_POOL_ALIGNMENT {
189*5225e6b1SAndroid Build Coastguard Worker let ptr = self.allocate(layout.size());
190*5225e6b1SAndroid Build Coastguard Worker assert_eq!(ptr as usize % EFI_ALLOCATE_POOL_ALIGNMENT, 0);
191*5225e6b1SAndroid Build Coastguard Worker return Ok(ptr);
192*5225e6b1SAndroid Build Coastguard Worker }
193*5225e6b1SAndroid Build Coastguard Worker
194*5225e6b1SAndroid Build Coastguard Worker // If requested alignment is > EFI_ALLOCATE_POOL_ALIGNMENT then make sure to allocate
195*5225e6b1SAndroid Build Coastguard Worker // bigger buffer and adjust ptr to be aligned.
196*5225e6b1SAndroid Build Coastguard Worker let mut offset: usize = 0usize;
197*5225e6b1SAndroid Build Coastguard Worker let extra_size = SafeNum::from(align) + size_of_val(&offset);
198*5225e6b1SAndroid Build Coastguard Worker let size = SafeNum::from(layout.size()) + extra_size;
199*5225e6b1SAndroid Build Coastguard Worker
200*5225e6b1SAndroid Build Coastguard Worker // TODO(300168989):
201*5225e6b1SAndroid Build Coastguard Worker // `AllocatePool()` can be slow for allocating large buffers. In this case,
202*5225e6b1SAndroid Build Coastguard Worker // `AllocatePages()` is recommended.
203*5225e6b1SAndroid Build Coastguard Worker let unaligned_ptr = self.allocate(size.try_into()?);
204*5225e6b1SAndroid Build Coastguard Worker if unaligned_ptr.is_null() {
205*5225e6b1SAndroid Build Coastguard Worker return Err(Error::Other(Some("Allocation failed")));
206*5225e6b1SAndroid Build Coastguard Worker }
207*5225e6b1SAndroid Build Coastguard Worker offset = align - (unaligned_ptr as usize % align);
208*5225e6b1SAndroid Build Coastguard Worker
209*5225e6b1SAndroid Build Coastguard Worker // SAFETY:
210*5225e6b1SAndroid Build Coastguard Worker // - `unaligned_ptr` is guaranteed to point to buffer big enough to contain offset+size
211*5225e6b1SAndroid Build Coastguard Worker // bytes since this is the size passed to `allocate`
212*5225e6b1SAndroid Build Coastguard Worker // - ptr+layout.size() is also pointing to valid buffer since actual allocate size takes
213*5225e6b1SAndroid Build Coastguard Worker // into account additional suffix for usize variable
214*5225e6b1SAndroid Build Coastguard Worker unsafe {
215*5225e6b1SAndroid Build Coastguard Worker let ptr = unaligned_ptr.add(offset);
216*5225e6b1SAndroid Build Coastguard Worker core::slice::from_raw_parts_mut(ptr.add(layout.size()), size_of_val(&offset))
217*5225e6b1SAndroid Build Coastguard Worker .copy_from_slice(&offset.to_ne_bytes());
218*5225e6b1SAndroid Build Coastguard Worker Ok(ptr)
219*5225e6b1SAndroid Build Coastguard Worker }
220*5225e6b1SAndroid Build Coastguard Worker })()
221*5225e6b1SAndroid Build Coastguard Worker .unwrap_or(null_mut()) as _
222*5225e6b1SAndroid Build Coastguard Worker }
223*5225e6b1SAndroid Build Coastguard Worker
dealloc(&self, ptr: *mut u8, layout: Layout)224*5225e6b1SAndroid Build Coastguard Worker unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
225*5225e6b1SAndroid Build Coastguard Worker // If alignment is EFI_ALLOCATE_POOL_ALIGNMENT or less, then we can just used ptr directly
226*5225e6b1SAndroid Build Coastguard Worker if layout.align() <= EFI_ALLOCATE_POOL_ALIGNMENT {
227*5225e6b1SAndroid Build Coastguard Worker self.deallocate(ptr);
228*5225e6b1SAndroid Build Coastguard Worker return;
229*5225e6b1SAndroid Build Coastguard Worker }
230*5225e6b1SAndroid Build Coastguard Worker
231*5225e6b1SAndroid Build Coastguard Worker let mut offset: usize = 0usize;
232*5225e6b1SAndroid Build Coastguard Worker offset = usize::from_ne_bytes(
233*5225e6b1SAndroid Build Coastguard Worker // SAFETY:
234*5225e6b1SAndroid Build Coastguard Worker // * `ptr` is allocated by `alloc` and has enough padding after `ptr`+size to hold
235*5225e6b1SAndroid Build Coastguard Worker // suffix `offset: usize`.
236*5225e6b1SAndroid Build Coastguard Worker // * Alignment of `ptr` is 1 for &[u8]
237*5225e6b1SAndroid Build Coastguard Worker unsafe { core::slice::from_raw_parts(ptr.add(layout.size()), size_of_val(&offset)) }
238*5225e6b1SAndroid Build Coastguard Worker .try_into()
239*5225e6b1SAndroid Build Coastguard Worker .unwrap(),
240*5225e6b1SAndroid Build Coastguard Worker );
241*5225e6b1SAndroid Build Coastguard Worker
242*5225e6b1SAndroid Build Coastguard Worker // SAFETY:
243*5225e6b1SAndroid Build Coastguard Worker // (`ptr` - `offset`) must be valid unaligned pointer to buffer allocated by `alloc`
244*5225e6b1SAndroid Build Coastguard Worker let real_start_ptr = unsafe { ptr.sub(offset) };
245*5225e6b1SAndroid Build Coastguard Worker self.deallocate(real_start_ptr);
246*5225e6b1SAndroid Build Coastguard Worker }
247*5225e6b1SAndroid Build Coastguard Worker }
248*5225e6b1SAndroid Build Coastguard Worker
249*5225e6b1SAndroid Build Coastguard Worker /// API for allocating raw memory via EFI_BOOT_SERVICES
efi_malloc(size: usize) -> *mut u8250*5225e6b1SAndroid Build Coastguard Worker pub fn efi_malloc(size: usize) -> *mut u8 {
251*5225e6b1SAndroid Build Coastguard Worker // SAFETY: See SAFETY of `internal_efi_entry()`.
252*5225e6b1SAndroid Build Coastguard Worker unsafe { EFI_GLOBAL_ALLOCATOR.allocate(size) }
253*5225e6b1SAndroid Build Coastguard Worker }
254*5225e6b1SAndroid Build Coastguard Worker
255*5225e6b1SAndroid Build Coastguard Worker /// API for deallocating raw memory previously allocated by `efi_malloc()`. Passing invalid
256*5225e6b1SAndroid Build Coastguard Worker /// pointer will cause the function to panic.
efi_free(ptr: *mut u8)257*5225e6b1SAndroid Build Coastguard Worker pub fn efi_free(ptr: *mut u8) {
258*5225e6b1SAndroid Build Coastguard Worker // SAFETY: See SAFETY of `internal_efi_entry()`.
259*5225e6b1SAndroid Build Coastguard Worker unsafe { EFI_GLOBAL_ALLOCATOR.deallocate(ptr) }
260*5225e6b1SAndroid Build Coastguard Worker }
261