Skip to content

Commit

Permalink
uefi: Add Service Binding Protocol abstraction
Browse files Browse the repository at this point in the history
- 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)

Signed-off-by: Ayush Singh <ayush@beagleboard.org>
  • Loading branch information
Ayush1325 committed Feb 27, 2025
1 parent bb2cc59 commit 6afe33f
Showing 1 changed file with 59 additions and 1 deletion.
60 changes: 59 additions & 1 deletion library/std/src/sys/pal/uefi/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//! - 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)
use r_efi::efi::{self, Guid};
use r_efi::protocols::{device_path, device_path_to_text, shell};
use r_efi::protocols::{device_path, device_path_to_text, service_binding, shell};

use crate::ffi::{OsStr, OsString};
use crate::io::{self, const_error};
Expand Down Expand Up @@ -500,3 +500,61 @@ pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result<BorrowedDeviceP

Ok(BorrowedDevicePath::new(protocol))
}

/// Helper for UEFI Protocols which are created and destroyed using
/// [EFI_SERVICE_BINDING_PROTCOL](https://uefi.org/specs/UEFI/2.11/11_Protocols_UEFI_Driver_Model.html#efi-service-binding-protocol)
#[allow(dead_code)]
pub(crate) struct ServiceProtocol {
service_guid: r_efi::efi::Guid,
handle: NonNull<crate::ffi::c_void>,
child_handle: NonNull<crate::ffi::c_void>,
}

impl ServiceProtocol {
#[allow(dead_code)]
pub(crate) fn open(service_guid: r_efi::efi::Guid) -> io::Result<Self> {
let handles = locate_handles(service_guid)?;

for handle in handles {
if let Ok(protocol) = open_protocol::<service_binding::Protocol>(handle, service_guid) {
let Ok(child_handle) = Self::create_child(protocol) else {
continue;
};

return Ok(Self { service_guid, handle, child_handle });
}
}

Err(io::const_error!(io::ErrorKind::NotFound, "No service binding protocol found"))
}

#[allow(dead_code)]
pub(crate) fn child_handle(&self) -> NonNull<crate::ffi::c_void> {
self.child_handle
}

fn create_child(
sbp: NonNull<service_binding::Protocol>,
) -> io::Result<NonNull<crate::ffi::c_void>> {
let mut child_handle: r_efi::efi::Handle = crate::ptr::null_mut();
let r = unsafe { ((*sbp.as_ptr()).create_child)(sbp.as_ptr(), &mut child_handle) };

if r.is_error() {
Err(crate::io::Error::from_raw_os_error(r.as_usize()))
} else {
NonNull::new(child_handle)
.ok_or(const_error!(io::ErrorKind::Other, "null child handle"))
}
}
}

impl Drop for ServiceProtocol {
fn drop(&mut self) {
if let Ok(sbp) = open_protocol::<service_binding::Protocol>(self.handle, self.service_guid)
{
let _ = unsafe {
((*sbp.as_ptr()).destroy_child)(sbp.as_ptr(), self.child_handle.as_ptr())
};
}
}
}

0 comments on commit 6afe33f

Please sign in to comment.