@@ -43,21 +43,22 @@ static IMAGE_HANDLE: GlobalImageHandle = GlobalImageHandle {
4343/// # Accessing protocols
4444///
4545/// Protocols can be opened using several methods of `BootServices`. Most
46- /// commonly, [`open_protocol`] should be used. This returns a
46+ /// commonly, [`open_protocol_exclusive`] should be used. This ensures that
47+ /// nothing else can use the protocol until it is closed, and returns a
4748/// [`ScopedProtocol`] that takes care of closing the protocol when it is
48- /// dropped. If the protocol is opened in [`Exclusive`] mode, UEFI ensures that
49- /// nothing else can use the protocol until it is closed.
49+ /// dropped.
5050///
5151/// Other methods for opening protocols:
5252///
53+ /// * [`open_protocol`]
5354/// * [`get_image_file_system`]
5455/// * [`handle_protocol`]
5556/// * [`locate_protocol`]
5657///
5758/// For protocol definitions, see the [`proto`] module.
5859///
5960/// [`proto`]: crate::proto
60- /// [`Exclusive `]: OpenProtocolAttributes::Exclusive
61+ /// [`open_protocol_exclusive `]: BootServices::open_protocol_exclusive
6162/// [`open_protocol`]: BootServices::open_protocol
6263/// [`get_image_file_system`]: BootServices::get_image_file_system
6364/// [`locate_protocol`]: BootServices::locate_protocol
@@ -623,7 +624,7 @@ impl BootServices {
623624 /// based on the protocol GUID.
624625 ///
625626 /// It is recommended that all new drivers and applications use
626- /// [`open_protocol`] instead of `handle_protocol`.
627+ /// [`open_protocol_exclusive`] or [` open_protocol`] instead of `handle_protocol`.
627628 ///
628629 /// UEFI protocols are neither thread-safe nor reentrant, but the firmware
629630 /// provides no mechanism to protect against concurrent usage. Such
@@ -635,10 +636,14 @@ impl BootServices {
635636 /// This method is unsafe because the handle database is not
636637 /// notified that the handle and protocol are in use; there is no
637638 /// guarantee that they will remain valid for the duration of their
638- /// use. Use [`open_protocol`] instead.
639+ /// use. Use [`open_protocol_exclusive`] if possible, otherwise use
640+ /// [`open_protocol`].
639641 ///
640642 /// [`open_protocol`]: BootServices::open_protocol
641- #[ deprecated( note = "it is recommended to use `open_protocol` instead" ) ]
643+ /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive
644+ #[ deprecated(
645+ note = "it is recommended to use `open_protocol_exclusive` or `open_protocol` instead"
646+ ) ]
642647 pub unsafe fn handle_protocol < P : ProtocolPointer + ?Sized > (
643648 & self ,
644649 handle : Handle ,
@@ -737,14 +742,7 @@ impl BootServices {
737742 /// # let boot_services: &BootServices = get_fake_val();
738743 /// # let image_handle: Handle = get_fake_val();
739744 /// let handle = boot_services.get_handle_for_protocol::<DevicePathToText>()?;
740- /// let device_path_to_text = boot_services.open_protocol::<DevicePathToText>(
741- /// OpenProtocolParams {
742- /// handle,
743- /// agent: image_handle,
744- /// controller: None,
745- /// },
746- /// OpenProtocolAttributes::Exclusive,
747- /// )?;
745+ /// let device_path_to_text = boot_services.open_protocol_exclusive::<DevicePathToText>(handle)?;
748746 /// # Ok(())
749747 /// # }
750748 /// ```
@@ -963,11 +961,14 @@ impl BootServices {
963961
964962 /// Open a protocol interface for a handle.
965963 ///
964+ /// See also [`open_protocol_exclusive`], which provides a safe
965+ /// subset of this functionality.
966+ ///
966967 /// This function attempts to get the protocol implementation of a
967968 /// handle, based on the protocol GUID. It is an extended version of
968969 /// [`handle_protocol`]. It is recommended that all
969- /// new drivers and applications use `open_protocol` instead of
970- /// `handle_protocol`.
970+ /// new drivers and applications use `open_protocol_exclusive` or
971+ /// `open_protocol` instead of ` handle_protocol`.
971972 ///
972973 /// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for
973974 /// details of the input parameters.
@@ -980,8 +981,19 @@ impl BootServices {
980981 /// protections must be implemented by user-level code, for example via a
981982 /// global `HashSet`.
982983 ///
984+ /// # Safety
985+ ///
986+ /// This function is unsafe because it can be used to open a
987+ /// protocol in ways that don't get tracked by the UEFI
988+ /// implementation. This could allow the protocol to be removed from
989+ /// a handle, or for the handle to be deleted entirely, while a
990+ /// reference to the protocol is still active. The caller is
991+ /// responsible for ensuring that the handle and protocol remain
992+ /// valid until the `ScopedProtocol` is dropped.
993+ ///
983994 /// [`handle_protocol`]: BootServices::handle_protocol
984- pub fn open_protocol < P : ProtocolPointer + ?Sized > (
995+ /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive
996+ pub unsafe fn open_protocol < P : ProtocolPointer + ?Sized > (
985997 & self ,
986998 params : OpenProtocolParams ,
987999 attributes : OpenProtocolAttributes ,
@@ -995,7 +1007,7 @@ impl BootServices {
9951007 params. controller ,
9961008 attributes as u32 ,
9971009 )
998- . into_with_val ( || unsafe {
1010+ . into_with_val ( || {
9991011 let interface = P :: mut_ptr_from_ffi ( interface) as * const UnsafeCell < P > ;
10001012
10011013 #[ allow( deprecated) ]
@@ -1017,14 +1029,19 @@ impl BootServices {
10171029 & self ,
10181030 handle : Handle ,
10191031 ) -> Result < ScopedProtocol < P > > {
1020- self . open_protocol :: < P > (
1021- OpenProtocolParams {
1022- handle,
1023- agent : self . image_handle ( ) ,
1024- controller : None ,
1025- } ,
1026- OpenProtocolAttributes :: Exclusive ,
1027- )
1032+ // Safety: opening in exclusive mode with the correct agent
1033+ // handle set ensures that the protocol cannot be modified or
1034+ // removed while it is open, so this usage is safe.
1035+ unsafe {
1036+ self . open_protocol :: < P > (
1037+ OpenProtocolParams {
1038+ handle,
1039+ agent : self . image_handle ( ) ,
1040+ controller : None ,
1041+ } ,
1042+ OpenProtocolAttributes :: Exclusive ,
1043+ )
1044+ }
10281045 }
10291046
10301047 /// Test whether a handle supports a protocol.
@@ -1099,9 +1116,15 @@ impl BootServices {
10991116 /// This method is unsafe because the handle database is not
11001117 /// notified that the handle and protocol are in use; there is no
11011118 /// guarantee that they will remain valid for the duration of their
1102- /// use. Use [`BootServices::get_handle_for_protocol`] and
1103- /// [`BootServices::open_protocol`] instead.
1104- #[ deprecated( note = "it is recommended to use `open_protocol` instead" ) ]
1119+ /// use. Use [`get_handle_for_protocol`] and either
1120+ /// [`open_protocol_exclusive`] or [`open_protocol`] instead.
1121+ ///
1122+ /// [`get_handle_for_protocol`]: BootServices::get_handle_for_protocol
1123+ /// [`open_protocol`]: BootServices::open_protocol
1124+ /// [`open_protocol_exclusive`]: BootServices::open_protocol_exclusive
1125+ #[ deprecated(
1126+ note = "it is recommended to use `open_protocol_exclusive` or `open_protocol` instead"
1127+ ) ]
11051128 pub unsafe fn locate_protocol < P : ProtocolPointer + ?Sized > ( & self ) -> Result < & UnsafeCell < P > > {
11061129 let mut ptr = ptr:: null_mut ( ) ;
11071130 ( self . locate_protocol ) ( & P :: GUID , ptr:: null_mut ( ) , & mut ptr) . into_with_val ( || {
@@ -1166,34 +1189,13 @@ impl BootServices {
11661189 & self ,
11671190 image_handle : Handle ,
11681191 ) -> Result < ScopedProtocol < SimpleFileSystem > > {
1169- let loaded_image = self . open_protocol :: < LoadedImage > (
1170- OpenProtocolParams {
1171- handle : image_handle,
1172- agent : image_handle,
1173- controller : None ,
1174- } ,
1175- OpenProtocolAttributes :: Exclusive ,
1176- ) ?;
1177-
1178- let device_path = self . open_protocol :: < DevicePath > (
1179- OpenProtocolParams {
1180- handle : loaded_image. device ( ) ,
1181- agent : image_handle,
1182- controller : None ,
1183- } ,
1184- OpenProtocolAttributes :: Exclusive ,
1185- ) ?;
1192+ let loaded_image = self . open_protocol_exclusive :: < LoadedImage > ( image_handle) ?;
1193+
1194+ let device_path = self . open_protocol_exclusive :: < DevicePath > ( loaded_image. device ( ) ) ?;
11861195
11871196 let device_handle = self . locate_device_path :: < SimpleFileSystem > ( & mut & * device_path) ?;
11881197
1189- self . open_protocol :: < SimpleFileSystem > (
1190- OpenProtocolParams {
1191- handle : device_handle,
1192- agent : image_handle,
1193- controller : None ,
1194- } ,
1195- OpenProtocolAttributes :: Exclusive ,
1196- )
1198+ self . open_protocol_exclusive ( device_handle)
11971199 }
11981200}
11991201
0 commit comments