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
14/// Type representing an alignment, which is always a power of two.
15///
16/// It is used to validate that a given value is a valid alignment, and to perform masking and
17/// alignment operations.
18///
19/// This is a temporary substitute for the [`Alignment`] nightly type from the standard library,
20/// and to be eventually replaced by it.
21///
22/// [`Alignment`]: https://github.com/rust-lang/rust/issues/102070
23///
24/// # Invariants
25///
26/// An alignment is always a power of two.
27#[repr(transparent)]
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct Alignment(NonZero<usize>);
30
31impl Alignment {
32    /// Validates that `ALIGN` is a power of two at build-time, and returns an [`Alignment`] of the
33    /// same value.
34    ///
35    /// A build error is triggered if `ALIGN` is not a power of two.
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// use kernel::ptr::Alignment;
41    ///
42    /// let v = Alignment::new::<16>();
43    /// assert_eq!(v.as_usize(), 16);
44    /// ```
45    #[inline(always)]
46    pub const fn new<const ALIGN: usize>() -> Self {
47        const {
48            assert!(
49                ALIGN.is_power_of_two(),
50                "Provided alignment is not a power of two."
51            );
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)]
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)]
89    pub const fn of<T>() -> Self {
90        #![allow(clippy::incompatible_msrv)]
91        // This cannot panic since alignments are always powers of two.
92        //
93        // We unfortunately cannot use `new` as it would require the `generic_const_exprs` feature.
94        const { Alignment::new_checked(align_of::<T>()).unwrap() }
95    }
96
97    /// Returns this alignment as a [`usize`].
98    ///
99    /// It is guaranteed to be a power of two.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use kernel::ptr::Alignment;
105    ///
106    /// assert_eq!(Alignment::new::<16>().as_usize(), 16);
107    /// ```
108    #[inline(always)]
109    pub const fn as_usize(self) -> usize {
110        self.as_nonzero().get()
111    }
112
113    /// Returns this alignment as a [`NonZero`].
114    ///
115    /// It is guaranteed to be a power of two.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// use kernel::ptr::Alignment;
121    ///
122    /// assert_eq!(Alignment::new::<16>().as_nonzero().get(), 16);
123    /// ```
124    #[inline(always)]
125    pub const fn as_nonzero(self) -> NonZero<usize> {
126        // Allow the compiler to know that the value is indeed a power of two. This can help
127        // optimize some operations down the line, like e.g. replacing divisions by bit shifts.
128        if !self.0.is_power_of_two() {
129            // SAFETY: Per the invariants, `self.0` is always a power of two so this block will
130            // never be reached.
131            unsafe { core::hint::unreachable_unchecked() }
132        }
133        self.0
134    }
135
136    /// Returns the base-2 logarithm of the alignment.
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use kernel::ptr::Alignment;
142    ///
143    /// assert_eq!(Alignment::of::<u8>().log2(), 0);
144    /// assert_eq!(Alignment::new::<16>().log2(), 4);
145    /// ```
146    #[inline(always)]
147    pub const fn log2(self) -> u32 {
148        self.0.ilog2()
149    }
150
151    /// Returns the mask for this alignment.
152    ///
153    /// This is equivalent to `!(self.as_usize() - 1)`.
154    ///
155    /// # Examples
156    ///
157    /// ```
158    /// use kernel::ptr::Alignment;
159    ///
160    /// assert_eq!(Alignment::new::<0x10>().mask(), !0xf);
161    /// ```
162    #[inline(always)]
163    pub const fn mask(self) -> usize {
164        // No underflow can occur as the alignment is guaranteed to be a power of two, and thus is
165        // non-zero.
166        !(self.as_usize() - 1)
167    }
168}
169
170/// Trait for items that can be aligned against an [`Alignment`].
171pub trait Alignable: Sized {
172    /// Aligns `self` down to `alignment`.
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// use kernel::ptr::{Alignable, Alignment};
178    ///
179    /// assert_eq!(0x2f_usize.align_down(Alignment::new::<0x10>()), 0x20);
180    /// assert_eq!(0x30usize.align_down(Alignment::new::<0x10>()), 0x30);
181    /// assert_eq!(0xf0u8.align_down(Alignment::new::<0x1000>()), 0x0);
182    /// ```
183    fn align_down(self, alignment: Alignment) -> Self;
184
185    /// Aligns `self` up to `alignment`, returning `None` if aligning would result in an overflow.
186    ///
187    /// # Examples
188    ///
189    /// ```
190    /// use kernel::ptr::{Alignable, Alignment};
191    ///
192    /// assert_eq!(0x4fusize.align_up(Alignment::new::<0x10>()), Some(0x50));
193    /// assert_eq!(0x40usize.align_up(Alignment::new::<0x10>()), Some(0x40));
194    /// assert_eq!(0x0usize.align_up(Alignment::new::<0x10>()), Some(0x0));
195    /// assert_eq!(u8::MAX.align_up(Alignment::new::<0x10>()), None);
196    /// assert_eq!(0x10u8.align_up(Alignment::new::<0x100>()), None);
197    /// assert_eq!(0x0u8.align_up(Alignment::new::<0x100>()), Some(0x0));
198    /// ```
199    fn align_up(self, alignment: Alignment) -> Option<Self>;
200}
201
202/// Implement [`Alignable`] for unsigned integer types.
203macro_rules! impl_alignable_uint {
204    ($($t:ty),*) => {
205        $(
206        impl Alignable for $t {
207            #[inline(always)]
208            fn align_down(self, alignment: Alignment) -> Self {
209                // The operands of `&` need to be of the same type so convert the alignment to
210                // `Self`. This means we need to compute the mask ourselves.
211                ::core::num::NonZero::<Self>::try_from(alignment.as_nonzero())
212                    .map(|align| self & !(align.get() - 1))
213                    // An alignment larger than `Self` always aligns down to `0`.
214                    .unwrap_or(0)
215            }
216
217            #[inline(always)]
218            fn align_up(self, alignment: Alignment) -> Option<Self> {
219                let aligned_down = self.align_down(alignment);
220                if self == aligned_down {
221                    Some(aligned_down)
222                } else {
223                    Self::try_from(alignment.as_usize())
224                        .ok()
225                        .and_then(|align| aligned_down.checked_add(align))
226                }
227            }
228        }
229        )*
230    };
231}
232
233impl_alignable_uint!(u8, u16, u32, u64, usize);
234
235/// Trait to represent compile-time known size information.
236///
237/// This is a generalization of [`size_of`] that works for dynamically sized types.
238pub trait KnownSize {
239    /// Get the size of an object of this type in bytes, with the metadata of the given pointer.
240    fn size(p: *const Self) -> usize;
241}
242
243impl<T> KnownSize for T {
244    #[inline(always)]
245    fn size(_: *const Self) -> usize {
246        size_of::<T>()
247    }
248}
249
250impl<T> KnownSize for [T] {
251    #[inline(always)]
252    fn size(p: *const Self) -> usize {
253        p.len() * size_of::<T>()
254    }
255}