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#[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 pub const fn new(efi_boot_services: &'a efi::BootServices) -> Self {
49 Self {
51 efi_boot_services: AtomicPtr::new(efi_boot_services as *const _ as *mut _),
52 _lifetime_marker: PhantomData,
53 }
54 }
55
56 pub const fn new_uninit() -> Self {
59 Self { efi_boot_services: AtomicPtr::new(ptr::null_mut()), _lifetime_marker: PhantomData }
60 }
61
62 pub fn initialize(&'a self, efi_boot_services: &'a efi::BootServices) {
66 if self.efi_boot_services.load(Ordering::Relaxed).is_null() {
67 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 fn efi_boot_services(&self) -> &efi::BootServices {
77 unsafe {
79 self.efi_boot_services.load(Ordering::SeqCst).as_ref::<'a>().expect("Boot services is not initialize.")
80 }
81 }
82}
83
84unsafe impl Sync for StandardBootServices<'static> {}
86unsafe impl Send for StandardBootServices<'static> {}
88
89#[cfg_attr(any(test, feature = "mockall"), automock)]
91pub trait BootServices {
92 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 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 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 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 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 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 fn close_event(&self, event: efi::Event) -> Result<(), efi::Status>;
182
183 fn signal_event(&self, event: efi::Event) -> Result<(), efi::Status>;
187
188 fn wait_for_event(&self, events: &mut [efi::Event]) -> Result<usize, efi::Status>;
192
193 fn check_event(&self, event: efi::Event) -> Result<(), efi::Status>;
197
198 fn set_timer(&self, event: efi::Event, timer_type: EventTimerType, trigger_time: u64) -> Result<(), efi::Status>;
202
203 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 fn raise_tpl(&self, tpl: Tpl) -> Tpl;
214
215 fn restore_tpl(&self, tpl: Tpl);
219
220 fn allocate_pages(
224 &self,
225 alloc_type: AllocType,
226 memory_type: MemoryType,
227 nb_pages: usize,
228 ) -> Result<usize, efi::Status>;
229
230 fn free_pages(&self, address: usize, nb_pages: usize) -> Result<(), efi::Status>;
234
235 fn get_memory_map<'a>(&'a self) -> Result<MemoryMap<'a, Self>, (efi::Status, usize)>;
239
240 fn allocate_pool(&self, pool_type: MemoryType, size: usize) -> Result<*mut u8, efi::Status>;
244
245 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 fn free_pool(&self, buffer: *mut u8) -> Result<(), efi::Status>;
255
256 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 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 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 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 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 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 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 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 fn register_protocol_notify(
404 &self,
405 protocol: &'static efi::Guid,
406 event: efi::Event,
407 ) -> Result<Registration, efi::Status>;
408
409 fn locate_handle<'a>(
413 &'a self,
414 search_type: HandleSearchType,
415 ) -> Result<BootServicesBox<'a, [efi::Handle], Self>, efi::Status>;
416
417 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 unsafe {
435 self.handle_protocol_unchecked(handle, protocol.protocol_guid()).map(|i| (i as *mut I).as_mut().unwrap())
436 }
437 }
438
439 fn handle_protocol_marker<P: Protocol<Interface = ()> + 'static>(
443 &self,
444 handle: efi::Handle,
445 protocol: &P,
446 ) -> Result<(), efi::Status> {
447 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 unsafe fn handle_protocol_unchecked(
455 &self,
456 handle: efi::Handle,
457 protocol: &efi::Guid,
458 ) -> Result<*mut c_void, efi::Status>;
459
460 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 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 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 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 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 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 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 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 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 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 fn protocols_per_handle<'a>(
583 &'a self,
584 handle: efi::Handle,
585 ) -> Result<BootServicesBox<'a, [&'static efi::Guid], Self>, efi::Status>;
586
587 fn locate_handle_buffer<'a>(
591 &'a self,
592 search_type: HandleSearchType,
593 ) -> Result<BootServicesBox<'a, [efi::Handle], Self>, efi::Status>;
594
595 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 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 fn locate_protocol_marker<P>(&self, protocol: &P, registration: Option<Registration>) -> Result<(), efi::Status>
631 where
632 P: Protocol<Interface = ()> + 'static,
633 {
634 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 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 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 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 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 fn start_image<'a>(
697 &'a self,
698 image_handle: efi::Handle,
699 ) -> Result<(), (efi::Status, Option<BootServicesBox<'a, [u8], Self>>)>;
700
701 fn unload_image(&self, image_handle: efi::Handle) -> Result<(), efi::Status>;
706
707 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 fn exit_boot_services(&self, image_handle: efi::Handle, map_key: usize) -> Result<(), efi::Status>;
723
724 fn set_watchdog_timer(&self, timeout: usize) -> Result<(), efi::Status>;
732
733 fn stall(&self, microseconds: usize) -> Result<(), efi::Status>;
737
738 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 unsafe fn copy_mem_unchecked(&self, dest: *mut c_void, src: *const c_void, length: usize);
751
752 fn set_mem(&self, buffer: &mut [u8], value: u8);
756
757 fn get_next_monotonic_count(&self) -> Result<u64, efi::Status>;
761
762 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 unsafe fn install_configuration_table_unchecked(
779 &self,
780 guid: &efi::Guid,
781 table: *mut c_void,
782 ) -> Result<(), efi::Status>;
783
784 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, _ => (),
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 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 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 let status = boot_services.free_pool(0xffff0000 as *mut u8);
1983 assert_eq!(status, Ok(()));
1984
1985 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}