boot_services/
boot_services.rs

1#![cfg_attr(all(not(test), not(feature = "mockall")), no_std)]
2
3#[cfg(feature = "global_allocator")]
4pub mod global_allocator;
5
6extern crate alloc;
7
8pub mod allocation;
9pub mod boxed;
10pub mod c_ptr;
11pub mod event;
12pub mod protocol_handler;
13pub mod tpl;
14
15#[cfg(any(test, feature = "mockall"))]
16use mockall::automock;
17
18use alloc::vec::Vec;
19use c_ptr::{CMutPtr, CMutRef, CPtr, PtrMetadata};
20use core::{
21    any::{Any, TypeId},
22    ffi::c_void,
23    marker::PhantomData,
24    mem::{self, MaybeUninit},
25    option::Option,
26    ptr::{self, NonNull},
27    sync::atomic::{AtomicPtr, Ordering},
28};
29
30use r_efi::efi;
31
32use allocation::{AllocType, MemoryMap, MemoryType};
33use boxed::BootServicesBox;
34use event::{EventNotifyCallback, EventTimerType, EventType};
35use protocol_handler::{HandleSearchType, Protocol, Registration};
36use tpl::{Tpl, TplGuard};
37
38/// This is the boot services used in the UEFI.
39/// it wraps an atomic ptr to [`efi::BootServices`]
40#[derive(Debug)]
41pub struct StandardBootServices<'a> {
42    efi_boot_services: AtomicPtr<efi::BootServices>,
43    _lifetime_marker: PhantomData<&'a efi::BootServices>,
44}
45
46impl<'a> StandardBootServices<'a> {
47    /// Create a new StandardBootServices with the provided [efi::BootServices].
48    pub const fn new(efi_boot_services: &'a efi::BootServices) -> Self {
49        // The efi::BootServices is only read, that is why we use a non mutable reference.
50        Self {
51            efi_boot_services: AtomicPtr::new(efi_boot_services as *const _ as *mut _),
52            _lifetime_marker: PhantomData,
53        }
54    }
55
56    /// Create a new StandardBootServices that is uninitialized.
57    /// The struct need to be initialize later with [Self::initialize], otherwise, subsequent call will panic.
58    pub const fn new_uninit() -> Self {
59        Self { efi_boot_services: AtomicPtr::new(ptr::null_mut()), _lifetime_marker: PhantomData }
60    }
61
62    /// Initialize the StandardBootServices with a reference to [efi::BootServices].
63    /// # Panics
64    /// This function will panic if already initialize.
65    pub fn initialize(&'a self, efi_boot_services: &'a efi::BootServices) {
66        if self.efi_boot_services.load(Ordering::Relaxed).is_null() {
67            // The efi::BootServices is only read, that is why we use a non mutable reference.
68            self.efi_boot_services.store(efi_boot_services as *const _ as *mut _, Ordering::SeqCst)
69        } else {
70            panic!("Boot services is already initialize.")
71        }
72    }
73
74    /// # Panics
75    /// This function will panic if it was not initialize.
76    fn efi_boot_services(&self) -> &efi::BootServices {
77        // SAFETY: This pointer is assume to be a valid efi::BootServices pointer since the only way to set it was via an efi::BootServices reference.
78        unsafe {
79            self.efi_boot_services.load(Ordering::SeqCst).as_ref::<'a>().expect("Boot services is not initialize.")
80        }
81    }
82}
83
84///SAFETY: StandardBootServices uses an atomic ptr to access the BootServices.
85unsafe impl Sync for StandardBootServices<'static> {}
86///SAFETY: When the lifetime is `'static`, the pointer is guaranteed to stay valid.
87unsafe impl Send for StandardBootServices<'static> {}
88
89/// Functions that are available *before* a successful call to EFI_BOOT_SERVICES.ExitBootServices().
90#[cfg_attr(any(test, feature = "mockall"), automock)]
91pub trait BootServices {
92    /// Create an event.
93    ///
94    /// [UEFI Spec Documentation: 7.1.1. EFI_BOOT_SERVICES.CreateEvent()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-createevent)
95    fn create_event<T>(
96        &self,
97        event_type: EventType,
98        notify_tpl: Tpl,
99        notify_function: Option<EventNotifyCallback<T>>,
100        notify_context: T,
101    ) -> Result<efi::Event, efi::Status>
102    where
103        T: CPtr<'static> + 'static,
104    {
105        //SAFETY: ['StaticPtr`] generic is used to guaranteed that rust borowing and rules are meet.
106        unsafe {
107            self.create_event_unchecked(
108                event_type,
109                notify_tpl,
110                mem::transmute(notify_function),
111                notify_context.into_ptr() as *mut T::Type,
112            )
113        }
114    }
115
116    /// Use [`BootServices::create_event`] when possible.
117    ///
118    /// # Safety
119    ///
120    /// When calling this method, you have to make sure that *notify_context* pointer is **null** or all of the following is true:
121    /// * The pointer must be properly aligned.
122    /// * It must be "dereferenceable" into type `T`
123    /// * It must remain a valid pointer for the lifetime of the event.
124    /// * You must enforce Rust’s borrowing[^borrowing rules] rules rules.
125    ///
126    /// [^borrowing rules]:
127    /// [Rust By Example Book: 15.3. Borrowing](https://doc.rust-lang.org/beta/rust-by-example/scope/borrow.html)
128    unsafe fn create_event_unchecked<T: Sized + 'static>(
129        &self,
130        event_type: EventType,
131        notify_tpl: Tpl,
132        notify_function: Option<EventNotifyCallback<*mut T>>,
133        notify_context: *mut T,
134    ) -> Result<efi::Event, efi::Status>;
135
136    /// Create an event in a group.
137    ///
138    /// [UEFI Spec Documentation: 7.1.2. EFI_BOOT_SERVICES.CreateEventEx()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-createeventex)
139    fn create_event_ex<T>(
140        &self,
141        event_type: EventType,
142        notify_tpl: Tpl,
143        notify_function: Option<EventNotifyCallback<T>>,
144        notify_context: T,
145        event_group: &'static efi::Guid,
146    ) -> Result<efi::Event, efi::Status>
147    where
148        T: CPtr<'static> + 'static,
149    {
150        //SAFETY: [`StaticPtr`] generic is used to guaranteed that rust borowing and rules are meet.
151        unsafe {
152            self.create_event_ex_unchecked(
153                event_type,
154                notify_tpl.into(),
155                mem::transmute(notify_function),
156                notify_context.into_ptr() as *mut <T as CPtr>::Type,
157                event_group,
158            )
159        }
160    }
161
162    /// Use [`BootServices::create_event_ex`] when possible.
163    ///
164    /// # Safety
165    ///
166    /// Make sure to comply to the same constraint as [`BootServices::create_event_unchecked`]
167    unsafe fn create_event_ex_unchecked<T: Sized + 'static>(
168        &self,
169        event_type: EventType,
170        notify_tpl: Tpl,
171        notify_function: EventNotifyCallback<*mut T>,
172        notify_context: *mut T,
173        event_group: &'static efi::Guid,
174    ) -> Result<efi::Event, efi::Status>;
175
176    /// Close an event.
177    ///
178    /// [UEFI Spec Documentation: 7.1.3. EFI_BOOT_SERVICES.CloseEvent()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-closeevent)
179    ///
180    /// [^note]: It is safe to call *close_event* in the notify function.
181    fn close_event(&self, event: efi::Event) -> Result<(), efi::Status>;
182
183    /// Signals an event.
184    ///
185    /// [UEFI Spec Documentation: 7.1.4. EFI_BOOT_SERVICES.SignalEvent()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-signalevent)
186    fn signal_event(&self, event: efi::Event) -> Result<(), efi::Status>;
187
188    /// Stops execution until an event is signaled.
189    ///
190    /// [UEFI Spec Documentation: 7.1.5. EFI_BOOT_SERVICES.WaitForEvent()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-waitforevent)
191    fn wait_for_event(&self, events: &mut [efi::Event]) -> Result<usize, efi::Status>;
192
193    /// Checks whether an event is in the signaled state.
194    ///
195    /// [UEFI Spec Documentation: 7.1.6. EFI_BOOT_SERVICES.CheckEvent()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-checkevent)
196    fn check_event(&self, event: efi::Event) -> Result<(), efi::Status>;
197
198    /// Sets the type of timer and the trigger time for a timer event.
199    ///
200    /// [UEFI Spec Documentation: 7.1.7. EFI_BOOT_SERVICES.SetTimer()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-settimer)
201    fn set_timer(&self, event: efi::Event, timer_type: EventTimerType, trigger_time: u64) -> Result<(), efi::Status>;
202
203    /// Raises a task's priority level and returns a [`TplGuard`] that will restore the tpl when dropped.
204    ///
205    /// See [`BootServices::raise_tpl`] and [`BootServices::restore_tpl`] for more details.
206    fn raise_tpl_guarded<'a>(&'a self, tpl: Tpl) -> TplGuard<'a, Self> {
207        TplGuard { boot_services: self, retore_tpl: self.raise_tpl(tpl) }
208    }
209
210    /// Raises a task’s priority level and returns its previous level.
211    ///
212    /// [UEFI Spec Documentation: 7.1.8. EFI_BOOT_SERVICES.RaiseTPL()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-raisetpl)
213    fn raise_tpl(&self, tpl: Tpl) -> Tpl;
214
215    /// Restores a task’s priority level to its previous value.
216    ///
217    /// [UEFI Spec Documentation: 7.1.9. EFI_BOOT_SERVICES.RestoreTPL()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-restoretpl)
218    fn restore_tpl(&self, tpl: Tpl);
219
220    /// Allocates memory pages from the system.
221    ///
222    /// [UEFI Spec Documentation: 7.2.1. EFI_BOOT_SERVICES.AllocatePages()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-allocatepages)
223    fn allocate_pages(
224        &self,
225        alloc_type: AllocType,
226        memory_type: MemoryType,
227        nb_pages: usize,
228    ) -> Result<usize, efi::Status>;
229
230    /// Frees memory pages.
231    ///
232    /// [UEFI Spec Documentation: 7.2.2. EFI_BOOT_SERVICES.FreePages()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-freepages)
233    fn free_pages(&self, address: usize, nb_pages: usize) -> Result<(), efi::Status>;
234
235    /// Returns the current memory map.
236    ///
237    /// [UEFI Spec Documentation: 7.2.3. EFI_BOOT_SERVICES.GetMemoryMap()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-getmemorymap)
238    fn get_memory_map<'a>(&'a self) -> Result<MemoryMap<'a, Self>, (efi::Status, usize)>;
239
240    /// Allocates pool memory.
241    ///
242    /// [UEFI Spec Documentation: 7.2.4. EFI_BOOT_SERVICES.AllocatePool()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-allocatepool)
243    fn allocate_pool(&self, pool_type: MemoryType, size: usize) -> Result<*mut u8, efi::Status>;
244
245    /// Allocates pool memory casted as given type.
246    fn allocate_pool_for_type<T: 'static>(&self, pool_type: MemoryType) -> Result<*mut T, efi::Status> {
247        let ptr = self.allocate_pool(pool_type, mem::size_of::<T>())?;
248        Ok(ptr as *mut T)
249    }
250
251    /// Returns pool memory to the system.
252    ///
253    /// [UEFI Spec Documentation: 7.2.5. EFI_BOOT_SERVICES.FreePool()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-freepool)
254    fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status>;
255
256    /// Installs a protocol interface on a device handle.
257    /// If the handle does not exist, it is created and added to the list of handles in the system.
258    ///
259    /// [UEFI Spec Documentation: 7.3.2. EFI_BOOT_SERVICES.InstallProtocolInterface()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-installprotocolinterface)
260    fn install_protocol_interface<P, R, I>(
261        &self,
262        handle: Option<efi::Handle>,
263        protocol: &P,
264        interface: R,
265    ) -> Result<(efi::Handle, PtrMetadata<'static, R>), efi::Status>
266    where
267        P: Protocol<Interface = I> + 'static,
268        R: CMutRef<'static, Type = I> + 'static,
269        I: 'static,
270    {
271        assert_ne!(
272            TypeId::of::<()>(),
273            TypeId::of::<I>(),
274            "Marker interface are not supported by install_protocol_interface, use install_protocol_marker instead."
275        );
276
277        let key = interface.metadata();
278        let handle = unsafe {
279            self.install_protocol_interface_unchecked(
280                handle,
281                protocol.protocol_guid(),
282                interface.into_mut_ptr() as *mut c_void,
283            )?
284        };
285        Ok((handle, key))
286    }
287
288    /// Installs a protocol marker (null) interface on a device handle.
289    /// If the handle does not exist, it is created and added to the list of handles in the system.
290    ///
291    /// [UEFI Spec Documentation: 7.3.2. EFI_BOOT_SERVICES.InstallProtocolInterface()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-installprotocolinterface)
292    fn install_protocol_marker<P>(&self, handle: Option<efi::Handle>, protocol: &P) -> Result<efi::Handle, efi::Status>
293    where
294        P: Protocol<Interface = ()> + 'static,
295    {
296        unsafe { self.install_protocol_interface_unchecked(handle, protocol.protocol_guid(), ptr::null_mut()) }
297    }
298
299    /// Use [`BootServices::install_protocol_interface`] when possible.
300    ///
301    /// # Safety
302    ///
303    /// When calling this method, you have to make sure that if *interface* pointer is non-null, it is adhereing to
304    /// the structure associated with the protocol.
305    unsafe fn install_protocol_interface_unchecked(
306        &self,
307        handle: Option<efi::Handle>,
308        protocol: &'static efi::Guid,
309        interface: *mut c_void,
310    ) -> Result<efi::Handle, efi::Status>;
311
312    /// Removes a protocol interface from a device handle.
313    ///
314    /// [UEFI Spec Documentation: 7.3.3. EFI_BOOT_SERVICES.UninstallProtocolInterface()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-uninstallprotocolinterface)
315    fn uninstall_protocol_interface<P, R, I>(
316        &self,
317        handle: efi::Handle,
318        protocol: &P,
319        key: PtrMetadata<'static, R>,
320    ) -> Result<R, efi::Status>
321    where
322        P: Protocol<Interface = I> + 'static,
323        R: CMutRef<'static, Type = I> + 'static,
324        I: 'static,
325    {
326        unsafe {
327            self.uninstall_protocol_interface_unchecked(handle, protocol.protocol_guid(), key.ptr_value as *mut c_void)
328        }?;
329        Ok(unsafe { key.into_original_ptr() })
330    }
331
332    /// Removes a protocol interface marker (null) from a device handle.
333    ///
334    /// [UEFI Spec Documentation: 7.3.3. EFI_BOOT_SERVICES.UninstallProtocolInterface()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-uninstallprotocolinterface)
335    fn uninstall_protocol_marker<P>(&self, handle: efi::Handle, protocol: &P) -> Result<(), efi::Status>
336    where
337        P: Protocol<Interface = ()> + 'static,
338    {
339        unsafe { self.uninstall_protocol_interface_unchecked(handle, protocol.protocol_guid(), ptr::null_mut()) }
340    }
341
342    /// Use [`BootServices::uninstall_protocol_interface`] when possible.
343    ///
344    /// # Safety
345    ///
346    /// interface must be a valid pointer and be of the type expected by to protocol.
347    unsafe fn uninstall_protocol_interface_unchecked(
348        &self,
349        handle: efi::Handle,
350        protocol: &'static efi::Guid,
351        interface: *mut c_void,
352    ) -> Result<(), efi::Status>;
353
354    /// Reinstalls a protocol interface on a device handle.
355    ///
356    /// [UEFI Spec Documentation: 7.3.4. EFI_BOOT_SERVICES.ReinstallProtocolInterface()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-reinstallprotocolinterface)
357    fn reinstall_protocol_interface<P, O, N, I>(
358        &self,
359        handle: efi::Handle,
360        protocol: &P,
361        old_protocol_interface_key: PtrMetadata<'static, O>,
362        new_protocol_interface: N,
363    ) -> Result<(PtrMetadata<'static, N>, O), efi::Status>
364    where
365        P: Protocol<Interface = I> + 'static,
366        O: CMutRef<'static, Type = I> + 'static,
367        N: CMutRef<'static, Type = I> + 'static,
368        I: 'static,
369    {
370        assert_ne!(
371            TypeId::of::<()>(),
372            TypeId::of::<I>(),
373            "Marker interface are not supported with reinstall_protocol_interface function."
374        );
375        let new_key = new_protocol_interface.metadata();
376        unsafe {
377            self.reinstall_protocol_interface_unchecked(
378                handle,
379                protocol.protocol_guid(),
380                old_protocol_interface_key.ptr_value as *mut _,
381                new_protocol_interface.into_mut_ptr() as *mut _,
382            )?;
383        }
384        Ok((new_key, unsafe { old_protocol_interface_key.into_original_ptr() }))
385    }
386
387    /// Use [`BootServices::reinstall_protocol_interface`] when possible.
388    ///
389    /// # Safety
390    /// When calling this method, you have to make sure that if *new_protocol_interface* pointer is non-null, it is adhereing to
391    /// the structure associated with the protocol.
392    unsafe fn reinstall_protocol_interface_unchecked(
393        &self,
394        handle: efi::Handle,
395        protocol: &'static efi::Guid,
396        old_protocol_interface: *mut c_void,
397        new_protocol_interface: *mut c_void,
398    ) -> Result<(), efi::Status>;
399
400    /// Creates an event that is to be signaled whenever an interface is installed for a specified protocol.
401    ///
402    /// [UEFI Spec Documentation: 7.3.5. EFI_BOOT_SERVICES.RegisterProtocolNotify()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-registerprotocolnotify)
403    fn register_protocol_notify(
404        &self,
405        protocol: &'static efi::Guid,
406        event: efi::Event,
407    ) -> Result<Registration, efi::Status>;
408
409    /// Returns an array of handles that support a specified protocol.
410    ///
411    /// [UEFI Spec Documentation: 7.3.6. EFI_BOOT_SERVICES.LocateHandle()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-locatehandle)
412    fn locate_handle<'a>(
413        &'a self,
414        search_type: HandleSearchType,
415    ) -> Result<BootServicesBox<'a, [efi::Handle], Self>, efi::Status>;
416
417    /// Queries a handle to determine if it supports a specified protocol and return a mutable reference to the interface.
418    ///
419    /// [UEFI Spec Documentation: 7.3.7. EFI_BOOT_SERVICES.HandleProtocol()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-handleprotocol)
420    ///
421    /// # Safety
422    /// Make sure to not create multiple mutable reference of interface.
423    unsafe fn handle_protocol<P: Protocol<Interface = I> + 'static, I: 'static>(
424        &self,
425        handle: efi::Handle,
426        protocol: &P,
427    ) -> Result<&'static mut I, efi::Status> {
428        assert_ne!(
429            TypeId::of::<()>(),
430            TypeId::of::<I>(),
431            "Marker interface are not supported with handle_protocol function, use handle_protocol_marker instead."
432        );
433        //SAFETY: The generic Protocol ensure that the interfaces is the right type for the specified protocol.
434        unsafe {
435            self.handle_protocol_unchecked(handle, protocol.protocol_guid()).map(|i| (i as *mut I).as_mut().unwrap())
436        }
437    }
438
439    /// Queries a handle to determine if it supports a specified protocol marker.
440    ///
441    /// [UEFI Spec Documentation: 7.3.7. EFI_BOOT_SERVICES.HandleProtocol()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-handleprotocol)
442    fn handle_protocol_marker<P: Protocol<Interface = ()> + 'static>(
443        &self,
444        handle: efi::Handle,
445        protocol: &P,
446    ) -> Result<(), efi::Status> {
447        //SAFETY: The generic Protocol ensure that the interfaces is the right type for the specified protocol.
448        let interface_marker = unsafe { self.handle_protocol_unchecked(handle, protocol.protocol_guid()) }?;
449        debug_assert!(interface_marker.is_null(), "Interface marker should be null.");
450        Ok(())
451    }
452
453    /// Use [`BootServices::handle_protocol`] when possible.
454    unsafe fn handle_protocol_unchecked(
455        &self,
456        handle: efi::Handle,
457        protocol: &efi::Guid,
458    ) -> Result<*mut c_void, efi::Status>;
459
460    /// Locates the handle to a device on the device path that supports the specified protocol.
461    ///
462    /// [UEFI Spec Documentation: 7.3.8. EFI_BOOT_SERVICES.LocateDevicePath()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-locatedevicepath)
463    ///
464    /// # Safety
465    ///
466    /// device path mut be valid pointers.
467    unsafe fn locate_device_path(
468        &self,
469        protocol: &efi::Guid,
470        device_path: *mut *mut efi::protocols::device_path::Protocol,
471    ) -> Result<efi::Handle, efi::Status>;
472
473    /// Queries a handle to determine if it supports a specified protocol.
474    /// If the protocol is supported by the handle, it opens the protocol on behalf of the calling agent.
475    ///
476    /// [UEFI Spec Documentation: 7.3.9. EFI_BOOT_SERVICES.OpenProtocol()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-openprotocol)
477    ///
478    /// # Safety
479    ///
480    /// Do not create more than one mutable reference to the interface.
481    unsafe fn open_protocol<P: Protocol<Interface = I> + 'static, I: 'static>(
482        &self,
483        handle: efi::Handle,
484        protocol: &P,
485        agent_handle: efi::Handle,
486        controller_handle: efi::Handle,
487        attribute: u32,
488    ) -> Result<&'static mut I, efi::Status> {
489        assert_ne!(
490            TypeId::of::<()>(),
491            TypeId::of::<I>(),
492            "Marker interface are not supported with open_protocol function, use open_protocol_marker instead."
493        );
494        //SAFETY: The generic Protocol ensure that the interfaces is the right type for the specified protocol.
495        unsafe {
496            self.open_protocol_unchecked(handle, protocol, agent_handle, controller_handle, attribute)
497                .map(|i| (i as *mut I).as_mut().unwrap())
498        }
499    }
500
501    /// Queries a handle to determine if it supports a specified protocol marker.
502    /// If the protocol is supported by the handle, it opens the protocol on behalf of the calling agent.
503    ///
504    /// [UEFI Spec Documentation: 7.3.9. EFI_BOOT_SERVICES.OpenProtocol()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-openprotocol)
505    fn open_protocol_marker<P: Protocol<Interface = ()> + 'static>(
506        &self,
507        handle: efi::Handle,
508        protocol: &P,
509        agent_handle: efi::Handle,
510        controller_handle: efi::Handle,
511        attribute: u32,
512    ) -> Result<(), efi::Status> {
513        //SAFETY: The generic Protocol ensure that the interfaces is the right type for the specified protocol.
514        let interface_marker =
515            unsafe { self.open_protocol_unchecked(handle, protocol, agent_handle, controller_handle, attribute)? };
516        assert!(interface_marker.is_null());
517        Ok(())
518    }
519
520    /// Use [`BootServices::open_protocol`] when possible.
521    ///
522    /// # Safety
523    ///
524    /// When calling this method, you have to make sure that if *agent_handle* pointer is non-null.
525    unsafe fn open_protocol_unchecked(
526        &self,
527        handle: efi::Handle,
528        protocol: &efi::Guid,
529        agent_handle: efi::Handle,
530        controller_handle: efi::Handle,
531        attribute: u32,
532    ) -> Result<*mut c_void, efi::Status>;
533
534    /// Closes a protocol on a handle that was previously opened.
535    ///
536    /// [UEFI Spec Documentation: 7.3.10. EFI_BOOT_SERVICES.CloseProtocol()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-closeprotocol)
537    fn close_protocol(
538        &self,
539        handle: efi::Handle,
540        protocol: &efi::Guid,
541        agent_handle: efi::Handle,
542        controller_handle: efi::Handle,
543    ) -> Result<(), efi::Status>;
544
545    /// Retrieves the list of agents that currently have a protocol interface opened.
546    ///
547    /// [UEFI Spec Documentation: 7.3.11. EFI_BOOT_SERVICES.OpenProtocolInformation()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-openprotocolinformation)
548    fn open_protocol_information<'a>(
549        &'a self,
550        handle: efi::Handle,
551        protocol: &efi::Guid,
552    ) -> Result<BootServicesBox<'a, [efi::OpenProtocolInformationEntry], Self>, efi::Status>;
553
554    /// Connects one or more drivers to a controller.
555    ///
556    /// # Safety
557    ///
558    /// When calling this method, you have to make sure that *driver_image_handle*'s last entry is null per UEFI specification.
559    ///
560    /// [UEFI Spec Documentation: 7.3.12. EFI_BOOT_SERVICES.ConnectController()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-connectcontroller)
561    unsafe fn connect_controller(
562        &self,
563        controller_handle: efi::Handle,
564        driver_image_handles: Vec<efi::Handle>,
565        remaining_device_path: *mut efi::protocols::device_path::Protocol,
566        recursive: bool,
567    ) -> Result<(), efi::Status>;
568
569    /// Disconnects one or more drivers from a controller.
570    ///
571    /// [UEFI Spec Documentation: 7.3.13. EFI_BOOT_SERVICES.DisconnectController()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-disconnectcontroller)
572    fn disconnect_controller(
573        &self,
574        controller_handle: efi::Handle,
575        driver_image_handle: Option<efi::Handle>,
576        child_handle: Option<efi::Handle>,
577    ) -> Result<(), efi::Status>;
578
579    /// Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated from pool.
580    ///
581    /// [UEFI Spec Documentation: 7.3.14. EFI_BOOT_SERVICES.ProtocolsPerHandle()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-protocolsperhandle)
582    fn protocols_per_handle<'a>(
583        &'a self,
584        handle: efi::Handle,
585    ) -> Result<BootServicesBox<'a, [&'static efi::Guid], Self>, efi::Status>;
586
587    /// Returns an array of handles that support the requested protocol in a buffer allocated from pool.
588    ///
589    /// [UEFI Spec Documentation: 7.3.15. EFI_BOOT_SERVICES.LocateHandleBuffer()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-locatehandlebuffer)
590    fn locate_handle_buffer<'a>(
591        &'a self,
592        search_type: HandleSearchType,
593    ) -> Result<BootServicesBox<'a, [efi::Handle], Self>, efi::Status>;
594
595    /// Returns the first protocol instance that matches the given protocol.
596    ///
597    /// [UEFI Spec Documentation: 7.3.16. EFI_BOOT_SERVICES.LocateProtocol()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-locateprotocol)
598    ///
599    /// # Safety
600    ///
601    /// Make sure to not create multiple mutable reference when using this api.
602    unsafe fn locate_protocol<P, I>(
603        &self,
604        protocol: &P,
605        registration: Option<Registration>,
606    ) -> Result<&'static mut I, efi::Status>
607    where
608        P: Protocol<Interface = I> + 'static,
609        I: Any + 'static,
610    {
611        assert_ne!(
612            TypeId::of::<()>(),
613            TypeId::of::<I>(),
614            "Marker interface are not supported by locate_protocol, use locate_protocol_marker instead."
615        );
616
617        //SAFETY: The generic Protocol ensure that the interfaces is the right type for the specified protocol.
618        let interface_ptr = unsafe {
619            self.locate_protocol_unchecked(
620                protocol.protocol_guid(),
621                registration.map_or(ptr::null_mut(), |r| r.as_ptr()),
622            )? as *mut I
623        };
624        Ok(interface_ptr.as_mut().unwrap())
625    }
626
627    /// Returns the first protocol instance that matches the given marker protocol.
628    ///
629    /// [UEFI Spec Documentation: 7.3.16. EFI_BOOT_SERVICES.LocateProtocol()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-locateprotocol)
630    fn locate_protocol_marker<P>(&self, protocol: &P, registration: Option<Registration>) -> Result<(), efi::Status>
631    where
632        P: Protocol<Interface = ()> + 'static,
633    {
634        //SAFETY: The generic Protocol ensure that the interfaces is the right type for the specified protocol.
635        let interface_ptr = unsafe {
636            self.locate_protocol_unchecked(
637                protocol.protocol_guid(),
638                registration.map_or(ptr::null_mut(), |r| r.as_ptr()),
639            )?
640        };
641        assert_eq!(ptr::null_mut(), interface_ptr);
642        Ok(())
643    }
644
645    /// Use [`BootServices::locate_protocol`] when possible.
646    ///
647    /// # Safety
648    ///
649    unsafe fn locate_protocol_unchecked(
650        &self,
651        protocol: &'static efi::Guid,
652        registration: *mut c_void,
653    ) -> Result<*mut c_void, efi::Status>;
654
655    /// Load an EFI image from a memory buffer.
656    ///
657    /// This uses [`Self::load_image`] behind the scene. This function assume that the request is not originating from the boot manager.
658    ///
659    fn load_image_from_source(
660        &self,
661        parent_image_handle: efi::Handle,
662        device_path: *mut efi::protocols::device_path::Protocol,
663        source_buffer: &[u8],
664    ) -> Result<efi::Handle, efi::Status> {
665        self.load_image(false, parent_image_handle, device_path, Some(source_buffer))
666    }
667
668    /// Load an EFI image from a file.
669    ///
670    /// This uses [`Self::load_image`] behind the scene. This function assume that the request is not originating from the boot manager.
671    ///
672    fn load_image_from_file(
673        &self,
674        parent_image_handle: efi::Handle,
675        file_device_path: NonNull<efi::protocols::device_path::Protocol>,
676    ) -> Result<efi::Handle, efi::Status> {
677        self.load_image(false, parent_image_handle, file_device_path.as_ptr(), None)
678    }
679
680    /// Loads an EFI image into memory.
681    ///
682    /// [UEFI Spec Documentation: 7.4.1. EFI_BOOT_SERVICES.LoadImage()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-loadimage)
683    ///
684    fn load_image<'a>(
685        &self,
686        boot_policy: bool,
687        parent_image_handle: efi::Handle,
688        device_path: *mut efi::protocols::device_path::Protocol,
689        source_buffer: Option<&'a [u8]>,
690    ) -> Result<efi::Handle, efi::Status>;
691
692    /// Transfers control to a loaded image’s entry point.
693    ///
694    /// [UEFI Spec Documentation: 7.4.2. EFI_BOOT_SERVICES.StartImage()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-startimage)
695    ///
696    fn start_image<'a>(
697        &'a self,
698        image_handle: efi::Handle,
699    ) -> Result<(), (efi::Status, Option<BootServicesBox<'a, [u8], Self>>)>;
700
701    /// Unloads an image.
702    ///
703    /// [UEFI Spec Documentation: 7.4.3. EFI_BOOT_SERVICES.UnloadImage()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-unloadimage)
704    ///
705    fn unload_image(&self, image_handle: efi::Handle) -> Result<(), efi::Status>;
706
707    /// Terminates a loaded EFI image and returns control to boot services.
708    ///
709    /// [UEFI Spec Documentation: 7.4.5. EFI_BOOT_SERVICES.Exit()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-exit)
710    ///
711    fn exit<'a>(
712        &'a self,
713        image_handle: efi::Handle,
714        exit_status: efi::Status,
715        exit_data: Option<BootServicesBox<'a, [u8], Self>>,
716    ) -> Result<(), efi::Status>;
717
718    /// Terminates all boot services.
719    ///
720    /// [UEFI Spec Documentation: EFI_BOOT_SERVICES.ExitBootServices()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-exitbootservices)
721    ///
722    fn exit_boot_services(&self, image_handle: efi::Handle, map_key: usize) -> Result<(), efi::Status>;
723
724    /// Sets the system’s watchdog timer.
725    ///
726    /// Note:  
727    /// We deliberately choose to ignore the watchdog code and data parameters because we are not using them.
728    /// Feel free to add those if needed.
729    ///
730    /// [UEFI Spec Documentation: 7.5.1. EFI_BOOT_SERVICES.SetWatchdogTimer()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-setwatchdogtimer)
731    fn set_watchdog_timer(&self, timeout: usize) -> Result<(), efi::Status>;
732
733    /// Induces a fine-grained stall
734    ///
735    /// [UEFI Spec Documentation: 7.5.2. EFI_BOOT_SERVICES.Stall()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-stall)
736    fn stall(&self, microseconds: usize) -> Result<(), efi::Status>;
737
738    /// Copies the contents of one buffer to another buffer.
739    ///
740    /// [UEFI Spec Documentation: 7.5.3. EFI_BOOT_SERVICES.CopyMem()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-copymem)
741    fn copy_mem<T: 'static>(&self, dest: &mut T, src: &T) {
742        unsafe { self.copy_mem_unchecked(dest as *mut T as _, src as *const T as _, mem::size_of::<T>()) }
743    }
744
745    /// Use of [`Self::copy_mem`] is preferable if the context allows it.
746    ///
747    /// # Safety
748    ///
749    /// dest and src must be valid pointer to a continuous chunk of memory of size length.
750    unsafe fn copy_mem_unchecked(&self, dest: *mut c_void, src: *const c_void, length: usize);
751
752    /// Fills a buffer with a specified value.
753    ///
754    /// [UEFI Spec Documentation: 7.5.4. EFI_BOOT_SERVICES.SetMem()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-setmem)
755    fn set_mem(&self, buffer: &mut [u8], value: u8);
756
757    /// Returns a monotonically increasing count for the platform.
758    ///
759    /// [UEFI Spec Documentation: 7.5.5. EFI_BOOT_SERVICES.GetNextMonotonicCount()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-getnextmonotoniccount)
760    fn get_next_monotonic_count(&self) -> Result<u64, efi::Status>;
761
762    /// Adds, updates, or removes a configuration table entry from the EFI System Table.
763    ///
764    /// [UEFI Spec Documentation: 7.5.6. EFI_BOOT_SERVICES.InstallConfigurationTable()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-installconfigurationtable)
765    fn install_configuration_table<T: CMutPtr<'static> + 'static>(
766        &self,
767        guid: &efi::Guid,
768        table: T,
769    ) -> Result<(), efi::Status> {
770        unsafe { self.install_configuration_table_unchecked(guid, table.into_mut_ptr() as *mut c_void) }
771    }
772
773    /// Use [`BootServices::install_configuration_table`] when possible.
774    ///
775    /// # Safety
776    ///
777    /// The table pointer must be the right type associated with the guid.
778    unsafe fn install_configuration_table_unchecked(
779        &self,
780        guid: &efi::Guid,
781        table: *mut c_void,
782    ) -> Result<(), efi::Status>;
783
784    /// Computes and returns a 32-bit CRC for a data buffer.
785    ///
786    /// [UEFI Spec Documentation: 7.5.7. EFI_BOOT_SERVICES.CalculateCrc32()](https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#efi-boot-services-calculatecrc32)
787    fn calculate_crc_32<T: 'static>(&self, data: &T) -> Result<u32, efi::Status> {
788        unsafe { self.calculate_crc_32_unchecked(data as *const T as _, mem::size_of::<T>()) }
789    }
790
791    unsafe fn calculate_crc_32_unchecked(&self, data: *const c_void, data_size: usize) -> Result<u32, efi::Status>;
792}
793
794macro_rules! efi_boot_services_fn {
795    ($efi_boot_services:expr, $fn_name:ident) => {{
796        match $efi_boot_services.$fn_name {
797            f if f as usize == 0 => panic!("Boot services function {} is not initialized.", stringify!($fn_name)),
798            f => f,
799        }
800    }};
801}
802
803impl BootServices for StandardBootServices<'_> {
804    unsafe fn create_event_unchecked<T: Sized + 'static>(
805        &self,
806        event_type: EventType,
807        notify_tpl: Tpl,
808        notify_function: Option<EventNotifyCallback<*mut T>>,
809        notify_context: *mut T,
810    ) -> Result<efi::Event, efi::Status> {
811        let mut event = MaybeUninit::zeroed();
812        let status = efi_boot_services_fn!(self.efi_boot_services(), create_event)(
813            event_type.into(),
814            notify_tpl.into(),
815            mem::transmute(notify_function),
816            notify_context as *mut c_void,
817            event.as_mut_ptr(),
818        );
819        if status.is_error() {
820            Err(status)
821        } else {
822            Ok(event.assume_init())
823        }
824    }
825
826    unsafe fn create_event_ex_unchecked<T: Sized + 'static>(
827        &self,
828        event_type: EventType,
829        notify_tpl: Tpl,
830        notify_function: EventNotifyCallback<*mut T>,
831        notify_context: *mut T,
832        event_group: &'static efi::Guid,
833    ) -> Result<efi::Event, efi::Status> {
834        let mut event = MaybeUninit::zeroed();
835        let status = efi_boot_services_fn!(self.efi_boot_services(), create_event_ex)(
836            event_type.into(),
837            notify_tpl.into(),
838            mem::transmute(notify_function),
839            notify_context as *mut c_void,
840            event_group as *const _,
841            event.as_mut_ptr(),
842        );
843        if status.is_error() {
844            Err(status)
845        } else {
846            Ok(event.assume_init())
847        }
848    }
849
850    fn close_event(&self, event: efi::Event) -> Result<(), efi::Status> {
851        match efi_boot_services_fn!(self.efi_boot_services(), close_event)(event) {
852            s if s.is_error() => Err(s),
853            _ => Ok(()),
854        }
855    }
856
857    fn signal_event(&self, event: efi::Event) -> Result<(), efi::Status> {
858        match efi_boot_services_fn!(self.efi_boot_services(), signal_event)(event) {
859            s if s.is_error() => Err(s),
860            _ => Ok(()),
861        }
862    }
863
864    fn wait_for_event(&self, events: &mut [efi::Event]) -> Result<usize, efi::Status> {
865        let mut index = MaybeUninit::zeroed();
866        let status = efi_boot_services_fn!(self.efi_boot_services(), wait_for_event)(
867            events.len(),
868            events.as_mut_ptr(),
869            index.as_mut_ptr(),
870        );
871        if status.is_error() {
872            Err(status)
873        } else {
874            Ok(unsafe { index.assume_init() })
875        }
876    }
877
878    fn check_event(&self, event: efi::Event) -> Result<(), efi::Status> {
879        match efi_boot_services_fn!(self.efi_boot_services(), check_event)(event) {
880            s if s.is_error() => Err(s),
881            _ => Ok(()),
882        }
883    }
884
885    fn set_timer(&self, event: efi::Event, timer_type: EventTimerType, trigger_time: u64) -> Result<(), efi::Status> {
886        match efi_boot_services_fn!(self.efi_boot_services(), set_timer)(event, timer_type.into(), trigger_time) {
887            s if s.is_error() => Err(s),
888            _ => Ok(()),
889        }
890    }
891
892    fn raise_tpl(&self, new_tpl: Tpl) -> Tpl {
893        efi_boot_services_fn!(self.efi_boot_services(), raise_tpl)(new_tpl.into()).into()
894    }
895
896    fn restore_tpl(&self, old_tpl: Tpl) {
897        efi_boot_services_fn!(self.efi_boot_services(), restore_tpl)(old_tpl.into())
898    }
899
900    fn allocate_pages(
901        &self,
902        alloc_type: AllocType,
903        memory_type: MemoryType,
904        nb_pages: usize,
905    ) -> Result<usize, efi::Status> {
906        let mut memory_address = match alloc_type {
907            AllocType::Address(address) => address,
908            AllocType::MaxAddress(address) => address,
909            _ => 0,
910        };
911        match efi_boot_services_fn!(self.efi_boot_services(), allocate_pages)(
912            alloc_type.into(),
913            memory_type.into(),
914            nb_pages,
915            ptr::addr_of_mut!(memory_address) as *mut u64,
916        ) {
917            s if s.is_error() => Err(s),
918            _ => Ok(memory_address),
919        }
920    }
921
922    fn free_pages(&self, address: usize, nb_pages: usize) -> Result<(), efi::Status> {
923        match efi_boot_services_fn!(self.efi_boot_services(), free_pages)(address as u64, nb_pages) {
924            s if s.is_error() => Err(s),
925            _ => Ok(()),
926        }
927    }
928
929    fn get_memory_map<'a>(&'a self) -> Result<MemoryMap<'a, Self>, (efi::Status, usize)> {
930        let get_memory_map = efi_boot_services_fn!(self.efi_boot_services(), get_memory_map);
931
932        let mut memory_map_size = 0;
933        let mut map_key = 0;
934        let mut descriptor_size = 0;
935        let mut descriptor_version = 0;
936
937        match get_memory_map(
938            ptr::addr_of_mut!(memory_map_size),
939            ptr::null_mut(),
940            ptr::addr_of_mut!(map_key),
941            ptr::addr_of_mut!(descriptor_size),
942            ptr::addr_of_mut!(descriptor_version),
943        ) {
944            s if s == efi::Status::BUFFER_TOO_SMALL => memory_map_size += 0x400, // add more space in case allocation makes the memory map bigger.
945            _ => (),
946        };
947
948        let buffer = self.allocate_pool(MemoryType::BOOT_SERVICES_DATA, memory_map_size).map_err(|s| (s, 0))?;
949
950        match get_memory_map(
951            ptr::addr_of_mut!(memory_map_size),
952            buffer as *mut _,
953            ptr::addr_of_mut!(map_key),
954            ptr::addr_of_mut!(descriptor_size),
955            ptr::addr_of_mut!(descriptor_version),
956        ) {
957            s if s == efi::Status::BUFFER_TOO_SMALL => return Err((s, memory_map_size)),
958            s if s.is_error() => return Err((s, 0)),
959            _ => (),
960        }
961        Ok(MemoryMap {
962            descriptors: unsafe { BootServicesBox::from_raw_parts_mut(buffer as *mut _, descriptor_size, self) },
963            map_key,
964            descriptor_version,
965        })
966    }
967
968    fn allocate_pool(&self, memory_type: MemoryType, size: usize) -> Result<*mut u8, efi::Status> {
969        let mut buffer = ptr::null_mut();
970        match efi_boot_services_fn!(self.efi_boot_services(), allocate_pool)(
971            memory_type.into(),
972            size,
973            ptr::addr_of_mut!(buffer),
974        ) {
975            s if s.is_error() => return Err(s),
976            _ => Ok(buffer as *mut u8),
977        }
978    }
979
980    fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status> {
981        match efi_boot_services_fn!(self.efi_boot_services(), free_pool)(buffer as *mut c_void) {
982            s if s.is_error() => return Err(s),
983            _ => Ok(()),
984        }
985    }
986
987    unsafe fn install_protocol_interface_unchecked(
988        &self,
989        handle: Option<efi::Handle>,
990        protocol: &'static efi::Guid,
991        interface: *mut c_void,
992    ) -> Result<efi::Handle, efi::Status> {
993        let mut handle = handle.unwrap_or(ptr::null_mut());
994        match efi_boot_services_fn!(self.efi_boot_services(), install_protocol_interface)(
995            ptr::addr_of_mut!(handle),
996            protocol as *const _ as *mut _,
997            efi::NATIVE_INTERFACE,
998            interface,
999        ) {
1000            s if s.is_error() => Err(s),
1001            _ => Ok(handle),
1002        }
1003    }
1004
1005    unsafe fn uninstall_protocol_interface_unchecked(
1006        &self,
1007        handle: efi::Handle,
1008        protocol: &'static efi::Guid,
1009        interface: *mut c_void,
1010    ) -> Result<(), efi::Status> {
1011        match efi_boot_services_fn!(self.efi_boot_services(), uninstall_protocol_interface)(
1012            handle,
1013            protocol as *const _ as *mut _,
1014            interface,
1015        ) {
1016            s if s.is_error() => Err(s),
1017            _ => Ok(()),
1018        }
1019    }
1020
1021    unsafe fn reinstall_protocol_interface_unchecked(
1022        &self,
1023        handle: efi::Handle,
1024        protocol: &'static efi::Guid,
1025        old_protocol_interface: *mut c_void,
1026        new_protocol_interface: *mut c_void,
1027    ) -> Result<(), efi::Status> {
1028        match efi_boot_services_fn!(self.efi_boot_services(), reinstall_protocol_interface)(
1029            handle,
1030            protocol as *const _ as *mut _,
1031            old_protocol_interface,
1032            new_protocol_interface,
1033        ) {
1034            s if s.is_error() => Err(s),
1035            _ => Ok(()),
1036        }
1037    }
1038
1039    fn register_protocol_notify(&self, protocol: &efi::Guid, event: efi::Event) -> Result<Registration, efi::Status> {
1040        let mut registration = MaybeUninit::uninit();
1041        match efi_boot_services_fn!(self.efi_boot_services(), register_protocol_notify)(
1042            protocol as *const _ as *mut _,
1043            event,
1044            registration.as_mut_ptr() as *mut _,
1045        ) {
1046            s if s.is_error() => Err(s),
1047            _ => Ok(unsafe { registration.assume_init() }),
1048        }
1049    }
1050
1051    fn locate_handle(
1052        &self,
1053        search_type: HandleSearchType,
1054    ) -> Result<BootServicesBox<[efi::Handle], Self>, efi::Status> {
1055        let locate_handle = efi_boot_services_fn!(self.efi_boot_services(), locate_handle);
1056
1057        let protocol = match search_type {
1058            HandleSearchType::ByProtocol(p) => p as *const _ as *mut _,
1059            _ => ptr::null_mut(),
1060        };
1061        let search_key = match search_type {
1062            HandleSearchType::ByRegisterNotify(r) => r.as_ptr(),
1063            _ => ptr::null_mut(),
1064        };
1065
1066        // Use to get the buffer_size
1067        let mut buffer_size = 0;
1068        locate_handle(search_type.into(), protocol, search_key, ptr::addr_of_mut!(buffer_size), ptr::null_mut());
1069
1070        let buffer = self.allocate_pool(MemoryType::BOOT_SERVICES_DATA, buffer_size)?;
1071
1072        match locate_handle(
1073            search_type.into(),
1074            protocol,
1075            search_key,
1076            ptr::addr_of_mut!(buffer_size),
1077            buffer as *mut efi::Handle,
1078        ) {
1079            s if s.is_error() => Err(s),
1080            _ => Ok(unsafe {
1081                BootServicesBox::from_raw_parts_mut(
1082                    buffer as *mut _,
1083                    buffer_size / mem::size_of::<efi::Handle>(),
1084                    &self,
1085                )
1086            }),
1087        }
1088    }
1089
1090    unsafe fn handle_protocol_unchecked(
1091        &self,
1092        handle: efi::Handle,
1093        protocol: &efi::Guid,
1094    ) -> Result<*mut c_void, efi::Status> {
1095        let mut interface = ptr::null_mut();
1096        match efi_boot_services_fn!(self.efi_boot_services(), handle_protocol)(
1097            handle,
1098            protocol as *const _ as *mut _,
1099            ptr::addr_of_mut!(interface),
1100        ) {
1101            s if s.is_error() => Err(s),
1102            _ => Ok(interface),
1103        }
1104    }
1105
1106    unsafe fn locate_device_path(
1107        &self,
1108        protocol: &efi::Guid,
1109        device_path: *mut *mut efi::protocols::device_path::Protocol,
1110    ) -> Result<efi::Handle, efi::Status> {
1111        let mut device = ptr::null_mut();
1112        match efi_boot_services_fn!(self.efi_boot_services(), locate_device_path)(
1113            protocol as *const _ as *mut _,
1114            device_path,
1115            ptr::addr_of_mut!(device),
1116        ) {
1117            s if s.is_error() => Err(s),
1118            _ => Ok(device),
1119        }
1120    }
1121
1122    unsafe fn open_protocol_unchecked(
1123        &self,
1124        handle: efi::Handle,
1125        protocol: &efi::Guid,
1126        agent_handle: efi::Handle,
1127        controller_handle: efi::Handle,
1128        attribute: u32,
1129    ) -> Result<*mut c_void, efi::Status> {
1130        let mut interface = ptr::null_mut();
1131        match efi_boot_services_fn!(self.efi_boot_services(), open_protocol)(
1132            handle,
1133            protocol as *const _ as *mut _,
1134            ptr::addr_of_mut!(interface),
1135            agent_handle,
1136            controller_handle,
1137            attribute,
1138        ) {
1139            s if s.is_error() => Err(s),
1140            _ => Ok(interface),
1141        }
1142    }
1143
1144    fn close_protocol(
1145        &self,
1146        handle: efi::Handle,
1147        protocol: &efi::Guid,
1148        agent_handle: efi::Handle,
1149        controller_handle: efi::Handle,
1150    ) -> Result<(), efi::Status> {
1151        match efi_boot_services_fn!(self.efi_boot_services(), close_protocol)(
1152            handle,
1153            protocol as *const _ as *mut _,
1154            agent_handle,
1155            controller_handle,
1156        ) {
1157            s if s.is_error() => Err(s),
1158            _ => Ok(()),
1159        }
1160    }
1161
1162    fn open_protocol_information(
1163        &self,
1164        handle: efi::Handle,
1165        protocol: &efi::Guid,
1166    ) -> Result<BootServicesBox<[efi::OpenProtocolInformationEntry], Self>, efi::Status>
1167    where
1168        Self: Sized,
1169    {
1170        let mut entry_buffer = ptr::null_mut();
1171        let mut entry_count = 0;
1172        match efi_boot_services_fn!(self.efi_boot_services(), open_protocol_information)(
1173            handle,
1174            protocol as *const _ as *mut _,
1175            ptr::addr_of_mut!(entry_buffer),
1176            ptr::addr_of_mut!(entry_count),
1177        ) {
1178            s if s.is_error() => Err(s),
1179            _ => Ok(unsafe { BootServicesBox::from_raw_parts_mut(entry_buffer, entry_count, self) }),
1180        }
1181    }
1182
1183    unsafe fn connect_controller(
1184        &self,
1185        controller_handle: efi::Handle,
1186        mut driver_image_handles: Vec<efi::Handle>,
1187        remaining_device_path: *mut efi::protocols::device_path::Protocol,
1188        recursive: bool,
1189    ) -> Result<(), efi::Status> {
1190        let driver_image_handles = if driver_image_handles.is_empty() {
1191            ptr::null_mut()
1192        } else {
1193            driver_image_handles.push(ptr::null_mut());
1194            driver_image_handles.as_mut_ptr()
1195        };
1196        match efi_boot_services_fn!(self.efi_boot_services(), connect_controller)(
1197            controller_handle,
1198            driver_image_handles,
1199            remaining_device_path,
1200            recursive.into(),
1201        ) {
1202            s if s.is_error() => Err(s),
1203            _ => Ok(()),
1204        }
1205    }
1206
1207    fn disconnect_controller(
1208        &self,
1209        controller_handle: efi::Handle,
1210        driver_image_handle: Option<efi::Handle>,
1211        child_handle: Option<efi::Handle>,
1212    ) -> Result<(), efi::Status> {
1213        match efi_boot_services_fn!(self.efi_boot_services(), disconnect_controller)(
1214            controller_handle,
1215            driver_image_handle.unwrap_or(ptr::null_mut()),
1216            child_handle.unwrap_or(ptr::null_mut()),
1217        ) {
1218            s if s.is_error() => Err(s),
1219            _ => Ok(()),
1220        }
1221    }
1222
1223    fn protocols_per_handle(
1224        &self,
1225        handle: efi::Handle,
1226    ) -> Result<BootServicesBox<[&'static efi::Guid], Self>, efi::Status> {
1227        let mut protocol_buffer = ptr::null_mut();
1228        let mut protocol_buffer_count = 0;
1229        match efi_boot_services_fn!(self.efi_boot_services(), protocols_per_handle)(
1230            handle,
1231            ptr::addr_of_mut!(protocol_buffer),
1232            ptr::addr_of_mut!(protocol_buffer_count),
1233        ) {
1234            s if s.is_error() => Err(s),
1235            _ => Ok(unsafe {
1236                BootServicesBox::<[_], _>::from_raw_parts_mut(protocol_buffer as *mut _, protocol_buffer_count, self)
1237            }),
1238        }
1239    }
1240
1241    fn locate_handle_buffer(
1242        &self,
1243        search_type: HandleSearchType,
1244    ) -> Result<BootServicesBox<[efi::Handle], Self>, efi::Status>
1245    where
1246        Self: Sized,
1247    {
1248        let mut buffer = ptr::null_mut();
1249        let mut buffer_count = 0;
1250        let protocol = match search_type {
1251            HandleSearchType::ByProtocol(p) => p as *const _ as *mut _,
1252            _ => ptr::null_mut(),
1253        };
1254        let search_key = match search_type {
1255            HandleSearchType::ByRegisterNotify(r) => r.as_ptr(),
1256            _ => ptr::null_mut(),
1257        };
1258        match efi_boot_services_fn!(self.efi_boot_services(), locate_handle_buffer)(
1259            search_type.into(),
1260            protocol,
1261            search_key,
1262            ptr::addr_of_mut!(buffer_count),
1263            ptr::addr_of_mut!(buffer),
1264        ) {
1265            s if s.is_error() => Err(s),
1266            _ => Ok(unsafe {
1267                BootServicesBox::<[_], _>::from_raw_parts_mut(buffer as *mut efi::Handle, buffer_count, self)
1268            }),
1269        }
1270    }
1271
1272    unsafe fn locate_protocol_unchecked(
1273        &self,
1274        protocol: &'static efi::Guid,
1275        registration: *mut c_void,
1276    ) -> Result<*mut c_void, efi::Status> {
1277        let mut interface = ptr::null_mut();
1278        match efi_boot_services_fn!(self.efi_boot_services(), locate_protocol)(
1279            protocol as *const _ as *mut _,
1280            registration,
1281            ptr::addr_of_mut!(interface),
1282        ) {
1283            s if s.is_error() => Err(s),
1284            _ => Ok(interface),
1285        }
1286    }
1287
1288    fn load_image(
1289        &self,
1290        boot_policy: bool,
1291        parent_image_handle: efi::Handle,
1292        device_path: *mut efi::protocols::device_path::Protocol,
1293        source_buffer: Option<&[u8]>,
1294    ) -> Result<efi::Handle, efi::Status> {
1295        let source_buffer_ptr =
1296            source_buffer.map_or(ptr::null_mut(), |buffer| buffer.as_ptr() as *const _ as *mut c_void);
1297        let source_buffer_size = source_buffer.map_or(0, |buffer| buffer.len());
1298        let mut image_handle = MaybeUninit::uninit();
1299        match efi_boot_services_fn!(self.efi_boot_services(), load_image)(
1300            boot_policy.into(),
1301            parent_image_handle,
1302            device_path,
1303            source_buffer_ptr,
1304            source_buffer_size,
1305            image_handle.as_mut_ptr(),
1306        ) {
1307            s if s.is_error() => Err(s),
1308            _ => Ok(unsafe { image_handle.assume_init() }),
1309        }
1310    }
1311
1312    fn start_image<'a>(
1313        &'a self,
1314        image_handle: efi::Handle,
1315    ) -> Result<(), (efi::Status, Option<BootServicesBox<'a, [u8], Self>>)> {
1316        let mut exit_data_size = MaybeUninit::uninit();
1317        let mut exit_data = MaybeUninit::uninit();
1318        match efi_boot_services_fn!(self.efi_boot_services(), start_image)(
1319            image_handle,
1320            exit_data_size.as_mut_ptr(),
1321            exit_data.as_mut_ptr(),
1322        ) {
1323            s if s.is_error() => {
1324                let data = (!exit_data.as_ptr().is_null()).then(|| unsafe {
1325                    BootServicesBox::from_raw_parts_mut(
1326                        exit_data.as_mut_ptr() as *mut u8,
1327                        exit_data_size.assume_init(),
1328                        self,
1329                    )
1330                });
1331                Err((s, data))
1332            }
1333            _ => Ok(()),
1334        }
1335    }
1336
1337    fn unload_image(&self, image_handle: efi::Handle) -> Result<(), efi::Status> {
1338        match efi_boot_services_fn!(self.efi_boot_services(), unload_image)(image_handle) {
1339            s if s.is_error() => Err(s),
1340            _ => Ok(()),
1341        }
1342    }
1343
1344    fn exit<'a>(
1345        &'a self,
1346        image_handle: efi::Handle,
1347        exit_status: efi::Status,
1348        exit_data: Option<BootServicesBox<'a, [u8], Self>>,
1349    ) -> Result<(), efi::Status> {
1350        let exit_data_ptr = exit_data.as_ref().map_or(ptr::null_mut(), |data| data.as_ptr() as *mut u16);
1351        let exit_data_size = exit_data.as_ref().map_or(0, |data| data.len());
1352        match efi_boot_services_fn!(self.efi_boot_services(), exit)(
1353            image_handle,
1354            exit_status,
1355            exit_data_size,
1356            exit_data_ptr,
1357        ) {
1358            s if s.is_error() => Err(s),
1359            _ => Ok(()),
1360        }
1361    }
1362
1363    fn exit_boot_services(&self, image_handle: efi::Handle, map_key: usize) -> Result<(), efi::Status> {
1364        match efi_boot_services_fn!(self.efi_boot_services(), exit_boot_services)(image_handle, map_key) {
1365            s if s.is_error() => Err(s),
1366            _ => Ok(()),
1367        }
1368    }
1369
1370    fn set_watchdog_timer(&self, timeout: usize) -> Result<(), efi::Status> {
1371        match efi_boot_services_fn!(self.efi_boot_services(), set_watchdog_timer)(timeout, 0, 0, ptr::null_mut()) {
1372            s if s.is_error() => Err(s),
1373            _ => Ok(()),
1374        }
1375    }
1376
1377    fn stall(&self, microseconds: usize) -> Result<(), efi::Status> {
1378        match efi_boot_services_fn!(self.efi_boot_services(), stall)(microseconds) {
1379            s if s.is_error() => Err(s),
1380            _ => Ok(()),
1381        }
1382    }
1383
1384    unsafe fn copy_mem_unchecked(&self, dest: *mut c_void, src: *const c_void, length: usize) {
1385        efi_boot_services_fn!(self.efi_boot_services(), copy_mem)(dest, src as *mut _, length);
1386    }
1387
1388    fn set_mem(&self, buffer: &mut [u8], value: u8) {
1389        efi_boot_services_fn!(self.efi_boot_services(), set_mem)(
1390            buffer.as_mut_ptr() as *mut c_void,
1391            buffer.len(),
1392            value,
1393        );
1394    }
1395
1396    fn get_next_monotonic_count(&self) -> Result<u64, efi::Status> {
1397        let mut count = MaybeUninit::uninit();
1398        match efi_boot_services_fn!(self.efi_boot_services(), get_next_monotonic_count)(count.as_mut_ptr()) {
1399            s if s.is_error() => Err(s),
1400            _ => Ok(unsafe { count.assume_init() }),
1401        }
1402    }
1403
1404    unsafe fn install_configuration_table_unchecked(
1405        &self,
1406        guid: &efi::Guid,
1407        table: *mut c_void,
1408    ) -> Result<(), efi::Status> {
1409        match efi_boot_services_fn!(self.efi_boot_services(), install_configuration_table)(
1410            guid as *const _ as *mut _,
1411            table,
1412        ) {
1413            s if s.is_error() => Err(s),
1414            _ => Ok(()),
1415        }
1416    }
1417
1418    unsafe fn calculate_crc_32_unchecked(&self, data: *const c_void, data_size: usize) -> Result<u32, efi::Status> {
1419        let mut crc32 = MaybeUninit::uninit();
1420        match efi_boot_services_fn!(self.efi_boot_services(), calculate_crc32)(
1421            data as *mut _,
1422            data_size,
1423            crc32.as_mut_ptr(),
1424        ) {
1425            s if s.is_error() => Err(s),
1426            _ => Ok(unsafe { crc32.assume_init() }),
1427        }
1428    }
1429}
1430
1431#[cfg(test)]
1432mod test {
1433    use c_ptr::CPtr;
1434    use efi::{protocols::device_path, Boolean, Char16, OpenProtocolInformationEntry};
1435
1436    use super::*;
1437    use core::{mem::MaybeUninit, ops::Deref, slice, sync::atomic::AtomicUsize, u32, u64};
1438    use std::os::raw::c_void;
1439
1440    macro_rules! boot_services {
1441        ($($efi_services:ident = $efi_service_fn:ident),*) => {{
1442            static BOOT_SERVICE: StandardBootServices = StandardBootServices::new_uninit();
1443            let efi_boot_services = unsafe {
1444                #[allow(unused_mut)]
1445                let mut bs = MaybeUninit::<efi::BootServices>::zeroed();
1446                $(
1447                bs.assume_init_mut().$efi_services = $efi_service_fn;
1448                )*
1449                bs.assume_init()
1450            };
1451            BOOT_SERVICE.initialize(&efi_boot_services);
1452            &BOOT_SERVICE
1453        }};
1454    }
1455
1456    static TEST_PROTOCOL_GUID: efi::Guid =
1457        efi::Guid::from_bytes(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1458
1459    struct TestProtocol;
1460    unsafe impl Protocol for TestProtocol {
1461        type Interface = u32;
1462
1463        fn protocol_guid(&self) -> &'static efi::Guid {
1464            &TEST_PROTOCOL_GUID
1465        }
1466    }
1467
1468    impl Deref for TestProtocol {
1469        type Target = efi::Guid;
1470
1471        fn deref(&self) -> &Self::Target {
1472            self.protocol_guid()
1473        }
1474    }
1475
1476    struct TestProtocolMarker;
1477
1478    unsafe impl Protocol for TestProtocolMarker {
1479        type Interface = ();
1480
1481        fn protocol_guid(&self) -> &'static efi::Guid {
1482            &TEST_PROTOCOL_GUID
1483        }
1484    }
1485
1486    impl Deref for TestProtocolMarker {
1487        type Target = efi::Guid;
1488
1489        fn deref(&self) -> &Self::Target {
1490            self.protocol_guid()
1491        }
1492    }
1493
1494    extern "efiapi" fn efi_allocate_pool_use_box(
1495        _mem_type: efi::MemoryType,
1496        size: usize,
1497        buffer: *mut *mut c_void,
1498    ) -> efi::Status {
1499        // Use u64 for ptr alignment.
1500        let allocation = vec![0 as u64; size.div_ceil(mem::size_of::<u64>())].into_boxed_slice();
1501        unsafe {
1502            *buffer = Box::into_raw(allocation) as *mut c_void;
1503        }
1504        efi::Status::SUCCESS
1505    }
1506
1507    extern "efiapi" fn efi_free_pool_use_box(buffer: *mut c_void) -> efi::Status {
1508        if buffer.is_null() {
1509            return efi::Status::INVALID_PARAMETER;
1510        }
1511
1512        unsafe {
1513            let _ = Box::from_raw(buffer as *mut u8);
1514        }
1515
1516        efi::Status::SUCCESS
1517    }
1518
1519    #[test]
1520    #[should_panic(expected = "Boot services is not initialize.")]
1521    fn test_that_accessing_uninit_boot_services_should_panic() {
1522        let bs = StandardBootServices::new_uninit();
1523        bs.efi_boot_services();
1524    }
1525
1526    #[test]
1527    #[should_panic(expected = "Boot services is already initialize.")]
1528    fn test_that_initializing_boot_services_multiple_time_should_panic() {
1529        let efi_bs = unsafe { MaybeUninit::<efi::BootServices>::zeroed().as_ptr().as_ref().unwrap() };
1530        let bs = StandardBootServices::new_uninit();
1531        bs.initialize(efi_bs);
1532        bs.initialize(efi_bs);
1533    }
1534
1535    #[test]
1536    #[should_panic = "Boot services function create_event is not initialized."]
1537    fn test_create_event_not_init() {
1538        let boot_services = boot_services!();
1539        let _ = boot_services.create_event(EventType::RUNTIME, Tpl::APPLICATION, None, ());
1540    }
1541
1542    #[test]
1543    fn test_create_event() {
1544        let boot_services = boot_services!(create_event = efi_create_event);
1545
1546        extern "efiapi" fn notify_callback(_e: efi::Event, ctx: Box<i32>) {
1547            assert_eq!(10, *ctx)
1548        }
1549
1550        extern "efiapi" fn efi_create_event(
1551            event_type: u32,
1552            notify_tpl: efi::Tpl,
1553            notify_function: Option<efi::EventNotify>,
1554            notify_context: *mut c_void,
1555            event: *mut efi::Event,
1556        ) -> efi::Status {
1557            assert_eq!(efi::EVT_RUNTIME | efi::EVT_NOTIFY_SIGNAL, event_type);
1558            assert_eq!(efi::TPL_APPLICATION, notify_tpl);
1559            assert_eq!(notify_callback as *const fn(), unsafe { mem::transmute(notify_function) });
1560            assert_ne!(ptr::null_mut(), notify_context);
1561            assert_ne!(ptr::null_mut(), event);
1562
1563            if let Some(notify_function) = notify_function {
1564                notify_function(ptr::null_mut(), notify_context);
1565            }
1566            efi::Status::SUCCESS
1567        }
1568
1569        let ctx = Box::new(10);
1570        let status = boot_services.create_event(
1571            EventType::RUNTIME | EventType::NOTIFY_SIGNAL,
1572            Tpl::APPLICATION,
1573            Some(notify_callback),
1574            ctx,
1575        );
1576
1577        assert!(matches!(status, Ok(_)));
1578    }
1579
1580    #[test]
1581    fn test_create_event_no_notify() {
1582        let boot_services = boot_services!(create_event = efi_create_event);
1583
1584        extern "efiapi" fn efi_create_event(
1585            event_type: u32,
1586            notify_tpl: efi::Tpl,
1587            notify_function: Option<efi::EventNotify>,
1588            notify_context: *mut c_void,
1589            event: *mut efi::Event,
1590        ) -> efi::Status {
1591            assert_eq!(efi::EVT_RUNTIME | efi::EVT_NOTIFY_SIGNAL, event_type);
1592            assert_eq!(efi::TPL_APPLICATION, notify_tpl);
1593            assert_eq!(None, notify_function);
1594            assert_eq!(ptr::null_mut(), notify_context);
1595            assert_ne!(ptr::null_mut(), event);
1596            efi::Status::SUCCESS
1597        }
1598
1599        let status =
1600            boot_services.create_event(EventType::RUNTIME | EventType::NOTIFY_SIGNAL, Tpl::APPLICATION, None, ());
1601
1602        assert!(matches!(status, Ok(_)));
1603    }
1604
1605    #[test]
1606    #[should_panic = "Boot services function create_event_ex is not initialized."]
1607    fn test_create_event_ex_not_init() {
1608        static GUID: efi::Guid = efi::Guid::from_fields(0, 0, 0, 0, 0, &[0; 6]);
1609        let boot_services = boot_services!();
1610        let _ = boot_services.create_event_ex(EventType::RUNTIME, Tpl::APPLICATION, None, (), &GUID);
1611    }
1612
1613    #[test]
1614    fn test_create_event_ex() {
1615        let boot_services = boot_services!(create_event_ex = efi_create_event_ex);
1616
1617        extern "efiapi" fn notify_callback(_e: efi::Event, ctx: Box<i32>) {
1618            assert_eq!(10, *ctx)
1619        }
1620
1621        extern "efiapi" fn efi_create_event_ex(
1622            event_type: u32,
1623            notify_tpl: efi::Tpl,
1624            notify_function: Option<efi::EventNotify>,
1625            notify_context: *const c_void,
1626            event_group: *const efi::Guid,
1627            event: *mut efi::Event,
1628        ) -> efi::Status {
1629            assert_eq!(efi::EVT_RUNTIME | efi::EVT_NOTIFY_SIGNAL, event_type);
1630            assert_eq!(efi::TPL_APPLICATION, notify_tpl);
1631            assert_eq!(notify_callback as *const fn(), unsafe { mem::transmute(notify_function) });
1632            assert_ne!(ptr::null(), notify_context);
1633            assert_eq!(ptr::addr_of!(GUID), event_group);
1634            assert_ne!(ptr::null_mut(), event);
1635
1636            if let Some(notify_function) = notify_function {
1637                notify_function(ptr::null_mut(), notify_context as *mut _);
1638            }
1639            efi::Status::SUCCESS
1640        }
1641        static GUID: efi::Guid = efi::Guid::from_fields(0, 0, 0, 0, 0, &[0; 6]);
1642        let ctx = Box::new(10);
1643        let status = boot_services.create_event_ex(
1644            EventType::RUNTIME | EventType::NOTIFY_SIGNAL,
1645            Tpl::APPLICATION,
1646            Some(notify_callback),
1647            ctx,
1648            &GUID,
1649        );
1650
1651        assert!(matches!(status, Ok(_)));
1652    }
1653
1654    #[test]
1655    fn test_create_event_ex_no_notify() {
1656        let boot_services = boot_services!(create_event_ex = efi_create_event_ex);
1657
1658        extern "efiapi" fn efi_create_event_ex(
1659            event_type: u32,
1660            notify_tpl: efi::Tpl,
1661            notify_function: Option<efi::EventNotify>,
1662            notify_context: *const c_void,
1663            event_group: *const efi::Guid,
1664            event: *mut efi::Event,
1665        ) -> efi::Status {
1666            assert_eq!(efi::EVT_RUNTIME | efi::EVT_NOTIFY_SIGNAL, event_type);
1667            assert_eq!(efi::TPL_APPLICATION, notify_tpl);
1668            assert_eq!(None, notify_function);
1669            assert_eq!(ptr::null(), notify_context);
1670            assert_eq!(ptr::addr_of!(GUID), event_group);
1671            assert_ne!(ptr::null_mut(), event);
1672            efi::Status::SUCCESS
1673        }
1674        static GUID: efi::Guid = efi::Guid::from_fields(0, 0, 0, 0, 0, &[0; 6]);
1675        let status = boot_services.create_event_ex(
1676            EventType::RUNTIME | EventType::NOTIFY_SIGNAL,
1677            Tpl::APPLICATION,
1678            None,
1679            (),
1680            &GUID,
1681        );
1682
1683        assert!(matches!(status, Ok(_)));
1684    }
1685
1686    #[test]
1687    #[should_panic = "Boot services function close_event is not initialized."]
1688    fn test_close_event_not_init() {
1689        let boot_services = boot_services!();
1690        let _ = boot_services.close_event(ptr::null_mut());
1691    }
1692
1693    #[test]
1694    fn test_close_event() {
1695        let boot_services = boot_services!(close_event = efi_close_event);
1696
1697        extern "efiapi" fn efi_close_event(event: efi::Event) -> efi::Status {
1698            assert_eq!(1, event as usize);
1699            efi::Status::SUCCESS
1700        }
1701
1702        let event = 1_usize as efi::Event;
1703        let status = boot_services.close_event(event);
1704        assert!(matches!(status, Ok(())));
1705    }
1706
1707    #[test]
1708    #[should_panic = "Boot services function signal_event is not initialized."]
1709    fn test_signal_event_not_init() {
1710        let boot_services = boot_services!();
1711        let _ = boot_services.signal_event(ptr::null_mut());
1712    }
1713
1714    #[test]
1715    fn test_signal_event() {
1716        let boot_services = boot_services!(signal_event = efi_signal_event);
1717
1718        extern "efiapi" fn efi_signal_event(event: efi::Event) -> efi::Status {
1719            assert_eq!(1, event as usize);
1720            efi::Status::SUCCESS
1721        }
1722
1723        let event = 1_usize as efi::Event;
1724        let status = boot_services.signal_event(event);
1725        assert!(matches!(status, Ok(())));
1726    }
1727
1728    #[test]
1729    #[should_panic = "Boot services function wait_for_event is not initialized."]
1730    fn test_wait_for_event_not_init() {
1731        let boot_services = boot_services!();
1732        let mut events = vec![];
1733        let _ = boot_services.wait_for_event(&mut events);
1734    }
1735
1736    #[test]
1737    fn test_wait_for_event() {
1738        let boot_services = boot_services!(wait_for_event = efi_wait_for_event);
1739
1740        extern "efiapi" fn efi_wait_for_event(
1741            number_of_event: usize,
1742            events: *mut efi::Event,
1743            index: *mut usize,
1744        ) -> efi::Status {
1745            assert_eq!(2, number_of_event);
1746            assert_ne!(ptr::null_mut(), events);
1747
1748            unsafe { ptr::write(index, 1) }
1749            efi::Status::SUCCESS
1750        }
1751
1752        let mut events = [1_usize as efi::Event, 2_usize as efi::Event];
1753        let status = boot_services.wait_for_event(&mut events);
1754        assert!(matches!(status, Ok(1)));
1755    }
1756
1757    #[test]
1758    #[should_panic = "Boot services function check_event is not initialized."]
1759    fn test_check_event_not_init() {
1760        let boot_services = boot_services!();
1761        let _ = boot_services.check_event(ptr::null_mut());
1762    }
1763
1764    #[test]
1765    fn test_check_event() {
1766        let boot_services = boot_services!(check_event = efi_check_event);
1767
1768        extern "efiapi" fn efi_check_event(event: efi::Event) -> efi::Status {
1769            assert_eq!(1, event as usize);
1770            efi::Status::SUCCESS
1771        }
1772
1773        let event = 1_usize as efi::Event;
1774        let status = boot_services.check_event(event);
1775        assert!(matches!(status, Ok(())));
1776    }
1777
1778    #[test]
1779    #[should_panic = "Boot services function set_timer is not initialized."]
1780    fn test_set_timer_not_init() {
1781        let boot_services = boot_services!();
1782        let _ = boot_services.set_timer(ptr::null_mut(), EventTimerType::Relative, 0);
1783    }
1784
1785    #[test]
1786    fn test_set_timer() {
1787        let boot_services = boot_services!(set_timer = efi_set_timer);
1788
1789        extern "efiapi" fn efi_set_timer(event: efi::Event, r#type: efi::TimerDelay, trigger_time: u64) -> efi::Status {
1790            assert_eq!(1, event as usize);
1791            assert_eq!(efi::TIMER_PERIODIC, r#type);
1792            assert_eq!(200, trigger_time);
1793            efi::Status::SUCCESS
1794        }
1795
1796        let event = 1_usize as efi::Event;
1797        let status = boot_services.set_timer(event, EventTimerType::Periodic, 200);
1798        assert!(matches!(status, Ok(())));
1799    }
1800
1801    #[test]
1802    fn test_raise_tpl_guarded() {
1803        let boot_services = boot_services!(raise_tpl = efi_raise_tpl, restore_tpl = efi_restore_tpl);
1804
1805        static CURRENT_TPL: AtomicUsize = AtomicUsize::new(efi::TPL_APPLICATION);
1806
1807        extern "efiapi" fn efi_raise_tpl(tpl: efi::Tpl) -> efi::Tpl {
1808            assert_eq!(efi::TPL_NOTIFY, tpl);
1809            CURRENT_TPL.swap(tpl, Ordering::Relaxed)
1810        }
1811
1812        extern "efiapi" fn efi_restore_tpl(tpl: efi::Tpl) {
1813            assert_eq!(efi::TPL_APPLICATION, tpl);
1814            CURRENT_TPL.swap(tpl, Ordering::Relaxed);
1815        }
1816
1817        let guard = boot_services.raise_tpl_guarded(Tpl::NOTIFY);
1818        assert_eq!(Tpl::APPLICATION, guard.retore_tpl);
1819        assert_eq!(efi::TPL_NOTIFY, CURRENT_TPL.load(Ordering::Relaxed));
1820        drop(guard);
1821        assert_eq!(efi::TPL_APPLICATION, CURRENT_TPL.load(Ordering::Relaxed));
1822    }
1823
1824    #[test]
1825    #[should_panic = "Boot services function raise_tpl is not initialized."]
1826    fn test_raise_tpl_not_init() {
1827        let boot_services = boot_services!();
1828        let _ = boot_services.raise_tpl(Tpl::CALLBACK);
1829    }
1830
1831    #[test]
1832    fn test_raise_tpl() {
1833        let boot_services = boot_services!(raise_tpl = efi_raise_tpl);
1834
1835        extern "efiapi" fn efi_raise_tpl(tpl: efi::Tpl) -> efi::Tpl {
1836            assert_eq!(efi::TPL_NOTIFY, tpl);
1837            efi::TPL_APPLICATION
1838        }
1839
1840        let status = boot_services.raise_tpl(Tpl::NOTIFY);
1841        assert_eq!(Tpl::APPLICATION, status);
1842    }
1843
1844    #[test]
1845    #[should_panic = "Boot services function restore_tpl is not initialized."]
1846    fn test_restore_tpl_not_init() {
1847        let boot_services = boot_services!();
1848        let _ = boot_services.restore_tpl(Tpl::APPLICATION);
1849    }
1850
1851    #[test]
1852    fn test_restore_tpl() {
1853        let boot_services = boot_services!(restore_tpl = efi_restore_tpl);
1854
1855        extern "efiapi" fn efi_restore_tpl(tpl: efi::Tpl) {
1856            assert_eq!(efi::TPL_APPLICATION, tpl);
1857        }
1858
1859        boot_services.restore_tpl(Tpl::APPLICATION);
1860    }
1861
1862    #[test]
1863    #[should_panic = "Boot services function allocate_pages is not initialized."]
1864    fn test_allocate_pages_not_init() {
1865        let boot_services = boot_services!();
1866        let _ = boot_services.allocate_pages(AllocType::AnyPage, MemoryType::ACPI_MEMORY_NVS, 0);
1867    }
1868
1869    #[test]
1870    fn test_allocate_pages() {
1871        let boot_services = boot_services!(allocate_pages = efi_allocate_pages);
1872
1873        extern "efiapi" fn efi_allocate_pages(
1874            alloc_type: u32,
1875            mem_type: u32,
1876            nb_pages: usize,
1877            memory: *mut u64,
1878        ) -> efi::Status {
1879            let expected_alloc_type: efi::AllocateType = AllocType::AnyPage.into();
1880            assert_eq!(expected_alloc_type, alloc_type);
1881            let expected_mem_type: efi::MemoryType = MemoryType::MEMORY_MAPPED_IO.into();
1882            assert_eq!(expected_mem_type, mem_type);
1883            assert_eq!(4, nb_pages);
1884            assert_ne!(ptr::null_mut(), memory);
1885            assert_eq!(0, unsafe { *memory });
1886            unsafe { ptr::write(memory, 17) }
1887            efi::Status::SUCCESS
1888        }
1889
1890        let status = boot_services.allocate_pages(AllocType::AnyPage, MemoryType::MEMORY_MAPPED_IO, 4);
1891
1892        assert!(matches!(status, Ok(17)));
1893    }
1894
1895    #[test]
1896    fn test_allocate_pages_at_specific_address() {
1897        let boot_services = boot_services!(allocate_pages = efi_allocate_pages);
1898
1899        extern "efiapi" fn efi_allocate_pages(
1900            alloc_type: u32,
1901            mem_type: u32,
1902            nb_pages: usize,
1903            memory: *mut u64,
1904        ) -> efi::Status {
1905            let expected_alloc_type: efi::AllocateType = AllocType::Address(17).into();
1906            assert_eq!(expected_alloc_type, alloc_type);
1907            let expected_mem_type: efi::MemoryType = MemoryType::MEMORY_MAPPED_IO.into();
1908            assert_eq!(expected_mem_type, mem_type);
1909            assert_eq!(4, nb_pages);
1910            assert_ne!(ptr::null_mut(), memory);
1911            assert_eq!(17, unsafe { *memory });
1912            efi::Status::SUCCESS
1913        }
1914
1915        let status = boot_services.allocate_pages(AllocType::Address(17), MemoryType::MEMORY_MAPPED_IO, 4);
1916        assert!(matches!(status, Ok(17)));
1917    }
1918
1919    #[test]
1920    #[should_panic = "Boot services function free_pages is not initialized."]
1921    fn test_free_pages_not_init() {
1922        let boot_services = boot_services!();
1923        _ = boot_services.free_pages(0, 0);
1924    }
1925
1926    #[test]
1927    fn test_free_pages() {
1928        let boot_services = boot_services!(free_pages = efi_free_pages);
1929
1930        extern "efiapi" fn efi_free_pages(address: efi::PhysicalAddress, nb_pages: usize) -> efi::Status {
1931            assert_eq!(address, 0x100000);
1932            assert_eq!(nb_pages, 10);
1933
1934            efi::Status::SUCCESS
1935        }
1936
1937        let status = boot_services.free_pages(0x100000, 10);
1938        assert!(matches!(status, Ok(())));
1939    }
1940
1941    #[test]
1942    #[should_panic = "Boot services function allocate_pool is not initialized."]
1943    fn test_allocate_pool_not_init() {
1944        let boot_services = boot_services!();
1945        _ = boot_services.allocate_pool(MemoryType::RESERVED_MEMORY_TYPE, 0);
1946    }
1947
1948    #[test]
1949    fn test_allocate_pool() {
1950        let boot_services = boot_services!(allocate_pool = efi_allocate_pool);
1951
1952        extern "efiapi" fn efi_allocate_pool(
1953            mem_type: efi::MemoryType,
1954            size: usize,
1955            buffer: *mut *mut c_void,
1956        ) -> efi::Status {
1957            let expected_mem_type: efi::MemoryType = MemoryType::MEMORY_MAPPED_IO.into();
1958            assert_eq!(mem_type, expected_mem_type);
1959            assert_eq!(size, 10);
1960            unsafe { ptr::write(buffer, 0x55AA as *mut c_void) };
1961            efi::Status::SUCCESS
1962        }
1963
1964        let status = boot_services.allocate_pool(MemoryType::MEMORY_MAPPED_IO, 10);
1965        assert_eq!(status, Ok(0x55AA as *mut u8));
1966    }
1967
1968    #[test]
1969    fn test_free_pool() {
1970        let boot_services = boot_services!(free_pool = efi_free_pool);
1971
1972        extern "efiapi" fn efi_free_pool(buffer: *mut c_void) -> efi::Status {
1973            if buffer.is_null() {
1974                return efi::Status::INVALID_PARAMETER;
1975            } else {
1976                assert_eq!(buffer, 0xffff0000 as *mut u8 as *mut c_void);
1977                return efi::Status::SUCCESS;
1978            }
1979        }
1980
1981        // positive test
1982        let status = boot_services.free_pool(0xffff0000 as *mut u8);
1983        assert_eq!(status, Ok(()));
1984
1985        // negative test
1986        let status = boot_services.free_pool(ptr::null_mut());
1987        assert_eq!(status, Err(efi::Status::INVALID_PARAMETER));
1988    }
1989
1990    #[test]
1991    #[should_panic = "Boot services function install_protocol_interface is not initialized."]
1992    fn test_install_protocol_interface_not_init() {
1993        let boot_services = boot_services!();
1994        let _ = boot_services.install_protocol_interface(None, &TestProtocol, Box::new(0));
1995    }
1996
1997    #[test]
1998    fn test_install_protocol_interface() {
1999        let boot_services = boot_services!(install_protocol_interface = efi_install_protocol_interface);
2000
2001        extern "efiapi" fn efi_install_protocol_interface(
2002            handle: *mut efi::Handle,
2003            guid: *mut efi::Guid,
2004            interface_type: u32,
2005            interface: *mut c_void,
2006        ) -> efi::Status {
2007            assert_ne!(ptr::null_mut(), handle);
2008            assert_eq!(ptr::null_mut(), unsafe { ptr::read(handle) });
2009            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(guid) });
2010            assert_eq!(efi::NATIVE_INTERFACE, interface_type);
2011            assert_eq!(42, unsafe { ptr::read(interface as *mut u32) });
2012
2013            unsafe {
2014                ptr::write(handle, 17 as usize as _);
2015            }
2016
2017            efi::Status::SUCCESS
2018        }
2019
2020        let (handle, _) = boot_services.install_protocol_interface(None, &TestProtocol, Box::new(42)).unwrap();
2021
2022        assert_eq!(17, handle as usize);
2023    }
2024
2025    #[test]
2026    fn test_install_protocol_marker() {
2027        let boot_services = boot_services!(install_protocol_interface = efi_install_protocol_interface);
2028
2029        extern "efiapi" fn efi_install_protocol_interface(
2030            handle: *mut efi::Handle,
2031            guid: *mut efi::Guid,
2032            interface_type: u32,
2033            interface: *mut c_void,
2034        ) -> efi::Status {
2035            assert_ne!(ptr::null_mut(), handle);
2036            assert_eq!(ptr::null_mut(), unsafe { ptr::read(handle) });
2037            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(guid) });
2038            assert_eq!(efi::NATIVE_INTERFACE, interface_type);
2039            assert_eq!(ptr::null_mut(), interface);
2040
2041            unsafe {
2042                ptr::write(handle, 17 as usize as _);
2043            }
2044
2045            efi::Status::SUCCESS
2046        }
2047
2048        let handle = boot_services.install_protocol_marker(None, &TestProtocolMarker).unwrap();
2049
2050        assert_eq!(17, handle as usize);
2051    }
2052
2053    #[test]
2054    #[should_panic = "Marker interface are not supported by install_protocol_interface, use install_protocol_marker instead."]
2055    fn test_install_protocol_marker_with_intall_protocol_interface() {
2056        let boot_services = boot_services!(install_protocol_interface = efi_install_protocol_interface);
2057
2058        extern "efiapi" fn efi_install_protocol_interface(
2059            _handle: *mut efi::Handle,
2060            _guid: *mut efi::Guid,
2061            _interface_type: u32,
2062            _interface: *mut c_void,
2063        ) -> efi::Status {
2064            efi::Status::SUCCESS
2065        }
2066
2067        _ = boot_services.install_protocol_interface(None, &TestProtocolMarker, Box::new(())).unwrap();
2068    }
2069    #[test]
2070    #[should_panic = "Boot services function uninstall_protocol_interface is not initialized."]
2071    fn test_uninstall_protocol_interface_not_init() {
2072        let boot_services = boot_services!();
2073        let b = Box::new(10);
2074        let key = CPtr::metadata(&b);
2075        _ = boot_services.uninstall_protocol_interface(ptr::null_mut(), &TestProtocol, key);
2076    }
2077
2078    #[test]
2079    fn test_uninstall_protocol_interface() {
2080        let boot_services = boot_services!(uninstall_protocol_interface = efi_uninstall_protocol_interface);
2081
2082        static ADDR: AtomicUsize = AtomicUsize::new(0);
2083
2084        extern "efiapi" fn efi_uninstall_protocol_interface(
2085            handle: efi::Handle,
2086            protocol: *mut efi::Guid,
2087            interface: *mut c_void,
2088        ) -> efi::Status {
2089            assert_eq!(1, handle as usize);
2090            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2091            assert_eq!(ADDR.load(Ordering::Relaxed), interface as usize);
2092            efi::Status::SUCCESS
2093        }
2094        let b = Box::new(10);
2095        let key = b.metadata();
2096        ADDR.store(key.ptr_value, Ordering::Relaxed);
2097        let ptr = b.into_ptr();
2098        let interface = boot_services.uninstall_protocol_interface(1 as usize as _, &TestProtocol, key).unwrap();
2099        assert_eq!(ptr, interface.as_ptr());
2100    }
2101
2102    #[test]
2103    fn test_uninstall_protocol_marker() {
2104        let boot_services = boot_services!(uninstall_protocol_interface = efi_uninstall_protocol_interface);
2105
2106        extern "efiapi" fn efi_uninstall_protocol_interface(
2107            handle: efi::Handle,
2108            protocol: *mut efi::Guid,
2109            interface: *mut c_void,
2110        ) -> efi::Status {
2111            assert_eq!(1, handle as usize);
2112            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2113            assert_eq!(ptr::null_mut(), interface);
2114            efi::Status::SUCCESS
2115        }
2116        _ = boot_services.uninstall_protocol_marker(1 as usize as _, &TestProtocolMarker).unwrap();
2117    }
2118
2119    #[test]
2120    #[should_panic = "Boot services function reinstall_protocol_interface is not initialized."]
2121    fn test_reinstall_protocol_interface_not_init() {
2122        let boot_services = boot_services!();
2123        let b = Box::new(10);
2124        let key = CPtr::metadata(&b);
2125        _ = boot_services.reinstall_protocol_interface(ptr::null_mut(), &TestProtocol, key, Box::new(10));
2126    }
2127
2128    #[test]
2129    fn test_reinstall_protocol_interface() {
2130        let boot_services = boot_services!(reinstall_protocol_interface = efi_reinstall_protocol_interface);
2131
2132        extern "efiapi" fn efi_reinstall_protocol_interface(
2133            handle: efi::Handle,
2134            protocol: *mut efi::Guid,
2135            old_interface: *mut c_void,
2136            new_interface: *mut c_void,
2137        ) -> efi::Status {
2138            assert_eq!(1, handle as usize);
2139            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2140            assert_ne!(ptr::null_mut(), old_interface);
2141            assert_ne!(ptr::null_mut(), new_interface);
2142            efi::Status::SUCCESS
2143        }
2144
2145        let old_interface = Box::new(10);
2146        let old_key = CPtr::metadata(&old_interface);
2147        let old_ptr = old_interface.into_ptr();
2148        let new_interface = Box::new(10);
2149        let new_ptr = new_interface.as_ptr();
2150        let (new_key, old_interface) =
2151            boot_services.reinstall_protocol_interface(1 as usize as _, &TestProtocol, old_key, new_interface).unwrap();
2152        assert_eq!(new_key.ptr_value, new_ptr as usize);
2153        assert_eq!(old_ptr, old_interface.into_ptr());
2154    }
2155
2156    #[test]
2157    #[should_panic = "Boot services function register_protocol_notify is not initialized."]
2158    fn test_register_protocol_notify_not_init() {
2159        let boot_services = boot_services!();
2160        _ = boot_services.register_protocol_notify(&TEST_PROTOCOL_GUID, ptr::null_mut());
2161    }
2162
2163    #[test]
2164    fn test_register_protocol_notify() {
2165        let boot_services = boot_services!(register_protocol_notify = efi_register_protocol_notify);
2166
2167        extern "efiapi" fn efi_register_protocol_notify(
2168            protocol: *mut efi::Guid,
2169            event: *mut c_void,
2170            registration: *mut *mut c_void,
2171        ) -> efi::Status {
2172            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2173            assert_eq!(1, event as usize);
2174            assert_ne!(ptr::null_mut(), registration);
2175            unsafe { ptr::write(registration, 10 as usize as _) };
2176            efi::Status::SUCCESS
2177        }
2178
2179        let registration = boot_services.register_protocol_notify(&TEST_PROTOCOL_GUID, 1 as usize as _).unwrap();
2180        assert_eq!(10, registration.as_ptr() as usize);
2181    }
2182
2183    #[test]
2184    #[should_panic = "Boot services function locate_handle is not initialized."]
2185    fn test_locate_handle_not_init() {
2186        let boot_services = boot_services!();
2187        _ = boot_services.locate_handle(HandleSearchType::AllHandle);
2188    }
2189
2190    #[test]
2191    fn test_locate_handle_all_handles() {
2192        let boot_services = boot_services!(
2193            locate_handle = efi_locate_handle,
2194            allocate_pool = efi_allocate_pool_use_box,
2195            free_pool = efi_free_pool_use_box
2196        );
2197
2198        extern "efiapi" fn efi_locate_handle(
2199            search_type: efi::LocateSearchType,
2200            protocol: *mut efi::Guid,
2201            search_key: *mut c_void,
2202            buffer_size: *mut usize,
2203            buffer: *mut efi::Handle,
2204        ) -> efi::Status {
2205            assert_eq!(efi::ALL_HANDLES, search_type);
2206            assert_eq!(ptr::null_mut(), protocol);
2207            assert_eq!(ptr::null_mut(), search_key);
2208            assert_ne!(ptr::null_mut(), buffer_size);
2209
2210            match buffer {
2211                buffer if buffer.is_null() => {
2212                    assert_eq!(0, unsafe { ptr::read(buffer_size) });
2213                    unsafe { ptr::write(buffer_size, 1 * mem::size_of::<usize>()) };
2214                }
2215                _ => {
2216                    unsafe { ptr::write(buffer, 10 as usize as _) };
2217                }
2218            }
2219
2220            efi::Status::SUCCESS
2221        }
2222
2223        let handles = boot_services.locate_handle(HandleSearchType::AllHandle).unwrap();
2224        assert_eq!(1, handles.len());
2225        assert_eq!(10, handles[0] as usize);
2226    }
2227
2228    #[test]
2229    fn test_locate_handle_by_protocol() {
2230        let boot_services = boot_services!(
2231            locate_handle = efi_locate_handle,
2232            allocate_pool = efi_allocate_pool_use_box,
2233            free_pool = efi_free_pool_use_box
2234        );
2235
2236        extern "efiapi" fn efi_locate_handle(
2237            search_type: efi::LocateSearchType,
2238            protocol: *mut efi::Guid,
2239            search_key: *mut c_void,
2240            buffer_size: *mut usize,
2241            buffer: *mut efi::Handle,
2242        ) -> efi::Status {
2243            assert_eq!(efi::BY_PROTOCOL, search_type);
2244            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2245            assert_eq!(ptr::null_mut(), search_key);
2246            assert_ne!(ptr::null_mut(), buffer_size);
2247
2248            match buffer {
2249                buffer if buffer.is_null() => {
2250                    assert_eq!(0, unsafe { ptr::read(buffer_size) });
2251                    unsafe { ptr::write(buffer_size, 1 * mem::size_of::<usize>()) };
2252                }
2253                _ => {
2254                    unsafe { ptr::write(buffer, 10 as usize as _) };
2255                }
2256            }
2257
2258            efi::Status::SUCCESS
2259        }
2260
2261        let handles = boot_services.locate_handle(HandleSearchType::ByProtocol(&TestProtocol)).unwrap();
2262        assert_eq!(1, handles.len());
2263        assert_eq!(10, handles[0] as usize);
2264    }
2265
2266    #[test]
2267    fn test_locate_handle_by_registry_notify() {
2268        let boot_services = boot_services!(
2269            locate_handle = efi_locate_handle,
2270            allocate_pool = efi_allocate_pool_use_box,
2271            free_pool = efi_free_pool_use_box
2272        );
2273
2274        extern "efiapi" fn efi_locate_handle(
2275            search_type: efi::LocateSearchType,
2276            protocol: *mut efi::Guid,
2277            search_key: *mut c_void,
2278            buffer_size: *mut usize,
2279            buffer: *mut efi::Handle,
2280        ) -> efi::Status {
2281            assert_eq!(efi::BY_REGISTER_NOTIFY, search_type);
2282            assert_eq!(ptr::null_mut(), protocol);
2283            assert_eq!(10, search_key as usize);
2284            assert_ne!(ptr::null_mut(), buffer_size);
2285
2286            match buffer {
2287                buffer if buffer.is_null() => {
2288                    assert_eq!(0, unsafe { ptr::read(buffer_size) });
2289                    unsafe { ptr::write(buffer_size, 1 * mem::size_of::<usize>()) };
2290                }
2291                _ => {
2292                    unsafe { ptr::write(buffer, 10 as usize as _) };
2293                }
2294            }
2295
2296            efi::Status::SUCCESS
2297        }
2298
2299        let handles = boot_services
2300            .locate_handle(HandleSearchType::ByRegisterNotify(unsafe { NonNull::new_unchecked(10 as usize as _) }))
2301            .unwrap();
2302        assert_eq!(1, handles.len());
2303        assert_eq!(10, handles[0] as usize);
2304    }
2305
2306    #[test]
2307    #[should_panic = "Boot services function handle_protocol is not initialized."]
2308    fn test_handle_protocol_not_init() {
2309        let boot_services = boot_services!();
2310        _ = unsafe { boot_services.handle_protocol(ptr::null_mut(), &TestProtocol) };
2311    }
2312
2313    #[test]
2314    fn test_handle_protocol() {
2315        let boot_services = boot_services!(handle_protocol = efi_handle_protocol);
2316
2317        extern "efiapi" fn efi_handle_protocol(
2318            handle: *mut c_void,
2319            protocol: *mut efi::Guid,
2320            interface: *mut *mut c_void,
2321        ) -> efi::Status {
2322            assert_eq!(1, handle as usize);
2323            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2324            assert_ne!(ptr::null_mut(), interface);
2325            let b = Box::new(12);
2326            unsafe { ptr::write(interface, b.into_mut_ptr() as *mut _) };
2327            efi::Status::SUCCESS
2328        }
2329
2330        let interface = unsafe { boot_services.handle_protocol(1 as usize as _, &TestProtocol) }.unwrap();
2331        assert_eq!(12, *interface);
2332    }
2333
2334    #[test]
2335    fn test_handle_protocol_marker() {
2336        let boot_services = boot_services!(handle_protocol = efi_handle_protocol);
2337
2338        extern "efiapi" fn efi_handle_protocol(
2339            handle: *mut c_void,
2340            protocol: *mut efi::Guid,
2341            interface: *mut *mut c_void,
2342        ) -> efi::Status {
2343            assert_eq!(1, handle as usize);
2344            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2345            assert_ne!(ptr::null_mut(), interface);
2346            efi::Status::SUCCESS
2347        }
2348
2349        boot_services.handle_protocol_marker(1 as usize as _, &TestProtocolMarker).unwrap();
2350    }
2351
2352    #[test]
2353    #[should_panic = "Marker interface are not supported with handle_protocol function, use handle_protocol_marker instead."]
2354    fn test_handle_protocol_with_marker_interface() {
2355        let boot_services = boot_services!(handle_protocol = efi_handle_protocol);
2356
2357        extern "efiapi" fn efi_handle_protocol(
2358            _handle: *mut c_void,
2359            _protocol: *mut efi::Guid,
2360            _interface: *mut *mut c_void,
2361        ) -> efi::Status {
2362            efi::Status::SUCCESS
2363        }
2364
2365        _ = unsafe { boot_services.handle_protocol(1 as usize as _, &TestProtocolMarker) };
2366    }
2367
2368    #[test]
2369    #[should_panic = "Boot services function locate_device_path is not initialized."]
2370    fn test_locate_device_path_not_init() {
2371        let boot_services = boot_services!();
2372        _ = unsafe { boot_services.locate_device_path(&TestProtocol, ptr::null_mut()) };
2373    }
2374
2375    #[test]
2376    fn test_locate_device_path() {
2377        let boot_services = boot_services!(locate_device_path = efi_locate_device_path);
2378
2379        extern "efiapi" fn efi_locate_device_path(
2380            protocol: *mut efi::Guid,
2381            device_path: *mut *mut device_path::Protocol,
2382            device: *mut efi::Handle,
2383        ) -> efi::Status {
2384            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2385            assert_eq!(1, device_path as usize);
2386            assert_ne!(ptr::null_mut(), device);
2387            unsafe { ptr::write(device, 12 as usize as _) };
2388            efi::Status::SUCCESS
2389        }
2390
2391        let handle = unsafe { boot_services.locate_device_path(&TestProtocol, 1 as usize as _) }.unwrap();
2392        assert_eq!(12, handle as usize);
2393    }
2394
2395    #[test]
2396    #[should_panic = "Boot services function open_protocol is not initialized."]
2397    fn test_open_protocol_not_init() {
2398        let boot_services = boot_services!();
2399        _ = unsafe { boot_services.open_protocol(ptr::null_mut(), &TestProtocol, ptr::null_mut(), ptr::null_mut(), 0) };
2400    }
2401
2402    #[test]
2403    fn test_open_protocol() {
2404        let boot_services = boot_services!(open_protocol = efi_open_protocol);
2405
2406        extern "efiapi" fn efi_open_protocol(
2407            handle: efi::Handle,
2408            protocol: *mut efi::Guid,
2409            interface: *mut *mut c_void,
2410            agent_handle: efi::Handle,
2411            controller_handle: efi::Handle,
2412            attributes: u32,
2413        ) -> efi::Status {
2414            assert_eq!(1, handle as usize);
2415            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2416            assert_ne!(ptr::null_mut(), interface);
2417            assert_eq!(2, agent_handle as usize);
2418            assert_eq!(3, controller_handle as usize);
2419            assert_eq!(4, attributes);
2420
2421            let b = Box::new(12);
2422            unsafe { ptr::write(interface, b.into_mut_ptr() as _) };
2423
2424            efi::Status::SUCCESS
2425        }
2426
2427        let interface = unsafe {
2428            boot_services.open_protocol(1 as usize as _, &TestProtocol, 2 as usize as _, 3 as usize as _, 4).unwrap()
2429        };
2430        assert_eq!(12, *interface)
2431    }
2432
2433    #[test]
2434    fn test_open_protocol_marker() {
2435        let boot_services = boot_services!(open_protocol = efi_open_protocol);
2436
2437        extern "efiapi" fn efi_open_protocol(
2438            handle: efi::Handle,
2439            protocol: *mut efi::Guid,
2440            interface: *mut *mut c_void,
2441            agent_handle: efi::Handle,
2442            controller_handle: efi::Handle,
2443            attributes: u32,
2444        ) -> efi::Status {
2445            assert_eq!(1, handle as usize);
2446            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2447            assert_ne!(ptr::null_mut(), interface);
2448            assert_eq!(2, agent_handle as usize);
2449            assert_eq!(3, controller_handle as usize);
2450            assert_eq!(4, attributes);
2451            efi::Status::SUCCESS
2452        }
2453
2454        boot_services
2455            .open_protocol_marker(1 as usize as _, &TestProtocolMarker, 2 as usize as _, 3 as usize as _, 4)
2456            .unwrap()
2457    }
2458
2459    #[test]
2460    #[should_panic = "Marker interface are not supported with open_protocol function, use open_protocol_marker instead."]
2461    fn test_open_protocol_with_marker_interface() {
2462        let boot_services = boot_services!(open_protocol = efi_open_protocol);
2463
2464        extern "efiapi" fn efi_open_protocol(
2465            _handle: efi::Handle,
2466            _protocol: *mut efi::Guid,
2467            _interface: *mut *mut c_void,
2468            _agent_handle: efi::Handle,
2469            _controller_handle: efi::Handle,
2470            _attributes: u32,
2471        ) -> efi::Status {
2472            efi::Status::SUCCESS
2473        }
2474
2475        let _ = unsafe {
2476            boot_services.open_protocol(1 as usize as _, &TestProtocolMarker, 2 as usize as _, 3 as usize as _, 4)
2477        };
2478    }
2479
2480    #[test]
2481    #[should_panic = "Boot services function close_protocol is not initialized."]
2482    fn test_close_protocol_not_init() {
2483        let boot_services = boot_services!();
2484        _ = boot_services.close_protocol(ptr::null_mut(), &TestProtocol, ptr::null_mut(), ptr::null_mut());
2485    }
2486
2487    #[test]
2488    fn test_close_protocol() {
2489        let boot_services = boot_services!(close_protocol = efi_close_protocol);
2490
2491        extern "efiapi" fn efi_close_protocol(
2492            handle: efi::Handle,
2493            protocol: *mut efi::Guid,
2494            agent_handle: efi::Handle,
2495            controller_handle: efi::Handle,
2496        ) -> efi::Status {
2497            assert_eq!(1, handle as usize);
2498            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2499            assert_eq!(2, agent_handle as usize);
2500            assert_eq!(3, controller_handle as usize);
2501
2502            efi::Status::SUCCESS
2503        }
2504
2505        _ = boot_services.close_protocol(1 as usize as _, &TestProtocol, 2 as usize as _, 3 as usize as _).unwrap();
2506    }
2507
2508    #[test]
2509    #[should_panic = "Boot services function open_protocol_information is not initialized."]
2510    fn test_open_protocol_information_not_init() {
2511        let boot_services = boot_services!();
2512        _ = boot_services.open_protocol_information(ptr::null_mut(), &TestProtocol);
2513    }
2514
2515    #[test]
2516    fn test_open_protocol_information() {
2517        let boot_services = boot_services!(
2518            open_protocol_information = efi_open_protocol_information,
2519            free_pool = efi_free_pool_use_box
2520        );
2521
2522        extern "efiapi" fn efi_open_protocol_information(
2523            handle: efi::Handle,
2524            protocol: *mut efi::Guid,
2525            entry_buffer: *mut *mut efi::OpenProtocolInformationEntry,
2526            entry_count: *mut usize,
2527        ) -> efi::Status {
2528            assert_eq!(1, handle as usize);
2529            assert_eq!(TEST_PROTOCOL_GUID, unsafe { ptr::read(protocol) });
2530            assert_ne!(ptr::null_mut(), entry_buffer);
2531            assert_ne!(ptr::null_mut(), entry_count);
2532
2533            let buff = Box::new([efi::OpenProtocolInformationEntry {
2534                agent_handle: ptr::null_mut(),
2535                controller_handle: ptr::null_mut(),
2536                attributes: 10,
2537                open_count: 0,
2538            }])
2539            .into_mut_ptr() as *mut OpenProtocolInformationEntry;
2540
2541            unsafe {
2542                ptr::write(entry_buffer, buff);
2543                ptr::write(entry_count, 1)
2544            };
2545
2546            efi::Status::SUCCESS
2547        }
2548
2549        let info = boot_services.open_protocol_information(1 as usize as _, &TestProtocol).unwrap();
2550        assert_eq!(1, info.len());
2551        assert_eq!(10, info[0].attributes);
2552    }
2553
2554    #[test]
2555    #[should_panic = "Boot services function connect_controller is not initialized."]
2556    fn test_connect_controller_not_init() {
2557        let boot_services = boot_services!();
2558        _ = unsafe { boot_services.connect_controller(ptr::null_mut(), vec![], ptr::null_mut(), false) };
2559    }
2560
2561    #[test]
2562    fn test_connect_controller() {
2563        let boot_services = boot_services!(connect_controller = efi_connect_controller);
2564
2565        extern "efiapi" fn efi_connect_controller(
2566            controller_handle: efi::Handle,
2567            driver_image_handles: *mut efi::Handle,
2568            remaining_device_path: *mut device_path::Protocol,
2569            recursive: Boolean,
2570        ) -> efi::Status {
2571            assert_eq!(1, controller_handle as usize);
2572            assert_eq!(ptr::null_mut(), driver_image_handles);
2573            assert_eq!(2, remaining_device_path as usize);
2574            assert_eq!(false, recursive.into());
2575            efi::Status::SUCCESS
2576        }
2577
2578        _ = unsafe { boot_services.connect_controller(1 as usize as _, vec![], 2 as usize as _, false) }.unwrap();
2579    }
2580
2581    #[test]
2582    fn test_connect_controller_with_image_handles() {
2583        let boot_services = boot_services!(connect_controller = efi_connect_controller);
2584
2585        extern "efiapi" fn efi_connect_controller(
2586            controller_handle: efi::Handle,
2587            driver_image_handles: *mut efi::Handle,
2588            remaining_device_path: *mut device_path::Protocol,
2589            recursive: Boolean,
2590        ) -> efi::Status {
2591            assert_eq!(1, controller_handle as usize);
2592            assert_ne!(ptr::null_mut(), driver_image_handles);
2593            let image_handles = unsafe { slice::from_raw_parts(driver_image_handles as *const usize, 3) };
2594            assert_eq!([1, 2, 0], image_handles);
2595            assert_eq!(2, remaining_device_path as usize);
2596            assert_eq!(false, recursive.into());
2597            efi::Status::SUCCESS
2598        }
2599
2600        _ = unsafe {
2601            boot_services.connect_controller(
2602                1 as usize as _,
2603                vec![1 as usize as _, 2 as usize as _],
2604                2 as usize as _,
2605                false,
2606            )
2607        }
2608        .unwrap();
2609    }
2610
2611    #[test]
2612    #[should_panic = "Boot services function disconnect_controller is not initialized."]
2613    fn test_disconnect_controller_not_init() {
2614        let boot_services = boot_services!();
2615        _ = boot_services.disconnect_controller(ptr::null_mut(), None, None);
2616    }
2617
2618    #[test]
2619    fn test_disconnect_controller() {
2620        let boot_services = boot_services!(disconnect_controller = efi_disconnect_controller);
2621
2622        extern "efiapi" fn efi_disconnect_controller(
2623            controller_handle: efi::Handle,
2624            driver_image_handle: efi::Handle,
2625            child_handle: efi::Handle,
2626        ) -> efi::Status {
2627            assert_eq!(1, controller_handle as usize);
2628            assert_eq!(ptr::null_mut(), driver_image_handle);
2629            assert_eq!(ptr::null_mut(), child_handle);
2630            efi::Status::SUCCESS
2631        }
2632        _ = boot_services.disconnect_controller(1 as usize as _, None, None).unwrap();
2633    }
2634
2635    #[test]
2636    fn test_disconnect_controller_with_handles() {
2637        let boot_services = boot_services!(disconnect_controller = efi_disconnect_controller);
2638
2639        extern "efiapi" fn efi_disconnect_controller(
2640            controller_handle: efi::Handle,
2641            driver_image_handle: efi::Handle,
2642            child_handle: efi::Handle,
2643        ) -> efi::Status {
2644            assert_eq!(1, controller_handle as usize);
2645            assert_eq!(2, driver_image_handle as usize);
2646            assert_eq!(3, child_handle as usize);
2647            efi::Status::SUCCESS
2648        }
2649        _ = boot_services.disconnect_controller(1 as usize as _, Some(2 as usize as _), Some(3 as usize as _)).unwrap();
2650    }
2651
2652    #[test]
2653    #[should_panic = "Boot services function protocols_per_handle is not initialized."]
2654    fn test_protocol_per_handle_not_init() {
2655        let boot_services = boot_services!();
2656        _ = boot_services.protocols_per_handle(ptr::null_mut());
2657    }
2658
2659    #[test]
2660    fn test_protocol_per_handle() {
2661        let boot_services =
2662            boot_services!(protocols_per_handle = efi_protocol_per_handle, free_pool = efi_free_pool_use_box);
2663
2664        extern "efiapi" fn efi_protocol_per_handle(
2665            handle: efi::Handle,
2666            protocol_buffer: *mut *mut *mut efi::Guid,
2667            protocol_buffer_count: *mut usize,
2668        ) -> efi::Status {
2669            assert_eq!(1, handle as usize);
2670            assert_ne!(ptr::null_mut(), protocol_buffer);
2671            assert_ne!(ptr::null_mut(), protocol_buffer_count);
2672
2673            #[allow(unused_allocation)]
2674            let buff = Box::new(ptr::addr_of!(TEST_PROTOCOL_GUID) as *mut efi::Guid).into_mut_ptr();
2675
2676            unsafe {
2677                ptr::write(protocol_buffer, buff);
2678                ptr::write(protocol_buffer_count, 1);
2679            }
2680
2681            efi::Status::SUCCESS
2682        }
2683
2684        let protocols = boot_services.protocols_per_handle(1 as usize as _).unwrap();
2685        assert_eq!(1, protocols.len());
2686        assert_eq!(TEST_PROTOCOL_GUID, *protocols[0]);
2687    }
2688
2689    #[test]
2690    #[should_panic = "Boot services function locate_protocol is not initialized."]
2691    fn test_locate_protocol_not_init() {
2692        let boot_services = boot_services!();
2693        _ = unsafe { boot_services.locate_protocol(&TestProtocol, None) };
2694    }
2695
2696    #[test]
2697    fn test_locate_protocol() {
2698        let boot_services = boot_services!(locate_protocol = efi_locate_protocol);
2699
2700        static PROTOCOL_INTERFACE: u32 = 10;
2701
2702        extern "efiapi" fn efi_locate_protocol(
2703            protocol_guid: *mut efi::Guid,
2704            registration: *mut c_void,
2705            interface: *mut *mut c_void,
2706        ) -> efi::Status {
2707            assert!(!protocol_guid.is_null());
2708            assert!(registration.is_null());
2709            assert!(!interface.is_null());
2710            assert_eq!(unsafe { ptr::read(protocol_guid) }, TEST_PROTOCOL_GUID);
2711            unsafe { ptr::write(interface, &PROTOCOL_INTERFACE as *const u32 as *mut u32 as *mut c_void) };
2712            efi::Status::SUCCESS
2713        }
2714
2715        let protocol = unsafe { boot_services.locate_protocol(&TestProtocol, None) }.unwrap();
2716        assert_eq!(PROTOCOL_INTERFACE, *protocol);
2717    }
2718
2719    #[test]
2720    fn test_locate_protocol_marker() {
2721        let boot_services = boot_services!(locate_protocol = efi_locate_protocol);
2722
2723        extern "efiapi" fn efi_locate_protocol(
2724            protocol_guid: *mut efi::Guid,
2725            registration: *mut c_void,
2726            interface: *mut *mut c_void,
2727        ) -> efi::Status {
2728            assert!(!protocol_guid.is_null());
2729            assert!(registration.is_null());
2730            assert!(!interface.is_null());
2731            assert_eq!(unsafe { ptr::read(protocol_guid) }, TEST_PROTOCOL_GUID);
2732            efi::Status::SUCCESS
2733        }
2734
2735        boot_services.locate_protocol_marker(&TestProtocolMarker, None).unwrap();
2736    }
2737
2738    #[test]
2739    #[should_panic = "Marker interface are not supported by locate_protocol, use locate_protocol_marker instead."]
2740    fn test_locate_protocol_marker_with_locate_protocol() {
2741        let boot_services = boot_services!(locate_protocol = efi_locate_protocol);
2742
2743        extern "efiapi" fn efi_locate_protocol(
2744            _protocol_guid: *mut efi::Guid,
2745            _registration: *mut c_void,
2746            _interface: *mut *mut c_void,
2747        ) -> efi::Status {
2748            efi::Status::SUCCESS
2749        }
2750
2751        unsafe { boot_services.locate_protocol(&TestProtocolMarker, None) }.unwrap();
2752    }
2753
2754    #[test]
2755    #[should_panic = "Boot services function load_image is not initialized."]
2756    fn test_load_image_not_init() {
2757        let boot_services = boot_services!();
2758        _ = boot_services.load_image(false, ptr::null_mut(), ptr::null_mut(), None);
2759    }
2760
2761    #[test]
2762    fn test_load_image() {
2763        let boot_services = boot_services!(load_image = efi_load_image);
2764
2765        extern "efiapi" fn efi_load_image(
2766            boot_policy: Boolean,
2767            parent_image_handler: *mut c_void,
2768            device_path: *mut device_path::Protocol,
2769            source_buffer: *mut c_void,
2770            source_size: usize,
2771            image_handler: *mut *mut c_void,
2772        ) -> efi::Status {
2773            assert_eq!(true, boot_policy.into());
2774            assert_eq!(1, parent_image_handler as usize);
2775            assert_eq!(2, device_path as usize);
2776            assert_eq!(5, source_size);
2777            let source = unsafe { slice::from_raw_parts(source_buffer as *mut u8, source_size) };
2778            assert_eq!(&[1_u8, 2, 3, 4, 5], source);
2779            unsafe {
2780                ptr::write(image_handler, 3 as usize as _);
2781            }
2782            efi::Status::SUCCESS
2783        }
2784
2785        let image_handle = boot_services
2786            .load_image(
2787                true,
2788                1 as usize as *mut c_void,
2789                2 as usize as *mut device_path::Protocol,
2790                Some(&[1_u8, 2, 3, 4, 5]),
2791            )
2792            .unwrap();
2793
2794        assert_eq!(3, image_handle as usize);
2795    }
2796
2797    #[test]
2798    fn test_load_image_from_source() {
2799        let boot_services = boot_services!(load_image = efi_load_image);
2800
2801        extern "efiapi" fn efi_load_image(
2802            boot_policy: Boolean,
2803            parent_image_handler: *mut c_void,
2804            device_path: *mut device_path::Protocol,
2805            source_buffer: *mut c_void,
2806            source_size: usize,
2807            _image_handler: *mut *mut c_void,
2808        ) -> efi::Status {
2809            assert_eq!(false, boot_policy.into());
2810            assert_eq!(1, parent_image_handler as usize);
2811            assert_eq!(2, device_path as usize);
2812            assert_eq!(5, source_size);
2813            let source = unsafe { slice::from_raw_parts(source_buffer as *mut u8, source_size) };
2814            assert_eq!(&[1_u8, 2, 3, 4, 5], source);
2815            efi::Status::SUCCESS
2816        }
2817
2818        _ = boot_services.load_image_from_source(1 as usize as _, 2 as usize as _, &[1_u8, 2, 3, 4, 5])
2819    }
2820
2821    #[test]
2822    fn test_load_image_from_file() {
2823        let boot_services = boot_services!(load_image = efi_load_image);
2824
2825        extern "efiapi" fn efi_load_image(
2826            boot_policy: Boolean,
2827            parent_image_handler: *mut c_void,
2828            device_path: *mut device_path::Protocol,
2829            source_buffer: *mut c_void,
2830            source_size: usize,
2831            _image_handler: *mut *mut c_void,
2832        ) -> efi::Status {
2833            assert_eq!(false, boot_policy.into());
2834            assert_eq!(1, parent_image_handler as usize);
2835            assert_eq!(2, device_path as usize);
2836            assert_eq!(ptr::null_mut(), source_buffer);
2837            assert_eq!(0, source_size);
2838            efi::Status::SUCCESS
2839        }
2840
2841        _ = boot_services.load_image_from_file(1 as usize as _, NonNull::new(2 as usize as _).unwrap());
2842    }
2843
2844    #[test]
2845    #[should_panic = "Boot services function start_image is not initialized."]
2846    fn test_start_image_not_init() {
2847        let boot_services = boot_services!();
2848        _ = boot_services.start_image(ptr::null_mut());
2849    }
2850
2851    #[test]
2852    fn test_start_image() {
2853        let boot_services = boot_services!(start_image = efi_start_image);
2854
2855        extern "efiapi" fn efi_start_image(
2856            image_handle: efi::Handle,
2857            exit_data_size: *mut usize,
2858            exit_data: *mut *mut Char16,
2859        ) -> efi::Status {
2860            assert_eq!(1, image_handle as usize);
2861            assert_ne!(ptr::null_mut(), exit_data_size);
2862            assert_ne!(ptr::null_mut(), exit_data);
2863            efi::Status::SUCCESS
2864        }
2865
2866        _ = boot_services.start_image(1 as usize as _).unwrap();
2867    }
2868
2869    #[test]
2870    #[should_panic = "Boot services function unload_image is not initialized."]
2871    fn test_unload_image_not_init() {
2872        let boot_services = boot_services!();
2873        _ = boot_services.unload_image(ptr::null_mut());
2874    }
2875
2876    #[test]
2877    fn test_unload_image() {
2878        let boot_services = boot_services!(unload_image = efi_unload_image);
2879
2880        extern "efiapi" fn efi_unload_image(image_handle: efi::Handle) -> efi::Status {
2881            assert_eq!(1, image_handle as usize);
2882            efi::Status::SUCCESS
2883        }
2884
2885        _ = boot_services.unload_image(1 as usize as _);
2886    }
2887
2888    #[test]
2889    #[should_panic = "Boot services function exit is not initialized."]
2890    fn test_exit_not_init() {
2891        let boot_services = boot_services!();
2892        _ = boot_services.exit(ptr::null_mut(), efi::Status::SUCCESS, None);
2893    }
2894
2895    #[test]
2896    fn test_exit() {
2897        let boot_services = boot_services!(exit = efi_exit);
2898
2899        extern "efiapi" fn efi_exit(
2900            image_handle: efi::Handle,
2901            exit_status: efi::Status,
2902            exit_data_size: usize,
2903            exit_data: *mut u16,
2904        ) -> efi::Status {
2905            assert_eq!(1, image_handle as usize);
2906            assert_eq!(efi::Status::SUCCESS, exit_status);
2907            assert_eq!(0, exit_data_size);
2908            assert_eq!(ptr::null_mut(), exit_data);
2909            efi::Status::SUCCESS
2910        }
2911
2912        _ = boot_services.exit(1 as usize as _, efi::Status::SUCCESS, None).unwrap();
2913    }
2914
2915    #[test]
2916    #[should_panic = "Boot services function exit_boot_services is not initialized."]
2917    fn test_exit_boot_services_not_init() {
2918        let boot_services = boot_services!();
2919        _ = boot_services.exit_boot_services(ptr::null_mut(), 0);
2920    }
2921
2922    #[test]
2923    fn test_exit_boot_services() {
2924        let boot_services = boot_services!(exit_boot_services = efi_exit_boot_services);
2925
2926        extern "efiapi" fn efi_exit_boot_services(image_handle: efi::Handle, map_key: usize) -> efi::Status {
2927            assert_eq!(1, image_handle as usize);
2928            assert_eq!(2, map_key);
2929            efi::Status::SUCCESS
2930        }
2931
2932        _ = boot_services.exit_boot_services(1 as usize as _, 2).unwrap();
2933    }
2934
2935    #[test]
2936    fn test_get_memory_map() {
2937        let boot_services = boot_services!(
2938            get_memory_map = efi_get_memory_map,
2939            allocate_pool = efi_allocate_pool_use_box,
2940            free_pool = efi_free_pool_use_box
2941        );
2942
2943        extern "efiapi" fn efi_get_memory_map(
2944            memory_map_size: *mut usize,
2945            memory_map: *mut efi::MemoryDescriptor,
2946            _map_key: *mut usize,
2947            descriptor_size: *mut usize,
2948            descriptor_version: *mut u32,
2949        ) -> efi::Status {
2950            if memory_map_size.is_null() {
2951                return efi::Status::INVALID_PARAMETER;
2952            }
2953
2954            let memory_map_size_value = unsafe { *memory_map_size };
2955            if memory_map_size_value == 0 {
2956                unsafe { ptr::write(memory_map_size, 0x400) };
2957                return efi::Status::BUFFER_TOO_SMALL;
2958            }
2959
2960            unsafe {
2961                (*memory_map).physical_start = 0xffffffffaaaabbbb;
2962                *descriptor_size = mem::size_of::<efi::MemoryDescriptor>();
2963                *descriptor_version = 1;
2964            }
2965            efi::Status::SUCCESS
2966        }
2967
2968        let status = boot_services.get_memory_map();
2969
2970        match status {
2971            Ok(memory_map) => {
2972                assert_eq!(memory_map.map_key, 0);
2973                assert_eq!(memory_map.descriptor_version, 1);
2974                assert_eq!(memory_map.descriptors[0].physical_start, 0xffffffffaaaabbbb);
2975            }
2976            Err((status, _)) => {
2977                assert!(false, "Error: {:?}", status);
2978            }
2979        }
2980    }
2981
2982    #[test]
2983    #[should_panic = "Boot services function set_watchdog_timer is not initialized."]
2984    fn test_set_watchdog_timer_not_init() {
2985        let boot_services = boot_services!();
2986        _ = boot_services.set_watchdog_timer(0)
2987    }
2988
2989    #[test]
2990    fn test_set_watchdog_timer() {
2991        let boot_services = boot_services!(set_watchdog_timer = efi_set_watchdog_timer);
2992
2993        extern "efiapi" fn efi_set_watchdog_timer(
2994            timeout: usize,
2995            watchdog_code: u64,
2996            data_size: usize,
2997            watchdog_data: *mut u16,
2998        ) -> efi::Status {
2999            assert_eq!(10, timeout);
3000            assert_eq!(0, watchdog_code);
3001            assert_eq!(0, data_size);
3002            assert_eq!(ptr::null_mut(), watchdog_data);
3003            efi::Status::SUCCESS
3004        }
3005
3006        boot_services.set_watchdog_timer(10).unwrap();
3007    }
3008
3009    #[test]
3010    #[should_panic = "Boot services function stall is not initialized."]
3011    fn test_stall_not_init() {
3012        let boot_services = boot_services!();
3013        _ = boot_services.stall(0);
3014    }
3015
3016    #[test]
3017    fn test_stall() {
3018        let boot_services = boot_services!(stall = efi_stall);
3019        extern "efiapi" fn efi_stall(microsecondes: usize) -> efi::Status {
3020            assert_eq!(10, microsecondes);
3021            efi::Status::SUCCESS
3022        }
3023        let status = boot_services.stall(10);
3024        assert_eq!(Ok(()), status);
3025    }
3026
3027    #[test]
3028    #[should_panic = "Boot services function copy_mem is not initialized."]
3029    fn test_copy_mem_not_init() {
3030        let boot_services = boot_services!();
3031        let mut dest = 0;
3032        let src = 0;
3033        boot_services.copy_mem(&mut dest, &src);
3034    }
3035
3036    #[test]
3037    #[allow(static_mut_refs)]
3038    fn test_copy_mem() {
3039        let boot_services = boot_services!(copy_mem = efi_copy_mem);
3040
3041        static A: [i32; 5] = [1, 2, 3, 4, 5];
3042        static mut B: [i32; 5] = [0; 5];
3043
3044        extern "efiapi" fn efi_copy_mem(dest: *mut c_void, src: *mut c_void, length: usize) {
3045            assert_eq!(unsafe { ptr::addr_of!(B) } as usize, dest as usize);
3046            assert_eq!(ptr::addr_of!(A) as usize, src as usize);
3047            assert_eq!(5 * mem::size_of::<i32>(), length);
3048        }
3049        boot_services.copy_mem(unsafe { &mut B }, &A);
3050    }
3051
3052    #[test]
3053    #[should_panic = "Boot services function set_mem is not initialized."]
3054    fn test_set_mem_not_init() {
3055        let boot_services = boot_services!();
3056        _ = boot_services.set_mem(&mut [0], 0);
3057    }
3058
3059    #[test]
3060    #[allow(static_mut_refs)]
3061    fn test_set_mem() {
3062        let boot_services = boot_services!(set_mem = efi_set_mem);
3063
3064        static mut BUFFER: [u8; 16] = [0; 16];
3065
3066        extern "efiapi" fn efi_set_mem(buffer: *mut c_void, size: usize, value: u8) {
3067            assert_eq!(unsafe { ptr::addr_of!(BUFFER) } as usize, buffer as usize);
3068            assert_eq!(16, size);
3069            assert_eq!(8, value);
3070        }
3071        _ = boot_services.set_mem(unsafe { &mut BUFFER }, 8);
3072    }
3073
3074    #[test]
3075    #[should_panic = "Boot services function get_next_monotonic_count is not initialized."]
3076    fn test_get_next_monotonic_count_not_init() {
3077        let boot_services = boot_services!();
3078        _ = boot_services.get_next_monotonic_count();
3079    }
3080
3081    #[test]
3082    fn test_get_next_monotonic_count() {
3083        let boot_services = boot_services!(get_next_monotonic_count = efi_get_next_monotonic_count);
3084        extern "efiapi" fn efi_get_next_monotonic_count(count: *mut u64) -> efi::Status {
3085            unsafe { ptr::write(count, 89) };
3086            efi::Status::SUCCESS
3087        }
3088        let status = boot_services.get_next_monotonic_count().unwrap();
3089        assert_eq!(89, status);
3090    }
3091
3092    #[test]
3093    #[should_panic = "Boot services function install_configuration_table is not initialized."]
3094    fn test_install_configuration_table_not_init() {
3095        let boot_services = boot_services!();
3096        let table = Box::new(());
3097        _ = boot_services.install_configuration_table(&efi::Guid::from_bytes(&[0; 16]), table);
3098    }
3099
3100    #[test]
3101    fn test_install_configuration_table() {
3102        let boot_services = boot_services!(install_configuration_table = efi_install_configuration_table);
3103
3104        static GUID: efi::Guid = efi::Guid::from_bytes(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
3105        static mut TABLE: i32 = 10;
3106
3107        extern "efiapi" fn efi_install_configuration_table(guid: *mut efi::Guid, table: *mut c_void) -> efi::Status {
3108            assert_eq!(ptr::addr_of!(GUID) as usize, guid as usize);
3109            assert_eq!(unsafe { ptr::addr_of!(TABLE) } as usize, table as usize);
3110            assert_eq!(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], unsafe { ptr::read(guid) }.as_bytes());
3111            assert_eq!(10, unsafe { ptr::read(table as *mut i32) });
3112            efi::Status::SUCCESS
3113        }
3114
3115        #[allow(static_mut_refs)]
3116        boot_services.install_configuration_table(&GUID, unsafe { &mut TABLE }).unwrap();
3117    }
3118
3119    #[test]
3120    #[should_panic = "Boot services function calculate_crc32 is not initialized."]
3121    fn test_calculate_crc32_not_init() {
3122        let boot_services = boot_services!();
3123        _ = boot_services.calculate_crc_32(&[0]);
3124    }
3125
3126    #[test]
3127    fn test_calculate_crc32() {
3128        let boot_services = boot_services!(calculate_crc32 = efi_calculate_crc32);
3129
3130        static BUFFER: [u8; 16] = [0; 16];
3131
3132        extern "efiapi" fn efi_calculate_crc32(
3133            buffer_ptr: *mut c_void,
3134            buffer_size: usize,
3135            crc: *mut u32,
3136        ) -> efi::Status {
3137            unsafe {
3138                assert_eq!(ptr::addr_of!(BUFFER) as usize, buffer_ptr as usize);
3139                assert_eq!(BUFFER.len(), buffer_size);
3140                ptr::write(crc, 10)
3141            }
3142            efi::Status::SUCCESS
3143        }
3144
3145        let crc = boot_services.calculate_crc_32(&BUFFER).unwrap();
3146        assert_eq!(10, crc);
3147    }
3148}