xref: /linux/rust/kernel/ptr.rs (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
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::{
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)]
34 pub struct Alignment(NonZero<usize>);
35 
36 impl 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 
172 impl<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`].
180 pub 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.
212 macro_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 
242 impl_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.
247 pub 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 
258 impl<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 
268 impl<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)]
300 pub 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 }
306