|
77 | 77 |
|
78 | 78 | pub mod build;
|
79 | 79 | pub mod text;
|
| 80 | +pub mod util; |
80 | 81 |
|
81 | 82 | mod device_path_gen;
|
82 | 83 | pub use device_path_gen::{
|
83 | 84 | acpi, bios_boot_spec, end, hardware, media, messaging, DevicePathNodeEnum,
|
84 | 85 | };
|
85 | 86 | pub use uefi_raw::protocol::device_path::{DeviceSubType, DeviceType};
|
86 | 87 |
|
| 88 | +use crate::mem::PoolAllocation; |
87 | 89 | use crate::proto::{unsafe_protocol, ProtocolPointer};
|
88 | 90 | use core::ffi::c_void;
|
89 | 91 | use core::fmt::{self, Debug, Display, Formatter};
|
@@ -94,6 +96,7 @@ use ptr_meta::Pointee;
|
94 | 96 | use {
|
95 | 97 | crate::boot::{self, OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol, SearchType},
|
96 | 98 | crate::proto::device_path::text::{AllowShortcuts, DevicePathToText, DisplayOnly},
|
| 99 | +crate::proto::device_path::util::DevicePathUtilities, |
97 | 100 | crate::{CString16, Identify},
|
98 | 101 | alloc::borrow::ToOwned,
|
99 | 102 | alloc::boxed::Box,
|
@@ -108,6 +111,30 @@ opaque_type! {
|
108 | 111 | pub struct FfiDevicePath;
|
109 | 112 | }
|
110 | 113 |
|
| 114 | +/// Device path allocated from UEFI pool memory. |
| 115 | +#[derive(Debug)] |
| 116 | +pub struct PoolDevicePath(pub(crate) PoolAllocation); |
| 117 | + |
| 118 | +impl Deref for PoolDevicePath { |
| 119 | +type Target = DevicePath; |
| 120 | + |
| 121 | +fn deref(&self) -> &Self::Target { |
| 122 | +unsafe { DevicePath::from_ffi_ptr(self.0.as_ptr().as_ptr().cast()) } |
| 123 | +} |
| 124 | +} |
| 125 | + |
| 126 | +/// Device path node allocated from UEFI pool memory. |
| 127 | +#[derive(Debug)] |
| 128 | +pub struct PoolDevicePathNode(pub(crate) PoolAllocation); |
| 129 | + |
| 130 | +impl Deref for PoolDevicePathNode { |
| 131 | +type Target = DevicePathNode; |
| 132 | + |
| 133 | +fn deref(&self) -> &Self::Target { |
| 134 | +unsafe { DevicePathNode::from_ffi_ptr(self.0.as_ptr().as_ptr().cast()) } |
| 135 | +} |
| 136 | +} |
| 137 | + |
111 | 138 | /// Header that appears at the start of every [`DevicePathNode`].
|
112 | 139 | #[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
113 | 140 | #[repr(C, packed)]
|
@@ -499,6 +526,25 @@ impl DevicePath {
|
499 | 526 | })
|
500 | 527 | .map_err(|_| DevicePathToTextError::OutOfMemory)
|
501 | 528 | }
|
| 529 | + |
| 530 | +/// Allocates and returns a new [`DevicePath`] by copying this one and appending the given `right` path. |
| 531 | + #[cfg(feature = "alloc")] |
| 532 | +pub fn append_path(&self, right: &Self) -> Result<PoolDevicePath, DevicePathUtilitiesError> { |
| 533 | +open_utility_protocol()? |
| 534 | +.append_path(self, right) |
| 535 | +.map_err(|_| DevicePathUtilitiesError::OutOfMemory) |
| 536 | +} |
| 537 | + |
| 538 | +/// Allocates and returns a new [`DevicePath`] by copying this one and appending the given `right` node. |
| 539 | + #[cfg(feature = "alloc")] |
| 540 | +pub fn append_node( |
| 541 | +&self, |
| 542 | +right: &DevicePathNode, |
| 543 | +) -> Result<PoolDevicePath, DevicePathUtilitiesError> { |
| 544 | +open_utility_protocol()? |
| 545 | +.append_node(self, right) |
| 546 | +.map_err(|_| DevicePathUtilitiesError::OutOfMemory) |
| 547 | +} |
502 | 548 | }
|
503 | 549 |
|
504 | 550 | impl Debug for DevicePath {
|
@@ -745,6 +791,63 @@ fn open_text_protocol() -> Result<ScopedProtocol<DevicePathToText>, DevicePathTo
|
745 | 791 | .map_err(DevicePathToTextError::CantOpenProtocol)
|
746 | 792 | }
|
747 | 793 |
|
| 794 | +/// Errors that may occur when working with the [`DevicePathUtilities`] protocol. |
| 795 | +/// |
| 796 | +/// These errors are typically encountered during operations involving device |
| 797 | +/// paths, such as appending or manipulating path segments. |
| 798 | +#[derive(Debug)] |
| 799 | +pub enum DevicePathUtilitiesError { |
| 800 | +/// Can't locate a handle buffer with handles associated with the |
| 801 | + /// [`DevicePathUtilities`] protocol. |
| 802 | + CantLocateHandleBuffer(crate::Error), |
| 803 | +/// No handle supporting the [`DevicePathUtilities`] protocol was found. |
| 804 | + NoHandle, |
| 805 | +/// The handle supporting the [`DevicePathUtilities`] protocol exists but |
| 806 | + /// it could not be opened. |
| 807 | + CantOpenProtocol(crate::Error), |
| 808 | +/// Memory allocation failed during device path operations. |
| 809 | + OutOfMemory, |
| 810 | +} |
| 811 | + |
| 812 | +impl Display for DevicePathUtilitiesError { |
| 813 | +fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
| 814 | +write!(f, "{self:?}") |
| 815 | +} |
| 816 | +} |
| 817 | + |
| 818 | +impl core::error::Error for DevicePathUtilitiesError { |
| 819 | +fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { |
| 820 | +match self { |
| 821 | +Self::CantLocateHandleBuffer(e) => Some(e), |
| 822 | +Self::CantOpenProtocol(e) => Some(e), |
| 823 | +_ => None, |
| 824 | +} |
| 825 | +} |
| 826 | +} |
| 827 | + |
| 828 | +/// Helper function to open the [`DevicePathUtilities`] protocol using the boot |
| 829 | +/// services. |
| 830 | +#[cfg(feature = "alloc")] |
| 831 | +fn open_utility_protocol() -> Result<ScopedProtocol<DevicePathUtilities>, DevicePathUtilitiesError> |
| 832 | +{ |
| 833 | +let &handle = boot::locate_handle_buffer(SearchType::ByProtocol(&DevicePathToText::GUID)) |
| 834 | +.map_err(DevicePathUtilitiesError::CantLocateHandleBuffer)? |
| 835 | +.first() |
| 836 | +.ok_or(DevicePathUtilitiesError::NoHandle)?; |
| 837 | + |
| 838 | +unsafe { |
| 839 | +boot::open_protocol::<DevicePathUtilities>( |
| 840 | +OpenProtocolParams { |
| 841 | +handle, |
| 842 | +agent: boot::image_handle(), |
| 843 | +controller: None, |
| 844 | +}, |
| 845 | +OpenProtocolAttributes::GetProtocol, |
| 846 | +) |
| 847 | +} |
| 848 | +.map_err(DevicePathUtilitiesError::CantOpenProtocol) |
| 849 | +} |
| 850 | + |
748 | 851 | #[cfg(test)]
|
749 | 852 | mod tests {
|
750 | 853 | use super::*;
|
|
0 commit comments