1//! Data type definitions
2//!
3//! This module defines the basic data types that are used throughout uefi-rs
4
5use 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)]
12pub struct Handle(NonNull<c_void>);
13
14impl 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)]
44pub struct Event(NonNull<c_void>);
45
46impl 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.
69pub 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.
116pub type PhysicalAddress = u64;
117
118/// Virtual memory address. This is always a 64-bit value, regardless
119/// of target platform.
120pub type VirtualAddress = u64;
121
122mod guid;
123pub use self::guid::Guid;
124pub use self::guid::Identify;
125
126pub mod chars;
127pub use self::chars::{Char16, Char8};
128
129#[macro_use]
130mod enums;
131
132mod strs;
133pub use self::strs::{
134 CStr16, CStr8, EqStrUntilNul, FromSliceWithNulError, FromStrWithBufError, UnalignedCStr16Error,
135};
136
137#[cfg(feature = "alloc")]
138mod owned_strs;
139#[cfg(feature = "alloc")]
140pub use self::owned_strs::{CString16, FromStrError};
141
142mod unaligned_slice;
143pub use unaligned_slice::UnalignedSlice;
144
145#[cfg(test)]
146mod 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