Skip to content

Commit 0bac239

Browse files
authored
Merge pull request #1300 from nicholasbishop/bishop-protocol-management
Add freestanding {install,reinstall,uninstall}_protocol_interface functions
2 parents e251d03 + e06b7fd commit 0bac239

File tree

2 files changed

+134
-2
lines changed

2 files changed

+134
-2
lines changed

uefi-test-runner/src/boot/misc.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use uefi::table::boot::{
99
Tpl,
1010
};
1111
use uefi::table::{Boot, SystemTable};
12-
use uefi::{boot, guid, Event, Guid, Identify};
12+
use uefi::{boot, guid, Event, Guid, Identify, Status};
1313

1414
pub fn test(st: &SystemTable<Boot>) {
1515
let bt = st.boot_services();
@@ -24,6 +24,7 @@ pub fn test(st: &SystemTable<Boot>) {
2424
test_watchdog(bt);
2525
info!("Testing protocol handler services...");
2626
test_register_protocol_notify(bt);
27+
test_protocol_interface_management();
2728
test_install_protocol_interface(bt);
2829
test_reinstall_protocol_interface(bt);
2930
test_uninstall_protocol_interface(bt);
@@ -133,6 +134,48 @@ fn test_register_protocol_notify(bt: &BootServices) {
133134
.expect("Failed to register protocol notify fn");
134135
}
135136

137+
fn test_protocol_interface_management() {
138+
let mut interface = TestProtocol { data: 123 };
139+
let interface_ptr: *mut _ = &mut interface;
140+
141+
// Install the protocol.
142+
let handle = unsafe {
143+
boot::install_protocol_interface(None, &TestProtocol::GUID, interface_ptr.cast())
144+
}
145+
.unwrap();
146+
147+
// Verify the handle was installed.
148+
assert_eq!(
149+
&*boot::locate_handle_buffer(SearchType::from_proto::<TestProtocol>()).unwrap(),
150+
[handle]
151+
);
152+
153+
// Re-install the protocol.
154+
unsafe {
155+
boot::reinstall_protocol_interface(
156+
handle,
157+
&TestProtocol::GUID,
158+
interface_ptr.cast(),
159+
interface_ptr.cast(),
160+
)
161+
}
162+
.unwrap();
163+
164+
// Uninstall the protocol.
165+
unsafe {
166+
boot::uninstall_protocol_interface(handle, &TestProtocol::GUID, interface_ptr.cast())
167+
}
168+
.unwrap();
169+
170+
// Verify the protocol was uninstalled.
171+
assert_eq!(
172+
boot::locate_handle_buffer(SearchType::from_proto::<TestProtocol>())
173+
.unwrap_err()
174+
.status(),
175+
Status::NOT_FOUND
176+
);
177+
}
178+
136179
fn test_install_protocol_interface(bt: &BootServices) {
137180
info!("Installing TestProtocol");
138181

uefi/src/boot.rs

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use core::ops::{Deref, DerefMut};
1111
use core::ptr::{self, NonNull};
1212
use core::sync::atomic::{AtomicPtr, Ordering};
1313
use core::{mem, slice};
14-
use uefi::{table, Char16, Event, Handle, Result, Status, StatusExt};
14+
use uefi::{table, Char16, Event, Guid, Handle, Result, Status, StatusExt};
15+
use uefi_raw::table::boot::InterfaceType;
1516

1617
#[cfg(doc)]
1718
use {
@@ -299,6 +300,94 @@ pub fn disconnect_controller(
299300
.to_result_with_err(|_| ())
300301
}
301302

303+
/// Installs a protocol interface on a device handle.
304+
///
305+
/// When a protocol interface is installed, firmware will call all functions
306+
/// that have registered to wait for that interface to be installed.
307+
///
308+
/// If `handle` is `None`, a new handle will be created and returned.
309+
///
310+
/// # Safety
311+
///
312+
/// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`.
313+
///
314+
/// # Errors
315+
///
316+
/// * [`Status::OUT_OF_RESOURCES`]: failed to allocate a new handle.
317+
/// * [`Status::INVALID_PARAMETER`]: this protocol is already installed on the handle.
318+
pub unsafe fn install_protocol_interface(
319+
handle: Option<Handle>,
320+
protocol: &Guid,
321+
interface: *const c_void,
322+
) -> Result<Handle> {
323+
let bt = boot_services_raw_panicking();
324+
let bt = unsafe { bt.as_ref() };
325+
326+
let mut handle = Handle::opt_to_ptr(handle);
327+
((bt.install_protocol_interface)(
328+
&mut handle,
329+
protocol,
330+
InterfaceType::NATIVE_INTERFACE,
331+
interface,
332+
))
333+
.to_result_with_val(|| Handle::from_ptr(handle).unwrap())
334+
}
335+
336+
/// Reinstalls a protocol interface on a device handle. `old_interface` is replaced with `new_interface`.
337+
/// These interfaces may be the same, in which case the registered protocol notifications occur for the handle
338+
/// without replacing the interface.
339+
///
340+
/// As with `install_protocol_interface`, any process that has registered to wait for the installation of
341+
/// the interface is notified.
342+
///
343+
/// # Safety
344+
///
345+
/// The caller is responsible for ensuring that there are no references to the `old_interface` that is being
346+
/// removed.
347+
///
348+
/// # Errors
349+
///
350+
/// * [`Status::NOT_FOUND`]: the old interface was not found on the handle.
351+
/// * [`Status::ACCESS_DENIED`]: the old interface is still in use and cannot be uninstalled.
352+
pub unsafe fn reinstall_protocol_interface(
353+
handle: Handle,
354+
protocol: &Guid,
355+
old_interface: *const c_void,
356+
new_interface: *const c_void,
357+
) -> Result<()> {
358+
let bt = boot_services_raw_panicking();
359+
let bt = unsafe { bt.as_ref() };
360+
361+
(bt.reinstall_protocol_interface)(handle.as_ptr(), protocol, old_interface, new_interface)
362+
.to_result()
363+
}
364+
365+
/// Removes a protocol interface from a device handle.
366+
///
367+
/// # Safety
368+
///
369+
/// The caller is responsible for ensuring that there are no references to a protocol interface
370+
/// that has been removed. Some protocols may not be able to be removed as there is no information
371+
/// available regarding the references. This includes Console I/O, Block I/O, Disk I/o, and handles
372+
/// to device protocols.
373+
///
374+
/// The caller is responsible for ensuring that they pass a valid `Guid` for `protocol`.
375+
///
376+
/// # Errors
377+
///
378+
/// * [`Status::NOT_FOUND`]: the interface was not found on the handle.
379+
/// * [`Status::ACCESS_DENIED`]: the interface is still in use and cannot be uninstalled.
380+
pub unsafe fn uninstall_protocol_interface(
381+
handle: Handle,
382+
protocol: &Guid,
383+
interface: *const c_void,
384+
) -> Result<()> {
385+
let bt = boot_services_raw_panicking();
386+
let bt = unsafe { bt.as_ref() };
387+
388+
(bt.uninstall_protocol_interface)(handle.as_ptr(), protocol, interface).to_result()
389+
}
390+
302391
/// Returns an array of handles that support the requested protocol in a
303392
/// pool-allocated buffer.
304393
///

0 commit comments

Comments
 (0)