33//! These functions will panic if called after exiting boot services. 
44
55use  crate :: data_types:: PhysicalAddress ; 
6+ use  crate :: proto:: { Protocol ,  ProtocolPointer } ; 
67use  core:: ffi:: c_void; 
7- use  core:: ops:: Deref ; 
8+ use  core:: ops:: { Deref ,   DerefMut } ; 
89use  core:: ptr:: { self ,  NonNull } ; 
910use  core:: slice; 
1011use  core:: sync:: atomic:: { AtomicPtr ,  Ordering } ; 
11- use  uefi:: { table,  Handle ,  Result ,  StatusExt } ; 
12+ use  uefi:: { table,  Handle ,  Result ,  Status ,   StatusExt } ; 
1213
13- #[ cfg( doc) ]  
14- use  uefi:: Status ; 
15- 
16- pub  use  uefi:: table:: boot:: { AllocateType ,  SearchType } ; 
14+ pub  use  uefi:: table:: boot:: { AllocateType ,  OpenProtocolAttributes ,  OpenProtocolParams ,  SearchType } ; 
1715pub  use  uefi_raw:: table:: boot:: MemoryType ; 
1816
1917/// Global image handle. This is only set by [`set_image_handle`], and it is 
@@ -162,6 +160,60 @@ pub fn locate_handle_buffer(search_ty: SearchType) -> Result<HandleBuffer> {
162160        } ) 
163161} 
164162
163+ /// Opens a protocol interface for a handle. 
164+ /// 
165+ /// See also `open_protocol_exclusive`, which provides a safe subset of this 
166+ /// functionality. 
167+ /// 
168+ /// This function attempts to get the protocol implementation of a handle, based 
169+ /// on the [protocol GUID]. 
170+ /// 
171+ /// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for details of the 
172+ /// input parameters. 
173+ /// 
174+ /// If successful, a [`ScopedProtocol`] is returned that will automatically 
175+ /// close the protocol interface when dropped. 
176+ /// 
177+ /// [protocol GUID]: uefi::data_types::Identify::GUID 
178+ /// 
179+ /// # Safety 
180+ /// 
181+ /// This function is unsafe because it can be used to open a protocol in ways 
182+ /// that don't get tracked by the UEFI implementation. This could allow the 
183+ /// protocol to be removed from a handle, or for the handle to be deleted 
184+ /// entirely, while a reference to the protocol is still active. The caller is 
185+ /// responsible for ensuring that the handle and protocol remain valid until the 
186+ /// `ScopedProtocol` is dropped. 
187+ /// 
188+ /// # Errors 
189+ /// 
190+ /// * [`Status::INVALID_PARAMETER`]: an invalid combination of `params` and 
191+ ///   `attributes` was provided. 
192+ /// * [`Status::UNSUPPORTED`]: the handle does not support the protocol. 
193+ /// * [`Status::ACCESS_DENIED`] or [`Status::ALREADY_STARTED`]: the protocol is 
194+ ///   already open in a way that is incompatible with the new request. 
195+ pub  unsafe  fn  open_protocol < P :  ProtocolPointer  + ?Sized > ( 
196+     params :  OpenProtocolParams , 
197+     attributes :  OpenProtocolAttributes , 
198+ )  -> Result < ScopedProtocol < P > >  { 
199+     let  bt = boot_services_raw_panicking ( ) ; 
200+     let  bt = unsafe  {  bt. as_ref ( )  } ; 
201+ 
202+     let  mut  interface = ptr:: null_mut ( ) ; 
203+     ( bt. open_protocol ) ( 
204+         params. handle . as_ptr ( ) , 
205+         & P :: GUID , 
206+         & mut  interface, 
207+         params. agent . as_ptr ( ) , 
208+         Handle :: opt_to_ptr ( params. controller ) , 
209+         attributes as  u32 , 
210+     ) 
211+     . to_result_with_val ( || ScopedProtocol  { 
212+         interface :  NonNull :: new ( P :: mut_ptr_from_ffi ( interface) ) , 
213+         open_params :  params, 
214+     } ) 
215+ } 
216+ 
165217/// A buffer returned by [`locate_handle_buffer`] that contains an array of 
166218/// [`Handle`]s that support the requested protocol. 
167219#[ derive( Debug ,  Eq ,  PartialEq ) ]  
@@ -183,3 +235,78 @@ impl Deref for HandleBuffer {
183235        unsafe  {  slice:: from_raw_parts ( self . buffer . as_ptr ( ) ,  self . count )  } 
184236    } 
185237} 
238+ 
239+ /// An open protocol interface. Automatically closes the protocol 
240+ /// interface on drop. 
241+ /// 
242+ /// Most protocols have interface data associated with them. `ScopedProtocol` 
243+ /// implements [`Deref`] and [`DerefMut`] to access this data. A few protocols 
244+ /// (such as [`DevicePath`] and [`LoadedImageDevicePath`]) may be installed with 
245+ /// null interface data, in which case [`Deref`] and [`DerefMut`] will 
246+ /// panic. The [`get`] and [`get_mut`] methods may be used to access the 
247+ /// optional interface data without panicking. 
248+ /// 
249+ /// [`DevicePath`]: crate::proto::device_path::DevicePath 
250+ /// [`LoadedImageDevicePath`]: crate::proto::device_path::LoadedImageDevicePath 
251+ /// [`get`]: ScopedProtocol::get 
252+ /// [`get_mut`]: ScopedProtocol::get_mut 
253+ #[ derive( Debug ) ]  
254+ pub  struct  ScopedProtocol < P :  Protocol  + ?Sized >  { 
255+     /// The protocol interface. 
256+ interface :  Option < NonNull < P > > , 
257+     open_params :  OpenProtocolParams , 
258+ } 
259+ 
260+ impl < P :  Protocol  + ?Sized >  Drop  for  ScopedProtocol < P >  { 
261+     fn  drop ( & mut  self )  { 
262+         let  bt = boot_services_raw_panicking ( ) ; 
263+         let  bt = unsafe  {  bt. as_ref ( )  } ; 
264+ 
265+         let  status = unsafe  { 
266+             ( bt. close_protocol ) ( 
267+                 self . open_params . handle . as_ptr ( ) , 
268+                 & P :: GUID , 
269+                 self . open_params . agent . as_ptr ( ) , 
270+                 Handle :: opt_to_ptr ( self . open_params . controller ) , 
271+             ) 
272+         } ; 
273+         // All of the error cases for close_protocol boil down to 
274+         // calling it with a different set of parameters than what was 
275+         // passed to open_protocol. The public API prevents such errors, 
276+         // and the error can't be propagated out of drop anyway, so just 
277+         // assert success. 
278+         assert_eq ! ( status,  Status :: SUCCESS ) ; 
279+     } 
280+ } 
281+ 
282+ impl < P :  Protocol  + ?Sized >  Deref  for  ScopedProtocol < P >  { 
283+     type  Target  = P ; 
284+ 
285+     #[ track_caller]  
286+     fn  deref ( & self )  -> & Self :: Target  { 
287+         unsafe  {  self . interface . unwrap ( ) . as_ref ( )  } 
288+     } 
289+ } 
290+ 
291+ impl < P :  Protocol  + ?Sized >  DerefMut  for  ScopedProtocol < P >  { 
292+     #[ track_caller]  
293+     fn  deref_mut ( & mut  self )  -> & mut  Self :: Target  { 
294+         unsafe  {  self . interface . unwrap ( ) . as_mut ( )  } 
295+     } 
296+ } 
297+ 
298+ impl < P :  Protocol  + ?Sized >  ScopedProtocol < P >  { 
299+     /// Get the protocol interface data, or `None` if the open protocol's 
300+ /// interface is null. 
301+ #[ must_use]  
302+     pub  fn  get ( & self )  -> Option < & P >  { 
303+         self . interface . map ( |p| unsafe  {  p. as_ref ( )  } ) 
304+     } 
305+ 
306+     /// Get the protocol interface data, or `None` if the open protocol's 
307+ /// interface is null. 
308+ #[ must_use]  
309+     pub  fn  get_mut ( & mut  self )  -> Option < & mut  P >  { 
310+         self . interface . map ( |mut  p| unsafe  {  p. as_mut ( )  } ) 
311+     } 
312+ } 
0 commit comments