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