@@ -12,7 +12,7 @@ use bitflags::bitflags;
1212use core:: cell:: UnsafeCell ;
1313use core:: ffi:: c_void;
1414use core:: mem:: { self , MaybeUninit } ;
15- use core:: ptr;
15+ use core:: { ptr, slice } ;
1616
1717/// Contains pointers to all of the boot services.
1818#[ repr( C ) ]
@@ -121,7 +121,11 @@ pub struct BootServices {
121121 open_protocol_information : usize ,
122122
123123 // Library services
124- protocols_per_handle : usize ,
124+ protocols_per_handle : unsafe extern "efiapi" fn (
125+ handle : Handle ,
126+ protocol_buffer : * mut * mut * const Guid ,
127+ protocol_buffer_count : * mut usize ,
128+ ) -> Status ,
125129 locate_handle_buffer : usize ,
126130 locate_protocol : extern "efiapi" fn (
127131 proto : & Guid ,
@@ -548,6 +552,36 @@ impl BootServices {
548552 unsafe { ( self . set_watchdog_timer ) ( timeout, watchdog_code, data_len, data) } . into ( )
549553 }
550554
555+ /// Get the list of protocol interface [`Guids`][Guid] that are installed
556+ /// on a [`Handle`].
557+ pub fn protocols_per_handle ( & self , handle : Handle ) -> Result < ProtocolsPerHandle > {
558+ let mut protocols = ptr:: null_mut ( ) ;
559+ let mut count = 0 ;
560+
561+ let mut status = unsafe { ( self . protocols_per_handle ) ( handle, & mut protocols, & mut count) } ;
562+
563+ if !status. is_error ( ) {
564+ // Ensure that protocols isn't null, and that none of the GUIDs
565+ // returned are null.
566+ if protocols. is_null ( ) {
567+ status = Status :: OUT_OF_RESOURCES ;
568+ } else {
569+ let protocols: & [ * const Guid ] = unsafe { slice:: from_raw_parts ( protocols, count) } ;
570+ if protocols. iter ( ) . any ( |ptr| ptr. is_null ( ) ) {
571+ status = Status :: OUT_OF_RESOURCES ;
572+ }
573+ }
574+ }
575+
576+ status. into_with_val ( || {
577+ let protocols = unsafe { slice:: from_raw_parts_mut ( protocols as * mut & Guid , count) } ;
578+ ProtocolsPerHandle {
579+ boot_services : self ,
580+ protocols,
581+ }
582+ } )
583+ }
584+
551585 /// Returns a protocol implementation, if present on the system.
552586 ///
553587 /// The caveats of `BootServices::handle_protocol()` also apply here.
@@ -933,3 +967,33 @@ pub enum TimerTrigger {
933967 /// Delay of 0 will be signalled on next timer tick.
934968 Relative ( u64 ) ,
935969}
970+
971+ /// Protocol interface [`Guids`][Guid] that are installed on a [`Handle`] as
972+ /// returned by [`BootServices::protocols_per_handle`].
973+ pub struct ProtocolsPerHandle < ' a > {
974+ // The pointer returned by `protocols_per_handle` has to be free'd with
975+ // `free_pool`, so keep a reference to boot services for that purpose.
976+ boot_services : & ' a BootServices ,
977+
978+ // This is mutable so that it can later be free'd with `free_pool`. Users
979+ // should only get an immutable reference though, so the field is not
980+ // public.
981+ protocols : & ' a mut [ & ' a Guid ] ,
982+ }
983+
984+ impl < ' a > Drop for ProtocolsPerHandle < ' a > {
985+ fn drop ( & mut self ) {
986+ // Ignore the result, we can't do anything about an error here.
987+ let _ = self
988+ . boot_services
989+ . free_pool ( self . protocols . as_mut_ptr ( ) as * mut u8 ) ;
990+ }
991+ }
992+
993+ impl < ' a > ProtocolsPerHandle < ' a > {
994+ /// Get the protocol interface [`Guids`][Guid] that are installed on the
995+ /// [`Handle`].
996+ pub fn protocols ( & self ) -> & [ & Guid ] {
997+ self . protocols
998+ }
999+ }
0 commit comments