xref: /linux/rust/kernel/ptr.rs (revision b06b348e855383ed80e041299f3925cdd7dff3da)
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)]
48     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)]
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         // 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)]
108     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)]
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)]
146     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)]
162     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     /// ```
182     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     /// ```
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.
239     fn size(p: *const Self) -> usize;
240 }
241 
242 impl<T> KnownSize for T {
243     #[inline(always)]
244     fn size(_: *const Self) -> usize {
245         size_of::<T>()
246     }
247 }
248 
249 impl<T> KnownSize for [T] {
250     #[inline(always)]
251     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)]
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