@@ -30,12 +30,23 @@ pub use strs::{str_num_latin1_chars, str_to_latin1};
3030pub use uefi_raw:: { PhysicalAddress , VirtualAddress } ;
3131pub use unaligned_slice:: UnalignedSlice ;
3232
33+ use crate :: Result ;
34+ use crate :: boot:: { self , OpenProtocolAttributes , OpenProtocolParams , ScopedProtocol } ;
35+ use crate :: proto:: device_path:: DevicePath ;
36+ use crate :: proto:: driver:: ComponentName2 ;
3337use core:: ffi:: c_void;
3438use core:: ptr:: { self , NonNull } ;
39+ #[ cfg( doc) ]
40+ use uefi_raw:: Status ;
3541
3642/// Opaque handle to an UEFI entity (protocol, image...), guaranteed to be non-null.
3743///
3844/// If you need to have a nullable handle (for a custom UEFI FFI for example) use `Option<Handle>`.
45+ ///
46+ /// A handle offers some convenient methods to better explore the context of
47+ /// it, such as:
48+ /// - [`Handle::component_name`]
49+ /// - [`Handle::device_path`]
3950#[ derive( Clone , Copy , Debug , Hash , Eq , PartialEq , Ord , PartialOrd ) ]
4051#[ repr( transparent) ]
4152pub struct Handle ( NonNull < c_void > ) ;
@@ -85,6 +96,78 @@ impl Handle {
8596 pub ( crate ) fn opt_to_ptr ( handle : Option < Self > ) -> * mut c_void {
8697 handle. map ( |h| h. 0 . as_ptr ( ) ) . unwrap_or ( ptr:: null_mut ( ) )
8798 }
99+
100+ // some convenient protocol helpers
101+
102+ /// Opens the underlying [`ComponentName2`], if it exists.
103+ ///
104+ /// # Example
105+ /// ```rust,no_run
106+ /// # use uefi::Handle;
107+ /// # let handle = unsafe { Handle::from_ptr(123 as *mut _).unwrap() };
108+ /// let cn2_prot = handle
109+ /// .component_name()
110+ /// .expect("should have component name (v2) protocol");
111+ /// log::info!(
112+ /// "driver: {}, controller: {}",
113+ /// cn2_prot.driver_name("en").unwrap(),
114+ /// cn2_prot.controller_name(handle, None, "en").unwrap()
115+ /// );
116+ /// ```
117+ ///
118+ /// # Errors
119+ ///
120+ /// * [`Status::INVALID_PARAMETER`]: an invalid combination of `params` and
121+ /// `attributes` was provided.
122+ /// * [`Status::UNSUPPORTED`]: the handle does not support the protocol.
123+ /// * [`Status::ACCESS_DENIED`] or [`Status::ALREADY_STARTED`]: the protocol is
124+ /// already open in a way that is incompatible with the new request.
125+ pub fn component_name ( & self ) -> Result < ScopedProtocol < ComponentName2 > > {
126+ // SAFETY: The protocol is only used for reading data.
127+ unsafe {
128+ boot:: open_protocol :: < ComponentName2 > (
129+ OpenProtocolParams {
130+ handle : * self ,
131+ agent : boot:: image_handle ( ) ,
132+ controller : None ,
133+ } ,
134+ OpenProtocolAttributes :: GetProtocol ,
135+ )
136+ }
137+ }
138+
139+ /// Opens the underlying [`DevicePath`] protocol, if it exists.
140+ ///
141+ /// # Example
142+ /// ```rust,no_run
143+ /// # use uefi::Handle;
144+ /// # let handle = unsafe { Handle::from_ptr(123 as *mut _).unwrap() };
145+ /// let device_path = handle
146+ /// .device_path()
147+ /// .expect("should have device path");
148+ /// log::info!("device path: {device_path}");
149+ /// ```
150+ ///
151+ /// # Errors
152+ ///
153+ /// * [`Status::INVALID_PARAMETER`]: an invalid combination of `params` and
154+ /// `attributes` was provided.
155+ /// * [`Status::UNSUPPORTED`]: the handle does not support the protocol.
156+ /// * [`Status::ACCESS_DENIED`] or [`Status::ALREADY_STARTED`]: the protocol is
157+ /// already open in a way that is incompatible with the new request.
158+ pub fn device_path ( & self ) -> Result < ScopedProtocol < DevicePath > > {
159+ // SAFETY: The protocol is only used for reading data.
160+ unsafe {
161+ boot:: open_protocol :: < DevicePath > (
162+ OpenProtocolParams {
163+ handle : * self ,
164+ agent : boot:: image_handle ( ) ,
165+ controller : None ,
166+ } ,
167+ OpenProtocolAttributes :: GetProtocol ,
168+ )
169+ }
170+ }
88171}
89172
90173/// Handle to an event structure, guaranteed to be non-null.
0 commit comments