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