1 // SPDX-License-Identifier: GPL-2.0
2
3 //! Types and functions to work with pointers and addresses.
4
5 pub mod projection;
6 pub use crate::project_pointer as project;
7
8 use core::mem::{
9 align_of,
10 size_of, //
11 };
12 use core::num::NonZero;
13
14 use crate::const_assert;
15
16 /// Type representing an alignment, which is always a power of two.
17 ///
18 /// It is used to validate that a given value is a valid alignment, and to perform masking and
19 /// alignment operations.
20 ///
21 /// This is a temporary substitute for the [`Alignment`] nightly type from the standard library,
22 /// and to be eventually replaced by it.
23 ///
24 /// [`Alignment`]: https://github.com/rust-lang/rust/issues/102070
25 ///
26 /// # Invariants
27 ///
28 /// An alignment is always a power of two.
29 #[repr(transparent)]
30 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
31 pub struct Alignment(NonZero<usize>);
32
33 impl Alignment {
34 /// Validates that `ALIGN` is a power of two at build-time, and returns an [`Alignment`] of the
35 /// same value.
36 ///
37 /// A build error is triggered if `ALIGN` is not a power of two.
38 ///
39 /// # Examples
40 ///
41 /// ```
42 /// use kernel::ptr::Alignment;
43 ///
44 /// let v = Alignment::new::<16>();
45 /// assert_eq!(v.as_usize(), 16);
46 /// ```
47 #[inline(always)]
new<const ALIGN: usize>() -> Self48 pub const fn new<const ALIGN: usize>() -> Self {
49 const_assert!(
50 ALIGN.is_power_of_two(),
51 "Provided alignment is not a power of two."
52 );
53
54 // INVARIANT: `align` is a power of two.
55 // SAFETY: `align` is a power of two, and thus non-zero.
56 Self(unsafe { NonZero::new_unchecked(ALIGN) })
57 }
58
59 /// Validates that `align` is a power of two at runtime, and returns an
60 /// [`Alignment`] of the same value.
61 ///
62 /// Returns [`None`] if `align` is not a power of two.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// use kernel::ptr::Alignment;
68 ///
69 /// assert_eq!(Alignment::new_checked(16), Some(Alignment::new::<16>()));
70 /// assert_eq!(Alignment::new_checked(15), None);
71 /// assert_eq!(Alignment::new_checked(1), Some(Alignment::new::<1>()));
72 /// assert_eq!(Alignment::new_checked(0), None);
73 /// ```
74 #[inline(always)]
new_checked(align: usize) -> Option<Self>75 pub const fn new_checked(align: usize) -> Option<Self> {
76 if align.is_power_of_two() {
77 // INVARIANT: `align` is a power of two.
78 // SAFETY: `align` is a power of two, and thus non-zero.
79 Some(Self(unsafe { NonZero::new_unchecked(align) }))
80 } else {
81 None
82 }
83 }
84
85 /// Returns the alignment of `T`.
86 ///
87 /// This is equivalent to [`align_of`], but with the return value provided as an [`Alignment`].
88 #[inline(always)]
of<T>() -> Self89 pub const fn of<T>() -> Self {
90 // This cannot panic since alignments are always powers of two.
91 //
92 // We unfortunately cannot use `new` as it would require the `generic_const_exprs` feature.
93 const { Alignment::new_checked(align_of::<T>()).unwrap() }
94 }
95
96 /// Returns this alignment as a [`usize`].
97 ///
98 /// It is guaranteed to be a power of two.
99 ///
100 /// # Examples
101 ///
102 /// ```
103 /// use kernel::ptr::Alignment;
104 ///
105 /// assert_eq!(Alignment::new::<16>().as_usize(), 16);
106 /// ```
107 #[inline(always)]
as_usize(self) -> usize108 pub const fn as_usize(self) -> usize {
109 self.as_nonzero().get()
110 }
111
112 /// Returns this alignment as a [`NonZero`].
113 ///
114 /// It is guaranteed to be a power of two.
115 ///
116 /// # Examples
117 ///
118 /// ```
119 /// use kernel::ptr::Alignment;
120 ///
121 /// assert_eq!(Alignment::new::<16>().as_nonzero().get(), 16);
122 /// ```
123 #[inline(always)]
as_nonzero(self) -> NonZero<usize>124 pub const fn as_nonzero(self) -> NonZero<usize> {
125 // Allow the compiler to know that the value is indeed a power of two. This can help
126 // optimize some operations down the line, like e.g. replacing divisions by bit shifts.
127 if !self.0.is_power_of_two() {
128 // SAFETY: Per the invariants, `self.0` is always a power of two so this block will
129 // never be reached.
130 unsafe { core::hint::unreachable_unchecked() }
131 }
132 self.0
133 }
134
135 /// Returns the base-2 logarithm of the alignment.
136 ///
137 /// # Examples
138 ///
139 /// ```
140 /// use kernel::ptr::Alignment;
141 ///
142 /// assert_eq!(Alignment::of::<u8>().log2(), 0);
143 /// assert_eq!(Alignment::new::<16>().log2(), 4);
144 /// ```
145 #[inline(always)]
log2(self) -> u32146 pub const fn log2(self) -> u32 {
147 self.0.ilog2()
148 }
149
150 /// Returns the mask for this alignment.
151 ///
152 /// This is equivalent to `!(self.as_usize() - 1)`.
153 ///
154 /// # Examples
155 ///
156 /// ```
157 /// use kernel::ptr::Alignment;
158 ///
159 /// assert_eq!(Alignment::new::<0x10>().mask(), !0xf);
160 /// ```
161 #[inline(always)]
mask(self) -> usize162 pub const fn mask(self) -> usize {
163 // No underflow can occur as the alignment is guaranteed to be a power of two, and thus is
164 // non-zero.
165 !(self.as_usize() - 1)
166 }
167 }
168
169 /// Trait for items that can be aligned against an [`Alignment`].
170 pub trait Alignable: Sized {
171 /// Aligns `self` down to `alignment`.
172 ///
173 /// # Examples
174 ///
175 /// ```
176 /// use kernel::ptr::{Alignable, Alignment};
177 ///
178 /// assert_eq!(0x2f_usize.align_down(Alignment::new::<0x10>()), 0x20);
179 /// assert_eq!(0x30usize.align_down(Alignment::new::<0x10>()), 0x30);
180 /// assert_eq!(0xf0u8.align_down(Alignment::new::<0x1000>()), 0x0);
181 /// ```
align_down(self, alignment: Alignment) -> Self182 fn align_down(self, alignment: Alignment) -> Self;
183
184 /// Aligns `self` up to `alignment`, returning `None` if aligning would result in an overflow.
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// use kernel::ptr::{Alignable, Alignment};
190 ///
191 /// assert_eq!(0x4fusize.align_up(Alignment::new::<0x10>()), Some(0x50));
192 /// assert_eq!(0x40usize.align_up(Alignment::new::<0x10>()), Some(0x40));
193 /// assert_eq!(0x0usize.align_up(Alignment::new::<0x10>()), Some(0x0));
194 /// assert_eq!(u8::MAX.align_up(Alignment::new::<0x10>()), None);
195 /// assert_eq!(0x10u8.align_up(Alignment::new::<0x100>()), None);
196 /// assert_eq!(0x0u8.align_up(Alignment::new::<0x100>()), Some(0x0));
197 /// ```
align_up(self, alignment: Alignment) -> Option<Self>198 fn align_up(self, alignment: Alignment) -> Option<Self>;
199 }
200
201 /// Implement [`Alignable`] for unsigned integer types.
202 macro_rules! impl_alignable_uint {
203 ($($t:ty),*) => {
204 $(
205 impl Alignable for $t {
206 #[inline(always)]
207 fn align_down(self, alignment: Alignment) -> Self {
208 // The operands of `&` need to be of the same type so convert the alignment to
209 // `Self`. This means we need to compute the mask ourselves.
210 ::core::num::NonZero::<Self>::try_from(alignment.as_nonzero())
211 .map(|align| self & !(align.get() - 1))
212 // An alignment larger than `Self` always aligns down to `0`.
213 .unwrap_or(0)
214 }
215
216 #[inline(always)]
217 fn align_up(self, alignment: Alignment) -> Option<Self> {
218 let aligned_down = self.align_down(alignment);
219 if self == aligned_down {
220 Some(aligned_down)
221 } else {
222 Self::try_from(alignment.as_usize())
223 .ok()
224 .and_then(|align| aligned_down.checked_add(align))
225 }
226 }
227 }
228 )*
229 };
230 }
231
232 impl_alignable_uint!(u8, u16, u32, u64, usize);
233
234 /// Trait to represent compile-time known size information.
235 ///
236 /// This is a generalization of [`size_of`] that works for dynamically sized types.
237 pub trait KnownSize {
238 /// Get the size of an object of this type in bytes, with the metadata of the given pointer.
size(p: *const Self) -> usize239 fn size(p: *const Self) -> usize;
240 }
241
242 impl<T> KnownSize for T {
243 #[inline(always)]
size(_: *const Self) -> usize244 fn size(_: *const Self) -> usize {
245 size_of::<T>()
246 }
247 }
248
249 impl<T> KnownSize for [T] {
250 #[inline(always)]
size(p: *const Self) -> usize251 fn size(p: *const Self) -> usize {
252 p.len() * size_of::<T>()
253 }
254 }
255
256 /// Aligns `value` up to `align`.
257 ///
258 /// This is the const-compatible equivalent of [`Alignable::align_up`].
259 ///
260 /// Returns [`None`] on overflow.
261 ///
262 /// # Examples
263 ///
264 /// ```
265 /// use kernel::{
266 /// ptr::{
267 /// const_align_up,
268 /// Alignment, //
269 /// },
270 /// sizes::SZ_4K, //
271 /// };
272 ///
273 /// assert_eq!(const_align_up(0x4f, Alignment::new::<16>()), Some(0x50));
274 /// assert_eq!(const_align_up(0x40, Alignment::new::<16>()), Some(0x40));
275 /// assert_eq!(const_align_up(1, Alignment::new::<SZ_4K>()), Some(SZ_4K));
276 /// ```
277 #[inline(always)]
const_align_up(value: usize, align: Alignment) -> Option<usize>278 pub const fn const_align_up(value: usize, align: Alignment) -> Option<usize> {
279 match value.checked_add(align.as_usize() - 1) {
280 Some(v) => Some(v & align.mask()),
281 None => None,
282 }
283 }
284