295 lines · 9.0 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 //! Types and functions to work with pointers and addresses. pub mod projection;pub use crate::project_pointer as project; use core::mem::{    align_of,    size_of, //};use core::num::NonZero; use crate::const_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 {        const_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 {        // 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); /// Trait to represent compile-time known size information.////// This is a generalization of [`size_of`] that works for dynamically sized types.pub trait KnownSize {    /// Minimum size of this type known at compile-time.    const MIN_SIZE: usize;     /// Minimum alignment of this type known at compile-time.    const MIN_ALIGN: Alignment;     /// Get the size of an object of this type in bytes, with the metadata of the given pointer.    fn size(p: *const Self) -> usize;} impl<T> KnownSize for T {    const MIN_SIZE: usize = size_of::<T>();    const MIN_ALIGN: Alignment = Alignment::of::<T>();     #[inline(always)]    fn size(_: *const Self) -> usize {        size_of::<T>()    }} impl<T> KnownSize for [T] {    const MIN_SIZE: usize = 0;    const MIN_ALIGN: Alignment = Alignment::of::<T>();     #[inline(always)]    fn size(p: *const Self) -> usize {        p.len() * size_of::<T>()    }} /// Aligns `value` up to `align`.////// This is the const-compatible equivalent of [`Alignable::align_up`].////// Returns [`None`] on overflow.////// # Examples////// ```/// use kernel::{///     ptr::{///         const_align_up,///         Alignment, /////     },///     sizes::SZ_4K, ///// };////// assert_eq!(const_align_up(0x4f, Alignment::new::<16>()), Some(0x50));/// assert_eq!(const_align_up(0x40, Alignment::new::<16>()), Some(0x40));/// assert_eq!(const_align_up(1, Alignment::new::<SZ_4K>()), Some(SZ_4K));/// ```#[inline(always)]pub const fn const_align_up(value: usize, align: Alignment) -> Option<usize> {    match value.checked_add(align.as_usize() - 1) {        Some(v) => Some(v & align.mask()),        None => None,    }}