3
3
//! These functions will panic if called after exiting boot services.
4
4
5
5
use crate :: data_types:: PhysicalAddress ;
6
+ use crate :: proto:: { Protocol , ProtocolPointer } ;
6
7
use core:: ffi:: c_void;
7
- use core:: ops:: Deref ;
8
+ use core:: ops:: { Deref , DerefMut } ;
8
9
use core:: ptr:: { self , NonNull } ;
9
10
use core:: slice;
10
11
use core:: sync:: atomic:: { AtomicPtr , Ordering } ;
11
- use uefi:: { table, Handle , Result , StatusExt } ;
12
+ use uefi:: { table, Handle , Result , Status , StatusExt } ;
12
13
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 } ;
17
15
pub use uefi_raw:: table:: boot:: MemoryType ;
18
16
19
17
/// 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> {
162
160
} )
163
161
}
164
162
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
+
165
217
/// A buffer returned by [`locate_handle_buffer`] that contains an array of
166
218
/// [`Handle`]s that support the requested protocol.
167
219
#[ derive( Debug , Eq , PartialEq ) ]
@@ -183,3 +235,78 @@ impl Deref for HandleBuffer {
183
235
unsafe { slice:: from_raw_parts ( self . buffer . as_ptr ( ) , self . count ) }
184
236
}
185
237
}
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