Skip to main content

kernel/
ptr.rs

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