1 //! Data type definitions 2 //! 3 //! This module defines the basic data types that are used throughout uefi-rs 4 5 use core::ffi::c_void; 6 use core::ptr::{self, NonNull}; 7 8 /// Opaque handle to an UEFI entity (protocol, image...), guaranteed to be non-null. 9 /// 10 /// If you need to have a nullable handle (for a custom UEFI FFI for example) use `Option<Handle>`. 11 #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] 12 #[repr(transparent)] 13 pub struct Handle(NonNull<c_void>); 14 15 impl Handle { 16 /// Creates a new [`Handle`]. 17 /// 18 /// # Safety 19 /// This function is unsafe because the caller must be sure that the pointer 20 /// is valid. Otherwise, further operations on the object might result in 21 /// undefined behaviour, even if the methods aren't marked as unsafe. 22 #[must_use] new(ptr: NonNull<c_void>) -> Self23 pub const unsafe fn new(ptr: NonNull<c_void>) -> Self { 24 Self(ptr) 25 } 26 27 /// Creates a new [`Handle`] from a raw address. The address might 28 /// come from the Multiboot2 information structure or something similar. 29 /// 30 /// # Example 31 /// ```no_run 32 /// use core::ffi::c_void; 33 /// use uefi::Handle; 34 /// 35 /// let image_handle_addr = 0xdeadbeef as *mut c_void; 36 /// 37 /// let uefi_image_handle = unsafe { 38 /// Handle::from_ptr(image_handle_addr).expect("Pointer must not be null!") 39 /// }; 40 /// ``` 41 /// 42 /// # Safety 43 /// This function is unsafe because the caller must be sure that the pointer 44 /// is valid. Otherwise, further operations on the object might result in 45 /// undefined behaviour, even if the methods aren't marked as unsafe. from_ptr(ptr: *mut c_void) -> Option<Self>46 pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> { 47 // shorthand for "|ptr| Self(ptr)" 48 NonNull::new(ptr).map(Self) 49 } 50 51 /// Get the underlying raw pointer. 52 #[must_use] as_ptr(&self) -> *mut c_void53 pub const fn as_ptr(&self) -> *mut c_void { 54 self.0.as_ptr() 55 } 56 opt_to_ptr(handle: Option<Self>) -> *mut c_void57 pub(crate) fn opt_to_ptr(handle: Option<Self>) -> *mut c_void { 58 handle.map(|h| h.0.as_ptr()).unwrap_or(ptr::null_mut()) 59 } 60 } 61 62 /// Handle to an event structure, guaranteed to be non-null. 63 /// 64 /// If you need to have a nullable event, use `Option<Event>`. 65 #[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] 66 #[repr(transparent)] 67 pub struct Event(NonNull<c_void>); 68 69 impl Event { 70 /// Clone this `Event` 71 /// 72 /// # Safety 73 /// When an event is closed by calling [`boot::close_event`], that event and ALL references 74 /// to it are invalidated and the underlying memory is freed by firmware. The caller must ensure 75 /// that any clones of a closed `Event` are never used again. 76 /// 77 /// [`boot::close_event`]: crate::boot::close_event 78 #[must_use] unsafe_clone(&self) -> Self79 pub const unsafe fn unsafe_clone(&self) -> Self { 80 Self(self.0) 81 } 82 83 /// Create an `Event` from a raw pointer. 84 /// 85 /// # Safety 86 /// 87 /// The caller must ensure that the pointer is valid. from_ptr(ptr: *mut c_void) -> Option<Self>88 pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> { 89 NonNull::new(ptr).map(Self) 90 } 91 92 /// Get the underlying raw pointer. 93 #[must_use] as_ptr(&self) -> *mut c_void94 pub const fn as_ptr(&self) -> *mut c_void { 95 self.0.as_ptr() 96 } 97 } 98 99 /// Trait for querying the alignment of a struct. 100 /// 101 /// For a statically-sized type the alignment can be retrieved with 102 /// [`core::mem::align_of`]. For a dynamically-sized type (DST), 103 /// [`core::mem::align_of_val`] provides the alignment given a reference. But in 104 /// some cases it's helpful to know the alignment of a DST prior to having a 105 /// value, meaning there's no reference to pass to `align_of_val`. For example, 106 /// when using an API that creates a value using a `[u8]` buffer, the alignment 107 /// of the buffer must be checked. The `Align` trait makes that possible by 108 /// allowing the appropriate alignment to be manually specified. 109 pub trait Align { 110 /// Required memory alignment for this type alignment() -> usize111 fn alignment() -> usize; 112 113 /// Calculate the offset from `val` necessary to make it aligned, 114 /// rounding up. For example, if `val` is 1 and the alignment is 8, 115 /// this will return 7. Returns 0 if `val == 0`. 116 #[must_use] offset_up_to_alignment(val: usize) -> usize117 fn offset_up_to_alignment(val: usize) -> usize { 118 assert!(Self::alignment() != 0); 119 let r = val % Self::alignment(); 120 if r == 0 { 121 0 122 } else { 123 Self::alignment() - r 124 } 125 } 126 127 /// Round `val` up so that it is aligned. 128 #[must_use] round_up_to_alignment(val: usize) -> usize129 fn round_up_to_alignment(val: usize) -> usize { 130 val + Self::offset_up_to_alignment(val) 131 } 132 133 /// Get a subslice of `buf` where the address of the first element 134 /// is aligned. Returns `None` if no element of the buffer is 135 /// aligned. align_buf(buf: &mut [u8]) -> Option<&mut [u8]>136 fn align_buf(buf: &mut [u8]) -> Option<&mut [u8]> { 137 let offset = buf.as_ptr().align_offset(Self::alignment()); 138 buf.get_mut(offset..) 139 } 140 141 /// Assert that some storage is correctly aligned for this type assert_aligned(storage: &mut [u8])142 fn assert_aligned(storage: &mut [u8]) { 143 if !storage.is_empty() { 144 assert_eq!( 145 storage.as_ptr().align_offset(Self::alignment()), 146 0, 147 "The provided storage is not correctly aligned for this type" 148 ) 149 } 150 } 151 } 152 153 impl Align for [u8] { alignment() -> usize154 fn alignment() -> usize { 155 1 156 } 157 } 158 159 mod guid; 160 pub use guid::{Guid, Identify}; 161 162 pub mod chars; 163 pub use chars::{Char16, Char8}; 164 165 #[macro_use] 166 mod opaque; 167 168 mod strs; 169 pub use strs::{ 170 CStr16, CStr8, EqStrUntilNul, FromSliceWithNulError, FromStrWithBufError, UnalignedCStr16Error, 171 }; 172 173 /// These functions are used in the implementation of the [`cstr8`] macro. 174 #[doc(hidden)] 175 pub use strs::{str_num_latin1_chars, str_to_latin1}; 176 177 #[cfg(feature = "alloc")] 178 mod owned_strs; 179 #[cfg(feature = "alloc")] 180 pub use owned_strs::{CString16, FromStrError}; 181 182 mod unaligned_slice; 183 pub use unaligned_slice::UnalignedSlice; 184 185 pub use uefi_raw::{PhysicalAddress, VirtualAddress}; 186 187 #[cfg(test)] 188 mod tests { 189 use super::*; 190 191 #[test] test_alignment()192 fn test_alignment() { 193 struct X {} 194 195 impl Align for X { 196 fn alignment() -> usize { 197 4 198 } 199 } 200 201 assert_eq!(X::offset_up_to_alignment(0), 0); 202 assert_eq!(X::offset_up_to_alignment(1), 3); 203 assert_eq!(X::offset_up_to_alignment(2), 2); 204 assert_eq!(X::offset_up_to_alignment(3), 1); 205 assert_eq!(X::offset_up_to_alignment(4), 0); 206 assert_eq!(X::offset_up_to_alignment(5), 3); 207 assert_eq!(X::offset_up_to_alignment(6), 2); 208 assert_eq!(X::offset_up_to_alignment(7), 1); 209 assert_eq!(X::offset_up_to_alignment(8), 0); 210 211 assert_eq!(X::round_up_to_alignment(0), 0); 212 assert_eq!(X::round_up_to_alignment(1), 4); 213 assert_eq!(X::round_up_to_alignment(2), 4); 214 assert_eq!(X::round_up_to_alignment(3), 4); 215 assert_eq!(X::round_up_to_alignment(4), 4); 216 assert_eq!(X::round_up_to_alignment(5), 8); 217 assert_eq!(X::round_up_to_alignment(6), 8); 218 assert_eq!(X::round_up_to_alignment(7), 8); 219 assert_eq!(X::round_up_to_alignment(8), 8); 220 221 // Get an intentionally misaligned buffer. 222 let mut buffer = [0u8; 16]; 223 let mut buffer = &mut buffer[..]; 224 if (buffer.as_ptr() as usize) % X::alignment() == 0 { 225 buffer = &mut buffer[1..]; 226 } 227 228 let buffer = X::align_buf(buffer).unwrap(); 229 X::assert_aligned(buffer); 230 } 231 } 232