@@ -43,21 +43,22 @@ static IMAGE_HANDLE: GlobalImageHandle = GlobalImageHandle {
43
43
/// # Accessing protocols
44
44
///
45
45
/// 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
47
48
/// [`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.
50
50
///
51
51
/// Other methods for opening protocols:
52
52
///
53
+ /// * [`open_protocol`]
53
54
/// * [`get_image_file_system`]
54
55
/// * [`handle_protocol`]
55
56
/// * [`locate_protocol`]
56
57
///
57
58
/// For protocol definitions, see the [`proto`] module.
58
59
///
59
60
/// [`proto`]: crate::proto
60
- /// [`Exclusive `]: OpenProtocolAttributes::Exclusive
61
+ /// [`open_protocol_exclusive `]: BootServices::open_protocol_exclusive
61
62
/// [`open_protocol`]: BootServices::open_protocol
62
63
/// [`get_image_file_system`]: BootServices::get_image_file_system
63
64
/// [`locate_protocol`]: BootServices::locate_protocol
@@ -623,7 +624,7 @@ impl BootServices {
623
624
/// based on the protocol GUID.
624
625
///
625
626
/// 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`.
627
628
///
628
629
/// UEFI protocols are neither thread-safe nor reentrant, but the firmware
629
630
/// provides no mechanism to protect against concurrent usage. Such
@@ -635,10 +636,14 @@ impl BootServices {
635
636
/// This method is unsafe because the handle database is not
636
637
/// notified that the handle and protocol are in use; there is no
637
638
/// 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`].
639
641
///
640
642
/// [`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
+ )]
642
647
pub unsafe fn handle_protocol<P: ProtocolPointer + ?Sized>(
643
648
&self,
644
649
handle: Handle,
@@ -737,14 +742,7 @@ impl BootServices {
737
742
/// # let boot_services: &BootServices = get_fake_val();
738
743
/// # let image_handle: Handle = get_fake_val();
739
744
/// 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)?;
748
746
/// # Ok(())
749
747
/// # }
750
748
/// ```
@@ -963,11 +961,14 @@ impl BootServices {
963
961
964
962
/// Open a protocol interface for a handle.
965
963
///
964
+ /// See also [`open_protocol_exclusive`], which provides a safe
965
+ /// subset of this functionality.
966
+ ///
966
967
/// This function attempts to get the protocol implementation of a
967
968
/// handle, based on the protocol GUID. It is an extended version of
968
969
/// [`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`.
971
972
///
972
973
/// See [`OpenProtocolParams`] and [`OpenProtocolAttributes`] for
973
974
/// details of the input parameters.
@@ -980,8 +981,19 @@ impl BootServices {
980
981
/// protections must be implemented by user-level code, for example via a
981
982
/// global `HashSet`.
982
983
///
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
+ ///
983
994
/// [`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>(
985
997
&self,
986
998
params: OpenProtocolParams,
987
999
attributes: OpenProtocolAttributes,
@@ -995,7 +1007,7 @@ impl BootServices {
995
1007
params.controller,
996
1008
attributes as u32,
997
1009
)
998
- .into_with_val(|| unsafe {
1010
+ .into_with_val(|| {
999
1011
let interface = P::mut_ptr_from_ffi(interface) as *const UnsafeCell<P>;
1000
1012
1001
1013
#[allow(deprecated)]
@@ -1017,14 +1029,19 @@ impl BootServices {
1017
1029
&self,
1018
1030
handle: Handle,
1019
1031
) -> 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
+ }
1028
1045
}
1029
1046
1030
1047
/// Test whether a handle supports a protocol.
@@ -1099,9 +1116,15 @@ impl BootServices {
1099
1116
/// This method is unsafe because the handle database is not
1100
1117
/// notified that the handle and protocol are in use; there is no
1101
1118
/// 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
+ )]
1105
1128
pub unsafe fn locate_protocol<P: ProtocolPointer + ?Sized>(&self) -> Result<&UnsafeCell<P>> {
1106
1129
let mut ptr = ptr::null_mut();
1107
1130
(self.locate_protocol)(&P::GUID, ptr::null_mut(), &mut ptr).into_with_val(|| {
@@ -1166,34 +1189,13 @@ impl BootServices {
1166
1189
&self,
1167
1190
image_handle: Handle,
1168
1191
) -> 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())?;
1186
1195
1187
1196
let device_handle = self.locate_device_path::<SimpleFileSystem>(&mut &*device_path)?;
1188
1197
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)
1197
1199
}
1198
1200
}
1199
1201
0 commit comments