Skip to main content

uefi/proto/device_path/
text.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! Protocols for converting between UEFI strings and [`DevicePath`]/[`DevicePathNode`].
4
5// Note on return types: the specification of the conversion functions
6// is a little unusual in that they return a pointer rather than
7// `EFI_STATUS`. A NULL pointer is used to indicate an error, and the
8// spec says that will only happen if the input pointer is null (which
9// can't happen here since we use references as input, not pointers), or
10// if there is insufficient memory. So we treat any NULL output as an
11// `OUT_OF_RESOURCES` error.
12
13use crate::data_types::PoolString;
14use crate::mem::PoolAllocation;
15use crate::proto::device_path::{DevicePath, DevicePathNode};
16use crate::proto::unsafe_protocol;
17use crate::{CStr16, Result, Status};
18use core::ptr::NonNull;
19use uefi_raw::protocol::device_path::{DevicePathFromTextProtocol, DevicePathToTextProtocol};
20
21use super::{PoolDevicePath, PoolDevicePathNode};
22
23/// Parameter for [`DevicePathToText`] that alters the output format.
24///
25/// * `DisplayOnly(false)` produces parseable output.
26/// * `DisplayOnly(true)` produces output that _may_ be shorter and not
27///   parseable.
28///
29/// Example of how a node's text representation may be altered by this
30/// parameter:
31/// * `DisplayOnly(false)`: `Ata(Primary,Master,0x1)`
32/// * `DisplayOnly(true)`: `Ata(0x1)`
33#[derive(Clone, Copy, Debug)]
34pub struct DisplayOnly(pub bool);
35
36/// Parameter for [`DevicePathToText`] that alters the output format.
37///
38/// * `AllowShortcuts(false)`: node names are based only on the node's type and
39///   subtype.
40/// * `AllowShortcuts(true)` _may_ alter the node name based on other fields
41///   within the node.
42///
43/// Example of how a node's text representation may be altered by this
44/// parameter:
45/// * `AllowShortcuts(false)`: `VenMsg(E0C14753-F9BE-11D2-9A0C-0090273FC14D)`
46/// * `AllowShortcuts(true)`: `VenPcAnsi()`
47#[derive(Clone, Copy, Debug)]
48pub struct AllowShortcuts(pub bool);
49
50/// Device Path to Text [`Protocol`].
51///
52/// Protocol for converting a [`DevicePath`] or `DevicePathNode`] to a string.
53///
54/// [`Protocol`]: uefi::proto::Protocol
55#[derive(Debug)]
56#[repr(transparent)]
57#[unsafe_protocol(DevicePathToTextProtocol::GUID)]
58pub struct DevicePathToText(DevicePathToTextProtocol);
59
60impl DevicePathToText {
61    /// Convert a [`DevicePathNode`] to a [`PoolString`].
62    ///
63    /// Returns an [`OUT_OF_RESOURCES`] error if there is insufficient
64    /// memory for the conversion.
65    ///
66    /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES
67    pub fn convert_device_node_to_text(
68        &self,
69        device_node: &DevicePathNode,
70        display_only: DisplayOnly,
71        allow_shortcuts: AllowShortcuts,
72    ) -> Result<PoolString> {
73        let text = unsafe {
74            (self.0.convert_device_node_to_text)(
75                device_node.as_ffi_ptr().cast(),
76                display_only.0.into(),
77                allow_shortcuts.0.into(),
78            )
79        };
80        unsafe { PoolString::new(text.cast()) }
81    }
82
83    /// Convert a [`DevicePath`] to a [`PoolString`].
84    ///
85    /// Returns an [`OUT_OF_RESOURCES`] error if there is insufficient
86    /// memory for the conversion.
87    ///
88    /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES
89    pub fn convert_device_path_to_text(
90        &self,
91        device_path: &DevicePath,
92        display_only: DisplayOnly,
93        allow_shortcuts: AllowShortcuts,
94    ) -> Result<PoolString> {
95        let text = unsafe {
96            (self.0.convert_device_path_to_text)(
97                device_path.as_ffi_ptr().cast(),
98                display_only.0.into(),
99                allow_shortcuts.0.into(),
100            )
101        };
102        unsafe { PoolString::new(text.cast()) }
103    }
104}
105
106/// Device Path from Text [`Protocol`].
107///
108/// Protocol for converting a string to a [`DevicePath`] or `DevicePathNode`].
109///
110/// [`Protocol`]: uefi::proto::Protocol
111#[derive(Debug)]
112#[repr(transparent)]
113#[unsafe_protocol("05c99a21-c70f-4ad2-8a5f-35df3343f51e")]
114pub struct DevicePathFromText(DevicePathFromTextProtocol);
115
116impl DevicePathFromText {
117    /// Convert a [`CStr16`] to a [`DevicePathNode`].
118    ///
119    /// If a non-device-node character is encountered, the rest of the string is ignored.
120    ///
121    /// Returns an [`OUT_OF_RESOURCES`] error if there is insufficient
122    /// memory for the conversion.
123    ///
124    /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES
125    pub fn convert_text_to_device_node(
126        &self,
127        text_device_node: &CStr16,
128    ) -> Result<PoolDevicePathNode> {
129        unsafe {
130            let ptr = (self.0.convert_text_to_device_node)(text_device_node.as_ptr().cast());
131            NonNull::new(ptr.cast_mut())
132                .map(|p| PoolDevicePathNode(PoolAllocation::new(p.cast())))
133                .ok_or_else(|| Status::OUT_OF_RESOURCES.into())
134        }
135    }
136
137    /// Convert a [`CStr16`] to a [`DevicePath`].
138    ///
139    /// If a non-device-node character is encountered, the rest of the string is ignored.
140    ///
141    /// Returns an [`OUT_OF_RESOURCES`] error if there is insufficient
142    /// memory for the conversion.
143    ///
144    /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES
145    pub fn convert_text_to_device_path(&self, text_device_path: &CStr16) -> Result<PoolDevicePath> {
146        unsafe {
147            let ptr = (self.0.convert_text_to_device_path)(text_device_path.as_ptr().cast());
148            NonNull::new(ptr.cast_mut())
149                .map(|p| PoolDevicePath(PoolAllocation::new(p.cast())))
150                .ok_or_else(|| Status::OUT_OF_RESOURCES.into())
151        }
152    }
153}