Skip to content

Commit 1855be5

Browse files
committed
Implement additional BootServices functions
- Implement `BootServices::install_protocol_interface` - Implement `BootServices::uninstall_protocol_interface` - Implement `BootServices::reinstall_protocol_interface` - Implement `BootServices::register_protocol_notify` - Add `SearchType::ByRegisterNotify` variant. - Add `SearchType::from_search_key` - Add `SearchKey` type that abstracts over an opaque pointer given by `BootServices::register_protocol_notify`.
1 parent 1068d2e commit 1855be5

File tree

3 files changed

+147
-14
lines changed

3 files changed

+147
-14
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
- Added structs to represent each type of device path node. All node
1717
types specified in the UEFI 2.10 Specification are now supported.
1818
- Added `DevicePathBuilder` for building new device paths.
19+
- Added `BootServices::install_protocol_interface`,
20+
`BootServices::uninstall_protocol_interface`, and
21+
`BootServices::reinstall_protocol_interface`.
22+
- Added `BootServices::register_protocol_notify`.
23+
- Added `SearchType::ByRegisterNotify` and `SearchKey` type.
1924

2025
### Changed
2126

src/data_types/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ pub type PhysicalAddress = u64;
117117
/// of target platform.
118118
pub type VirtualAddress = u64;
119119

120+
/// Opaque pointer returned by `BootServices::register_protocol_notify() to be used
121+
/// with `BootServices::locate_handle` as the `key` parameter.
122+
#[derive(Debug, Clone, Copy)]
123+
#[repr(transparent)]
124+
pub struct SearchKey(NonNull<c_void>);
125+
120126
mod guid;
121127
pub use self::guid::Guid;
122128
pub use self::guid::{unsafe_guid, Identify};

src/table/boot.rs

+136-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! UEFI services available during boot.
22
33
use super::{Header, Revision};
4-
use crate::data_types::{Align, PhysicalAddress, VirtualAddress};
4+
use crate::data_types::{Align, PhysicalAddress, SearchKey, VirtualAddress};
55
use crate::proto::device_path::{DevicePath, FfiDevicePath};
66
#[cfg(feature = "exts")]
77
use crate::proto::{loaded_image::LoadedImage, media::fs::SimpleFileSystem};
@@ -128,17 +128,32 @@ pub struct BootServices {
128128
check_event: unsafe extern "efiapi" fn(event: Event) -> Status,
129129

130130
// Protocol handlers
131-
install_protocol_interface: usize,
132-
reinstall_protocol_interface: usize,
133-
uninstall_protocol_interface: usize,
131+
install_protocol_interface: unsafe extern "efiapi" fn(
132+
handle: Option<&Handle>,
133+
guid: &Guid,
134+
interface_type: InterfaceType,
135+
interface: Option<NonNull<c_void>>,
136+
) -> Status,
137+
reinstall_protocol_interface: unsafe extern "efiapi" fn(
138+
handle: Handle,
139+
protocol: &Guid,
140+
old_interface: Option<NonNull<c_void>>,
141+
new_interface: Option<NonNull<c_void>>,
142+
) -> Status,
143+
uninstall_protocol_interface: unsafe extern "efiapi" fn(
144+
handle: Handle,
145+
protocol: &Guid,
146+
interface: Option<NonNull<c_void>>,
147+
) -> Status,
134148
handle_protocol:
135149
extern "efiapi" fn(handle: Handle, proto: &Guid, out_proto: &mut *mut c_void) -> Status,
136150
_reserved: usize,
137-
register_protocol_notify: usize,
151+
register_protocol_notify:
152+
extern "efiapi" fn(protocol: &Guid, event: Event, registration: *mut SearchKey) -> Status,
138153
locate_handle: unsafe extern "efiapi" fn(
139154
search_ty: i32,
140-
proto: *const Guid,
141-
key: *mut c_void,
155+
proto: Option<&Guid>,
156+
key: Option<SearchKey>,
142157
buf_sz: &mut usize,
143158
buf: *mut MaybeUninit<Handle>,
144159
) -> Status,
@@ -221,8 +236,8 @@ pub struct BootServices {
221236
) -> Status,
222237
locate_handle_buffer: unsafe extern "efiapi" fn(
223238
search_ty: i32,
224-
proto: *const Guid,
225-
key: *const c_void,
239+
proto: Option<&Guid>,
240+
key: Option<SearchKey>,
226241
no_handles: &mut usize,
227242
buf: &mut *mut Handle,
228243
) -> Status,
@@ -618,6 +633,72 @@ impl BootServices {
618633
}
619634
}
620635

636+
/// Installs a protocol interface on a device handle. If `handle` is `None`, one will be
637+
/// created and added to the list of handles in the system and then returned.
638+
///
639+
/// When a protocol interface is installed, firmware will call all functions that have registered
640+
/// to wait for that interface to be installed.
641+
///
642+
/// # Safety
643+
///
644+
/// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`.
645+
pub unsafe fn install_protocol_interface(
646+
&self,
647+
handle: Option<&Handle>,
648+
protocol: &Guid,
649+
interface: Option<NonNull<c_void>>,
650+
) -> Result<Handle> {
651+
((self.install_protocol_interface)(
652+
handle,
653+
protocol,
654+
InterfaceType::NATIVE_INTERFACE,
655+
interface,
656+
))
657+
// this `unwrapped_unchecked` is safe, `handle` is guaranteed to be Some() if this call is
658+
// successful
659+
.into_with_val(|| *handle.unwrap_unchecked())
660+
}
661+
662+
/// Reinstalls a protocol interface on a device handle. `old_interface` is replaced with `new_interface`.
663+
/// These interfaces may be the same, in which case the registered protocol notifies occur for the handle
664+
/// without replacing the interface.
665+
///
666+
/// As with `install_protocol_interface`, any process that has registered to wait for the installation of
667+
/// the interface is notified.
668+
///
669+
/// # Safety
670+
///
671+
/// The caller is responsible for ensuring that there are no references to the `old_interface` that is being
672+
/// removed.
673+
pub unsafe fn reinstall_protocol_interface(
674+
&self,
675+
handle: Handle,
676+
protocol: &Guid,
677+
old_interface: Option<NonNull<c_void>>,
678+
new_interface: Option<NonNull<c_void>>,
679+
) -> Result<()> {
680+
(self.reinstall_protocol_interface)(handle, protocol, old_interface, new_interface).into()
681+
}
682+
683+
/// Removes a protocol interface from a device handle.
684+
///
685+
/// # Safety
686+
///
687+
/// The caller is responsible for ensuring that there are no references to a protocol interface
688+
/// that has been removed. Some protocols may not be able to be removed as there is no information
689+
/// available regarding the references. This includes Console I/O, Block I/O, Disk I/o, and handles
690+
/// to device protocols.
691+
///
692+
/// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`.
693+
pub unsafe fn uninstall_protocol_interface(
694+
&self,
695+
handle: Handle,
696+
protocol: &Guid,
697+
interface: Option<NonNull<c_void>>,
698+
) -> Result<()> {
699+
(self.uninstall_protocol_interface)(handle, protocol, interface).into()
700+
}
701+
621702
/// Query a handle for a certain protocol.
622703
///
623704
/// This function attempts to get the protocol implementation of a handle,
@@ -655,6 +736,26 @@ impl BootServices {
655736
})
656737
}
657738

739+
/// Registers `event` to be signalled whenever a protocol interface is registered for
740+
/// `protocol` by `install_protocol_interface()` or `reinstall_protocol_interface()`.
741+
///
742+
/// Once `event` has been signalled, `BootServices::locate_handle()` can be used to identify
743+
/// the newly (re)installed handles that support `protocol`. The returned `SearchKey` on success
744+
/// corresponds to the `search_key` parameter in `locate_handle()`.
745+
///
746+
/// Events can be unregistered from protocol interface notification by calling `close_event()`.
747+
pub fn register_protocol_notify(
748+
&self,
749+
protocol: &Guid,
750+
event: Event,
751+
) -> Result<(Event, SearchKey)> {
752+
let mut key: MaybeUninit<SearchKey> = MaybeUninit::uninit();
753+
// Safety: we clone `event` a couple times, but there will be only one left once we return.
754+
unsafe { (self.register_protocol_notify)(protocol, event.unsafe_clone(), key.as_mut_ptr()) }
755+
// Safety: as long as this call is successful, `key` will be valid.
756+
.into_with_val(|| unsafe { (event.unsafe_clone(), key.assume_init()) })
757+
}
758+
658759
/// Enumerates all handles installed on the system which match a certain query.
659760
///
660761
/// You should first call this function with `None` for the output buffer,
@@ -677,8 +778,9 @@ impl BootServices {
677778

678779
// Obtain the needed data from the parameters.
679780
let (ty, guid, key) = match search_ty {
680-
SearchType::AllHandles => (0, ptr::null(), ptr::null_mut()),
681-
SearchType::ByProtocol(guid) => (2, guid as *const _, ptr::null_mut()),
781+
SearchType::AllHandles => (0, None, None),
782+
SearchType::ByRegisterNotify(registration) => (1, None, Some(registration)),
783+
SearchType::ByProtocol(guid) => (2, Some(guid), None),
682784
};
683785

684786
let status = unsafe { (self.locate_handle)(ty, guid, key, &mut buffer_size, buffer) };
@@ -1095,8 +1197,9 @@ impl BootServices {
10951197

10961198
// Obtain the needed data from the parameters.
10971199
let (ty, guid, key) = match search_ty {
1098-
SearchType::AllHandles => (0, ptr::null(), ptr::null_mut()),
1099-
SearchType::ByProtocol(guid) => (2, guid as *const _, ptr::null_mut()),
1200+
SearchType::AllHandles => (0, None, None),
1201+
SearchType::ByRegisterNotify(registration) => (1, None, Some(registration)),
1202+
SearchType::ByProtocol(guid) => (2, Some(guid), None),
11001203
};
11011204

11021205
unsafe { (self.locate_handle_buffer)(ty, guid, key, &mut num_handles, &mut buffer) }
@@ -1731,7 +1834,9 @@ pub enum SearchType<'guid> {
17311834
/// If the protocol implements the `Protocol` interface,
17321835
/// you can use the `from_proto` function to construct a new `SearchType`.
17331836
ByProtocol(&'guid Guid),
1734-
// TODO: add ByRegisterNotify once the corresponding function is implemented.
1837+
/// Return all handles that implement a protocol when an interface for that protocol
1838+
/// is (re)installed.
1839+
ByRegisterNotify(SearchKey),
17351840
}
17361841

17371842
impl<'guid> SearchType<'guid> {
@@ -1741,6 +1846,13 @@ impl<'guid> SearchType<'guid> {
17411846
}
17421847
}
17431848

1849+
impl SearchType<'_> {
1850+
/// Constructs a new search type from a SearchKey.
1851+
pub fn from_search_key(key: SearchKey) -> Self {
1852+
SearchType::ByRegisterNotify(key)
1853+
}
1854+
}
1855+
17441856
bitflags! {
17451857
/// Flags describing the type of an UEFI event and its attributes.
17461858
pub struct EventType: u32 {
@@ -1844,3 +1956,13 @@ impl<'a> HandleBuffer<'a> {
18441956
unsafe { slice::from_raw_parts(self.buffer, self.count) }
18451957
}
18461958
}
1959+
1960+
newtype_enum! {
1961+
/// Interface type of a protocol interface
1962+
///
1963+
/// Only has one variant when this was written (v2.10 of the UEFI spec)
1964+
pub enum InterfaceType: i32 => {
1965+
/// Native interface
1966+
NATIVE_INTERFACE = 0,
1967+
}
1968+
}

0 commit comments

Comments
 (0)