xref: /linux/rust/kernel/ptr.rs (revision f41941aab3acd33f13d65a2ae496329bc8ae4de0)
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 /// 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)]
29 pub struct Alignment(NonZero<usize>);
30 
31 impl 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`].
171 pub 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.
203 macro_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 
233 impl_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.
238 pub 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 
243 impl<T> KnownSize for T {
244     #[inline(always)]
245     fn size(_: *const Self) -> usize {
246         size_of::<T>()
247     }
248 }
249 
250 impl<T> KnownSize for [T] {
251     #[inline(always)]
252     fn size(p: *const Self) -> usize {
253         p.len() * size_of::<T>()
254     }
255 }
256