Skip to content

Commit 24d481c

Browse files
authored
Rollup merge of rust-lang#137477 - Ayush1325:uefi-service-binding, r=Noratrieb
uefi: Add Service Binding Protocol abstraction - Some UEFI protocols such as TCP4, TCP6, UDP4, UDP6, etc are managed by service binding protocol. - A new instance of such protocols is created and destroyed using the corresponding service binding protocol. - This PR adds abstractions to make using such protocols simpler using Rust Drop trait. - The reason to add these abstractions in a seperate PR from TCP4 Protocol is to make review easier. [EFI_SERVICE_BINDING_PROTCOL](https://uefi.org/specs/UEFI/2.11/11_Protocols_UEFI_Driver_Model.html#efi-service-binding-protocol) cc ````@nicholasbishop````
2 parents fde23c8 + 86aae8e commit 24d481c

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

Diff for: library/std/src/sys/pal/uefi/helpers.rs

+60-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles)
1111
1212
use r_efi::efi::{self, Guid};
13-
use r_efi::protocols::{device_path, device_path_to_text, shell};
13+
use r_efi::protocols::{device_path, device_path_to_text, service_binding, shell};
1414

1515
use crate::ffi::{OsStr, OsString};
1616
use crate::io::{self, const_error};
@@ -500,3 +500,62 @@ pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result<BorrowedDeviceP
500500

501501
Ok(BorrowedDevicePath::new(protocol))
502502
}
503+
504+
/// Helper for UEFI Protocols which are created and destroyed using
505+
/// [EFI_SERVICE_BINDING_PROTCOL](https://uefi.org/specs/UEFI/2.11/11_Protocols_UEFI_Driver_Model.html#efi-service-binding-protocol)
506+
pub(crate) struct ServiceProtocol {
507+
service_guid: r_efi::efi::Guid,
508+
handle: NonNull<crate::ffi::c_void>,
509+
child_handle: NonNull<crate::ffi::c_void>,
510+
}
511+
512+
impl ServiceProtocol {
513+
#[expect(dead_code)]
514+
pub(crate) fn open(service_guid: r_efi::efi::Guid) -> io::Result<Self> {
515+
let handles = locate_handles(service_guid)?;
516+
517+
for handle in handles {
518+
if let Ok(protocol) = open_protocol::<service_binding::Protocol>(handle, service_guid) {
519+
let Ok(child_handle) = Self::create_child(protocol) else {
520+
continue;
521+
};
522+
523+
return Ok(Self { service_guid, handle, child_handle });
524+
}
525+
}
526+
527+
Err(io::const_error!(io::ErrorKind::NotFound, "no service binding protocol found"))
528+
}
529+
530+
#[expect(dead_code)]
531+
pub(crate) fn child_handle(&self) -> NonNull<crate::ffi::c_void> {
532+
self.child_handle
533+
}
534+
535+
fn create_child(
536+
sbp: NonNull<service_binding::Protocol>,
537+
) -> io::Result<NonNull<crate::ffi::c_void>> {
538+
let mut child_handle: r_efi::efi::Handle = crate::ptr::null_mut();
539+
// SAFETY: A new handle is allocated if a pointer to NULL is passed.
540+
let r = unsafe { ((*sbp.as_ptr()).create_child)(sbp.as_ptr(), &mut child_handle) };
541+
542+
if r.is_error() {
543+
Err(crate::io::Error::from_raw_os_error(r.as_usize()))
544+
} else {
545+
NonNull::new(child_handle)
546+
.ok_or(const_error!(io::ErrorKind::Other, "null child handle"))
547+
}
548+
}
549+
}
550+
551+
impl Drop for ServiceProtocol {
552+
fn drop(&mut self) {
553+
if let Ok(sbp) = open_protocol::<service_binding::Protocol>(self.handle, self.service_guid)
554+
{
555+
// SAFETY: Child handle must be allocated by the current service binding protocol.
556+
let _ = unsafe {
557+
((*sbp.as_ptr()).destroy_child)(sbp.as_ptr(), self.child_handle.as_ptr())
558+
};
559+
}
560+
}
561+
}

0 commit comments

Comments
 (0)