@@ -123,8 +123,20 @@ pub struct BootServices {
123123 disconnect_controller :  usize , 
124124
125125 // Protocol open / close services 
126-  open_protocol :  usize , 
127-  close_protocol :  usize , 
126+  open_protocol :  extern  "efiapi"  fn ( 
127+  handle :  Handle , 
128+  protocol :  & Guid , 
129+  interface :  & mut  * mut  c_void , 
130+  agent_handle :  Handle , 
131+  controller_handle :  Option < Handle > , 
132+  attributes :  u32 , 
133+  )  -> Status , 
134+  close_protocol :  extern  "efiapi"  fn ( 
135+  handle :  Handle , 
136+  protocol :  & Guid , 
137+  agent_handle :  Handle , 
138+  controller_handle :  Option < Handle > , 
139+  )  -> Status , 
128140 open_protocol_information :  usize , 
129141
130142 // Library services 
@@ -481,10 +493,16 @@ impl BootServices {
481493/// This function attempts to get the protocol implementation of a handle, 
482494/// based on the protocol GUID. 
483495/// 
496+ /// It is recommended that all new drivers and applications use 
497+ /// [`open_protocol`] instead of `handle_protocol`. 
498+ /// 
484499/// UEFI protocols are neither thread-safe nor reentrant, but the firmware 
485500/// provides no mechanism to protect against concurrent usage. Such 
486501/// protections must be implemented by user-level code, for example via a 
487502/// global `HashSet`. 
503+ /// 
504+ /// [`open_protocol`]: BootServices::open_protocol 
505+ #[ deprecated( note = "it is recommended to use `open_protocol` instead" ) ]  
488506 pub  fn  handle_protocol < P :  Protocol > ( & self ,  handle :  Handle )  -> Result < & UnsafeCell < P > >  { 
489507 let  mut  ptr = ptr:: null_mut ( ) ; 
490508 ( self . handle_protocol ) ( handle,  & P :: GUID ,  & mut  ptr) . into_with_val ( || { 
@@ -672,6 +690,67 @@ impl BootServices {
672690 unsafe  {  ( self . set_watchdog_timer ) ( timeout,  watchdog_code,  data_len,  data)  } . into ( ) 
673691 } 
674692
693+  /// Open a protocol interface for a handle. 
694+ /// 
695+ /// This function attempts to get the protocol implementation of a 
696+ /// handle, based on the protocol GUID. It is an extended version of 
697+ /// [`handle_protocol`]. It is recommended that all 
698+ /// new drivers and applications use `open_protocol` instead of 
699+ /// `handle_protocol`. 
700+ /// 
701+ /// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for 
702+ /// details of the input parameters. 
703+ /// 
704+ /// If successful, a [`ScopedProtocol`] is returned that will 
705+ /// automatically close the protocol interface when dropped. 
706+ /// 
707+ /// UEFI protocols are neither thread-safe nor reentrant, but the firmware 
708+ /// provides no mechanism to protect against concurrent usage. Such 
709+ /// protections must be implemented by user-level code, for example via a 
710+ /// global `HashSet`. 
711+ /// 
712+ /// [`handle_protocol`]: BootServices::handle_protocol 
713+ pub  fn  open_protocol < P :  Protocol > ( 
714+  & self , 
715+  params :  OpenProtocolParams , 
716+  attributes :  OpenProtocolAttributes , 
717+  )  -> Result < ScopedProtocol < P > >  { 
718+  let  mut  interface = ptr:: null_mut ( ) ; 
719+  ( self . open_protocol ) ( 
720+  params. handle , 
721+  & P :: GUID , 
722+  & mut  interface, 
723+  params. agent , 
724+  params. controller , 
725+  attributes as  u32 , 
726+  ) 
727+  . into_with_val ( || { 
728+  let  interface = interface as  * mut  P  as  * mut  UnsafeCell < P > ; 
729+  unsafe  { 
730+  ScopedProtocol  { 
731+  interface :  & * interface, 
732+  open_params :  params, 
733+  boot_services :  self , 
734+  } 
735+  } 
736+  } ) 
737+  } 
738+ 
739+  /// Test whether a handle supports a protocol. 
740+ pub  fn  test_protocol < P :  Protocol > ( & self ,  params :  OpenProtocolParams )  -> Result < ( ) >  { 
741+  const  TEST_PROTOCOL :  u32  = 0x04 ; 
742+  let  mut  interface = ptr:: null_mut ( ) ; 
743+  ( self . open_protocol ) ( 
744+  params. handle , 
745+  & P :: GUID , 
746+  & mut  interface, 
747+  params. agent , 
748+  params. controller , 
749+  TEST_PROTOCOL , 
750+  ) 
751+  . into_with_val ( || ( ) ) 
752+  } 
753+ 
675754 /// Get the list of protocol interface [`Guids`][Guid] that are installed 
676755/// on a [`Handle`]. 
677756pub  fn  protocols_per_handle ( & self ,  handle :  Handle )  -> Result < ProtocolsPerHandle >  { 
@@ -770,24 +849,45 @@ impl BootServices {
770849pub  fn  get_image_file_system ( 
771850 & self , 
772851 image_handle :  Handle , 
773-  )  -> Result < & UnsafeCell < SimpleFileSystem > >  { 
852+  )  -> Result < ScopedProtocol < SimpleFileSystem > >  { 
774853 let  loaded_image = self 
775-  . handle_protocol :: < LoadedImage > ( image_handle) ?
854+  . open_protocol :: < LoadedImage > ( 
855+  OpenProtocolParams  { 
856+  handle :  image_handle, 
857+  agent :  image_handle, 
858+  controller :  None , 
859+  } , 
860+  OpenProtocolAttributes :: Exclusive , 
861+  ) ?
776862 . expect ( "Failed to retrieve `LoadedImage` protocol from handle" ) ; 
777-  let  loaded_image = unsafe  {  & * loaded_image. get ( )  } ; 
863+  let  loaded_image = unsafe  {  & * loaded_image. interface . get ( )  } ; 
778864
779865 let  device_handle = loaded_image. device ( ) ; 
780866
781867 let  device_path = self 
782-  . handle_protocol :: < DevicePath > ( device_handle) ?
868+  . open_protocol :: < DevicePath > ( 
869+  OpenProtocolParams  { 
870+  handle :  device_handle, 
871+  agent :  image_handle, 
872+  controller :  None , 
873+  } , 
874+  OpenProtocolAttributes :: Exclusive , 
875+  ) ?
783876 . expect ( "Failed to retrieve `DevicePath` protocol from image's device handle" ) ; 
784-  let  mut  device_path = unsafe  {  & * device_path. get ( )  } ; 
877+  let  mut  device_path = unsafe  {  & * device_path. interface . get ( )  } ; 
785878
786879 let  device_handle = self 
787880 . locate_device_path :: < SimpleFileSystem > ( & mut  device_path) ?
788881 . expect ( "Failed to locate `SimpleFileSystem` protocol on device path" ) ; 
789882
790-  self . handle_protocol :: < SimpleFileSystem > ( device_handle) 
883+  self . open_protocol :: < SimpleFileSystem > ( 
884+  OpenProtocolParams  { 
885+  handle :  device_handle, 
886+  agent :  image_handle, 
887+  controller :  None , 
888+  } , 
889+  OpenProtocolAttributes :: Exclusive , 
890+  ) 
791891 } 
792892} 
793893
@@ -962,6 +1062,97 @@ impl Drop for TplGuard<'_> {
9621062 } 
9631063} 
9641064
1065+ // OpenProtocolAttributes is safe to model as a regular enum because it 
1066+ // is only used as an input. The attributes are bitflags, but all valid 
1067+ // combinations are listed in the spec and only ByDriver and Exclusive 
1068+ // can actually be combined. 
1069+ // 
1070+ // Some values intentionally excluded: 
1071+ // 
1072+ // ByHandleProtocol (0x01) excluded because it is only intended to be 
1073+ // used in an implementation of `HandleProtocol`. 
1074+ // 
1075+ // TestProtocol (0x04) excluded because it doesn't actually open the 
1076+ // protocol, just tests if it's present on the handle. Since that 
1077+ // changes the interface significantly, that's exposed as a separate 
1078+ // method: `BootServices::test_protocol`. 
1079+ 
1080+ /// Attributes for [`BootServices::open_protocol`]. 
1081+ #[ repr( u32 ) ]  
1082+ pub  enum  OpenProtocolAttributes  { 
1083+  /// Used by drivers to get a protocol interface for a handle. The 
1084+ /// driver will not be informed if the interface is uninstalled or 
1085+ /// reinstalled. 
1086+ GetProtocol  = 0x02 , 
1087+ 
1088+  /// Used by bus drivers to show that a protocol is being used by one 
1089+ /// of the child controllers of the bus. 
1090+ ByChildController  = 0x08 , 
1091+ 
1092+  /// Used by a driver to gain access to a protocol interface. When 
1093+ /// this mode is used, the driver's `Stop` function will be called 
1094+ /// if the protocol interface is reinstalled or uninstalled. Once a 
1095+ /// protocol interface is opened with this attribute, no other 
1096+ /// drivers will be allowed to open the same protocol interface with 
1097+ /// the `ByDriver` attribute. 
1098+ ByDriver  = 0x10 , 
1099+ 
1100+  /// Used by a driver to gain exclusive access to a protocol 
1101+ /// interface. If any other drivers have the protocol interface 
1102+ /// opened with an attribute of `ByDriver`, then an attempt will be 
1103+ /// made to remove them with `DisconnectController`. 
1104+ ByDriverExclusive  = 0x30 , 
1105+ 
1106+  /// Used by applications to gain exclusive access to a protocol 
1107+ /// interface. If any drivers have the protocol opened with an 
1108+ /// attribute of `ByDriver`, then an attempt will be made to remove 
1109+ /// them by calling the driver's `Stop` function. 
1110+ Exclusive  = 0x20 , 
1111+ } 
1112+ 
1113+ /// Parameters passed to [`BootServices::open_protocol`]. 
1114+ pub  struct  OpenProtocolParams  { 
1115+  /// The handle for the protocol to open. 
1116+ pub  handle :  Handle , 
1117+ 
1118+  /// The handle of the calling agent. For drivers, this is the handle 
1119+ /// containing the `EFI_DRIVER_BINDING_PROTOCOL` instance. For 
1120+ /// applications, this is the image handle. 
1121+ pub  agent :  Handle , 
1122+ 
1123+  /// For drivers, this is the controller handle that requires the 
1124+ /// protocol interface. For applications this should be set to 
1125+ /// `None`. 
1126+ pub  controller :  Option < Handle > , 
1127+ } 
1128+ 
1129+ /// An open protocol interface. Automatically closes the protocol 
1130+ /// interface on drop. 
1131+ pub  struct  ScopedProtocol < ' a ,  P :  Protocol >  { 
1132+  /// The protocol interface. 
1133+ pub  interface :  & ' a  UnsafeCell < P > , 
1134+ 
1135+  open_params :  OpenProtocolParams , 
1136+  boot_services :  & ' a  BootServices , 
1137+ } 
1138+ 
1139+ impl < ' a ,  P :  Protocol >  Drop  for  ScopedProtocol < ' a ,  P >  { 
1140+  fn  drop ( & mut  self )  { 
1141+  let  status = ( self . boot_services . close_protocol ) ( 
1142+  self . open_params . handle , 
1143+  & P :: GUID , 
1144+  self . open_params . agent , 
1145+  self . open_params . controller , 
1146+  ) ; 
1147+  // All of the error cases for close_protocol boil down to 
1148+  // calling it with a different set of parameters than what was 
1149+  // passed to open_protocol. The public API prevents such errors, 
1150+  // and the error can't be propagated out of drop anyway, so just 
1151+  // assert success. 
1152+  assert_eq ! ( status,  Status :: SUCCESS ) ; 
1153+  } 
1154+ } 
1155+ 
9651156/// Type of allocation to perform. 
9661157#[ derive( Debug ,  Copy ,  Clone ) ]  
9671158pub  enum  AllocateType  { 
0 commit comments