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