xref: /aosp_15_r20/bootable/libbootloader/gbl/libefi/src/lib.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
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 //! The library implements Rust wrappers for a set of UEFI interfaces needed by GBL. It also
16*5225e6b1SAndroid Build Coastguard Worker //! provides a global allocator and supports auto release of dynamic UEFI resource such as
17*5225e6b1SAndroid Build Coastguard Worker //! protocols and UEFI allocated buffers.
18*5225e6b1SAndroid Build Coastguard Worker //!
19*5225e6b1SAndroid Build Coastguard Worker //! # Examples
20*5225e6b1SAndroid Build Coastguard Worker //!
21*5225e6b1SAndroid Build Coastguard Worker //! The following example covers the basic use pattern of the library. It scans all block devices
22*5225e6b1SAndroid Build Coastguard Worker //! and prints out the device path, block size and io alignment info for each of them.
23*5225e6b1SAndroid Build Coastguard Worker //!
24*5225e6b1SAndroid Build Coastguard Worker //! ```
25*5225e6b1SAndroid Build Coastguard Worker //! fn main(image: EfiHandle, systab_ptr: *mut EfiSystemTable) -> liberror::Result<()> {
26*5225e6b1SAndroid Build Coastguard Worker //!     let efi_entry = initialize(image, systab_ptr)?;
27*5225e6b1SAndroid Build Coastguard Worker //!     let mut con_out = efi_entry.system_table().con_out()?;
28*5225e6b1SAndroid Build Coastguard Worker //!     let boot_services = efi_entry.system_table().boot_services();
29*5225e6b1SAndroid Build Coastguard Worker //!     let path_to_text = boot_services.find_first_and_open::<DevicePathToTextProtocol>()?;
30*5225e6b1SAndroid Build Coastguard Worker //!
31*5225e6b1SAndroid Build Coastguard Worker //!     write!(con_out, "Scanning block devices...\n")?;
32*5225e6b1SAndroid Build Coastguard Worker //!
33*5225e6b1SAndroid Build Coastguard Worker //!     let block_handles = boot_services.locate_handle_buffer_by_protocol::<BlockIoProtocol>()?;
34*5225e6b1SAndroid Build Coastguard Worker //!
35*5225e6b1SAndroid Build Coastguard Worker //!     for (i, handle) in block_handles.handles().iter().enumerate() {
36*5225e6b1SAndroid Build Coastguard Worker //!         let path = boot_services.open_protocol::<DevicePathProtocol>(*handle)?;
37*5225e6b1SAndroid Build Coastguard Worker //!         write!(con_out, "Block Device #{}: ", i)?;
38*5225e6b1SAndroid Build Coastguard Worker //!         path_to_text.convert_device_path_to_text(&path, false, false)?.print()?;
39*5225e6b1SAndroid Build Coastguard Worker //!         write!(con_out, "\n")?;
40*5225e6b1SAndroid Build Coastguard Worker //!
41*5225e6b1SAndroid Build Coastguard Worker //!         let block_io_protocol = boot_services.open_protocol::<BlockIoProtocol>(*handle)?;
42*5225e6b1SAndroid Build Coastguard Worker //!         let media = block_io_protocol.media()?;
43*5225e6b1SAndroid Build Coastguard Worker //!         write!(con_out, "  block size = {}\n", media.block_size)?;
44*5225e6b1SAndroid Build Coastguard Worker //!         write!(con_out, "  io alignment = {}\n", media.io_align)?;
45*5225e6b1SAndroid Build Coastguard Worker //!     }
46*5225e6b1SAndroid Build Coastguard Worker //!
47*5225e6b1SAndroid Build Coastguard Worker //!     Ok(())
48*5225e6b1SAndroid Build Coastguard Worker //! }
49*5225e6b1SAndroid Build Coastguard Worker //! ```
50*5225e6b1SAndroid Build Coastguard Worker 
51*5225e6b1SAndroid Build Coastguard Worker #![cfg_attr(not(test), no_std)]
52*5225e6b1SAndroid Build Coastguard Worker 
53*5225e6b1SAndroid Build Coastguard Worker extern crate alloc;
54*5225e6b1SAndroid Build Coastguard Worker use alloc::vec::Vec;
55*5225e6b1SAndroid Build Coastguard Worker 
56*5225e6b1SAndroid Build Coastguard Worker #[cfg(not(test))]
57*5225e6b1SAndroid Build Coastguard Worker mod allocation;
58*5225e6b1SAndroid Build Coastguard Worker 
59*5225e6b1SAndroid Build Coastguard Worker #[cfg(not(test))]
60*5225e6b1SAndroid Build Coastguard Worker pub use allocation::{efi_free, efi_malloc, EfiAllocator};
61*5225e6b1SAndroid Build Coastguard Worker 
62*5225e6b1SAndroid Build Coastguard Worker /// The Android EFI protocol implementation of an A/B slot manager.
63*5225e6b1SAndroid Build Coastguard Worker pub mod ab_slots;
64*5225e6b1SAndroid Build Coastguard Worker pub mod protocol;
65*5225e6b1SAndroid Build Coastguard Worker pub mod utils;
66*5225e6b1SAndroid Build Coastguard Worker 
67*5225e6b1SAndroid Build Coastguard Worker #[cfg(not(test))]
68*5225e6b1SAndroid Build Coastguard Worker use core::{fmt::Write, panic::PanicInfo};
69*5225e6b1SAndroid Build Coastguard Worker 
70*5225e6b1SAndroid Build Coastguard Worker use core::{marker::PhantomData, ptr::null_mut, slice::from_raw_parts};
71*5225e6b1SAndroid Build Coastguard Worker use efi_types::{
72*5225e6b1SAndroid Build Coastguard Worker     EfiBootService, EfiConfigurationTable, EfiEvent, EfiGuid, EfiHandle,
73*5225e6b1SAndroid Build Coastguard Worker     EfiMemoryAttributesTableHeader, EfiMemoryDescriptor, EfiMemoryType, EfiRuntimeService,
74*5225e6b1SAndroid Build Coastguard Worker     EfiSystemTable, EfiTimerDelay, EFI_EVENT_TYPE_NOTIFY_SIGNAL, EFI_EVENT_TYPE_NOTIFY_WAIT,
75*5225e6b1SAndroid Build Coastguard Worker     EFI_EVENT_TYPE_RUNTIME, EFI_EVENT_TYPE_SIGNAL_EXIT_BOOT_SERVICES,
76*5225e6b1SAndroid Build Coastguard Worker     EFI_EVENT_TYPE_SIGNAL_VIRTUAL_ADDRESS_CHANGE, EFI_EVENT_TYPE_TIMER,
77*5225e6b1SAndroid Build Coastguard Worker     EFI_LOCATE_HANDLE_SEARCH_TYPE_BY_PROTOCOL, EFI_OPEN_PROTOCOL_ATTRIBUTE_BY_HANDLE_PROTOCOL,
78*5225e6b1SAndroid Build Coastguard Worker     EFI_RESET_TYPE, EFI_RESET_TYPE_EFI_RESET_COLD, EFI_STATUS, EFI_STATUS_SUCCESS,
79*5225e6b1SAndroid Build Coastguard Worker };
80*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result};
81*5225e6b1SAndroid Build Coastguard Worker use libutils::aligned_subslice;
82*5225e6b1SAndroid Build Coastguard Worker use protocol::{
83*5225e6b1SAndroid Build Coastguard Worker     simple_text_output::SimpleTextOutputProtocol,
84*5225e6b1SAndroid Build Coastguard Worker     {Protocol, ProtocolInfo},
85*5225e6b1SAndroid Build Coastguard Worker };
86*5225e6b1SAndroid Build Coastguard Worker use zerocopy::{FromBytes, Ref};
87*5225e6b1SAndroid Build Coastguard Worker 
88*5225e6b1SAndroid Build Coastguard Worker /// `EfiEntry` stores the EFI system table pointer and image handle passed from the entry point.
89*5225e6b1SAndroid Build Coastguard Worker /// It's the root data structure that derives all other wrapper APIs and structures.
90*5225e6b1SAndroid Build Coastguard Worker pub struct EfiEntry {
91*5225e6b1SAndroid Build Coastguard Worker     image_handle: EfiHandle,
92*5225e6b1SAndroid Build Coastguard Worker     systab_ptr: *const EfiSystemTable,
93*5225e6b1SAndroid Build Coastguard Worker }
94*5225e6b1SAndroid Build Coastguard Worker 
95*5225e6b1SAndroid Build Coastguard Worker impl EfiEntry {
96*5225e6b1SAndroid Build Coastguard Worker     /// Gets an instance of `SystemTable`.
97*5225e6b1SAndroid Build Coastguard Worker     ///
98*5225e6b1SAndroid Build Coastguard Worker     /// Panics if the pointer is NULL.
system_table(&self) -> SystemTable99*5225e6b1SAndroid Build Coastguard Worker     pub fn system_table(&self) -> SystemTable {
100*5225e6b1SAndroid Build Coastguard Worker         self.system_table_checked().unwrap()
101*5225e6b1SAndroid Build Coastguard Worker     }
102*5225e6b1SAndroid Build Coastguard Worker 
103*5225e6b1SAndroid Build Coastguard Worker     /// Gets an instance of `SystemTable` if pointer is valid.
system_table_checked(&self) -> Result<SystemTable>104*5225e6b1SAndroid Build Coastguard Worker     pub fn system_table_checked(&self) -> Result<SystemTable> {
105*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: Pointers to UEFI data strucutres.
106*5225e6b1SAndroid Build Coastguard Worker         Ok(SystemTable {
107*5225e6b1SAndroid Build Coastguard Worker             efi_entry: self,
108*5225e6b1SAndroid Build Coastguard Worker             table: unsafe { self.systab_ptr.as_ref() }.ok_or(Error::Unsupported)?,
109*5225e6b1SAndroid Build Coastguard Worker         })
110*5225e6b1SAndroid Build Coastguard Worker     }
111*5225e6b1SAndroid Build Coastguard Worker 
112*5225e6b1SAndroid Build Coastguard Worker     /// Gets the image handle.
image_handle(&self) -> DeviceHandle113*5225e6b1SAndroid Build Coastguard Worker     pub fn image_handle(&self) -> DeviceHandle {
114*5225e6b1SAndroid Build Coastguard Worker         DeviceHandle(self.image_handle)
115*5225e6b1SAndroid Build Coastguard Worker     }
116*5225e6b1SAndroid Build Coastguard Worker }
117*5225e6b1SAndroid Build Coastguard Worker 
118*5225e6b1SAndroid Build Coastguard Worker /// The vendor GUID for UEFI variables defined by GBL.
119*5225e6b1SAndroid Build Coastguard Worker pub const GBL_EFI_VENDOR_GUID: EfiGuid =
120*5225e6b1SAndroid Build Coastguard Worker     EfiGuid::new(0x5a6d92f3, 0xa2d0, 0x4083, [0x91, 0xa1, 0xa5, 0x0f, 0x6c, 0x3d, 0x98, 0x30]);
121*5225e6b1SAndroid Build Coastguard Worker 
122*5225e6b1SAndroid Build Coastguard Worker /// GUID for UEFI Memory Attributes Table
123*5225e6b1SAndroid Build Coastguard Worker pub const EFI_MEMORY_ATTRIBUTES_GUID: EfiGuid =
124*5225e6b1SAndroid Build Coastguard Worker     EfiGuid::new(0xdcfa911d, 0x26eb, 0x469f, [0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20]);
125*5225e6b1SAndroid Build Coastguard Worker 
126*5225e6b1SAndroid Build Coastguard Worker /// The name of the UEFI variable that GBL defines to determine whether to boot Fuchsia.
127*5225e6b1SAndroid Build Coastguard Worker /// The value of the variable is ignored: if the variable is present,
128*5225e6b1SAndroid Build Coastguard Worker /// it indicates that the bootloader should attempt to boot a Fuchsia target.
129*5225e6b1SAndroid Build Coastguard Worker /// This may include reinitializing GPT partitions and partition contents.
130*5225e6b1SAndroid Build Coastguard Worker pub const GBL_EFI_OS_BOOT_TARGET_VARNAME: &str = "gbl_os_boot_fuchsia";
131*5225e6b1SAndroid Build Coastguard Worker 
132*5225e6b1SAndroid Build Coastguard Worker /// Creates an `EfiEntry` and initialize EFI global allocator.
133*5225e6b1SAndroid Build Coastguard Worker ///
134*5225e6b1SAndroid Build Coastguard Worker /// # Safety
135*5225e6b1SAndroid Build Coastguard Worker ///
136*5225e6b1SAndroid Build Coastguard Worker /// The API modifies internal global state. It should only be called once upon EFI entry to obtain
137*5225e6b1SAndroid Build Coastguard Worker /// an instance of `EfiEntry` for accessing other APIs. Calling it again when EFI APIs are already
138*5225e6b1SAndroid Build Coastguard Worker /// being used can introduce a risk of race.
139*5225e6b1SAndroid Build Coastguard Worker #[cfg(not(test))]
initialize( image_handle: EfiHandle, systab_ptr: *const EfiSystemTable, ) -> Result<EfiEntry>140*5225e6b1SAndroid Build Coastguard Worker pub unsafe fn initialize(
141*5225e6b1SAndroid Build Coastguard Worker     image_handle: EfiHandle,
142*5225e6b1SAndroid Build Coastguard Worker     systab_ptr: *const EfiSystemTable,
143*5225e6b1SAndroid Build Coastguard Worker ) -> Result<EfiEntry> {
144*5225e6b1SAndroid Build Coastguard Worker     // SAFETY: By safety requirement of this function, `initialize` is only called once upon
145*5225e6b1SAndroid Build Coastguard Worker     // entering EFI application, where there should be no event notify function that can be
146*5225e6b1SAndroid Build Coastguard Worker     // triggered.
147*5225e6b1SAndroid Build Coastguard Worker     unsafe {
148*5225e6b1SAndroid Build Coastguard Worker         // Create one for internal global allocator.
149*5225e6b1SAndroid Build Coastguard Worker         allocation::init_efi_global_alloc(EfiEntry { image_handle, systab_ptr })?;
150*5225e6b1SAndroid Build Coastguard Worker     }
151*5225e6b1SAndroid Build Coastguard Worker     Ok(EfiEntry { image_handle, systab_ptr })
152*5225e6b1SAndroid Build Coastguard Worker }
153*5225e6b1SAndroid Build Coastguard Worker 
154*5225e6b1SAndroid Build Coastguard Worker /// Exits boot service and returns the memory map in the given buffer.
155*5225e6b1SAndroid Build Coastguard Worker ///
156*5225e6b1SAndroid Build Coastguard Worker /// The API takes ownership of the given `entry` and causes it to go out of scope.
157*5225e6b1SAndroid Build Coastguard Worker /// This enforces strict compile time check that any reference/borrow in effect will cause compile
158*5225e6b1SAndroid Build Coastguard Worker /// errors.
159*5225e6b1SAndroid Build Coastguard Worker ///
160*5225e6b1SAndroid Build Coastguard Worker /// Existing heap allocated memories will maintain their states. All system memory including them
161*5225e6b1SAndroid Build Coastguard Worker /// will be under onwership of the subsequent OS or OS loader code.
exit_boot_services(entry: EfiEntry, mmap_buffer: &mut [u8]) -> Result<EfiMemoryMap>162*5225e6b1SAndroid Build Coastguard Worker pub fn exit_boot_services(entry: EfiEntry, mmap_buffer: &mut [u8]) -> Result<EfiMemoryMap> {
163*5225e6b1SAndroid Build Coastguard Worker     let aligned = aligned_subslice(mmap_buffer, core::mem::align_of::<EfiMemoryDescriptor>())?;
164*5225e6b1SAndroid Build Coastguard Worker 
165*5225e6b1SAndroid Build Coastguard Worker     let res = entry.system_table().boot_services().get_memory_map(aligned)?;
166*5225e6b1SAndroid Build Coastguard Worker     entry.system_table().boot_services().exit_boot_services(&res)?;
167*5225e6b1SAndroid Build Coastguard Worker     // SAFETY:
168*5225e6b1SAndroid Build Coastguard Worker     // At this point, UEFI has successfully exited boot services and no event/notification can be
169*5225e6b1SAndroid Build Coastguard Worker     // triggered.
170*5225e6b1SAndroid Build Coastguard Worker     #[cfg(not(test))]
171*5225e6b1SAndroid Build Coastguard Worker     unsafe {
172*5225e6b1SAndroid Build Coastguard Worker         allocation::exit_efi_global_alloc();
173*5225e6b1SAndroid Build Coastguard Worker     }
174*5225e6b1SAndroid Build Coastguard Worker     Ok(res)
175*5225e6b1SAndroid Build Coastguard Worker }
176*5225e6b1SAndroid Build Coastguard Worker 
177*5225e6b1SAndroid Build Coastguard Worker /// `SystemTable` provides methods for accessing fields in `EFI_SYSTEM_TABLE`.
178*5225e6b1SAndroid Build Coastguard Worker #[derive(Clone, Copy)]
179*5225e6b1SAndroid Build Coastguard Worker pub struct SystemTable<'a> {
180*5225e6b1SAndroid Build Coastguard Worker     efi_entry: &'a EfiEntry,
181*5225e6b1SAndroid Build Coastguard Worker     table: &'a EfiSystemTable,
182*5225e6b1SAndroid Build Coastguard Worker }
183*5225e6b1SAndroid Build Coastguard Worker 
184*5225e6b1SAndroid Build Coastguard Worker impl<'a> SystemTable<'a> {
185*5225e6b1SAndroid Build Coastguard Worker     /// Creates an instance of `BootServices`
186*5225e6b1SAndroid Build Coastguard Worker     ///
187*5225e6b1SAndroid Build Coastguard Worker     /// Panics if not implemented by UEFI.
boot_services(&self) -> BootServices<'a>188*5225e6b1SAndroid Build Coastguard Worker     pub fn boot_services(&self) -> BootServices<'a> {
189*5225e6b1SAndroid Build Coastguard Worker         self.boot_services_checked().unwrap()
190*5225e6b1SAndroid Build Coastguard Worker     }
191*5225e6b1SAndroid Build Coastguard Worker 
192*5225e6b1SAndroid Build Coastguard Worker     /// Creates an instance of `BootServices`
193*5225e6b1SAndroid Build Coastguard Worker     ///
194*5225e6b1SAndroid Build Coastguard Worker     /// Returns Err(()) if not implemented by UEFI.
boot_services_checked(&self) -> Result<BootServices<'a>>195*5225e6b1SAndroid Build Coastguard Worker     pub fn boot_services_checked(&self) -> Result<BootServices<'a>> {
196*5225e6b1SAndroid Build Coastguard Worker         Ok(BootServices {
197*5225e6b1SAndroid Build Coastguard Worker             efi_entry: self.efi_entry,
198*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: Pointers to UEFI data strucutres.
199*5225e6b1SAndroid Build Coastguard Worker             boot_services: unsafe { self.table.boot_services.as_ref() }
200*5225e6b1SAndroid Build Coastguard Worker                 .ok_or(Error::Unsupported)?,
201*5225e6b1SAndroid Build Coastguard Worker         })
202*5225e6b1SAndroid Build Coastguard Worker     }
203*5225e6b1SAndroid Build Coastguard Worker 
204*5225e6b1SAndroid Build Coastguard Worker     /// Creates an instance of `RuntimeServices`
205*5225e6b1SAndroid Build Coastguard Worker     ///
206*5225e6b1SAndroid Build Coastguard Worker     /// Panics if run time services is not implemented.
runtime_services(&self) -> RuntimeServices207*5225e6b1SAndroid Build Coastguard Worker     pub fn runtime_services(&self) -> RuntimeServices {
208*5225e6b1SAndroid Build Coastguard Worker         self.runtime_services_checked().unwrap()
209*5225e6b1SAndroid Build Coastguard Worker     }
210*5225e6b1SAndroid Build Coastguard Worker 
211*5225e6b1SAndroid Build Coastguard Worker     /// Creates an instance of `RuntimeServices` if available from system table.
runtime_services_checked(&self) -> Result<RuntimeServices>212*5225e6b1SAndroid Build Coastguard Worker     pub fn runtime_services_checked(&self) -> Result<RuntimeServices> {
213*5225e6b1SAndroid Build Coastguard Worker         Ok(RuntimeServices {
214*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: Pointers to UEFI data strucutres.
215*5225e6b1SAndroid Build Coastguard Worker             runtime_services: *unsafe { self.table.runtime_services.as_ref() }
216*5225e6b1SAndroid Build Coastguard Worker                 .ok_or(Error::Unsupported)?,
217*5225e6b1SAndroid Build Coastguard Worker         })
218*5225e6b1SAndroid Build Coastguard Worker     }
219*5225e6b1SAndroid Build Coastguard Worker 
220*5225e6b1SAndroid Build Coastguard Worker     /// Gets the `EFI_SYSTEM_TABLE.ConOut` field.
con_out(&self) -> Result<Protocol<'a, SimpleTextOutputProtocol>>221*5225e6b1SAndroid Build Coastguard Worker     pub fn con_out(&self) -> Result<Protocol<'a, SimpleTextOutputProtocol>> {
222*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: `EFI_SYSTEM_TABLE.ConOut` is a pointer to EfiSimpleTextOutputProtocol structure
223*5225e6b1SAndroid Build Coastguard Worker         // by definition. It lives until ExitBootService and thus as long as `self.efi_entry` or,
224*5225e6b1SAndroid Build Coastguard Worker         // 'a
225*5225e6b1SAndroid Build Coastguard Worker         Ok(unsafe {
226*5225e6b1SAndroid Build Coastguard Worker             Protocol::<SimpleTextOutputProtocol>::new(
227*5225e6b1SAndroid Build Coastguard Worker                 // No device handle. This protocol is a permanent reference.
228*5225e6b1SAndroid Build Coastguard Worker                 DeviceHandle(null_mut()),
229*5225e6b1SAndroid Build Coastguard Worker                 self.table.con_out,
230*5225e6b1SAndroid Build Coastguard Worker                 self.efi_entry,
231*5225e6b1SAndroid Build Coastguard Worker             )
232*5225e6b1SAndroid Build Coastguard Worker         })
233*5225e6b1SAndroid Build Coastguard Worker     }
234*5225e6b1SAndroid Build Coastguard Worker 
235*5225e6b1SAndroid Build Coastguard Worker     /// Gets the `EFI_SYSTEM_TABLE.ConfigurationTable` array.
configuration_table(&self) -> Option<&[EfiConfigurationTable]>236*5225e6b1SAndroid Build Coastguard Worker     pub fn configuration_table(&self) -> Option<&[EfiConfigurationTable]> {
237*5225e6b1SAndroid Build Coastguard Worker         match self.table.configuration_table.is_null() {
238*5225e6b1SAndroid Build Coastguard Worker             true => None,
239*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: Non-null pointer to EFI configuration table.
240*5225e6b1SAndroid Build Coastguard Worker             false => unsafe {
241*5225e6b1SAndroid Build Coastguard Worker                 Some(from_raw_parts(
242*5225e6b1SAndroid Build Coastguard Worker                     self.table.configuration_table,
243*5225e6b1SAndroid Build Coastguard Worker                     self.table.number_of_table_entries,
244*5225e6b1SAndroid Build Coastguard Worker                 ))
245*5225e6b1SAndroid Build Coastguard Worker             },
246*5225e6b1SAndroid Build Coastguard Worker         }
247*5225e6b1SAndroid Build Coastguard Worker     }
248*5225e6b1SAndroid Build Coastguard Worker }
249*5225e6b1SAndroid Build Coastguard Worker 
250*5225e6b1SAndroid Build Coastguard Worker /// `BootServices` provides methods for accessing various EFI_BOOT_SERVICES interfaces.
251*5225e6b1SAndroid Build Coastguard Worker #[derive(Clone, Copy)]
252*5225e6b1SAndroid Build Coastguard Worker pub struct BootServices<'a> {
253*5225e6b1SAndroid Build Coastguard Worker     efi_entry: &'a EfiEntry,
254*5225e6b1SAndroid Build Coastguard Worker     boot_services: &'a EfiBootService,
255*5225e6b1SAndroid Build Coastguard Worker }
256*5225e6b1SAndroid Build Coastguard Worker 
257*5225e6b1SAndroid Build Coastguard Worker impl<'a> BootServices<'a> {
258*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICES.AllocatePool()`.
259*5225e6b1SAndroid Build Coastguard Worker     #[allow(dead_code)]
allocate_pool( &self, pool_type: EfiMemoryType, size: usize, ) -> Result<*mut core::ffi::c_void>260*5225e6b1SAndroid Build Coastguard Worker     fn allocate_pool(
261*5225e6b1SAndroid Build Coastguard Worker         &self,
262*5225e6b1SAndroid Build Coastguard Worker         pool_type: EfiMemoryType,
263*5225e6b1SAndroid Build Coastguard Worker         size: usize,
264*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<*mut core::ffi::c_void> {
265*5225e6b1SAndroid Build Coastguard Worker         let mut out: *mut core::ffi::c_void = null_mut();
266*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: `EFI_BOOT_SERVICES` method call.
267*5225e6b1SAndroid Build Coastguard Worker         unsafe {
268*5225e6b1SAndroid Build Coastguard Worker             efi_call!(self.boot_services.allocate_pool, pool_type, size, &mut out)?;
269*5225e6b1SAndroid Build Coastguard Worker         }
270*5225e6b1SAndroid Build Coastguard Worker         Ok(out)
271*5225e6b1SAndroid Build Coastguard Worker     }
272*5225e6b1SAndroid Build Coastguard Worker 
273*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICES.FreePool()`.
free_pool(&self, buf: *mut core::ffi::c_void) -> Result<()>274*5225e6b1SAndroid Build Coastguard Worker     fn free_pool(&self, buf: *mut core::ffi::c_void) -> Result<()> {
275*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: `EFI_BOOT_SERVICES` method call.
276*5225e6b1SAndroid Build Coastguard Worker         unsafe { efi_call!(self.boot_services.free_pool, buf) }
277*5225e6b1SAndroid Build Coastguard Worker     }
278*5225e6b1SAndroid Build Coastguard Worker 
279*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICES.OpenProtocol()`.
open_protocol<T: ProtocolInfo>(&self, handle: DeviceHandle) -> Result<Protocol<'a, T>>280*5225e6b1SAndroid Build Coastguard Worker     pub fn open_protocol<T: ProtocolInfo>(&self, handle: DeviceHandle) -> Result<Protocol<'a, T>> {
281*5225e6b1SAndroid Build Coastguard Worker         let mut out_handle: EfiHandle = null_mut();
282*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
283*5225e6b1SAndroid Build Coastguard Worker         unsafe {
284*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
285*5225e6b1SAndroid Build Coastguard Worker                 self.boot_services.open_protocol,
286*5225e6b1SAndroid Build Coastguard Worker                 handle.0,
287*5225e6b1SAndroid Build Coastguard Worker                 &T::GUID,
288*5225e6b1SAndroid Build Coastguard Worker                 &mut out_handle as *mut _,
289*5225e6b1SAndroid Build Coastguard Worker                 self.efi_entry.image_handle().0,
290*5225e6b1SAndroid Build Coastguard Worker                 null_mut(),
291*5225e6b1SAndroid Build Coastguard Worker                 EFI_OPEN_PROTOCOL_ATTRIBUTE_BY_HANDLE_PROTOCOL
292*5225e6b1SAndroid Build Coastguard Worker             )?;
293*5225e6b1SAndroid Build Coastguard Worker         }
294*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: `EFI_SYSTEM_TABLE.OpenProtocol` returns a valid pointer to `T::InterfaceType`
295*5225e6b1SAndroid Build Coastguard Worker         // on success. The pointer remains valid until closed by
296*5225e6b1SAndroid Build Coastguard Worker         // `EFI_BOOT_SERVICES.CloseProtocol()` when Protocol goes out of scope.
297*5225e6b1SAndroid Build Coastguard Worker         Ok(unsafe { Protocol::<T>::new(handle, out_handle as *mut _, self.efi_entry) })
298*5225e6b1SAndroid Build Coastguard Worker     }
299*5225e6b1SAndroid Build Coastguard Worker 
300*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICES.CloseProtocol()`.
301*5225e6b1SAndroid Build Coastguard Worker     #[allow(dead_code)]
close_protocol<T: ProtocolInfo>(&self, handle: DeviceHandle) -> Result<()>302*5225e6b1SAndroid Build Coastguard Worker     fn close_protocol<T: ProtocolInfo>(&self, handle: DeviceHandle) -> Result<()> {
303*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
304*5225e6b1SAndroid Build Coastguard Worker         unsafe {
305*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
306*5225e6b1SAndroid Build Coastguard Worker                 self.boot_services.close_protocol,
307*5225e6b1SAndroid Build Coastguard Worker                 handle.0,
308*5225e6b1SAndroid Build Coastguard Worker                 &T::GUID,
309*5225e6b1SAndroid Build Coastguard Worker                 self.efi_entry.image_handle().0,
310*5225e6b1SAndroid Build Coastguard Worker                 null_mut()
311*5225e6b1SAndroid Build Coastguard Worker             )
312*5225e6b1SAndroid Build Coastguard Worker         }
313*5225e6b1SAndroid Build Coastguard Worker     }
314*5225e6b1SAndroid Build Coastguard Worker 
315*5225e6b1SAndroid Build Coastguard Worker     /// Call `EFI_BOOT_SERVICES.LocateHandleBuffer()` with fixed
316*5225e6b1SAndroid Build Coastguard Worker     /// `EFI_LOCATE_HANDLE_SEARCH_TYPE_BY_PROTOCOL` and without search key.
locate_handle_buffer_by_protocol<T: ProtocolInfo>(&self) -> Result<LocatedHandles<'a>>317*5225e6b1SAndroid Build Coastguard Worker     pub fn locate_handle_buffer_by_protocol<T: ProtocolInfo>(&self) -> Result<LocatedHandles<'a>> {
318*5225e6b1SAndroid Build Coastguard Worker         let mut num_handles: usize = 0;
319*5225e6b1SAndroid Build Coastguard Worker         let mut handles: *mut EfiHandle = null_mut();
320*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
321*5225e6b1SAndroid Build Coastguard Worker         unsafe {
322*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
323*5225e6b1SAndroid Build Coastguard Worker                 self.boot_services.locate_handle_buffer,
324*5225e6b1SAndroid Build Coastguard Worker                 EFI_LOCATE_HANDLE_SEARCH_TYPE_BY_PROTOCOL,
325*5225e6b1SAndroid Build Coastguard Worker                 &T::GUID,
326*5225e6b1SAndroid Build Coastguard Worker                 null_mut(),
327*5225e6b1SAndroid Build Coastguard Worker                 &mut num_handles as *mut usize as *mut _,
328*5225e6b1SAndroid Build Coastguard Worker                 &mut handles as *mut *mut EfiHandle
329*5225e6b1SAndroid Build Coastguard Worker             )?
330*5225e6b1SAndroid Build Coastguard Worker         };
331*5225e6b1SAndroid Build Coastguard Worker         // `handles` should be a valid pointer if the above succeeds. But just double check
332*5225e6b1SAndroid Build Coastguard Worker         // to be safe. If assert fails, then there's a bug in the UEFI firmware.
333*5225e6b1SAndroid Build Coastguard Worker         assert!(!handles.is_null());
334*5225e6b1SAndroid Build Coastguard Worker         Ok(LocatedHandles::new(handles, num_handles, self.efi_entry))
335*5225e6b1SAndroid Build Coastguard Worker     }
336*5225e6b1SAndroid Build Coastguard Worker 
337*5225e6b1SAndroid Build Coastguard Worker     /// Search and open the first found target EFI protocol.
find_first_and_open<T: ProtocolInfo>(&self) -> Result<Protocol<'a, T>>338*5225e6b1SAndroid Build Coastguard Worker     pub fn find_first_and_open<T: ProtocolInfo>(&self) -> Result<Protocol<'a, T>> {
339*5225e6b1SAndroid Build Coastguard Worker         // We don't use EFI_BOOT_SERVICES.LocateProtocol() because it doesn't give device handle
340*5225e6b1SAndroid Build Coastguard Worker         // which is required to close the protocol.
341*5225e6b1SAndroid Build Coastguard Worker         let handle = *self
342*5225e6b1SAndroid Build Coastguard Worker             .locate_handle_buffer_by_protocol::<T>()?
343*5225e6b1SAndroid Build Coastguard Worker             .handles()
344*5225e6b1SAndroid Build Coastguard Worker             .first()
345*5225e6b1SAndroid Build Coastguard Worker             .ok_or(Error::NotFound)?;
346*5225e6b1SAndroid Build Coastguard Worker         self.open_protocol::<T>(handle)
347*5225e6b1SAndroid Build Coastguard Worker     }
348*5225e6b1SAndroid Build Coastguard Worker 
349*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICE.GetMemoryMap()`.
get_memory_map<'b>(&self, mmap_buffer: &'b mut [u8]) -> Result<EfiMemoryMap<'b>>350*5225e6b1SAndroid Build Coastguard Worker     pub fn get_memory_map<'b>(&self, mmap_buffer: &'b mut [u8]) -> Result<EfiMemoryMap<'b>> {
351*5225e6b1SAndroid Build Coastguard Worker         let mut mmap_size = mmap_buffer.len();
352*5225e6b1SAndroid Build Coastguard Worker         let mut map_key: usize = 0;
353*5225e6b1SAndroid Build Coastguard Worker         let mut descriptor_size: usize = 0;
354*5225e6b1SAndroid Build Coastguard Worker         let mut descriptor_version: u32 = 0;
355*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
356*5225e6b1SAndroid Build Coastguard Worker         unsafe {
357*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
358*5225e6b1SAndroid Build Coastguard Worker                 self.boot_services.get_memory_map,
359*5225e6b1SAndroid Build Coastguard Worker                 &mut mmap_size,
360*5225e6b1SAndroid Build Coastguard Worker                 mmap_buffer.as_mut_ptr() as *mut _,
361*5225e6b1SAndroid Build Coastguard Worker                 &mut map_key,
362*5225e6b1SAndroid Build Coastguard Worker                 &mut descriptor_size,
363*5225e6b1SAndroid Build Coastguard Worker                 &mut descriptor_version
364*5225e6b1SAndroid Build Coastguard Worker             )
365*5225e6b1SAndroid Build Coastguard Worker         }?;
366*5225e6b1SAndroid Build Coastguard Worker         Ok(EfiMemoryMap::new(
367*5225e6b1SAndroid Build Coastguard Worker             &mut mmap_buffer[..mmap_size],
368*5225e6b1SAndroid Build Coastguard Worker             map_key,
369*5225e6b1SAndroid Build Coastguard Worker             descriptor_size,
370*5225e6b1SAndroid Build Coastguard Worker             descriptor_version,
371*5225e6b1SAndroid Build Coastguard Worker         ))
372*5225e6b1SAndroid Build Coastguard Worker     }
373*5225e6b1SAndroid Build Coastguard Worker 
374*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICE.ExitBootServices()`.
exit_boot_services<'b>(&self, mmap: &'b EfiMemoryMap<'b>) -> Result<()>375*5225e6b1SAndroid Build Coastguard Worker     fn exit_boot_services<'b>(&self, mmap: &'b EfiMemoryMap<'b>) -> Result<()> {
376*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
377*5225e6b1SAndroid Build Coastguard Worker         unsafe {
378*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
379*5225e6b1SAndroid Build Coastguard Worker                 self.boot_services.exit_boot_services,
380*5225e6b1SAndroid Build Coastguard Worker                 self.efi_entry.image_handle().0,
381*5225e6b1SAndroid Build Coastguard Worker                 mmap.map_key()
382*5225e6b1SAndroid Build Coastguard Worker             )
383*5225e6b1SAndroid Build Coastguard Worker         }
384*5225e6b1SAndroid Build Coastguard Worker     }
385*5225e6b1SAndroid Build Coastguard Worker 
386*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICE.Stall()`.
stall(&self, micro: usize) -> Result<()>387*5225e6b1SAndroid Build Coastguard Worker     pub fn stall(&self, micro: usize) -> Result<()> {
388*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
389*5225e6b1SAndroid Build Coastguard Worker         unsafe { efi_call!(self.boot_services.stall, micro) }
390*5225e6b1SAndroid Build Coastguard Worker     }
391*5225e6b1SAndroid Build Coastguard Worker 
392*5225e6b1SAndroid Build Coastguard Worker     /// Wraps `EFI_BOOT_SERVICE.CreateEvent()`.
393*5225e6b1SAndroid Build Coastguard Worker     ///
394*5225e6b1SAndroid Build Coastguard Worker     /// This function creates an event without a notification callback function; to create an event
395*5225e6b1SAndroid Build Coastguard Worker     /// with a notification, see [create_event_with_notification].
396*5225e6b1SAndroid Build Coastguard Worker     ///
397*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
398*5225e6b1SAndroid Build Coastguard Worker     /// * `event_type`: The EFI event type.
create_event(&self, event_type: EventType) -> Result<Event<'a, 'static>>399*5225e6b1SAndroid Build Coastguard Worker     pub fn create_event(&self, event_type: EventType) -> Result<Event<'a, 'static>> {
400*5225e6b1SAndroid Build Coastguard Worker         let mut efi_event: EfiEvent = null_mut();
401*5225e6b1SAndroid Build Coastguard Worker         // SAFETY:
402*5225e6b1SAndroid Build Coastguard Worker         // * all parameters obey the `CreateEvent()` spec
403*5225e6b1SAndroid Build Coastguard Worker         // * on success we take ownership of the provided `efi_event`
404*5225e6b1SAndroid Build Coastguard Worker         unsafe {
405*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
406*5225e6b1SAndroid Build Coastguard Worker                 self.boot_services.create_event,
407*5225e6b1SAndroid Build Coastguard Worker                 event_type as u32,
408*5225e6b1SAndroid Build Coastguard Worker                 0,
409*5225e6b1SAndroid Build Coastguard Worker                 None,
410*5225e6b1SAndroid Build Coastguard Worker                 null_mut(),
411*5225e6b1SAndroid Build Coastguard Worker                 &mut efi_event
412*5225e6b1SAndroid Build Coastguard Worker             )?;
413*5225e6b1SAndroid Build Coastguard Worker         }
414*5225e6b1SAndroid Build Coastguard Worker         Ok(Event::new(self.efi_entry, efi_event, None))
415*5225e6b1SAndroid Build Coastguard Worker     }
416*5225e6b1SAndroid Build Coastguard Worker 
417*5225e6b1SAndroid Build Coastguard Worker     /// Wraps `EFI_BOOT_SERVICE.CreateEvent()`.
418*5225e6b1SAndroid Build Coastguard Worker     ///
419*5225e6b1SAndroid Build Coastguard Worker     /// This function creates an event with a notification callback function.
420*5225e6b1SAndroid Build Coastguard Worker     ///
421*5225e6b1SAndroid Build Coastguard Worker     /// Unlike [create_event], this function is unsafe because the callback will be executed
422*5225e6b1SAndroid Build Coastguard Worker     /// concurrently with the main application code at a higher interrupt level, and there are
423*5225e6b1SAndroid Build Coastguard Worker     /// a few cases where this can lead to races.
424*5225e6b1SAndroid Build Coastguard Worker     ///
425*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
426*5225e6b1SAndroid Build Coastguard Worker     /// * `event_type`: The EFI event type.
427*5225e6b1SAndroid Build Coastguard Worker     /// * `cb`: An [EventNotify] which implements the event notification function and provides the
428*5225e6b1SAndroid Build Coastguard Worker     ///         task level priority setting.
429*5225e6b1SAndroid Build Coastguard Worker     ///
430*5225e6b1SAndroid Build Coastguard Worker     /// # Safety
431*5225e6b1SAndroid Build Coastguard Worker     /// Most of the safety conditions are enforced at compile-time by the [Sync] requirement on
432*5225e6b1SAndroid Build Coastguard Worker     /// [EventNotifyCallback] - this ensures that e.g. callers cannot capture their raw [EfiEntry]
433*5225e6b1SAndroid Build Coastguard Worker     /// in a callback, but will need to wrap it in a [Sync] type which will ensure safe sharing
434*5225e6b1SAndroid Build Coastguard Worker     /// between the main application and the callback.
435*5225e6b1SAndroid Build Coastguard Worker     ///
436*5225e6b1SAndroid Build Coastguard Worker     /// The exception is the global allocation and panic hooks, which use a separate global
437*5225e6b1SAndroid Build Coastguard Worker     /// [EfiEntry] that is not synchronized outside the main application. The caller must ensure
438*5225e6b1SAndroid Build Coastguard Worker     /// that the main application code is not using its [EfiEntry] while a notification callback
439*5225e6b1SAndroid Build Coastguard Worker     /// is trying to concurrently use the global [EfiEntry].
440*5225e6b1SAndroid Build Coastguard Worker     ///
441*5225e6b1SAndroid Build Coastguard Worker     /// The easiest way to accomplish this is to write notifications callbacks that:
442*5225e6b1SAndroid Build Coastguard Worker     /// * do not allocate or deallocate heap memory
443*5225e6b1SAndroid Build Coastguard Worker     /// * do not panic
444*5225e6b1SAndroid Build Coastguard Worker     /// Callbacks following these guidelines are safe as they do not use the global [EfiEntry].
445*5225e6b1SAndroid Build Coastguard Worker     ///
446*5225e6b1SAndroid Build Coastguard Worker     /// If that is not possible, then the caller must ensure that nothing else makes any calls into
447*5225e6b1SAndroid Build Coastguard Worker     /// UEFI while the returned [Event] is alive; the callback function must have exclusive access
448*5225e6b1SAndroid Build Coastguard Worker     /// to the UEFI APIs so it can use the globals without triggering UEFI reentry.
449*5225e6b1SAndroid Build Coastguard Worker     ///
450*5225e6b1SAndroid Build Coastguard Worker     /// In unittests there is no global [EfiEntry] so this is always safe.
create_event_with_notification<'e>( &self, event_type: EventType, notify: &'e mut EventNotify, ) -> Result<Event<'a, 'e>>451*5225e6b1SAndroid Build Coastguard Worker     pub unsafe fn create_event_with_notification<'e>(
452*5225e6b1SAndroid Build Coastguard Worker         &self,
453*5225e6b1SAndroid Build Coastguard Worker         event_type: EventType,
454*5225e6b1SAndroid Build Coastguard Worker         notify: &'e mut EventNotify,
455*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<Event<'a, 'e>> {
456*5225e6b1SAndroid Build Coastguard Worker         let mut efi_event: EfiEvent = null_mut();
457*5225e6b1SAndroid Build Coastguard Worker         // SAFETY:
458*5225e6b1SAndroid Build Coastguard Worker         // Pointers passed are output/callback context pointers which will not be retained by the
459*5225e6b1SAndroid Build Coastguard Worker         // callback (`fn efi_event_cb()`).
460*5225e6b1SAndroid Build Coastguard Worker         // The returned `Event` enforces a borrow to `cb` for 'e. It closes the event when it
461*5225e6b1SAndroid Build Coastguard Worker         // goes out of scope. This ensures that `cb` lives at least as long as the event is in
462*5225e6b1SAndroid Build Coastguard Worker         // effect and there can be no other borrows to `cb`.
463*5225e6b1SAndroid Build Coastguard Worker         unsafe {
464*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
465*5225e6b1SAndroid Build Coastguard Worker                 self.boot_services.create_event,
466*5225e6b1SAndroid Build Coastguard Worker                 event_type as u32,
467*5225e6b1SAndroid Build Coastguard Worker                 notify.tpl as usize,
468*5225e6b1SAndroid Build Coastguard Worker                 Some(efi_event_cb),
469*5225e6b1SAndroid Build Coastguard Worker                 notify as *mut _ as *mut _,
470*5225e6b1SAndroid Build Coastguard Worker                 &mut efi_event
471*5225e6b1SAndroid Build Coastguard Worker             )?;
472*5225e6b1SAndroid Build Coastguard Worker         }
473*5225e6b1SAndroid Build Coastguard Worker         Ok(Event::new(self.efi_entry, efi_event, Some(notify.cb)))
474*5225e6b1SAndroid Build Coastguard Worker     }
475*5225e6b1SAndroid Build Coastguard Worker 
476*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICE.CloseEvent()`.
close_event(&self, event: &Event) -> Result<()>477*5225e6b1SAndroid Build Coastguard Worker     fn close_event(&self, event: &Event) -> Result<()> {
478*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
479*5225e6b1SAndroid Build Coastguard Worker         unsafe { efi_call!(self.boot_services.close_event, event.efi_event) }
480*5225e6b1SAndroid Build Coastguard Worker     }
481*5225e6b1SAndroid Build Coastguard Worker 
482*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICE.CheckEvent()`.
483*5225e6b1SAndroid Build Coastguard Worker     ///
484*5225e6b1SAndroid Build Coastguard Worker     /// On success, returns true if the event is signaled, false if not.
check_event(&self, event: &Event) -> Result<bool>485*5225e6b1SAndroid Build Coastguard Worker     pub fn check_event(&self, event: &Event) -> Result<bool> {
486*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
487*5225e6b1SAndroid Build Coastguard Worker         match unsafe { efi_call!(self.boot_services.check_event, event.efi_event) } {
488*5225e6b1SAndroid Build Coastguard Worker             Err(e) if e != Error::NotReady => Err(e),
489*5225e6b1SAndroid Build Coastguard Worker             Ok(()) => Ok(true),
490*5225e6b1SAndroid Build Coastguard Worker             _ => Ok(false),
491*5225e6b1SAndroid Build Coastguard Worker         }
492*5225e6b1SAndroid Build Coastguard Worker     }
493*5225e6b1SAndroid Build Coastguard Worker 
494*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_BOOT_SERVICE.SetTimer()`.
set_timer( &self, event: &Event, delay_type: EfiTimerDelay, trigger_time: u64, ) -> Result<()>495*5225e6b1SAndroid Build Coastguard Worker     pub fn set_timer(
496*5225e6b1SAndroid Build Coastguard Worker         &self,
497*5225e6b1SAndroid Build Coastguard Worker         event: &Event,
498*5225e6b1SAndroid Build Coastguard Worker         delay_type: EfiTimerDelay,
499*5225e6b1SAndroid Build Coastguard Worker         trigger_time: u64,
500*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<()> {
501*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: EFI_BOOT_SERVICES method call.
502*5225e6b1SAndroid Build Coastguard Worker         unsafe {
503*5225e6b1SAndroid Build Coastguard Worker             efi_call!(self.boot_services.set_timer, event.efi_event, delay_type, trigger_time)
504*5225e6b1SAndroid Build Coastguard Worker         }
505*5225e6b1SAndroid Build Coastguard Worker     }
506*5225e6b1SAndroid Build Coastguard Worker }
507*5225e6b1SAndroid Build Coastguard Worker 
508*5225e6b1SAndroid Build Coastguard Worker /// `RuntimeServices` provides methods for accessing various EFI_RUNTIME_SERVICES interfaces.
509*5225e6b1SAndroid Build Coastguard Worker #[derive(Clone, Copy)]
510*5225e6b1SAndroid Build Coastguard Worker pub struct RuntimeServices {
511*5225e6b1SAndroid Build Coastguard Worker     runtime_services: EfiRuntimeService,
512*5225e6b1SAndroid Build Coastguard Worker }
513*5225e6b1SAndroid Build Coastguard Worker 
514*5225e6b1SAndroid Build Coastguard Worker impl RuntimeServices {
515*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_RUNTIME_SERVICES.GetVariable()`.
get_variable(&self, guid: &EfiGuid, name: &str, out: &mut [u8]) -> Result<usize>516*5225e6b1SAndroid Build Coastguard Worker     pub fn get_variable(&self, guid: &EfiGuid, name: &str, out: &mut [u8]) -> Result<usize> {
517*5225e6b1SAndroid Build Coastguard Worker         let mut size = out.len();
518*5225e6b1SAndroid Build Coastguard Worker 
519*5225e6b1SAndroid Build Coastguard Worker         let mut name_utf16: Vec<u16> = name.encode_utf16().collect();
520*5225e6b1SAndroid Build Coastguard Worker         name_utf16.push(0); // null-terminator
521*5225e6b1SAndroid Build Coastguard Worker 
522*5225e6b1SAndroid Build Coastguard Worker         // SAFETY:
523*5225e6b1SAndroid Build Coastguard Worker         // * `&mut size` and `&mut out` are input/output params only and will not be retained
524*5225e6b1SAndroid Build Coastguard Worker         // * `&mut size` and `&mut out` are valid pointers and outlive the call
525*5225e6b1SAndroid Build Coastguard Worker         unsafe {
526*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
527*5225e6b1SAndroid Build Coastguard Worker                 @bufsize size,
528*5225e6b1SAndroid Build Coastguard Worker                 self.runtime_services.get_variable,
529*5225e6b1SAndroid Build Coastguard Worker                 name_utf16.as_ptr(),
530*5225e6b1SAndroid Build Coastguard Worker                 guid,
531*5225e6b1SAndroid Build Coastguard Worker                 null_mut(),
532*5225e6b1SAndroid Build Coastguard Worker                 &mut size,
533*5225e6b1SAndroid Build Coastguard Worker                 out.as_mut_ptr() as *mut core::ffi::c_void
534*5225e6b1SAndroid Build Coastguard Worker             )?;
535*5225e6b1SAndroid Build Coastguard Worker         }
536*5225e6b1SAndroid Build Coastguard Worker         Ok(size)
537*5225e6b1SAndroid Build Coastguard Worker     }
538*5225e6b1SAndroid Build Coastguard Worker 
539*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_RUNTIME_SERVICES.SetVariable()`.
set_variable(&self, guid: &EfiGuid, name: &str, data: &[u8]) -> Result<()>540*5225e6b1SAndroid Build Coastguard Worker     pub fn set_variable(&self, guid: &EfiGuid, name: &str, data: &[u8]) -> Result<()> {
541*5225e6b1SAndroid Build Coastguard Worker         let mut name_utf16: Vec<u16> = name.encode_utf16().collect();
542*5225e6b1SAndroid Build Coastguard Worker         name_utf16.push(0); // null-terminator
543*5225e6b1SAndroid Build Coastguard Worker 
544*5225e6b1SAndroid Build Coastguard Worker         // SAFETY:
545*5225e6b1SAndroid Build Coastguard Worker         // * `data.as_mut_ptr()` and `name_utf16.as_ptr()` are valid pointers,
546*5225e6b1SAndroid Build Coastguard Worker         // * outlive the call, and are not retained.
547*5225e6b1SAndroid Build Coastguard Worker         unsafe {
548*5225e6b1SAndroid Build Coastguard Worker             efi_call!(
549*5225e6b1SAndroid Build Coastguard Worker                 self.runtime_services.set_variable,
550*5225e6b1SAndroid Build Coastguard Worker                 name_utf16.as_ptr(),
551*5225e6b1SAndroid Build Coastguard Worker                 guid,
552*5225e6b1SAndroid Build Coastguard Worker                 0,
553*5225e6b1SAndroid Build Coastguard Worker                 data.len(),
554*5225e6b1SAndroid Build Coastguard Worker                 data.as_ptr() as *const core::ffi::c_void
555*5225e6b1SAndroid Build Coastguard Worker             )
556*5225e6b1SAndroid Build Coastguard Worker         }
557*5225e6b1SAndroid Build Coastguard Worker     }
558*5225e6b1SAndroid Build Coastguard Worker 
559*5225e6b1SAndroid Build Coastguard Worker     /// Wrapper of `EFI_RUNTIME_SERVICES.reset_system`.
reset_system( &self, reset_type: EFI_RESET_TYPE, reset_status: EFI_STATUS, reset_data: Option<&mut [u8]>, ) -> !560*5225e6b1SAndroid Build Coastguard Worker     pub fn reset_system(
561*5225e6b1SAndroid Build Coastguard Worker         &self,
562*5225e6b1SAndroid Build Coastguard Worker         reset_type: EFI_RESET_TYPE,
563*5225e6b1SAndroid Build Coastguard Worker         reset_status: EFI_STATUS,
564*5225e6b1SAndroid Build Coastguard Worker         reset_data: Option<&mut [u8]>,
565*5225e6b1SAndroid Build Coastguard Worker     ) -> ! {
566*5225e6b1SAndroid Build Coastguard Worker         let (reset_data_len, reset_data_ptr) = match reset_data {
567*5225e6b1SAndroid Build Coastguard Worker             Some(v) => (v.len(), v.as_mut_ptr() as _),
568*5225e6b1SAndroid Build Coastguard Worker             _ => (0, null_mut()),
569*5225e6b1SAndroid Build Coastguard Worker         };
570*5225e6b1SAndroid Build Coastguard Worker         // SAFETY:
571*5225e6b1SAndroid Build Coastguard Worker         // * `reset_data_ptr` is either a valid pointer or NULL which by UEFI spec is allowed.
572*5225e6b1SAndroid Build Coastguard Worker         // * The call reboots the device and thus is not expected to return.
573*5225e6b1SAndroid Build Coastguard Worker         unsafe {
574*5225e6b1SAndroid Build Coastguard Worker             self.runtime_services.reset_system.unwrap()(
575*5225e6b1SAndroid Build Coastguard Worker                 reset_type,
576*5225e6b1SAndroid Build Coastguard Worker                 reset_status,
577*5225e6b1SAndroid Build Coastguard Worker                 reset_data_len,
578*5225e6b1SAndroid Build Coastguard Worker                 reset_data_ptr,
579*5225e6b1SAndroid Build Coastguard Worker             );
580*5225e6b1SAndroid Build Coastguard Worker         }
581*5225e6b1SAndroid Build Coastguard Worker 
582*5225e6b1SAndroid Build Coastguard Worker         unreachable!();
583*5225e6b1SAndroid Build Coastguard Worker     }
584*5225e6b1SAndroid Build Coastguard Worker 
585*5225e6b1SAndroid Build Coastguard Worker     /// Performs a cold reset without status code or data.
cold_reset(&self) -> !586*5225e6b1SAndroid Build Coastguard Worker     pub fn cold_reset(&self) -> ! {
587*5225e6b1SAndroid Build Coastguard Worker         self.reset_system(EFI_RESET_TYPE_EFI_RESET_COLD, EFI_STATUS_SUCCESS, None)
588*5225e6b1SAndroid Build Coastguard Worker     }
589*5225e6b1SAndroid Build Coastguard Worker }
590*5225e6b1SAndroid Build Coastguard Worker 
591*5225e6b1SAndroid Build Coastguard Worker /// EFI Event type to pass to BootServicess::create_event.
592*5225e6b1SAndroid Build Coastguard Worker /// See UEFI documentation for details.
593*5225e6b1SAndroid Build Coastguard Worker #[allow(missing_docs)]
594*5225e6b1SAndroid Build Coastguard Worker #[repr(u32)]
595*5225e6b1SAndroid Build Coastguard Worker pub enum EventType {
596*5225e6b1SAndroid Build Coastguard Worker     Timer = EFI_EVENT_TYPE_TIMER,
597*5225e6b1SAndroid Build Coastguard Worker     RunTime = EFI_EVENT_TYPE_RUNTIME,
598*5225e6b1SAndroid Build Coastguard Worker     NotifyWait = EFI_EVENT_TYPE_NOTIFY_WAIT,
599*5225e6b1SAndroid Build Coastguard Worker     NotifySignal = EFI_EVENT_TYPE_NOTIFY_SIGNAL,
600*5225e6b1SAndroid Build Coastguard Worker     SignalExitBootServices = EFI_EVENT_TYPE_SIGNAL_EXIT_BOOT_SERVICES,
601*5225e6b1SAndroid Build Coastguard Worker     SignalVirtualAddressChange = EFI_EVENT_TYPE_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
602*5225e6b1SAndroid Build Coastguard Worker 
603*5225e6b1SAndroid Build Coastguard Worker     // Valid combinations:
604*5225e6b1SAndroid Build Coastguard Worker     TimerNotifySignal = EFI_EVENT_TYPE_TIMER | EFI_EVENT_TYPE_NOTIFY_SIGNAL,
605*5225e6b1SAndroid Build Coastguard Worker }
606*5225e6b1SAndroid Build Coastguard Worker 
607*5225e6b1SAndroid Build Coastguard Worker /// EFI task level priority setting for event notify function.
608*5225e6b1SAndroid Build Coastguard Worker /// See UEFI documentation for details.
609*5225e6b1SAndroid Build Coastguard Worker #[allow(missing_docs)]
610*5225e6b1SAndroid Build Coastguard Worker #[repr(usize)]
611*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone)]
612*5225e6b1SAndroid Build Coastguard Worker pub enum Tpl {
613*5225e6b1SAndroid Build Coastguard Worker     Application = 4,
614*5225e6b1SAndroid Build Coastguard Worker     Callback = 8,
615*5225e6b1SAndroid Build Coastguard Worker     Notify = 16,
616*5225e6b1SAndroid Build Coastguard Worker     HighLevel = 31,
617*5225e6b1SAndroid Build Coastguard Worker }
618*5225e6b1SAndroid Build Coastguard Worker 
619*5225e6b1SAndroid Build Coastguard Worker /// Event notification callback function.
620*5225e6b1SAndroid Build Coastguard Worker ///
621*5225e6b1SAndroid Build Coastguard Worker /// The callback function itself takes the [EfiEvent] as an argument and has no return value.
622*5225e6b1SAndroid Build Coastguard Worker /// This type is a mutable borrow of a closure to ensure that it will outlive the [EfiEvent] and
623*5225e6b1SAndroid Build Coastguard Worker /// that the callback has exclusive access to it.
624*5225e6b1SAndroid Build Coastguard Worker ///
625*5225e6b1SAndroid Build Coastguard Worker /// Additionally, the function must be [Sync] because it will be run concurrently to the main app
626*5225e6b1SAndroid Build Coastguard Worker /// code at a higher interrupt level. One consequence of this is that we cannot capture an
627*5225e6b1SAndroid Build Coastguard Worker /// [EfiEntry] or any related object in the closure, as they are not [Sync]. This is intentional;
628*5225e6b1SAndroid Build Coastguard Worker /// in general UEFI APIs are not reentrant except in very limited ways, and we could trigger
629*5225e6b1SAndroid Build Coastguard Worker /// undefined behavior if we try to call into UEFI while the main application code is also in the
630*5225e6b1SAndroid Build Coastguard Worker /// middle of a UEFI call. Instead, the notification should signal the main app code to make any
631*5225e6b1SAndroid Build Coastguard Worker /// necessary UEFI calls once it regains control.
632*5225e6b1SAndroid Build Coastguard Worker pub type EventNotifyCallback<'a> = &'a mut (dyn FnMut(EfiEvent) + Sync);
633*5225e6b1SAndroid Build Coastguard Worker 
634*5225e6b1SAndroid Build Coastguard Worker /// `EventNotify` contains the task level priority setting and a mutable reference to a
635*5225e6b1SAndroid Build Coastguard Worker /// closure for the callback. It is passed as the context pointer to low level EFI event
636*5225e6b1SAndroid Build Coastguard Worker /// notification function entry (`unsafe extern "C" fn efi_event_cb(...)`).
637*5225e6b1SAndroid Build Coastguard Worker pub struct EventNotify<'e> {
638*5225e6b1SAndroid Build Coastguard Worker     tpl: Tpl,
639*5225e6b1SAndroid Build Coastguard Worker     cb: EventNotifyCallback<'e>,
640*5225e6b1SAndroid Build Coastguard Worker }
641*5225e6b1SAndroid Build Coastguard Worker 
642*5225e6b1SAndroid Build Coastguard Worker impl<'e> EventNotify<'e> {
643*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new [EventNotify].
new(tpl: Tpl, cb: EventNotifyCallback<'e>) -> Self644*5225e6b1SAndroid Build Coastguard Worker     pub fn new(tpl: Tpl, cb: EventNotifyCallback<'e>) -> Self {
645*5225e6b1SAndroid Build Coastguard Worker         Self { tpl, cb }
646*5225e6b1SAndroid Build Coastguard Worker     }
647*5225e6b1SAndroid Build Coastguard Worker }
648*5225e6b1SAndroid Build Coastguard Worker 
649*5225e6b1SAndroid Build Coastguard Worker /// `Event` wraps the raw `EfiEvent` handle and internally enforces a borrow of the registered
650*5225e6b1SAndroid Build Coastguard Worker /// callback for the given life time `'n`. The event is automatically closed when going out of
651*5225e6b1SAndroid Build Coastguard Worker /// scope.
652*5225e6b1SAndroid Build Coastguard Worker pub struct Event<'a, 'n> {
653*5225e6b1SAndroid Build Coastguard Worker     // If `efi_entry` is None, it represents an unowned Event and won't get closed on drop.
654*5225e6b1SAndroid Build Coastguard Worker     efi_entry: Option<&'a EfiEntry>,
655*5225e6b1SAndroid Build Coastguard Worker     efi_event: EfiEvent,
656*5225e6b1SAndroid Build Coastguard Worker     // The actual callback has been passed into UEFI via raw pointer in [create_event], so we
657*5225e6b1SAndroid Build Coastguard Worker     // use [PhantomData] to ensure the callback will outlive the event.
658*5225e6b1SAndroid Build Coastguard Worker     cb: PhantomData<Option<EventNotifyCallback<'n>>>,
659*5225e6b1SAndroid Build Coastguard Worker }
660*5225e6b1SAndroid Build Coastguard Worker 
661*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'n> Event<'a, 'n> {
662*5225e6b1SAndroid Build Coastguard Worker     /// Creates an instance of owned `Event`. The `Event` is closed when going out of scope.
new( efi_entry: &'a EfiEntry, efi_event: EfiEvent, _cb: Option<EventNotifyCallback<'n>>, ) -> Self663*5225e6b1SAndroid Build Coastguard Worker     fn new(
664*5225e6b1SAndroid Build Coastguard Worker         efi_entry: &'a EfiEntry,
665*5225e6b1SAndroid Build Coastguard Worker         efi_event: EfiEvent,
666*5225e6b1SAndroid Build Coastguard Worker         _cb: Option<EventNotifyCallback<'n>>,
667*5225e6b1SAndroid Build Coastguard Worker     ) -> Self {
668*5225e6b1SAndroid Build Coastguard Worker         Self { efi_entry: Some(efi_entry), efi_event, cb: PhantomData }
669*5225e6b1SAndroid Build Coastguard Worker     }
670*5225e6b1SAndroid Build Coastguard Worker 
671*5225e6b1SAndroid Build Coastguard Worker     /// Creates an  unowned `Event`. The `Event` is not closed when going out of scope.
672*5225e6b1SAndroid Build Coastguard Worker     // TODO allow unused?
673*5225e6b1SAndroid Build Coastguard Worker     #[allow(dead_code)]
new_unowned(efi_event: EfiEvent) -> Self674*5225e6b1SAndroid Build Coastguard Worker     fn new_unowned(efi_event: EfiEvent) -> Self {
675*5225e6b1SAndroid Build Coastguard Worker         Self { efi_entry: None, efi_event: efi_event, cb: PhantomData }
676*5225e6b1SAndroid Build Coastguard Worker     }
677*5225e6b1SAndroid Build Coastguard Worker }
678*5225e6b1SAndroid Build Coastguard Worker 
679*5225e6b1SAndroid Build Coastguard Worker impl Drop for Event<'_, '_> {
drop(&mut self)680*5225e6b1SAndroid Build Coastguard Worker     fn drop(&mut self) {
681*5225e6b1SAndroid Build Coastguard Worker         if let Some(efi_entry) = self.efi_entry {
682*5225e6b1SAndroid Build Coastguard Worker             efi_entry.system_table().boot_services().close_event(self).unwrap();
683*5225e6b1SAndroid Build Coastguard Worker         }
684*5225e6b1SAndroid Build Coastguard Worker     }
685*5225e6b1SAndroid Build Coastguard Worker }
686*5225e6b1SAndroid Build Coastguard Worker 
687*5225e6b1SAndroid Build Coastguard Worker /// Event notify function entry for EFI events.
688*5225e6b1SAndroid Build Coastguard Worker ///
689*5225e6b1SAndroid Build Coastguard Worker /// Safety:
690*5225e6b1SAndroid Build Coastguard Worker ///
691*5225e6b1SAndroid Build Coastguard Worker ///   `ctx` must point to a `EventNotify` type object.
692*5225e6b1SAndroid Build Coastguard Worker ///   `ctx` must live longer than the event.
693*5225e6b1SAndroid Build Coastguard Worker ///   There should be no other references to `ctx`.
efi_event_cb(event: EfiEvent, ctx: *mut core::ffi::c_void)694*5225e6b1SAndroid Build Coastguard Worker unsafe extern "C" fn efi_event_cb(event: EfiEvent, ctx: *mut core::ffi::c_void) {
695*5225e6b1SAndroid Build Coastguard Worker     // SAFETY: By safety requirement of this function, ctx points to a valid `EventNotify` object,
696*5225e6b1SAndroid Build Coastguard Worker     // outlives the event/the function call, and there is no other borrows.
697*5225e6b1SAndroid Build Coastguard Worker     let event_cb = unsafe { (ctx as *mut EventNotify).as_mut() }.unwrap();
698*5225e6b1SAndroid Build Coastguard Worker     (event_cb.cb)(event);
699*5225e6b1SAndroid Build Coastguard Worker }
700*5225e6b1SAndroid Build Coastguard Worker 
701*5225e6b1SAndroid Build Coastguard Worker /// A type for accessing memory map.
702*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug)]
703*5225e6b1SAndroid Build Coastguard Worker pub struct EfiMemoryMap<'a> {
704*5225e6b1SAndroid Build Coastguard Worker     buffer: &'a mut [u8],
705*5225e6b1SAndroid Build Coastguard Worker     map_key: usize,
706*5225e6b1SAndroid Build Coastguard Worker     descriptor_size: usize,
707*5225e6b1SAndroid Build Coastguard Worker     descriptor_version: u32,
708*5225e6b1SAndroid Build Coastguard Worker }
709*5225e6b1SAndroid Build Coastguard Worker 
710*5225e6b1SAndroid Build Coastguard Worker /// Iterator for traversing `EfiMemoryDescriptor` items in `EfiMemoryMap::buffer`.
711*5225e6b1SAndroid Build Coastguard Worker pub struct EfiMemoryMapIter<'a: 'b, 'b> {
712*5225e6b1SAndroid Build Coastguard Worker     memory_map: &'b EfiMemoryMap<'a>,
713*5225e6b1SAndroid Build Coastguard Worker     offset: usize,
714*5225e6b1SAndroid Build Coastguard Worker }
715*5225e6b1SAndroid Build Coastguard Worker 
716*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'b> Iterator for EfiMemoryMapIter<'a, 'b> {
717*5225e6b1SAndroid Build Coastguard Worker     type Item = &'b EfiMemoryDescriptor;
718*5225e6b1SAndroid Build Coastguard Worker 
next(&mut self) -> Option<Self::Item>719*5225e6b1SAndroid Build Coastguard Worker     fn next(&mut self) -> Option<Self::Item> {
720*5225e6b1SAndroid Build Coastguard Worker         if self.offset >= self.memory_map.buffer.len() {
721*5225e6b1SAndroid Build Coastguard Worker             return None;
722*5225e6b1SAndroid Build Coastguard Worker         }
723*5225e6b1SAndroid Build Coastguard Worker         let bytes = &self.memory_map.buffer[self.offset..][..self.memory_map.descriptor_size];
724*5225e6b1SAndroid Build Coastguard Worker         self.offset += self.memory_map.descriptor_size;
725*5225e6b1SAndroid Build Coastguard Worker         Some(Ref::<_, EfiMemoryDescriptor>::new_from_prefix(bytes).unwrap().0.into_ref())
726*5225e6b1SAndroid Build Coastguard Worker     }
727*5225e6b1SAndroid Build Coastguard Worker }
728*5225e6b1SAndroid Build Coastguard Worker 
729*5225e6b1SAndroid Build Coastguard Worker impl<'a> EfiMemoryMap<'a> {
730*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new instance with the given parameters obtained from `get_memory_map()`.
new( buffer: &'a mut [u8], map_key: usize, descriptor_size: usize, descriptor_version: u32, ) -> Self731*5225e6b1SAndroid Build Coastguard Worker     fn new(
732*5225e6b1SAndroid Build Coastguard Worker         buffer: &'a mut [u8],
733*5225e6b1SAndroid Build Coastguard Worker         map_key: usize,
734*5225e6b1SAndroid Build Coastguard Worker         descriptor_size: usize,
735*5225e6b1SAndroid Build Coastguard Worker         descriptor_version: u32,
736*5225e6b1SAndroid Build Coastguard Worker     ) -> Self {
737*5225e6b1SAndroid Build Coastguard Worker         Self { buffer, map_key, descriptor_size, descriptor_version }
738*5225e6b1SAndroid Build Coastguard Worker     }
739*5225e6b1SAndroid Build Coastguard Worker 
740*5225e6b1SAndroid Build Coastguard Worker     /// Returns the buffer.
buffer(&self) -> &[u8]741*5225e6b1SAndroid Build Coastguard Worker     pub fn buffer(&self) -> &[u8] {
742*5225e6b1SAndroid Build Coastguard Worker         self.buffer
743*5225e6b1SAndroid Build Coastguard Worker     }
744*5225e6b1SAndroid Build Coastguard Worker 
745*5225e6b1SAndroid Build Coastguard Worker     /// Returns the value of `map_key`.
map_key(&self) -> usize746*5225e6b1SAndroid Build Coastguard Worker     pub fn map_key(&self) -> usize {
747*5225e6b1SAndroid Build Coastguard Worker         self.map_key
748*5225e6b1SAndroid Build Coastguard Worker     }
749*5225e6b1SAndroid Build Coastguard Worker 
750*5225e6b1SAndroid Build Coastguard Worker     /// Returns the value of `descriptor_version`.
descriptor_version(&self) -> u32751*5225e6b1SAndroid Build Coastguard Worker     pub fn descriptor_version(&self) -> u32 {
752*5225e6b1SAndroid Build Coastguard Worker         self.descriptor_version
753*5225e6b1SAndroid Build Coastguard Worker     }
754*5225e6b1SAndroid Build Coastguard Worker 
755*5225e6b1SAndroid Build Coastguard Worker     /// Returns the number of descriptors.
len(&self) -> usize756*5225e6b1SAndroid Build Coastguard Worker     pub fn len(&self) -> usize {
757*5225e6b1SAndroid Build Coastguard Worker         self.buffer.len() / self.descriptor_size
758*5225e6b1SAndroid Build Coastguard Worker     }
759*5225e6b1SAndroid Build Coastguard Worker }
760*5225e6b1SAndroid Build Coastguard Worker 
761*5225e6b1SAndroid Build Coastguard Worker impl<'a: 'b, 'b> IntoIterator for &'b EfiMemoryMap<'a> {
762*5225e6b1SAndroid Build Coastguard Worker     type Item = &'b EfiMemoryDescriptor;
763*5225e6b1SAndroid Build Coastguard Worker     type IntoIter = EfiMemoryMapIter<'a, 'b>;
764*5225e6b1SAndroid Build Coastguard Worker 
into_iter(self) -> Self::IntoIter765*5225e6b1SAndroid Build Coastguard Worker     fn into_iter(self) -> Self::IntoIter {
766*5225e6b1SAndroid Build Coastguard Worker         EfiMemoryMapIter { memory_map: self, offset: 0 }
767*5225e6b1SAndroid Build Coastguard Worker     }
768*5225e6b1SAndroid Build Coastguard Worker }
769*5225e6b1SAndroid Build Coastguard Worker 
770*5225e6b1SAndroid Build Coastguard Worker /// A type for accessing Memory attributes table
771*5225e6b1SAndroid Build Coastguard Worker pub struct EfiMemoryAttributesTable<'a> {
772*5225e6b1SAndroid Build Coastguard Worker     /// EfiMemoryAttributesTable header
773*5225e6b1SAndroid Build Coastguard Worker     pub header: &'a EfiMemoryAttributesTableHeader,
774*5225e6b1SAndroid Build Coastguard Worker     tail: &'a [u8],
775*5225e6b1SAndroid Build Coastguard Worker }
776*5225e6b1SAndroid Build Coastguard Worker 
777*5225e6b1SAndroid Build Coastguard Worker /// Iterator for traversing `EfiMemoryAttributesTable` descriptors.
778*5225e6b1SAndroid Build Coastguard Worker pub struct EfiMemoryAttributesTableIter<'a> {
779*5225e6b1SAndroid Build Coastguard Worker     descriptor_size: usize,
780*5225e6b1SAndroid Build Coastguard Worker     tail: &'a [u8],
781*5225e6b1SAndroid Build Coastguard Worker }
782*5225e6b1SAndroid Build Coastguard Worker 
783*5225e6b1SAndroid Build Coastguard Worker impl<'a> Iterator for EfiMemoryAttributesTableIter<'a> {
784*5225e6b1SAndroid Build Coastguard Worker     type Item = &'a EfiMemoryDescriptor;
785*5225e6b1SAndroid Build Coastguard Worker 
next(&mut self) -> Option<Self::Item>786*5225e6b1SAndroid Build Coastguard Worker     fn next(&mut self) -> Option<Self::Item> {
787*5225e6b1SAndroid Build Coastguard Worker         // Descriptor size can be greater than `EfiMemoryDescriptor`, so we potentially slice off
788*5225e6b1SAndroid Build Coastguard Worker         // pieces greater than struct size. Thus can't just convert buffer to slice of
789*5225e6b1SAndroid Build Coastguard Worker         // corresponding type.
790*5225e6b1SAndroid Build Coastguard Worker         if let Some((desc_bytes, tail_new)) = self.tail.split_at_checked(self.descriptor_size) {
791*5225e6b1SAndroid Build Coastguard Worker             let desc =
792*5225e6b1SAndroid Build Coastguard Worker                 Ref::<_, EfiMemoryDescriptor>::new_from_prefix(desc_bytes).unwrap().0.into_ref();
793*5225e6b1SAndroid Build Coastguard Worker             self.tail = tail_new;
794*5225e6b1SAndroid Build Coastguard Worker             Some(desc)
795*5225e6b1SAndroid Build Coastguard Worker         } else {
796*5225e6b1SAndroid Build Coastguard Worker             None
797*5225e6b1SAndroid Build Coastguard Worker         }
798*5225e6b1SAndroid Build Coastguard Worker     }
799*5225e6b1SAndroid Build Coastguard Worker }
800*5225e6b1SAndroid Build Coastguard Worker 
801*5225e6b1SAndroid Build Coastguard Worker impl<'a> EfiMemoryAttributesTable<'a> {
802*5225e6b1SAndroid Build Coastguard Worker     /// Creates a new instance with the given parameters obtained from `get_memory_map()`.
803*5225e6b1SAndroid Build Coastguard Worker     ///
804*5225e6b1SAndroid Build Coastguard Worker     /// # Returns
805*5225e6b1SAndroid Build Coastguard Worker     /// Ok(EfiMemoryAttributesTable) - on success
806*5225e6b1SAndroid Build Coastguard Worker     /// Err(Error::NotFound) - if table type is incorrect
807*5225e6b1SAndroid Build Coastguard Worker     /// Err(e) - if error `e` occurred parsing table buffer
808*5225e6b1SAndroid Build Coastguard Worker     //
809*5225e6b1SAndroid Build Coastguard Worker     // SAFETY:
810*5225e6b1SAndroid Build Coastguard Worker     // `configuration_table` must be valid EFI Configuration Table object.
new( configuration_table: EfiConfigurationTable, ) -> Result<EfiMemoryAttributesTable<'a>>811*5225e6b1SAndroid Build Coastguard Worker     pub unsafe fn new(
812*5225e6b1SAndroid Build Coastguard Worker         configuration_table: EfiConfigurationTable,
813*5225e6b1SAndroid Build Coastguard Worker     ) -> Result<EfiMemoryAttributesTable<'a>> {
814*5225e6b1SAndroid Build Coastguard Worker         if configuration_table.vendor_guid != EFI_MEMORY_ATTRIBUTES_GUID {
815*5225e6b1SAndroid Build Coastguard Worker             return Err(Error::NotFound);
816*5225e6b1SAndroid Build Coastguard Worker         }
817*5225e6b1SAndroid Build Coastguard Worker         let buf = configuration_table.vendor_table;
818*5225e6b1SAndroid Build Coastguard Worker 
819*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: Buffer provided by EFI configuration table.
820*5225e6b1SAndroid Build Coastguard Worker         let header = unsafe {
821*5225e6b1SAndroid Build Coastguard Worker             let header_bytes =
822*5225e6b1SAndroid Build Coastguard Worker                 from_raw_parts(buf as *const u8, size_of::<EfiMemoryAttributesTableHeader>());
823*5225e6b1SAndroid Build Coastguard Worker             EfiMemoryAttributesTableHeader::ref_from(header_bytes).ok_or(Error::InvalidInput)?
824*5225e6b1SAndroid Build Coastguard Worker         };
825*5225e6b1SAndroid Build Coastguard Worker 
826*5225e6b1SAndroid Build Coastguard Worker         // Note: `descriptor_size` may be bigger than `EfiMemoryDescriptor`.
827*5225e6b1SAndroid Build Coastguard Worker         let descriptor_size: usize = header.descriptor_size.try_into().unwrap();
828*5225e6b1SAndroid Build Coastguard Worker         let descriptors_count: usize = header.number_of_entries.try_into().unwrap();
829*5225e6b1SAndroid Build Coastguard Worker 
830*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: Buffer provided by EFI configuration table.
831*5225e6b1SAndroid Build Coastguard Worker         let tail = unsafe {
832*5225e6b1SAndroid Build Coastguard Worker             from_raw_parts(
833*5225e6b1SAndroid Build Coastguard Worker                 (buf as *const u8).add(core::mem::size_of_val(header)),
834*5225e6b1SAndroid Build Coastguard Worker                 descriptors_count * descriptor_size,
835*5225e6b1SAndroid Build Coastguard Worker             )
836*5225e6b1SAndroid Build Coastguard Worker         };
837*5225e6b1SAndroid Build Coastguard Worker 
838*5225e6b1SAndroid Build Coastguard Worker         Ok(Self { header, tail })
839*5225e6b1SAndroid Build Coastguard Worker     }
840*5225e6b1SAndroid Build Coastguard Worker }
841*5225e6b1SAndroid Build Coastguard Worker 
842*5225e6b1SAndroid Build Coastguard Worker impl<'a> IntoIterator for &EfiMemoryAttributesTable<'a> {
843*5225e6b1SAndroid Build Coastguard Worker     type Item = &'a EfiMemoryDescriptor;
844*5225e6b1SAndroid Build Coastguard Worker     type IntoIter = EfiMemoryAttributesTableIter<'a>;
845*5225e6b1SAndroid Build Coastguard Worker 
into_iter(self) -> Self::IntoIter846*5225e6b1SAndroid Build Coastguard Worker     fn into_iter(self) -> Self::IntoIter {
847*5225e6b1SAndroid Build Coastguard Worker         let descriptor_size = usize::try_from(self.header.descriptor_size).unwrap();
848*5225e6b1SAndroid Build Coastguard Worker         let tail = &self.tail[..];
849*5225e6b1SAndroid Build Coastguard Worker         EfiMemoryAttributesTableIter { descriptor_size, tail }
850*5225e6b1SAndroid Build Coastguard Worker     }
851*5225e6b1SAndroid Build Coastguard Worker }
852*5225e6b1SAndroid Build Coastguard Worker 
853*5225e6b1SAndroid Build Coastguard Worker /// A type representing a UEFI handle to a UEFI device.
854*5225e6b1SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, PartialEq)]
855*5225e6b1SAndroid Build Coastguard Worker pub struct DeviceHandle(EfiHandle);
856*5225e6b1SAndroid Build Coastguard Worker 
857*5225e6b1SAndroid Build Coastguard Worker impl DeviceHandle {
858*5225e6b1SAndroid Build Coastguard Worker     /// Public constructor
new(handle: EfiHandle) -> Self859*5225e6b1SAndroid Build Coastguard Worker     pub fn new(handle: EfiHandle) -> Self {
860*5225e6b1SAndroid Build Coastguard Worker         Self(handle)
861*5225e6b1SAndroid Build Coastguard Worker     }
862*5225e6b1SAndroid Build Coastguard Worker }
863*5225e6b1SAndroid Build Coastguard Worker 
864*5225e6b1SAndroid Build Coastguard Worker /// `LocatedHandles` holds the array of handles return by
865*5225e6b1SAndroid Build Coastguard Worker /// `BootServices::locate_handle_buffer_by_protocol()`.
866*5225e6b1SAndroid Build Coastguard Worker pub struct LocatedHandles<'a> {
867*5225e6b1SAndroid Build Coastguard Worker     handles: &'a [DeviceHandle],
868*5225e6b1SAndroid Build Coastguard Worker     efi_entry: &'a EfiEntry,
869*5225e6b1SAndroid Build Coastguard Worker }
870*5225e6b1SAndroid Build Coastguard Worker 
871*5225e6b1SAndroid Build Coastguard Worker impl<'a> LocatedHandles<'a> {
new(handles: *mut EfiHandle, len: usize, efi_entry: &'a EfiEntry) -> Self872*5225e6b1SAndroid Build Coastguard Worker     pub(crate) fn new(handles: *mut EfiHandle, len: usize, efi_entry: &'a EfiEntry) -> Self {
873*5225e6b1SAndroid Build Coastguard Worker         // Implementation is not suppose to call this with a NULL pointer.
874*5225e6b1SAndroid Build Coastguard Worker         debug_assert!(!handles.is_null());
875*5225e6b1SAndroid Build Coastguard Worker         Self {
876*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: Given correct UEFI firmware, non-null pointer points to valid memory.
877*5225e6b1SAndroid Build Coastguard Worker             // The memory is owned by the objects.
878*5225e6b1SAndroid Build Coastguard Worker             handles: unsafe { from_raw_parts(handles as *mut DeviceHandle, len) },
879*5225e6b1SAndroid Build Coastguard Worker             efi_entry: efi_entry,
880*5225e6b1SAndroid Build Coastguard Worker         }
881*5225e6b1SAndroid Build Coastguard Worker     }
882*5225e6b1SAndroid Build Coastguard Worker     /// Get the list of handles as a slice.
handles(&self) -> &[DeviceHandle]883*5225e6b1SAndroid Build Coastguard Worker     pub fn handles(&self) -> &[DeviceHandle] {
884*5225e6b1SAndroid Build Coastguard Worker         self.handles
885*5225e6b1SAndroid Build Coastguard Worker     }
886*5225e6b1SAndroid Build Coastguard Worker }
887*5225e6b1SAndroid Build Coastguard Worker 
888*5225e6b1SAndroid Build Coastguard Worker impl Drop for LocatedHandles<'_> {
drop(&mut self)889*5225e6b1SAndroid Build Coastguard Worker     fn drop(&mut self) {
890*5225e6b1SAndroid Build Coastguard Worker         self.efi_entry
891*5225e6b1SAndroid Build Coastguard Worker             .system_table()
892*5225e6b1SAndroid Build Coastguard Worker             .boot_services()
893*5225e6b1SAndroid Build Coastguard Worker             .free_pool(self.handles.as_ptr() as *mut _)
894*5225e6b1SAndroid Build Coastguard Worker             .unwrap();
895*5225e6b1SAndroid Build Coastguard Worker     }
896*5225e6b1SAndroid Build Coastguard Worker }
897*5225e6b1SAndroid Build Coastguard Worker 
898*5225e6b1SAndroid Build Coastguard Worker /// Helper macro for printing message via `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL` in
899*5225e6b1SAndroid Build Coastguard Worker /// `EFI_SYSTEM_TABLE.ConOut`.
900*5225e6b1SAndroid Build Coastguard Worker #[macro_export]
901*5225e6b1SAndroid Build Coastguard Worker macro_rules! efi_print {
902*5225e6b1SAndroid Build Coastguard Worker     ( $efi_entry:expr, $( $x:expr ),* $(,)? ) => {
903*5225e6b1SAndroid Build Coastguard Worker             write!($efi_entry.system_table().con_out().unwrap(), $($x,)*).unwrap()
904*5225e6b1SAndroid Build Coastguard Worker     };
905*5225e6b1SAndroid Build Coastguard Worker }
906*5225e6b1SAndroid Build Coastguard Worker 
907*5225e6b1SAndroid Build Coastguard Worker /// Similar to [efi_print!], but automatically adds the UEFI newline sequence (`\r\n`).
908*5225e6b1SAndroid Build Coastguard Worker #[macro_export]
909*5225e6b1SAndroid Build Coastguard Worker macro_rules! efi_println {
910*5225e6b1SAndroid Build Coastguard Worker     ( $efi_entry:expr, $( $x:expr ),* $(,)? ) => {
911*5225e6b1SAndroid Build Coastguard Worker         {
912*5225e6b1SAndroid Build Coastguard Worker             efi_print!($efi_entry, $($x,)*);
913*5225e6b1SAndroid Build Coastguard Worker             efi_print!($efi_entry, "\r\n");
914*5225e6b1SAndroid Build Coastguard Worker         }
915*5225e6b1SAndroid Build Coastguard Worker     };
916*5225e6b1SAndroid Build Coastguard Worker }
917*5225e6b1SAndroid Build Coastguard Worker 
918*5225e6b1SAndroid Build Coastguard Worker /// Resets system. Hangs if not supported.
919*5225e6b1SAndroid Build Coastguard Worker #[cfg(not(test))]
reset() -> !920*5225e6b1SAndroid Build Coastguard Worker pub fn reset() -> ! {
921*5225e6b1SAndroid Build Coastguard Worker     efi_try_print!("Resetting...\r\n");
922*5225e6b1SAndroid Build Coastguard Worker     match allocation::internal_efi_entry_and_rt().1 {
923*5225e6b1SAndroid Build Coastguard Worker         Some(rt) => rt.cold_reset(),
924*5225e6b1SAndroid Build Coastguard Worker         _ => efi_try_print!("Runtime services not supported. Hangs...\r\n"),
925*5225e6b1SAndroid Build Coastguard Worker     }
926*5225e6b1SAndroid Build Coastguard Worker     loop {}
927*5225e6b1SAndroid Build Coastguard Worker }
928*5225e6b1SAndroid Build Coastguard Worker 
929*5225e6b1SAndroid Build Coastguard Worker /// Provides a builtin panic handler.
930*5225e6b1SAndroid Build Coastguard Worker /// In the long term, to improve flexibility, consider allowing application to install a custom
931*5225e6b1SAndroid Build Coastguard Worker /// handler into `EfiEntry` to be called here.
932*5225e6b1SAndroid Build Coastguard Worker /// Don't set this as the panic handler so that other crates' tests can depend on libefi.
933*5225e6b1SAndroid Build Coastguard Worker #[cfg(not(test))]
panic(panic: &PanicInfo) -> !934*5225e6b1SAndroid Build Coastguard Worker pub fn panic(panic: &PanicInfo) -> ! {
935*5225e6b1SAndroid Build Coastguard Worker     efi_try_print!("Panics! {}\r\n", panic);
936*5225e6b1SAndroid Build Coastguard Worker     reset();
937*5225e6b1SAndroid Build Coastguard Worker }
938*5225e6b1SAndroid Build Coastguard Worker 
939*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
940*5225e6b1SAndroid Build Coastguard Worker mod test {
941*5225e6b1SAndroid Build Coastguard Worker     use super::*;
942*5225e6b1SAndroid Build Coastguard Worker     use crate::protocol::block_io::BlockIoProtocol;
943*5225e6b1SAndroid Build Coastguard Worker     use efi_types::{
944*5225e6b1SAndroid Build Coastguard Worker         EfiBlockIoProtocol, EfiEventNotify, EfiLocateHandleSearchType, EfiStatus, EfiTpl,
945*5225e6b1SAndroid Build Coastguard Worker         EFI_MEMORY_TYPE_LOADER_CODE, EFI_MEMORY_TYPE_LOADER_DATA, EFI_STATUS_NOT_FOUND,
946*5225e6b1SAndroid Build Coastguard Worker         EFI_STATUS_NOT_READY, EFI_STATUS_SUCCESS, EFI_STATUS_UNSUPPORTED,
947*5225e6b1SAndroid Build Coastguard Worker     };
948*5225e6b1SAndroid Build Coastguard Worker     use std::{cell::RefCell, collections::VecDeque, mem::size_of, slice::from_raw_parts_mut};
949*5225e6b1SAndroid Build Coastguard Worker     use zerocopy::AsBytes;
950*5225e6b1SAndroid Build Coastguard Worker 
951*5225e6b1SAndroid Build Coastguard Worker     /// Helper function to generate a Protocol from an interface type.
generate_protocol<'a, P: ProtocolInfo>( efi_entry: &'a EfiEntry, proto: &'a mut P::InterfaceType, ) -> Protocol<'a, P>952*5225e6b1SAndroid Build Coastguard Worker     pub fn generate_protocol<'a, P: ProtocolInfo>(
953*5225e6b1SAndroid Build Coastguard Worker         efi_entry: &'a EfiEntry,
954*5225e6b1SAndroid Build Coastguard Worker         proto: &'a mut P::InterfaceType,
955*5225e6b1SAndroid Build Coastguard Worker     ) -> Protocol<'a, P> {
956*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: proto is a valid pointer and lasts at least as long as efi_entry.
957*5225e6b1SAndroid Build Coastguard Worker         unsafe { Protocol::<'a, P>::new(DeviceHandle::new(null_mut()), proto, efi_entry) }
958*5225e6b1SAndroid Build Coastguard Worker     }
959*5225e6b1SAndroid Build Coastguard Worker 
960*5225e6b1SAndroid Build Coastguard Worker     /// A structure to store the traces of arguments/outputs for EFI methods.
961*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
962*5225e6b1SAndroid Build Coastguard Worker     pub struct EfiCallTraces {
963*5225e6b1SAndroid Build Coastguard Worker         pub free_pool_trace: FreePoolTrace,
964*5225e6b1SAndroid Build Coastguard Worker         pub open_protocol_trace: OpenProtocolTrace,
965*5225e6b1SAndroid Build Coastguard Worker         pub close_protocol_trace: CloseProtocolTrace,
966*5225e6b1SAndroid Build Coastguard Worker         pub locate_handle_buffer_trace: LocateHandleBufferTrace,
967*5225e6b1SAndroid Build Coastguard Worker         pub get_memory_map_trace: GetMemoryMapTrace,
968*5225e6b1SAndroid Build Coastguard Worker         pub exit_boot_services_trace: ExitBootServicespTrace,
969*5225e6b1SAndroid Build Coastguard Worker         pub create_event_trace: CreateEventTrace,
970*5225e6b1SAndroid Build Coastguard Worker         pub close_event_trace: CloseEventTrace,
971*5225e6b1SAndroid Build Coastguard Worker         pub check_event_trace: CheckEventTrace,
972*5225e6b1SAndroid Build Coastguard Worker     }
973*5225e6b1SAndroid Build Coastguard Worker 
974*5225e6b1SAndroid Build Coastguard Worker     // Declares a global instance of EfiCallTraces.
975*5225e6b1SAndroid Build Coastguard Worker     // Need to use thread local storage because rust unit test is multi-threaded.
976*5225e6b1SAndroid Build Coastguard Worker     thread_local! {
977*5225e6b1SAndroid Build Coastguard Worker         static EFI_CALL_TRACES: RefCell<EfiCallTraces> = RefCell::new(Default::default());
978*5225e6b1SAndroid Build Coastguard Worker     }
979*5225e6b1SAndroid Build Coastguard Worker 
980*5225e6b1SAndroid Build Coastguard Worker     /// Exports for unit-test in submodules.
efi_call_traces() -> &'static std::thread::LocalKey<RefCell<EfiCallTraces>>981*5225e6b1SAndroid Build Coastguard Worker     pub fn efi_call_traces() -> &'static std::thread::LocalKey<RefCell<EfiCallTraces>> {
982*5225e6b1SAndroid Build Coastguard Worker         &EFI_CALL_TRACES
983*5225e6b1SAndroid Build Coastguard Worker     }
984*5225e6b1SAndroid Build Coastguard Worker 
985*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.FreePool() test implementation.
986*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
987*5225e6b1SAndroid Build Coastguard Worker     pub struct FreePoolTrace {
988*5225e6b1SAndroid Build Coastguard Worker         // Capture `buf`
989*5225e6b1SAndroid Build Coastguard Worker         pub inputs: VecDeque<*mut core::ffi::c_void>,
990*5225e6b1SAndroid Build Coastguard Worker     }
991*5225e6b1SAndroid Build Coastguard Worker 
992*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.FreePool` C API in test environment.
free_pool(buf: *mut core::ffi::c_void) -> EfiStatus993*5225e6b1SAndroid Build Coastguard Worker     extern "C" fn free_pool(buf: *mut core::ffi::c_void) -> EfiStatus {
994*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
995*5225e6b1SAndroid Build Coastguard Worker             traces.borrow_mut().free_pool_trace.inputs.push_back(buf);
996*5225e6b1SAndroid Build Coastguard Worker             EFI_STATUS_SUCCESS
997*5225e6b1SAndroid Build Coastguard Worker         })
998*5225e6b1SAndroid Build Coastguard Worker     }
999*5225e6b1SAndroid Build Coastguard Worker 
1000*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.OpenProtocol() test implementation.
1001*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1002*5225e6b1SAndroid Build Coastguard Worker     pub struct OpenProtocolTrace {
1003*5225e6b1SAndroid Build Coastguard Worker         // Capture `handle`, `protocol_guid`, `agent_handle`.
1004*5225e6b1SAndroid Build Coastguard Worker         pub inputs: VecDeque<(DeviceHandle, EfiGuid, EfiHandle)>,
1005*5225e6b1SAndroid Build Coastguard Worker         // Return `intf`, EfiStatus.
1006*5225e6b1SAndroid Build Coastguard Worker         pub outputs: VecDeque<(EfiHandle, EfiStatus)>,
1007*5225e6b1SAndroid Build Coastguard Worker     }
1008*5225e6b1SAndroid Build Coastguard Worker 
1009*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.OpenProtocol` C API in test environment.
1010*5225e6b1SAndroid Build Coastguard Worker     ///
1011*5225e6b1SAndroid Build Coastguard Worker     /// # Safety
1012*5225e6b1SAndroid Build Coastguard Worker     ///
1013*5225e6b1SAndroid Build Coastguard Worker     ///   Caller should guarantee that `intf` and `protocol_guid` point to valid memory locations.
open_protocol( handle: EfiHandle, protocol_guid: *const EfiGuid, intf: *mut *mut core::ffi::c_void, agent_handle: EfiHandle, _: EfiHandle, attr: u32, ) -> EfiStatus1014*5225e6b1SAndroid Build Coastguard Worker     unsafe extern "C" fn open_protocol(
1015*5225e6b1SAndroid Build Coastguard Worker         handle: EfiHandle,
1016*5225e6b1SAndroid Build Coastguard Worker         protocol_guid: *const EfiGuid,
1017*5225e6b1SAndroid Build Coastguard Worker         intf: *mut *mut core::ffi::c_void,
1018*5225e6b1SAndroid Build Coastguard Worker         agent_handle: EfiHandle,
1019*5225e6b1SAndroid Build Coastguard Worker         _: EfiHandle,
1020*5225e6b1SAndroid Build Coastguard Worker         attr: u32,
1021*5225e6b1SAndroid Build Coastguard Worker     ) -> EfiStatus {
1022*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(attr, EFI_OPEN_PROTOCOL_ATTRIBUTE_BY_HANDLE_PROTOCOL);
1023*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
1024*5225e6b1SAndroid Build Coastguard Worker             let trace = &mut traces.borrow_mut().open_protocol_trace;
1025*5225e6b1SAndroid Build Coastguard Worker             trace.inputs.push_back((
1026*5225e6b1SAndroid Build Coastguard Worker                 DeviceHandle(handle),
1027*5225e6b1SAndroid Build Coastguard Worker                 // SAFETY: function safety docs require valid `protocol_guid`.
1028*5225e6b1SAndroid Build Coastguard Worker                 unsafe { *protocol_guid },
1029*5225e6b1SAndroid Build Coastguard Worker                 agent_handle,
1030*5225e6b1SAndroid Build Coastguard Worker             ));
1031*5225e6b1SAndroid Build Coastguard Worker 
1032*5225e6b1SAndroid Build Coastguard Worker             let (intf_handle, status) = trace.outputs.pop_front().unwrap();
1033*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: function safety docs require valid `intf`.
1034*5225e6b1SAndroid Build Coastguard Worker             unsafe { *intf = intf_handle };
1035*5225e6b1SAndroid Build Coastguard Worker 
1036*5225e6b1SAndroid Build Coastguard Worker             status
1037*5225e6b1SAndroid Build Coastguard Worker         })
1038*5225e6b1SAndroid Build Coastguard Worker     }
1039*5225e6b1SAndroid Build Coastguard Worker 
1040*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.CloseProtocol() test implementation.
1041*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1042*5225e6b1SAndroid Build Coastguard Worker     pub struct CloseProtocolTrace {
1043*5225e6b1SAndroid Build Coastguard Worker         // Capture `handle`, `protocol_guid`, `agent_handle`
1044*5225e6b1SAndroid Build Coastguard Worker         pub inputs: VecDeque<(DeviceHandle, EfiGuid, EfiHandle)>,
1045*5225e6b1SAndroid Build Coastguard Worker     }
1046*5225e6b1SAndroid Build Coastguard Worker 
1047*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.CloseProtocol` C API in test environment.
1048*5225e6b1SAndroid Build Coastguard Worker     ///
1049*5225e6b1SAndroid Build Coastguard Worker     /// # Safety
1050*5225e6b1SAndroid Build Coastguard Worker     ///
1051*5225e6b1SAndroid Build Coastguard Worker     ///   Caller should guarantee that `protocol_guid` points to valid memory location.
close_protocol( handle: EfiHandle, protocol_guid: *const EfiGuid, agent_handle: EfiHandle, _: EfiHandle, ) -> EfiStatus1052*5225e6b1SAndroid Build Coastguard Worker     unsafe extern "C" fn close_protocol(
1053*5225e6b1SAndroid Build Coastguard Worker         handle: EfiHandle,
1054*5225e6b1SAndroid Build Coastguard Worker         protocol_guid: *const EfiGuid,
1055*5225e6b1SAndroid Build Coastguard Worker         agent_handle: EfiHandle,
1056*5225e6b1SAndroid Build Coastguard Worker         _: EfiHandle,
1057*5225e6b1SAndroid Build Coastguard Worker     ) -> EfiStatus {
1058*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
1059*5225e6b1SAndroid Build Coastguard Worker             traces.borrow_mut().close_protocol_trace.inputs.push_back((
1060*5225e6b1SAndroid Build Coastguard Worker                 DeviceHandle(handle),
1061*5225e6b1SAndroid Build Coastguard Worker                 // SAFETY: function safety docs require valid `protocol_guid`.
1062*5225e6b1SAndroid Build Coastguard Worker                 unsafe { *protocol_guid },
1063*5225e6b1SAndroid Build Coastguard Worker                 agent_handle,
1064*5225e6b1SAndroid Build Coastguard Worker             ));
1065*5225e6b1SAndroid Build Coastguard Worker             EFI_STATUS_SUCCESS
1066*5225e6b1SAndroid Build Coastguard Worker         })
1067*5225e6b1SAndroid Build Coastguard Worker     }
1068*5225e6b1SAndroid Build Coastguard Worker 
1069*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.LocateHandleBuffer.
1070*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1071*5225e6b1SAndroid Build Coastguard Worker     pub struct LocateHandleBufferTrace {
1072*5225e6b1SAndroid Build Coastguard Worker         // Capture `protocol`.
1073*5225e6b1SAndroid Build Coastguard Worker         pub inputs: VecDeque<EfiGuid>,
1074*5225e6b1SAndroid Build Coastguard Worker         // For returning in `num_handles` and `buf`.
1075*5225e6b1SAndroid Build Coastguard Worker         pub outputs: VecDeque<(usize, *mut DeviceHandle)>,
1076*5225e6b1SAndroid Build Coastguard Worker     }
1077*5225e6b1SAndroid Build Coastguard Worker 
1078*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.LocateHandleBuffer` C API in test environment.
1079*5225e6b1SAndroid Build Coastguard Worker     ///
1080*5225e6b1SAndroid Build Coastguard Worker     /// # Safety
1081*5225e6b1SAndroid Build Coastguard Worker     /// Caller should guarantee that `protocol`, `num_handles`, and `buf` point to valid memory
1082*5225e6b1SAndroid Build Coastguard Worker     /// locations.
locate_handle_buffer( search_type: EfiLocateHandleSearchType, protocol: *const EfiGuid, search_key: *mut core::ffi::c_void, num_handles: *mut usize, buf: *mut *mut EfiHandle, ) -> EfiStatus1083*5225e6b1SAndroid Build Coastguard Worker     unsafe extern "C" fn locate_handle_buffer(
1084*5225e6b1SAndroid Build Coastguard Worker         search_type: EfiLocateHandleSearchType,
1085*5225e6b1SAndroid Build Coastguard Worker         protocol: *const EfiGuid,
1086*5225e6b1SAndroid Build Coastguard Worker         search_key: *mut core::ffi::c_void,
1087*5225e6b1SAndroid Build Coastguard Worker         num_handles: *mut usize,
1088*5225e6b1SAndroid Build Coastguard Worker         buf: *mut *mut EfiHandle,
1089*5225e6b1SAndroid Build Coastguard Worker     ) -> EfiStatus {
1090*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(search_type, EFI_LOCATE_HANDLE_SEARCH_TYPE_BY_PROTOCOL);
1091*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(search_key, null_mut());
1092*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
1093*5225e6b1SAndroid Build Coastguard Worker             let trace = &mut traces.borrow_mut().locate_handle_buffer_trace;
1094*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: function safety docs require valid `protocol`.
1095*5225e6b1SAndroid Build Coastguard Worker             unsafe { trace.inputs.push_back(*protocol) };
1096*5225e6b1SAndroid Build Coastguard Worker 
1097*5225e6b1SAndroid Build Coastguard Worker             let (num, handles) = trace.outputs.pop_front().unwrap();
1098*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: function safety docs require valid `num_handles`.
1099*5225e6b1SAndroid Build Coastguard Worker             unsafe { *num_handles = num as usize };
1100*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: function safety docs require valid `buf`.
1101*5225e6b1SAndroid Build Coastguard Worker             unsafe { *buf = handles as *mut EfiHandle };
1102*5225e6b1SAndroid Build Coastguard Worker 
1103*5225e6b1SAndroid Build Coastguard Worker             EFI_STATUS_SUCCESS
1104*5225e6b1SAndroid Build Coastguard Worker         })
1105*5225e6b1SAndroid Build Coastguard Worker     }
1106*5225e6b1SAndroid Build Coastguard Worker 
1107*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.GetMemoryMap.
1108*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1109*5225e6b1SAndroid Build Coastguard Worker     pub struct GetMemoryMapTrace {
1110*5225e6b1SAndroid Build Coastguard Worker         // Capture `memory_map_size` and `memory_map` argument.
1111*5225e6b1SAndroid Build Coastguard Worker         pub inputs: VecDeque<(usize, *mut EfiMemoryDescriptor)>,
1112*5225e6b1SAndroid Build Coastguard Worker         // Output value `map_key`, `memory_map_size`.
1113*5225e6b1SAndroid Build Coastguard Worker         pub outputs: VecDeque<(usize, usize)>,
1114*5225e6b1SAndroid Build Coastguard Worker     }
1115*5225e6b1SAndroid Build Coastguard Worker 
1116*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.GetMemoryMap` C API in test environment.
1117*5225e6b1SAndroid Build Coastguard Worker     ///
1118*5225e6b1SAndroid Build Coastguard Worker     /// # Safety
1119*5225e6b1SAndroid Build Coastguard Worker     ///
1120*5225e6b1SAndroid Build Coastguard Worker     ///   Caller should guarantee that `memory_map_size`, `map_key` and `desc_size` point to valid
1121*5225e6b1SAndroid Build Coastguard Worker     ///   memory locations.
get_memory_map( memory_map_size: *mut usize, memory_map: *mut EfiMemoryDescriptor, map_key: *mut usize, desc_size: *mut usize, _: *mut u32, ) -> EfiStatus1122*5225e6b1SAndroid Build Coastguard Worker     unsafe extern "C" fn get_memory_map(
1123*5225e6b1SAndroid Build Coastguard Worker         memory_map_size: *mut usize,
1124*5225e6b1SAndroid Build Coastguard Worker         memory_map: *mut EfiMemoryDescriptor,
1125*5225e6b1SAndroid Build Coastguard Worker         map_key: *mut usize,
1126*5225e6b1SAndroid Build Coastguard Worker         desc_size: *mut usize,
1127*5225e6b1SAndroid Build Coastguard Worker         _: *mut u32,
1128*5225e6b1SAndroid Build Coastguard Worker     ) -> EfiStatus {
1129*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
1130*5225e6b1SAndroid Build Coastguard Worker             let trace = &mut traces.borrow_mut().get_memory_map_trace;
1131*5225e6b1SAndroid Build Coastguard Worker             trace.inputs.push_back((unsafe { *memory_map_size }, memory_map));
1132*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: function safety docs require valid `memory_map_size`and `map_key`.
1133*5225e6b1SAndroid Build Coastguard Worker             unsafe { (*map_key, *memory_map_size) = trace.outputs.pop_front().unwrap() };
1134*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: function safety docs require valid `desc_size`.
1135*5225e6b1SAndroid Build Coastguard Worker             unsafe { *desc_size = size_of::<EfiMemoryDescriptor>() };
1136*5225e6b1SAndroid Build Coastguard Worker             EFI_STATUS_SUCCESS
1137*5225e6b1SAndroid Build Coastguard Worker         })
1138*5225e6b1SAndroid Build Coastguard Worker     }
1139*5225e6b1SAndroid Build Coastguard Worker 
1140*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.ExitBootServices.
1141*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1142*5225e6b1SAndroid Build Coastguard Worker     pub struct ExitBootServicespTrace {
1143*5225e6b1SAndroid Build Coastguard Worker         // Capture `image_handle`, `map_key`
1144*5225e6b1SAndroid Build Coastguard Worker         pub inputs: VecDeque<(EfiHandle, usize)>,
1145*5225e6b1SAndroid Build Coastguard Worker     }
1146*5225e6b1SAndroid Build Coastguard Worker 
1147*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.ExitBootServices` C API in test environment.
exit_boot_services(image_handle: EfiHandle, map_key: usize) -> EfiStatus1148*5225e6b1SAndroid Build Coastguard Worker     extern "C" fn exit_boot_services(image_handle: EfiHandle, map_key: usize) -> EfiStatus {
1149*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
1150*5225e6b1SAndroid Build Coastguard Worker             let trace = &mut traces.borrow_mut().exit_boot_services_trace;
1151*5225e6b1SAndroid Build Coastguard Worker             trace.inputs.push_back((image_handle, map_key));
1152*5225e6b1SAndroid Build Coastguard Worker             EFI_STATUS_SUCCESS
1153*5225e6b1SAndroid Build Coastguard Worker         })
1154*5225e6b1SAndroid Build Coastguard Worker     }
1155*5225e6b1SAndroid Build Coastguard Worker 
1156*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.CreateEvent.
1157*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1158*5225e6b1SAndroid Build Coastguard Worker     pub struct CreateEventTrace {
1159*5225e6b1SAndroid Build Coastguard Worker         // Capture `type_`, `notify_tpl`, `notify_fn`, `notify_ctx`
1160*5225e6b1SAndroid Build Coastguard Worker         pub inputs: VecDeque<(u32, EfiTpl, EfiEventNotify, *mut core::ffi::c_void)>,
1161*5225e6b1SAndroid Build Coastguard Worker         // Output a EfiEvent.
1162*5225e6b1SAndroid Build Coastguard Worker         pub outputs: VecDeque<EfiEvent>,
1163*5225e6b1SAndroid Build Coastguard Worker     }
1164*5225e6b1SAndroid Build Coastguard Worker 
1165*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.CreateEvent` C API in test environment.
1166*5225e6b1SAndroid Build Coastguard Worker     ///
1167*5225e6b1SAndroid Build Coastguard Worker     /// # Safety
1168*5225e6b1SAndroid Build Coastguard Worker     ///
1169*5225e6b1SAndroid Build Coastguard Worker     ///   Caller should guarantee that `event` points to valid memory location.
create_event( type_: u32, notify_tpl: EfiTpl, notify_fn: EfiEventNotify, notify_ctx: *mut core::ffi::c_void, event: *mut EfiEvent, ) -> EfiStatus1170*5225e6b1SAndroid Build Coastguard Worker     unsafe extern "C" fn create_event(
1171*5225e6b1SAndroid Build Coastguard Worker         type_: u32,
1172*5225e6b1SAndroid Build Coastguard Worker         notify_tpl: EfiTpl,
1173*5225e6b1SAndroid Build Coastguard Worker         notify_fn: EfiEventNotify,
1174*5225e6b1SAndroid Build Coastguard Worker         notify_ctx: *mut core::ffi::c_void,
1175*5225e6b1SAndroid Build Coastguard Worker         event: *mut EfiEvent,
1176*5225e6b1SAndroid Build Coastguard Worker     ) -> EfiStatus {
1177*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
1178*5225e6b1SAndroid Build Coastguard Worker             let trace = &mut traces.borrow_mut().create_event_trace;
1179*5225e6b1SAndroid Build Coastguard Worker             trace.inputs.push_back((type_, notify_tpl, notify_fn, notify_ctx));
1180*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: function safety docs require valid `event`.
1181*5225e6b1SAndroid Build Coastguard Worker             unsafe { *event = trace.outputs.pop_front().unwrap() };
1182*5225e6b1SAndroid Build Coastguard Worker             EFI_STATUS_SUCCESS
1183*5225e6b1SAndroid Build Coastguard Worker         })
1184*5225e6b1SAndroid Build Coastguard Worker     }
1185*5225e6b1SAndroid Build Coastguard Worker 
1186*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.CloseEvent.
1187*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1188*5225e6b1SAndroid Build Coastguard Worker     pub struct CloseEventTrace {
1189*5225e6b1SAndroid Build Coastguard Worker         // Capture `event`
1190*5225e6b1SAndroid Build Coastguard Worker         pub inputs: VecDeque<EfiEvent>,
1191*5225e6b1SAndroid Build Coastguard Worker     }
1192*5225e6b1SAndroid Build Coastguard Worker 
1193*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.CloseEvent` C API in test environment.
close_event(event: EfiEvent) -> EfiStatus1194*5225e6b1SAndroid Build Coastguard Worker     extern "C" fn close_event(event: EfiEvent) -> EfiStatus {
1195*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
1196*5225e6b1SAndroid Build Coastguard Worker             let trace = &mut traces.borrow_mut().close_event_trace;
1197*5225e6b1SAndroid Build Coastguard Worker             trace.inputs.push_back(event);
1198*5225e6b1SAndroid Build Coastguard Worker             EFI_STATUS_SUCCESS
1199*5225e6b1SAndroid Build Coastguard Worker         })
1200*5225e6b1SAndroid Build Coastguard Worker     }
1201*5225e6b1SAndroid Build Coastguard Worker 
1202*5225e6b1SAndroid Build Coastguard Worker     /// EFI_BOOT_SERVICE.CheckEvent.
1203*5225e6b1SAndroid Build Coastguard Worker     #[derive(Default)]
1204*5225e6b1SAndroid Build Coastguard Worker     pub struct CheckEventTrace {
1205*5225e6b1SAndroid Build Coastguard Worker         // EfiStatus for return.
1206*5225e6b1SAndroid Build Coastguard Worker         pub outputs: VecDeque<EfiStatus>,
1207*5225e6b1SAndroid Build Coastguard Worker     }
1208*5225e6b1SAndroid Build Coastguard Worker 
1209*5225e6b1SAndroid Build Coastguard Worker     /// Mock of the `EFI_BOOT_SERVICE.CheckEvent` C API in test environment.
check_event(_: EfiEvent) -> EfiStatus1210*5225e6b1SAndroid Build Coastguard Worker     extern "C" fn check_event(_: EfiEvent) -> EfiStatus {
1211*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|traces| {
1212*5225e6b1SAndroid Build Coastguard Worker             let trace = &mut traces.borrow_mut().check_event_trace;
1213*5225e6b1SAndroid Build Coastguard Worker             trace.outputs.pop_front().unwrap()
1214*5225e6b1SAndroid Build Coastguard Worker         })
1215*5225e6b1SAndroid Build Coastguard Worker     }
1216*5225e6b1SAndroid Build Coastguard Worker 
1217*5225e6b1SAndroid Build Coastguard Worker     /// A test wrapper that sets up a system table, image handle and runs a test function like it
1218*5225e6b1SAndroid Build Coastguard Worker     /// is an EFI application.
1219*5225e6b1SAndroid Build Coastguard Worker     /// TODO(300168989): Investigate using procedural macro to generate test that auto calls this.
run_test(func: impl FnOnce(EfiHandle, *mut EfiSystemTable) -> ())1220*5225e6b1SAndroid Build Coastguard Worker     pub fn run_test(func: impl FnOnce(EfiHandle, *mut EfiSystemTable) -> ()) {
1221*5225e6b1SAndroid Build Coastguard Worker         // Reset all traces
1222*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|trace| {
1223*5225e6b1SAndroid Build Coastguard Worker             *trace.borrow_mut() = Default::default();
1224*5225e6b1SAndroid Build Coastguard Worker         });
1225*5225e6b1SAndroid Build Coastguard Worker 
1226*5225e6b1SAndroid Build Coastguard Worker         let mut systab: EfiSystemTable = Default::default();
1227*5225e6b1SAndroid Build Coastguard Worker         let mut boot_services: EfiBootService = Default::default();
1228*5225e6b1SAndroid Build Coastguard Worker 
1229*5225e6b1SAndroid Build Coastguard Worker         boot_services.free_pool = Some(free_pool);
1230*5225e6b1SAndroid Build Coastguard Worker         boot_services.open_protocol = Some(open_protocol);
1231*5225e6b1SAndroid Build Coastguard Worker         boot_services.close_protocol = Some(close_protocol);
1232*5225e6b1SAndroid Build Coastguard Worker         boot_services.locate_handle_buffer = Some(locate_handle_buffer);
1233*5225e6b1SAndroid Build Coastguard Worker         boot_services.get_memory_map = Some(get_memory_map);
1234*5225e6b1SAndroid Build Coastguard Worker         boot_services.exit_boot_services = Some(exit_boot_services);
1235*5225e6b1SAndroid Build Coastguard Worker         boot_services.create_event = Some(create_event);
1236*5225e6b1SAndroid Build Coastguard Worker         boot_services.close_event = Some(close_event);
1237*5225e6b1SAndroid Build Coastguard Worker         boot_services.check_event = Some(check_event);
1238*5225e6b1SAndroid Build Coastguard Worker         systab.boot_services = &mut boot_services as *mut _;
1239*5225e6b1SAndroid Build Coastguard Worker         let image_handle: usize = 1234; // Don't care.
1240*5225e6b1SAndroid Build Coastguard Worker 
1241*5225e6b1SAndroid Build Coastguard Worker         func(image_handle as EfiHandle, &mut systab as *mut _);
1242*5225e6b1SAndroid Build Coastguard Worker 
1243*5225e6b1SAndroid Build Coastguard Worker         // Reset all traces
1244*5225e6b1SAndroid Build Coastguard Worker         EFI_CALL_TRACES.with(|trace| {
1245*5225e6b1SAndroid Build Coastguard Worker             *trace.borrow_mut() = Default::default();
1246*5225e6b1SAndroid Build Coastguard Worker         });
1247*5225e6b1SAndroid Build Coastguard Worker     }
1248*5225e6b1SAndroid Build Coastguard Worker 
1249*5225e6b1SAndroid Build Coastguard Worker     /// Constructs a mock protocol `P` and run the given callback on it.
1250*5225e6b1SAndroid Build Coastguard Worker     ///
1251*5225e6b1SAndroid Build Coastguard Worker     /// This is similar to `run_test()`, but also provides the construction of a single mock
1252*5225e6b1SAndroid Build Coastguard Worker     /// protocol to reduce boilerplate for tests to check the interface between a C EFI protocol
1253*5225e6b1SAndroid Build Coastguard Worker     /// struct and our Rust wrappers.
1254*5225e6b1SAndroid Build Coastguard Worker     ///
1255*5225e6b1SAndroid Build Coastguard Worker     /// # Arguments
1256*5225e6b1SAndroid Build Coastguard Worker     /// * `c_interface`: the raw C struct interface implementing the desired protocol.
1257*5225e6b1SAndroid Build Coastguard Worker     /// * `f`: the callback function to run, given the resulting protocol as an argument.
run_test_with_mock_protocol<P: ProtocolInfo>( mut c_interface: P::InterfaceType, f: impl FnOnce(&Protocol<P>), )1258*5225e6b1SAndroid Build Coastguard Worker     pub fn run_test_with_mock_protocol<P: ProtocolInfo>(
1259*5225e6b1SAndroid Build Coastguard Worker         mut c_interface: P::InterfaceType,
1260*5225e6b1SAndroid Build Coastguard Worker         f: impl FnOnce(&Protocol<P>),
1261*5225e6b1SAndroid Build Coastguard Worker     ) {
1262*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1263*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1264*5225e6b1SAndroid Build Coastguard Worker             // SAFETY:
1265*5225e6b1SAndroid Build Coastguard Worker             // * `c_interface` is a valid C interface for proto `P`
1266*5225e6b1SAndroid Build Coastguard Worker             // * `c_interface` outlives the created `protocol`
1267*5225e6b1SAndroid Build Coastguard Worker             let protocol = unsafe {
1268*5225e6b1SAndroid Build Coastguard Worker                 Protocol::new(DeviceHandle::new(null_mut()), &mut c_interface, &efi_entry)
1269*5225e6b1SAndroid Build Coastguard Worker             };
1270*5225e6b1SAndroid Build Coastguard Worker             f(&protocol);
1271*5225e6b1SAndroid Build Coastguard Worker         });
1272*5225e6b1SAndroid Build Coastguard Worker     }
1273*5225e6b1SAndroid Build Coastguard Worker 
1274*5225e6b1SAndroid Build Coastguard Worker     /// Get the pointer to an object as an EfiHandle type.
as_efi_handle<T>(val: &mut T) -> EfiHandle1275*5225e6b1SAndroid Build Coastguard Worker     pub fn as_efi_handle<T>(val: &mut T) -> EfiHandle {
1276*5225e6b1SAndroid Build Coastguard Worker         val as *mut T as *mut _
1277*5225e6b1SAndroid Build Coastguard Worker     }
1278*5225e6b1SAndroid Build Coastguard Worker 
1279*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_open_close_protocol()1280*5225e6b1SAndroid Build Coastguard Worker     fn test_open_close_protocol() {
1281*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1282*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1283*5225e6b1SAndroid Build Coastguard Worker 
1284*5225e6b1SAndroid Build Coastguard Worker             // Set up open_protocol trace
1285*5225e6b1SAndroid Build Coastguard Worker             let mut block_io: EfiBlockIoProtocol = Default::default();
1286*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1287*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().open_protocol_trace.outputs =
1288*5225e6b1SAndroid Build Coastguard Worker                     VecDeque::from([(as_efi_handle(&mut block_io), EFI_STATUS_SUCCESS)]);
1289*5225e6b1SAndroid Build Coastguard Worker             });
1290*5225e6b1SAndroid Build Coastguard Worker 
1291*5225e6b1SAndroid Build Coastguard Worker             let mut device_handle: usize = 0; // Don't care
1292*5225e6b1SAndroid Build Coastguard Worker             {
1293*5225e6b1SAndroid Build Coastguard Worker                 // Open a protocol
1294*5225e6b1SAndroid Build Coastguard Worker                 let protocol = efi_entry
1295*5225e6b1SAndroid Build Coastguard Worker                     .system_table()
1296*5225e6b1SAndroid Build Coastguard Worker                     .boot_services()
1297*5225e6b1SAndroid Build Coastguard Worker                     .open_protocol::<BlockIoProtocol>(DeviceHandle(as_efi_handle(
1298*5225e6b1SAndroid Build Coastguard Worker                         &mut device_handle,
1299*5225e6b1SAndroid Build Coastguard Worker                     )))
1300*5225e6b1SAndroid Build Coastguard Worker                     .unwrap();
1301*5225e6b1SAndroid Build Coastguard Worker 
1302*5225e6b1SAndroid Build Coastguard Worker                 // Validate call args
1303*5225e6b1SAndroid Build Coastguard Worker                 EFI_CALL_TRACES.with(|trace| {
1304*5225e6b1SAndroid Build Coastguard Worker                     assert_eq!(
1305*5225e6b1SAndroid Build Coastguard Worker                         trace.borrow_mut().open_protocol_trace.inputs,
1306*5225e6b1SAndroid Build Coastguard Worker                         [(
1307*5225e6b1SAndroid Build Coastguard Worker                             DeviceHandle(as_efi_handle(&mut device_handle)),
1308*5225e6b1SAndroid Build Coastguard Worker                             BlockIoProtocol::GUID,
1309*5225e6b1SAndroid Build Coastguard Worker                             image_handle
1310*5225e6b1SAndroid Build Coastguard Worker                         ),]
1311*5225e6b1SAndroid Build Coastguard Worker                     );
1312*5225e6b1SAndroid Build Coastguard Worker 
1313*5225e6b1SAndroid Build Coastguard Worker                     // close_protocol not called yet.
1314*5225e6b1SAndroid Build Coastguard Worker                     assert_eq!(trace.borrow_mut().close_protocol_trace.inputs, []);
1315*5225e6b1SAndroid Build Coastguard Worker                 });
1316*5225e6b1SAndroid Build Coastguard Worker 
1317*5225e6b1SAndroid Build Coastguard Worker                 // The protocol gets the correct EfiBlockIoProtocol structure we pass in.
1318*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(protocol.interface_ptr(), &mut block_io as *mut _);
1319*5225e6b1SAndroid Build Coastguard Worker             }
1320*5225e6b1SAndroid Build Coastguard Worker 
1321*5225e6b1SAndroid Build Coastguard Worker             // Close protocol is called as `protocol` goes out of scope.
1322*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES
1323*5225e6b1SAndroid Build Coastguard Worker                 .with(|trace| assert_eq!(trace.borrow_mut().close_protocol_trace.inputs, []));
1324*5225e6b1SAndroid Build Coastguard Worker         })
1325*5225e6b1SAndroid Build Coastguard Worker     }
1326*5225e6b1SAndroid Build Coastguard Worker 
1327*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_null_efi_method()1328*5225e6b1SAndroid Build Coastguard Worker     fn test_null_efi_method() {
1329*5225e6b1SAndroid Build Coastguard Worker         // Test that wrapper call fails if efi method is None.
1330*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1331*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1332*5225e6b1SAndroid Build Coastguard Worker 
1333*5225e6b1SAndroid Build Coastguard Worker             // Set up open_protocol trace
1334*5225e6b1SAndroid Build Coastguard Worker             let mut block_io: EfiBlockIoProtocol = Default::default();
1335*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1336*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().open_protocol_trace.outputs =
1337*5225e6b1SAndroid Build Coastguard Worker                     VecDeque::from([(as_efi_handle(&mut block_io), EFI_STATUS_SUCCESS)]);
1338*5225e6b1SAndroid Build Coastguard Worker             });
1339*5225e6b1SAndroid Build Coastguard Worker 
1340*5225e6b1SAndroid Build Coastguard Worker             // Set the method to None.
1341*5225e6b1SAndroid Build Coastguard Worker             // SAFETY:
1342*5225e6b1SAndroid Build Coastguard Worker             // run_test() guarantees `boot_services` pointer points to valid object.
1343*5225e6b1SAndroid Build Coastguard Worker             unsafe { (*(*systab_ptr).boot_services).open_protocol = None };
1344*5225e6b1SAndroid Build Coastguard Worker 
1345*5225e6b1SAndroid Build Coastguard Worker             let mut device_handle: usize = 0; // Don't care
1346*5225e6b1SAndroid Build Coastguard Worker             assert!(efi_entry
1347*5225e6b1SAndroid Build Coastguard Worker                 .system_table()
1348*5225e6b1SAndroid Build Coastguard Worker                 .boot_services()
1349*5225e6b1SAndroid Build Coastguard Worker                 .open_protocol::<BlockIoProtocol>(DeviceHandle(as_efi_handle(&mut device_handle)))
1350*5225e6b1SAndroid Build Coastguard Worker                 .is_err());
1351*5225e6b1SAndroid Build Coastguard Worker         })
1352*5225e6b1SAndroid Build Coastguard Worker     }
1353*5225e6b1SAndroid Build Coastguard Worker 
1354*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_error_efi_method()1355*5225e6b1SAndroid Build Coastguard Worker     fn test_error_efi_method() {
1356*5225e6b1SAndroid Build Coastguard Worker         // Test that wrapper call fails if efi method returns error.
1357*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1358*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1359*5225e6b1SAndroid Build Coastguard Worker 
1360*5225e6b1SAndroid Build Coastguard Worker             // Set up open_protocol trace.
1361*5225e6b1SAndroid Build Coastguard Worker             let mut block_io: EfiBlockIoProtocol = Default::default();
1362*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1363*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().open_protocol_trace.outputs =
1364*5225e6b1SAndroid Build Coastguard Worker                     VecDeque::from([(as_efi_handle(&mut block_io), EFI_STATUS_NOT_FOUND)]);
1365*5225e6b1SAndroid Build Coastguard Worker             });
1366*5225e6b1SAndroid Build Coastguard Worker 
1367*5225e6b1SAndroid Build Coastguard Worker             let mut device_handle: usize = 0; // Don't care
1368*5225e6b1SAndroid Build Coastguard Worker             assert!(efi_entry
1369*5225e6b1SAndroid Build Coastguard Worker                 .system_table()
1370*5225e6b1SAndroid Build Coastguard Worker                 .boot_services()
1371*5225e6b1SAndroid Build Coastguard Worker                 .open_protocol::<BlockIoProtocol>(DeviceHandle(as_efi_handle(&mut device_handle)))
1372*5225e6b1SAndroid Build Coastguard Worker                 .is_err());
1373*5225e6b1SAndroid Build Coastguard Worker         })
1374*5225e6b1SAndroid Build Coastguard Worker     }
1375*5225e6b1SAndroid Build Coastguard Worker 
1376*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_locate_handle_buffer_by_protocol()1377*5225e6b1SAndroid Build Coastguard Worker     fn test_locate_handle_buffer_by_protocol() {
1378*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1379*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1380*5225e6b1SAndroid Build Coastguard Worker 
1381*5225e6b1SAndroid Build Coastguard Worker             // Set up locate_handle_buffer_trace trace.
1382*5225e6b1SAndroid Build Coastguard Worker             let mut located_handles: [DeviceHandle; 3] =
1383*5225e6b1SAndroid Build Coastguard Worker                 [DeviceHandle(1 as *mut _), DeviceHandle(2 as *mut _), DeviceHandle(3 as *mut _)];
1384*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1385*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().locate_handle_buffer_trace.outputs =
1386*5225e6b1SAndroid Build Coastguard Worker                     VecDeque::from([(located_handles.len(), located_handles.as_mut_ptr())]);
1387*5225e6b1SAndroid Build Coastguard Worker             });
1388*5225e6b1SAndroid Build Coastguard Worker 
1389*5225e6b1SAndroid Build Coastguard Worker             {
1390*5225e6b1SAndroid Build Coastguard Worker                 let handles = efi_entry
1391*5225e6b1SAndroid Build Coastguard Worker                     .system_table()
1392*5225e6b1SAndroid Build Coastguard Worker                     .boot_services()
1393*5225e6b1SAndroid Build Coastguard Worker                     .locate_handle_buffer_by_protocol::<BlockIoProtocol>()
1394*5225e6b1SAndroid Build Coastguard Worker                     .unwrap();
1395*5225e6b1SAndroid Build Coastguard Worker 
1396*5225e6b1SAndroid Build Coastguard Worker                 // Returned handles are expected.
1397*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(handles.handles().to_vec(), located_handles);
1398*5225e6b1SAndroid Build Coastguard Worker             }
1399*5225e6b1SAndroid Build Coastguard Worker 
1400*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1401*5225e6b1SAndroid Build Coastguard Worker                 let traces = traces.borrow_mut();
1402*5225e6b1SAndroid Build Coastguard Worker                 // Arguments are passed correctly.
1403*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(traces.locate_handle_buffer_trace.inputs, [BlockIoProtocol::GUID]);
1404*5225e6b1SAndroid Build Coastguard Worker                 // Free pool is called with the correct address.
1405*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(traces.free_pool_trace.inputs, [located_handles.as_mut_ptr() as *mut _]);
1406*5225e6b1SAndroid Build Coastguard Worker             });
1407*5225e6b1SAndroid Build Coastguard Worker         })
1408*5225e6b1SAndroid Build Coastguard Worker     }
1409*5225e6b1SAndroid Build Coastguard Worker 
1410*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_find_first_and_open()1411*5225e6b1SAndroid Build Coastguard Worker     fn test_find_first_and_open() {
1412*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1413*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1414*5225e6b1SAndroid Build Coastguard Worker 
1415*5225e6b1SAndroid Build Coastguard Worker             // Set up locate_handle_buffer_trace trace.
1416*5225e6b1SAndroid Build Coastguard Worker             let mut located_handles: [DeviceHandle; 3] =
1417*5225e6b1SAndroid Build Coastguard Worker                 [DeviceHandle(1 as *mut _), DeviceHandle(2 as *mut _), DeviceHandle(3 as *mut _)];
1418*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1419*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().locate_handle_buffer_trace.outputs =
1420*5225e6b1SAndroid Build Coastguard Worker                     VecDeque::from([(located_handles.len(), located_handles.as_mut_ptr())]);
1421*5225e6b1SAndroid Build Coastguard Worker             });
1422*5225e6b1SAndroid Build Coastguard Worker 
1423*5225e6b1SAndroid Build Coastguard Worker             // Set up open_protocol trace.
1424*5225e6b1SAndroid Build Coastguard Worker             let mut block_io: EfiBlockIoProtocol = Default::default();
1425*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1426*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().open_protocol_trace.outputs =
1427*5225e6b1SAndroid Build Coastguard Worker                     VecDeque::from([(as_efi_handle(&mut block_io), EFI_STATUS_SUCCESS)]);
1428*5225e6b1SAndroid Build Coastguard Worker             });
1429*5225e6b1SAndroid Build Coastguard Worker 
1430*5225e6b1SAndroid Build Coastguard Worker             efi_entry
1431*5225e6b1SAndroid Build Coastguard Worker                 .system_table()
1432*5225e6b1SAndroid Build Coastguard Worker                 .boot_services()
1433*5225e6b1SAndroid Build Coastguard Worker                 .find_first_and_open::<BlockIoProtocol>()
1434*5225e6b1SAndroid Build Coastguard Worker                 .unwrap();
1435*5225e6b1SAndroid Build Coastguard Worker 
1436*5225e6b1SAndroid Build Coastguard Worker             // Check open_protocol is called on the first handle.
1437*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1438*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(
1439*5225e6b1SAndroid Build Coastguard Worker                     traces.borrow_mut().open_protocol_trace.inputs,
1440*5225e6b1SAndroid Build Coastguard Worker                     [(DeviceHandle(1 as *mut _), BlockIoProtocol::GUID, image_handle),]
1441*5225e6b1SAndroid Build Coastguard Worker                 );
1442*5225e6b1SAndroid Build Coastguard Worker             });
1443*5225e6b1SAndroid Build Coastguard Worker         })
1444*5225e6b1SAndroid Build Coastguard Worker     }
1445*5225e6b1SAndroid Build Coastguard Worker 
1446*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_exit_boot_services()1447*5225e6b1SAndroid Build Coastguard Worker     fn test_exit_boot_services() {
1448*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1449*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1450*5225e6b1SAndroid Build Coastguard Worker             // Create a buffer large enough to hold two EfiMemoryDescriptor.
1451*5225e6b1SAndroid Build Coastguard Worker             let mut descriptors: [EfiMemoryDescriptor; 2] = [
1452*5225e6b1SAndroid Build Coastguard Worker                 EfiMemoryDescriptor {
1453*5225e6b1SAndroid Build Coastguard Worker                     memory_type: EFI_MEMORY_TYPE_LOADER_DATA,
1454*5225e6b1SAndroid Build Coastguard Worker                     padding: 0,
1455*5225e6b1SAndroid Build Coastguard Worker                     physical_start: 0,
1456*5225e6b1SAndroid Build Coastguard Worker                     virtual_start: 0,
1457*5225e6b1SAndroid Build Coastguard Worker                     number_of_pages: 0,
1458*5225e6b1SAndroid Build Coastguard Worker                     attributes: 0,
1459*5225e6b1SAndroid Build Coastguard Worker                 },
1460*5225e6b1SAndroid Build Coastguard Worker                 EfiMemoryDescriptor {
1461*5225e6b1SAndroid Build Coastguard Worker                     memory_type: EFI_MEMORY_TYPE_LOADER_CODE,
1462*5225e6b1SAndroid Build Coastguard Worker                     padding: 0,
1463*5225e6b1SAndroid Build Coastguard Worker                     physical_start: 0,
1464*5225e6b1SAndroid Build Coastguard Worker                     virtual_start: 0,
1465*5225e6b1SAndroid Build Coastguard Worker                     number_of_pages: 0,
1466*5225e6b1SAndroid Build Coastguard Worker                     attributes: 0,
1467*5225e6b1SAndroid Build Coastguard Worker                 },
1468*5225e6b1SAndroid Build Coastguard Worker             ];
1469*5225e6b1SAndroid Build Coastguard Worker             let map_key: usize = 12345;
1470*5225e6b1SAndroid Build Coastguard Worker             // Set up get_memory_map trace.
1471*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1472*5225e6b1SAndroid Build Coastguard Worker                 // Output only the first EfiMemoryDescriptor.
1473*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().get_memory_map_trace.outputs =
1474*5225e6b1SAndroid Build Coastguard Worker                     VecDeque::from([(map_key, 1 * size_of::<EfiMemoryDescriptor>())]);
1475*5225e6b1SAndroid Build Coastguard Worker             });
1476*5225e6b1SAndroid Build Coastguard Worker 
1477*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: Buffer is guaranteed valid.
1478*5225e6b1SAndroid Build Coastguard Worker             let buffer = unsafe {
1479*5225e6b1SAndroid Build Coastguard Worker                 from_raw_parts_mut(
1480*5225e6b1SAndroid Build Coastguard Worker                     descriptors.as_mut_ptr() as *mut u8,
1481*5225e6b1SAndroid Build Coastguard Worker                     descriptors.len() * size_of::<EfiMemoryDescriptor>(),
1482*5225e6b1SAndroid Build Coastguard Worker                 )
1483*5225e6b1SAndroid Build Coastguard Worker             };
1484*5225e6b1SAndroid Build Coastguard Worker 
1485*5225e6b1SAndroid Build Coastguard Worker             // Test `exit_boot_services`
1486*5225e6b1SAndroid Build Coastguard Worker             let desc = super::exit_boot_services(efi_entry, buffer).unwrap();
1487*5225e6b1SAndroid Build Coastguard Worker 
1488*5225e6b1SAndroid Build Coastguard Worker             // Validate that UEFI APIs are correctly called.
1489*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1490*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(
1491*5225e6b1SAndroid Build Coastguard Worker                     traces.borrow_mut().get_memory_map_trace.inputs,
1492*5225e6b1SAndroid Build Coastguard Worker                     [(
1493*5225e6b1SAndroid Build Coastguard Worker                         descriptors.len() * size_of::<EfiMemoryDescriptor>(),
1494*5225e6b1SAndroid Build Coastguard Worker                         descriptors.as_mut_ptr()
1495*5225e6b1SAndroid Build Coastguard Worker                     )]
1496*5225e6b1SAndroid Build Coastguard Worker                 );
1497*5225e6b1SAndroid Build Coastguard Worker 
1498*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(
1499*5225e6b1SAndroid Build Coastguard Worker                     traces.borrow_mut().exit_boot_services_trace.inputs,
1500*5225e6b1SAndroid Build Coastguard Worker                     [(image_handle, map_key)],
1501*5225e6b1SAndroid Build Coastguard Worker                 );
1502*5225e6b1SAndroid Build Coastguard Worker             });
1503*5225e6b1SAndroid Build Coastguard Worker 
1504*5225e6b1SAndroid Build Coastguard Worker             // Validate that the returned `EfiMemoryMap` contains only 1 EfiMemoryDescriptor.
1505*5225e6b1SAndroid Build Coastguard Worker             assert_eq!(desc.into_iter().map(|v| *v).collect::<Vec<_>>(), descriptors[..1].to_vec());
1506*5225e6b1SAndroid Build Coastguard Worker             // Validate that the returned `EfiMemoryMap` has the correct map_key.
1507*5225e6b1SAndroid Build Coastguard Worker             assert_eq!(desc.map_key(), map_key);
1508*5225e6b1SAndroid Build Coastguard Worker         })
1509*5225e6b1SAndroid Build Coastguard Worker     }
1510*5225e6b1SAndroid Build Coastguard Worker 
1511*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_exit_boot_services_unaligned_buffer()1512*5225e6b1SAndroid Build Coastguard Worker     fn test_exit_boot_services_unaligned_buffer() {
1513*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1514*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1515*5225e6b1SAndroid Build Coastguard Worker             // Create a buffer for 2 EfiMemoryDescriptor.
1516*5225e6b1SAndroid Build Coastguard Worker             let descriptors: [EfiMemoryDescriptor; 2] = [
1517*5225e6b1SAndroid Build Coastguard Worker                 EfiMemoryDescriptor {
1518*5225e6b1SAndroid Build Coastguard Worker                     memory_type: EFI_MEMORY_TYPE_LOADER_DATA,
1519*5225e6b1SAndroid Build Coastguard Worker                     padding: 0,
1520*5225e6b1SAndroid Build Coastguard Worker                     physical_start: 0,
1521*5225e6b1SAndroid Build Coastguard Worker                     virtual_start: 0,
1522*5225e6b1SAndroid Build Coastguard Worker                     number_of_pages: 0,
1523*5225e6b1SAndroid Build Coastguard Worker                     attributes: 0,
1524*5225e6b1SAndroid Build Coastguard Worker                 },
1525*5225e6b1SAndroid Build Coastguard Worker                 EfiMemoryDescriptor {
1526*5225e6b1SAndroid Build Coastguard Worker                     memory_type: EFI_MEMORY_TYPE_LOADER_CODE,
1527*5225e6b1SAndroid Build Coastguard Worker                     padding: 0,
1528*5225e6b1SAndroid Build Coastguard Worker                     physical_start: 0,
1529*5225e6b1SAndroid Build Coastguard Worker                     virtual_start: 0,
1530*5225e6b1SAndroid Build Coastguard Worker                     number_of_pages: 0,
1531*5225e6b1SAndroid Build Coastguard Worker                     attributes: 0,
1532*5225e6b1SAndroid Build Coastguard Worker                 },
1533*5225e6b1SAndroid Build Coastguard Worker             ];
1534*5225e6b1SAndroid Build Coastguard Worker 
1535*5225e6b1SAndroid Build Coastguard Worker             let map_key: usize = 12345;
1536*5225e6b1SAndroid Build Coastguard Worker             // Set up get_memory_map trace.
1537*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1538*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().get_memory_map_trace.outputs =
1539*5225e6b1SAndroid Build Coastguard Worker                     VecDeque::from([(map_key, 2 * size_of::<EfiMemoryDescriptor>())]);
1540*5225e6b1SAndroid Build Coastguard Worker             });
1541*5225e6b1SAndroid Build Coastguard Worker 
1542*5225e6b1SAndroid Build Coastguard Worker             // Construct the destination buffer.
1543*5225e6b1SAndroid Build Coastguard Worker             let mut buffer = [0u8; 256];
1544*5225e6b1SAndroid Build Coastguard Worker             let alignment = core::mem::align_of::<EfiMemoryDescriptor>();
1545*5225e6b1SAndroid Build Coastguard Worker             let size = core::mem::size_of::<EfiMemoryDescriptor>();
1546*5225e6b1SAndroid Build Coastguard Worker             let aligned = aligned_subslice(&mut buffer[..], alignment).unwrap();
1547*5225e6b1SAndroid Build Coastguard Worker             // Offset by 1 element so that we can make an unaligned buffer starting somewhere in
1548*5225e6b1SAndroid Build Coastguard Worker             // between.
1549*5225e6b1SAndroid Build Coastguard Worker             let start = aligned.get_mut(size..).unwrap();
1550*5225e6b1SAndroid Build Coastguard Worker             start[..size].clone_from_slice(descriptors[0].as_bytes());
1551*5225e6b1SAndroid Build Coastguard Worker             start[size..][..size].clone_from_slice(descriptors[1].as_bytes());
1552*5225e6b1SAndroid Build Coastguard Worker             // Pass an unaligned address.
1553*5225e6b1SAndroid Build Coastguard Worker             let desc = super::exit_boot_services(efi_entry, &mut aligned[size - 1..]).unwrap();
1554*5225e6b1SAndroid Build Coastguard Worker             // Validate that the returned `EfiMemoryMap` contains the correct EfiMemoryDescriptor.
1555*5225e6b1SAndroid Build Coastguard Worker             assert_eq!(desc.into_iter().map(|v| *v).collect::<Vec<_>>(), descriptors[..2].to_vec());
1556*5225e6b1SAndroid Build Coastguard Worker             // Validate that the returned `EfiMemoryMap` has the correct map_key.
1557*5225e6b1SAndroid Build Coastguard Worker             assert_eq!(desc.map_key(), map_key);
1558*5225e6b1SAndroid Build Coastguard Worker         });
1559*5225e6b1SAndroid Build Coastguard Worker     }
1560*5225e6b1SAndroid Build Coastguard Worker 
1561*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_create_event_with_notify_fn()1562*5225e6b1SAndroid Build Coastguard Worker     fn test_create_event_with_notify_fn() {
1563*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1564*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1565*5225e6b1SAndroid Build Coastguard Worker             let mut cb_impl = |_: EfiEvent| {};
1566*5225e6b1SAndroid Build Coastguard Worker             let mut cb = EventNotify::new(Tpl::Callback, &mut cb_impl);
1567*5225e6b1SAndroid Build Coastguard Worker             let event: EfiEvent = 1234usize as _;
1568*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1569*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().create_event_trace.outputs.push_back(event);
1570*5225e6b1SAndroid Build Coastguard Worker             });
1571*5225e6b1SAndroid Build Coastguard Worker             {
1572*5225e6b1SAndroid Build Coastguard Worker                 // SAFETY: event notifications are always safe in unittests.
1573*5225e6b1SAndroid Build Coastguard Worker                 let _ = unsafe {
1574*5225e6b1SAndroid Build Coastguard Worker                     efi_entry
1575*5225e6b1SAndroid Build Coastguard Worker                         .system_table()
1576*5225e6b1SAndroid Build Coastguard Worker                         .boot_services()
1577*5225e6b1SAndroid Build Coastguard Worker                         .create_event_with_notification(EventType::Timer, &mut cb)
1578*5225e6b1SAndroid Build Coastguard Worker                 }
1579*5225e6b1SAndroid Build Coastguard Worker                 .unwrap();
1580*5225e6b1SAndroid Build Coastguard Worker             }
1581*5225e6b1SAndroid Build Coastguard Worker             let efi_cb: EfiEventNotify = Some(efi_event_cb);
1582*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1583*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(
1584*5225e6b1SAndroid Build Coastguard Worker                     traces.borrow_mut().create_event_trace.inputs,
1585*5225e6b1SAndroid Build Coastguard Worker                     [(
1586*5225e6b1SAndroid Build Coastguard Worker                         EventType::Timer as _,
1587*5225e6b1SAndroid Build Coastguard Worker                         Tpl::Callback as _,
1588*5225e6b1SAndroid Build Coastguard Worker                         efi_cb,
1589*5225e6b1SAndroid Build Coastguard Worker                         &mut cb as *mut _ as *mut _
1590*5225e6b1SAndroid Build Coastguard Worker                     )]
1591*5225e6b1SAndroid Build Coastguard Worker                 )
1592*5225e6b1SAndroid Build Coastguard Worker             });
1593*5225e6b1SAndroid Build Coastguard Worker             // Verify close_event is called.
1594*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES
1595*5225e6b1SAndroid Build Coastguard Worker                 .with(|traces| assert_eq!(traces.borrow_mut().close_event_trace.inputs, [event]));
1596*5225e6b1SAndroid Build Coastguard Worker         });
1597*5225e6b1SAndroid Build Coastguard Worker     }
1598*5225e6b1SAndroid Build Coastguard Worker 
1599*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_create_event_wo_notify_fn()1600*5225e6b1SAndroid Build Coastguard Worker     fn test_create_event_wo_notify_fn() {
1601*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1602*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1603*5225e6b1SAndroid Build Coastguard Worker             let event: EfiEvent = 1234usize as _;
1604*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1605*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().create_event_trace.outputs.push_back(event);
1606*5225e6b1SAndroid Build Coastguard Worker             });
1607*5225e6b1SAndroid Build Coastguard Worker             {
1608*5225e6b1SAndroid Build Coastguard Worker                 let _ = efi_entry
1609*5225e6b1SAndroid Build Coastguard Worker                     .system_table()
1610*5225e6b1SAndroid Build Coastguard Worker                     .boot_services()
1611*5225e6b1SAndroid Build Coastguard Worker                     .create_event(EventType::Timer)
1612*5225e6b1SAndroid Build Coastguard Worker                     .unwrap();
1613*5225e6b1SAndroid Build Coastguard Worker             }
1614*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1615*5225e6b1SAndroid Build Coastguard Worker                 assert_eq!(
1616*5225e6b1SAndroid Build Coastguard Worker                     traces.borrow_mut().create_event_trace.inputs,
1617*5225e6b1SAndroid Build Coastguard Worker                     [(EventType::Timer as _, 0, None, null_mut())]
1618*5225e6b1SAndroid Build Coastguard Worker                 )
1619*5225e6b1SAndroid Build Coastguard Worker             });
1620*5225e6b1SAndroid Build Coastguard Worker         });
1621*5225e6b1SAndroid Build Coastguard Worker     }
1622*5225e6b1SAndroid Build Coastguard Worker 
1623*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_check_event()1624*5225e6b1SAndroid Build Coastguard Worker     fn test_check_event() {
1625*5225e6b1SAndroid Build Coastguard Worker         run_test(|image_handle, systab_ptr| {
1626*5225e6b1SAndroid Build Coastguard Worker             let efi_entry = EfiEntry { image_handle, systab_ptr };
1627*5225e6b1SAndroid Build Coastguard Worker             let event: EfiEvent = 1234usize as _;
1628*5225e6b1SAndroid Build Coastguard Worker             EFI_CALL_TRACES.with(|traces| {
1629*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().create_event_trace.outputs.push_back(event);
1630*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().check_event_trace.outputs.push_back(EFI_STATUS_SUCCESS);
1631*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().check_event_trace.outputs.push_back(EFI_STATUS_NOT_READY);
1632*5225e6b1SAndroid Build Coastguard Worker                 traces.borrow_mut().check_event_trace.outputs.push_back(EFI_STATUS_UNSUPPORTED);
1633*5225e6b1SAndroid Build Coastguard Worker             });
1634*5225e6b1SAndroid Build Coastguard Worker             let res =
1635*5225e6b1SAndroid Build Coastguard Worker                 efi_entry.system_table().boot_services().create_event(EventType::Timer).unwrap();
1636*5225e6b1SAndroid Build Coastguard Worker             assert_eq!(efi_entry.system_table().boot_services().check_event(&res), Ok(true));
1637*5225e6b1SAndroid Build Coastguard Worker             assert_eq!(efi_entry.system_table().boot_services().check_event(&res), Ok(false));
1638*5225e6b1SAndroid Build Coastguard Worker             assert!(efi_entry.system_table().boot_services().check_event(&res).is_err());
1639*5225e6b1SAndroid Build Coastguard Worker         });
1640*5225e6b1SAndroid Build Coastguard Worker     }
1641*5225e6b1SAndroid Build Coastguard Worker }
1642