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