1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
// SPDX-License-Identifier: GPL-2.0
//! Types and functions to work with pointers and addresses.
use core::fmt::Debug;
use core::mem::align_of;
use core::num::NonZero;
use crate::build_assert;
/// Type representing an alignment, which is always a power of two.
///
/// It is used to validate that a given value is a valid alignment, and to perform masking and
/// alignment operations.
///
/// This is a temporary substitute for the [`Alignment`] nightly type from the standard library,
/// and to be eventually replaced by it.
///
/// [`Alignment`]: https://github.com/rust-lang/rust/issues/102070
///
/// # Invariants
///
/// An alignment is always a power of two.
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Alignment(NonZero<usize>);
impl Alignment {
/// Validates that `ALIGN` is a power of two at build-time, and returns an [`Alignment`] of the
/// same value.
///
/// A build error is triggered if `ALIGN` is not a power of two.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// let v = Alignment::new::<16>();
/// assert_eq!(v.as_usize(), 16);
/// ```
#[inline(always)]
pub const fn new<const ALIGN: usize>() -> Self {
build_assert!(
ALIGN.is_power_of_two(),
"Provided alignment is not a power of two."
);
// INVARIANT: `align` is a power of two.
// SAFETY: `align` is a power of two, and thus non-zero.
Self(unsafe { NonZero::new_unchecked(ALIGN) })
}
/// Validates that `align` is a power of two at runtime, and returns an
/// [`Alignment`] of the same value.
///
/// Returns [`None`] if `align` is not a power of two.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::new_checked(16), Some(Alignment::new::<16>()));
/// assert_eq!(Alignment::new_checked(15), None);
/// assert_eq!(Alignment::new_checked(1), Some(Alignment::new::<1>()));
/// assert_eq!(Alignment::new_checked(0), None);
/// ```
#[inline(always)]
pub const fn new_checked(align: usize) -> Option<Self> {
if align.is_power_of_two() {
// INVARIANT: `align` is a power of two.
// SAFETY: `align` is a power of two, and thus non-zero.
Some(Self(unsafe { NonZero::new_unchecked(align) }))
} else {
None
}
}
/// Returns the alignment of `T`.
///
/// This is equivalent to [`align_of`], but with the return value provided as an [`Alignment`].
#[inline(always)]
pub const fn of<T>() -> Self {
#![allow(clippy::incompatible_msrv)]
// This cannot panic since alignments are always powers of two.
//
// We unfortunately cannot use `new` as it would require the `generic_const_exprs` feature.
const { Alignment::new_checked(align_of::<T>()).unwrap() }
}
/// Returns this alignment as a [`usize`].
///
/// It is guaranteed to be a power of two.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::new::<16>().as_usize(), 16);
/// ```
#[inline(always)]
pub const fn as_usize(self) -> usize {
self.as_nonzero().get()
}
/// Returns this alignment as a [`NonZero`].
///
/// It is guaranteed to be a power of two.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::new::<16>().as_nonzero().get(), 16);
/// ```
#[inline(always)]
pub const fn as_nonzero(self) -> NonZero<usize> {
// Allow the compiler to know that the value is indeed a power of two. This can help
// optimize some operations down the line, like e.g. replacing divisions by bit shifts.
if !self.0.is_power_of_two() {
// SAFETY: Per the invariants, `self.0` is always a power of two so this block will
// never be reached.
unsafe { core::hint::unreachable_unchecked() }
}
self.0
}
/// Returns the base-2 logarithm of the alignment.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::of::<u8>().log2(), 0);
/// assert_eq!(Alignment::new::<16>().log2(), 4);
/// ```
#[inline(always)]
pub const fn log2(self) -> u32 {
self.0.ilog2()
}
/// Returns the mask for this alignment.
///
/// This is equivalent to `!(self.as_usize() - 1)`.
///
/// # Examples
///
/// ```
/// use kernel::ptr::Alignment;
///
/// assert_eq!(Alignment::new::<0x10>().mask(), !0xf);
/// ```
#[inline(always)]
pub const fn mask(self) -> usize {
// No underflow can occur as the alignment is guaranteed to be a power of two, and thus is
// non-zero.
!(self.as_usize() - 1)
}
}
/// Trait for items that can be aligned against an [`Alignment`].
pub trait Alignable: Sized {
/// Aligns `self` down to `alignment`.
///
/// # Examples
///
/// ```
/// use kernel::ptr::{Alignable, Alignment};
///
/// assert_eq!(0x2f_usize.align_down(Alignment::new::<0x10>()), 0x20);
/// assert_eq!(0x30usize.align_down(Alignment::new::<0x10>()), 0x30);
/// assert_eq!(0xf0u8.align_down(Alignment::new::<0x1000>()), 0x0);
/// ```
fn align_down(self, alignment: Alignment) -> Self;
/// Aligns `self` up to `alignment`, returning `None` if aligning would result in an overflow.
///
/// # Examples
///
/// ```
/// use kernel::ptr::{Alignable, Alignment};
///
/// assert_eq!(0x4fusize.align_up(Alignment::new::<0x10>()), Some(0x50));
/// assert_eq!(0x40usize.align_up(Alignment::new::<0x10>()), Some(0x40));
/// assert_eq!(0x0usize.align_up(Alignment::new::<0x10>()), Some(0x0));
/// assert_eq!(u8::MAX.align_up(Alignment::new::<0x10>()), None);
/// assert_eq!(0x10u8.align_up(Alignment::new::<0x100>()), None);
/// assert_eq!(0x0u8.align_up(Alignment::new::<0x100>()), Some(0x0));
/// ```
fn align_up(self, alignment: Alignment) -> Option<Self>;
}
/// Implement [`Alignable`] for unsigned integer types.
macro_rules! impl_alignable_uint {
($($t:ty),*) => {
$(
impl Alignable for $t {
#[inline(always)]
fn align_down(self, alignment: Alignment) -> Self {
// The operands of `&` need to be of the same type so convert the alignment to
// `Self`. This means we need to compute the mask ourselves.
::core::num::NonZero::<Self>::try_from(alignment.as_nonzero())
.map(|align| self & !(align.get() - 1))
// An alignment larger than `Self` always aligns down to `0`.
.unwrap_or(0)
}
#[inline(always)]
fn align_up(self, alignment: Alignment) -> Option<Self> {
let aligned_down = self.align_down(alignment);
if self == aligned_down {
Some(aligned_down)
} else {
Self::try_from(alignment.as_usize())
.ok()
.and_then(|align| aligned_down.checked_add(align))
}
}
}
)*
};
}
impl_alignable_uint!(u8, u16, u32, u64, usize);