1 //! `DevicePathToText` and `DevicePathFromText` Protocol 2 3 // Note on return types: the specification of the conversion functions 4 // is a little unusual in that they return a pointer rather than 5 // `EFI_STATUS`. A NULL pointer is used to indicate an error, and the 6 // spec says that will only happen if the input pointer is null (which 7 // can't happen here since we use references as input, not pointers), or 8 // if there is insufficient memory. So we treat any NULL output as an 9 // `OUT_OF_RESOURCES` error. 10 11 use crate::proto::device_path::{DevicePath, DevicePathNode}; 12 use crate::proto::unsafe_protocol; 13 use crate::{boot, CStr16, Char16, Result, Status}; 14 use core::ops::Deref; 15 use core::ptr::NonNull; 16 use uefi_raw::protocol::device_path::{DevicePathFromTextProtocol, DevicePathToTextProtocol}; 17 18 /// This struct is a wrapper of `display_only` parameter 19 /// used by Device Path to Text protocol. 20 /// 21 /// The `display_only` parameter controls whether the longer 22 /// (parseable) or shorter (display-only) form of the conversion 23 /// is used. If `display_only` is TRUE, then the shorter text 24 /// representation of the display node is used, where applicable. 25 /// If `display_only` is FALSE, then the longer text representation 26 /// of the display node is used. 27 #[derive(Clone, Copy, Debug)] 28 pub struct DisplayOnly(pub bool); 29 30 /// This struct is a wrapper of `allow_shortcuts` parameter 31 /// used by Device Path to Text protocol. 32 /// 33 /// The `allow_shortcuts` is FALSE, then the shortcut forms of 34 /// text representation for a device node cannot be used. A 35 /// shortcut form is one which uses information other than the 36 /// type or subtype. If `allow_shortcuts is TRUE, then the 37 /// shortcut forms of text representation for a device node 38 /// can be used, where applicable. 39 #[derive(Clone, Copy, Debug)] 40 pub struct AllowShortcuts(pub bool); 41 42 /// Wrapper for a string internally allocated from 43 /// UEFI boot services memory. 44 #[derive(Debug)] 45 pub struct PoolString(NonNull<Char16>); 46 47 impl PoolString { new(text: *const Char16) -> Result<Self>48 fn new(text: *const Char16) -> Result<Self> { 49 NonNull::new(text.cast_mut()) 50 .map(Self) 51 .ok_or(Status::OUT_OF_RESOURCES.into()) 52 } 53 } 54 55 impl Deref for PoolString { 56 type Target = CStr16; 57 deref(&self) -> &Self::Target58 fn deref(&self) -> &Self::Target { 59 unsafe { CStr16::from_ptr(self.0.as_ptr()) } 60 } 61 } 62 63 impl Drop for PoolString { drop(&mut self)64 fn drop(&mut self) { 65 unsafe { boot::free_pool(self.0.cast()) }.expect("Failed to free pool [{addr:#?}]"); 66 } 67 } 68 69 /// Device Path to Text protocol. 70 /// 71 /// This protocol provides common utility functions for converting device 72 /// nodes and device paths to a text representation. 73 #[derive(Debug)] 74 #[repr(transparent)] 75 #[unsafe_protocol(DevicePathToTextProtocol::GUID)] 76 pub struct DevicePathToText(DevicePathToTextProtocol); 77 78 impl DevicePathToText { 79 /// Convert a device node to its text representation. 80 /// 81 /// Returns an [`OUT_OF_RESOURCES`] error if there is insufficient 82 /// memory for the conversion. 83 /// 84 /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES convert_device_node_to_text( &self, device_node: &DevicePathNode, display_only: DisplayOnly, allow_shortcuts: AllowShortcuts, ) -> Result<PoolString>85 pub fn convert_device_node_to_text( 86 &self, 87 device_node: &DevicePathNode, 88 display_only: DisplayOnly, 89 allow_shortcuts: AllowShortcuts, 90 ) -> Result<PoolString> { 91 let text_device_node = unsafe { 92 (self.0.convert_device_node_to_text)( 93 device_node.as_ffi_ptr().cast(), 94 display_only.0, 95 allow_shortcuts.0, 96 ) 97 }; 98 PoolString::new(text_device_node.cast()) 99 } 100 101 /// Convert a device path to its text representation. 102 /// 103 /// Returns an [`OUT_OF_RESOURCES`] error if there is insufficient 104 /// memory for the conversion. 105 /// 106 /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES convert_device_path_to_text( &self, device_path: &DevicePath, display_only: DisplayOnly, allow_shortcuts: AllowShortcuts, ) -> Result<PoolString>107 pub fn convert_device_path_to_text( 108 &self, 109 device_path: &DevicePath, 110 display_only: DisplayOnly, 111 allow_shortcuts: AllowShortcuts, 112 ) -> Result<PoolString> { 113 let text_device_path = unsafe { 114 (self.0.convert_device_path_to_text)( 115 device_path.as_ffi_ptr().cast(), 116 display_only.0, 117 allow_shortcuts.0, 118 ) 119 }; 120 PoolString::new(text_device_path.cast()) 121 } 122 } 123 124 /// Device Path from Text protocol. 125 /// 126 /// This protocol provides common utilities for converting text to 127 /// device paths and device nodes. 128 #[derive(Debug)] 129 #[repr(transparent)] 130 #[unsafe_protocol("05c99a21-c70f-4ad2-8a5f-35df3343f51e")] 131 pub struct DevicePathFromText(DevicePathFromTextProtocol); 132 133 impl DevicePathFromText { 134 /// Convert text to the binary representation of a device node. 135 /// 136 /// `text_device_node` is the text representation of a device node. 137 /// Conversion starts with the first character and continues until 138 /// the first non-device node character. 139 /// 140 /// Returns an [`OUT_OF_RESOURCES`] error if there is insufficient 141 /// memory for the conversion. 142 /// 143 /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES convert_text_to_device_node( &self, text_device_node: &CStr16, ) -> Result<&DevicePathNode>144 pub fn convert_text_to_device_node( 145 &self, 146 text_device_node: &CStr16, 147 ) -> Result<&DevicePathNode> { 148 unsafe { 149 let ptr = (self.0.convert_text_to_device_node)(text_device_node.as_ptr().cast()); 150 if ptr.is_null() { 151 Err(Status::OUT_OF_RESOURCES.into()) 152 } else { 153 Ok(DevicePathNode::from_ffi_ptr(ptr.cast())) 154 } 155 } 156 } 157 158 /// Convert a text to its binary device path representation. 159 /// 160 /// `text_device_path` is the text representation of a device path. 161 /// Conversion starts with the first character and continues until 162 /// the first non-device path character. 163 /// 164 /// Returns an [`OUT_OF_RESOURCES`] error if there is insufficient 165 /// memory for the conversion. 166 /// 167 /// [`OUT_OF_RESOURCES`]: Status::OUT_OF_RESOURCES convert_text_to_device_path(&self, text_device_path: &CStr16) -> Result<&DevicePath>168 pub fn convert_text_to_device_path(&self, text_device_path: &CStr16) -> Result<&DevicePath> { 169 unsafe { 170 let ptr = (self.0.convert_text_to_device_path)(text_device_path.as_ptr().cast()); 171 if ptr.is_null() { 172 Err(Status::OUT_OF_RESOURCES.into()) 173 } else { 174 Ok(DevicePath::from_ffi_ptr(ptr.cast())) 175 } 176 } 177 } 178 } 179