Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284// 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 { /// 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 { #[inline(always)] fn size(_: *const Self) -> usize { size_of::<T>() }}
impl<T> KnownSize for [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, }}