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