Alignment operations are very common in the kernel. Since they are
always performed using a power-of-two value, enforcing this invariant
through a dedicated type leads to fewer bugs and can improve the
generated code.
Introduce the `Alignment` type, inspired by the nightly Rust type of the
same name and providing the same interface, and a new `Alignable` trait
allowing unsigned integers to be aligned up or down.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
rust/kernel/lib.rs | 2 +
rust/kernel/ptr.rs | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 221 insertions(+)
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index ed53169e795c0badf548025a57f946fa18bc73e3..c26a8b235fc78eb2e1bf71ac193f720e2581c6d2 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -17,6 +17,7 @@
// the unstable features in use.
//
// Stable since Rust 1.79.0.
+#![feature(generic_nonzero)]
#![feature(inline_const)]
//
// Stable since Rust 1.81.0.
@@ -110,6 +111,7 @@
pub mod platform;
pub mod prelude;
pub mod print;
+pub mod ptr;
pub mod rbtree;
pub mod regulator;
pub mod revocable;
diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d7aa59c20fad9706d3c6b9cf4d2c7096115b66a8
--- /dev/null
+++ b/rust/kernel/ptr.rs
@@ -0,0 +1,219 @@
+// 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.
+///
+/// TODO: 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` cannot be asserted to be 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(align: usize) -> Self {
+ build_assert!(align.is_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.
+ ///
+ /// [`None`] is returned 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`.
+ #[inline(always)]
+ pub const fn of<T>() -> Self {
+ Self::new(align_of::<T>())
+ }
+
+ /// 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);
--
2.50.1
On Thu, Aug 21, 2025 at 2:42 PM Alexandre Courbot <acourbot@nvidia.com> wrote: > > +/// TODO: Temporary substitute for the [`Alignment`] nightly type from the standard library, and to > +/// be eventually replaced by it. Should this be a comment, i.e. `//`, rather than part of the docs? (It is fine intermixing if needed, or putting them at the end of the docs too). > + /// Validates that `align` is a power of two at runtime, and returns an > + /// [`Alignment`] of the same value. > + /// > + /// [`None`] is returned if `align` is not a power of two. "Returns [`None`] if ..." is probably simpler. (Sending these two nits since you will send a new version with the const generic.) Thanks! Cheers, Miguel
On Mon Sep 8, 2025 at 9:18 PM JST, Miguel Ojeda wrote: > On Thu, Aug 21, 2025 at 2:42 PM Alexandre Courbot <acourbot@nvidia.com> wrote: >> >> +/// TODO: Temporary substitute for the [`Alignment`] nightly type from the standard library, and to >> +/// be eventually replaced by it. > > Should this be a comment, i.e. `//`, rather than part of the docs? (It > is fine intermixing if needed, or putting them at the end of the docs > too). It's probably better as a regular comment indeed. > >> + /// Validates that `align` is a power of two at runtime, and returns an >> + /// [`Alignment`] of the same value. >> + /// >> + /// [`None`] is returned if `align` is not a power of two. > > "Returns [`None`] if ..." is probably simpler. > > (Sending these two nits since you will send a new version with the > const generic.) Thanks, I'll apply them!
On 8/21/25 2:42 PM, Alexandre Courbot wrote: > + /// 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` cannot be asserted to be 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(align: usize) -> Self { > + build_assert!(align.is_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) }) > + } For DmaMask::new() we used a const generic instead, which makes it more obvious to the caller that the argument must be known at compile time. So, I'd prefer this here as well. Either way, Reviewed-by: Danilo Krummrich <dakr@kernel.org>
On Mon Sep 8, 2025 at 9:02 PM JST, Danilo Krummrich wrote: > On 8/21/25 2:42 PM, Alexandre Courbot wrote: >> + /// 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` cannot be asserted to be 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(align: usize) -> Self { >> + build_assert!(align.is_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) }) >> + } > > For DmaMask::new() we used a const generic instead, which makes it more obvious > to the caller that the argument must be known at compile time. So, I'd prefer > this here as well. Ah, being consistent is good, and I think I prefer the const generic as well. Let's do the same thing here.
On Thu, Aug 21, 2025 at 09:42:17PM +0900, Alexandre Courbot wrote: > Alignment operations are very common in the kernel. Since they are > always performed using a power-of-two value, enforcing this invariant > through a dedicated type leads to fewer bugs and can improve the > generated code. > > Introduce the `Alignment` type, inspired by the nightly Rust type of the > same name and providing the same interface, and a new `Alignable` trait > allowing unsigned integers to be aligned up or down. > > Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
© 2016 - 2025 Red Hat, Inc.