• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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