summaryrefslogtreecommitdiff
path: root/rust/kernel/num
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-18 11:25:09 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-18 11:25:09 -0700
commitd24f5cdbeff8b6a063fca92d0a1f94122a799b59 (patch)
tree1c0c344db3c18572d7176c7caec4a8abdd295647 /rust/kernel/num
parent2df813c9a6b6704b75aec7538d2225292e6b6fe6 (diff)
parent47f27155f17498fccb1f222f79089642337498a9 (diff)
Merge tag 'rust-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull Rust updates from Miguel Ojeda: "Toolchain and infrastructure: - Warn when using 'bindgen' < 0.72.1 with 'libclang' >= 22, since that combination may fail to build. It includes a probe for the bug in case 'bindgen' happens to be patched, and tests In parallel, Nathan updated the instructions for the kernel.org LLVM+Rust toolchains so that the latest version of 'bindgen' is installed, which should avoid some of these situations - Support testing 'rust_is_available.sh' with 'bash' as '/bin/sh' - Fix an objtool warning by adding one more 'noreturn' function for Rust 1.99.0 (expected 2026-10-01) - Fix build error in the 'rusttest' target due to ambiguity when the 'rustc-dev' component is installed, which was uncovered by the work to support Rust's GCC backend ('rustc_codegen_gcc') - Fix future Clang warnings in the upcoming powerpc support due to macro redefinitions in the UAPI helper header by including the arch-aware 'ioctl.h' header 'kernel' crate: - Rework module ownership support: - Move the module-related types into a new 'module' module and make the 'THIS_MODULE' pointer a constant of 'ModuleMetadata' so that modules can provide the pointer in const contexts, and add a 'this_module' 'const fn' to retrieve it This was enabled by upstream Rust's work on the 'const_mut_refs' and 'const_refs_to_static' features which were stabilized back in Rust 1.83.0 - Teach '#[vtable]' to associate implementations with their owning module, defaulting to the local one, including fallbacks for doctests, uses within the 'kernel' crate (like upcoming KUnit '#[test]'s for DRM) and 'rusttest' - Set 'fops.owner' from the module pointer for DRM and miscdevice - Migrate Rust Binder and configfs away from the old 'THIS_MODULE' 'static' and finally remove it from the 'module!' macro - 'num' module: - Add the new 'casts' module for lossless integer conversions Rust's 'core' library's 'From' implementations do not cover conversions that are not portable or future-proof. However, the kernel supports a narrower set of architectures, which makes it helpful to provide more infallible conversions, instead of having developers use 'as' casts, which carry the risk of silently losing data This goes along with previous work we did to avoid casts in Rust kernel code since they are more powerful than needed Thus, provide safe 'const' conversion functions (e.g. 'usize_as_u64' and 'u64_into_u8'), as well as the 'FromSafeCast' and 'IntoSafeCast' extension traits that provide conversions that are known to be lossless in the kernel, and an 'arch' submodule defining conversions that are known to be lossless on particular architectures (e.g. 64-bit platforms). For instance: // Conversion in const context. const USIZED_CONST: usize = u8_as_usize(255u8); // Non-const conversions. let a = u64::from_safe_cast(4096usize); let b: u64 = 4096usize.into_safe_cast(); - Add 'Bounded::shr_exact' method in the vein of 'try_shrink' which shifts a bounded right only if it loses no set bits - Fix unsoundness issue in the 'Bounded::shr' method by rejecting, at compile-time, shifts of at least the type's bit width - 'fmt' module: - Route '{:p}' raw pointer formatting through the kernel's hashed '%p' format to prevent address leaks, including support for width and padding. Include tests for both 'no_hash_pointers' case and the default (hashed) one - Fix the '{:p}' forwarding implementation, which could print the address of a temporary stack variable - 'time' module: - Make 'Delta' generic over its time unit, with a default unit of nanoseconds ('Nsec'), preserving the existing behavior. Then, add a 'Jiffy' time unit - Add the 'Delta::as_millis_ceil()' method - Fix 'as_micros_ceil()' rounding near 'i64::MAX', which could yield a result one microsecond too small - 'sync' module: - Implement 'ForeignOwnable' for 'ARef<T>', allowing C code to own an 'ARef<T>' - Add a safe abstraction for 'rcu_barrier()' - 'error' module: add all of the remaining error codes, except the deprecated compatibility aliases - 'bug' module: - Fix build error on UML in 'warn_on!' for callers from within the 'kernel' crate - Fix future 'dead_code' warning on arm and loongarch64 and under 'CONFIG_BUG=n' in 'warn_on!', which would trigger with the upcoming SRCU abstractions - Fix future build error in 'rusttest' on cross-compilation cases, which would trigger when 'warn_on!' has callers inside the 'kernel' crate - 'bitfield' module: fix build error for the upcoming support for Rust's GCC backend ('rustc_codegen_gcc') by always inlining a couple conversions used in tests 'pin-init' crate: - User-visible changes: - Merge the '__pinned_init' and '__init' methods and make 'Init' a marker trait - Introduce public APIs 'raw_init' and 'raw_try_init' to prevent users from needing to invoke the internal '__pinned_init' and '__init' methods - Emit errors for duplicate '#[pin]' attributes - Link 'Zeroable::zeroed' and 'pin_init::zeroed' in documentation - Other changes: - Fix unwind safety issues - Clean up lint 'allow' and 'expect's - Overhaul '#[cfg]' handling to pave the way for tuple structs and self-referential structs - Mark many functions as '#[inline]' for better codegen with '-C opt-level=s' ('CC_OPTIMIZE_FOR_SIZE') 'MAINTAINERS': - Update 'MODULE SUPPORT' to cover the new 'module' module And some other fixes, cleanups and improvements" * tag 'rust-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (54 commits) rust: add functions and traits for lossless integer conversions rust: kernel: add `LocalModule` fallback for `#[vtable]` `impl`s rust: fmt: route {:p} through HashedPtr to prevent address leaks rust: fmt: fix {:p} printing stack addresses rust: module: update MAINTAINERS to cover module.rs rust: macros: remove `THIS_MODULE` static from `module!` rust_binder: use `LocalModule` for `THIS_MODULE` rust: configfs: use `LocalModule` for `THIS_MODULE` rust: miscdevice: set fops.owner from driver module pointer rust: drm: set fops.owner from driver module pointer rust: macros: auto-insert OwnerModule in #[vtable] rust: doctest: add LocalModule fallback for #[vtable] ThisModule rust: module: add `THIS_MODULE` const to `ModuleMetadata` trait rust: module: move module types into `module.rs` rust: num: add Bounded::shr_exact rust: num: reject Bounded::shr overshifts at build time rust: num: use const_assert! in Bounded rust: uapi: replace direct asm-generic/ioctl.h include with linux/ioctl.h rust: time: add Delta::as_millis_ceil() rust: time: add jiffies time unit for Delta ...
Diffstat (limited to 'rust/kernel/num')
-rw-r--r--rust/kernel/num/bounded.rs36
-rw-r--r--rust/kernel/num/casts.rs298
2 files changed, 332 insertions, 2 deletions
diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
index dafe77782d79..d192610a687d 100644
--- a/rust/kernel/num/bounded.rs
+++ b/rust/kernel/num/bounded.rs
@@ -485,13 +485,45 @@ where
/// assert_eq!(v_shifted.get(), 0xff);
/// ```
pub fn shr<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
- const { assert!(RES + SHIFT >= N) }
+ const_assert!(SHIFT < T::BITS);
+ const_assert!(RES + SHIFT >= N);
// SAFETY: We shift the value right by `SHIFT`, reducing the number of bits needed to
// represent the shifted value by as much, and just asserted that `RES >= N - SHIFT`.
unsafe { Bounded::__new(self.0 >> SHIFT) }
}
+ /// Right-shifts `self` by `SHIFT` if that loses no set bits, and returns the result as a
+ /// `Bounded<_, RES>`, where `RES >= N - SHIFT`.
+ ///
+ /// Returns [`None`] if any of the `SHIFT` least significant bits of `self` is set.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::Bounded;
+ ///
+ /// let v = Bounded::<u32, 16>::new::<0xff00>();
+ /// let v_shifted: Option<Bounded<u32, 8>> = v.shr_exact::<8, _>();
+ ///
+ /// assert_eq!(v_shifted.map(|v| v.get()), Some(0xff));
+ ///
+ /// // A set bit would be shifted out.
+ /// let v = Bounded::<u32, 16>::new::<0xff01>();
+ /// let v_shifted: Option<Bounded<u32, 8>> = v.shr_exact::<8, _>();
+ ///
+ /// assert!(v_shifted.is_none());
+ /// ```
+ #[inline]
+ pub fn shr_exact<const SHIFT: u32, const RES: u32>(self) -> Option<Bounded<T, RES>> {
+ let shifted = self.shr::<SHIFT, RES>();
+ if shifted.get() << SHIFT == self.0 {
+ Some(shifted)
+ } else {
+ None
+ }
+ }
+
/// Left-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, RES>`, where `RES >=
/// N + SHIFT`.
///
@@ -506,7 +538,7 @@ where
/// assert_eq!(v_shifted.get(), 0xff00);
/// ```
pub fn shl<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
- const { assert!(RES >= N + SHIFT) }
+ const_assert!(RES >= N + SHIFT);
// SAFETY: We shift the value left by `SHIFT`, augmenting the number of bits needed to
// represent the shifted value by as much, and just asserted that `RES >= N + SHIFT`.
diff --git a/rust/kernel/num/casts.rs b/rust/kernel/num/casts.rs
new file mode 100644
index 000000000000..7e6c7dec747d
--- /dev/null
+++ b/rust/kernel/num/casts.rs
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Helpers for performing lossless integer casts.
+//!
+//! The `as` keyword can be used to perform casts between integer types, but it unfortunately makes
+//! no distinction between casts that are lossless, and casts from a larger type into a smaller one
+//! that might silently strip data away. Thus, its use in the kernel is discouraged in favor of
+//! [`From`] implementations.
+//!
+//! Conversely, there are casts that are lossless depending on the build architecture (such as
+//! casting [`usize`] to [`u64`] on 32 or 64 bit archs), but not supported by [`From`]
+//! implementations in the standard library because they are not portable. It does however make
+//! sense for the kernel to support these, if only for code that is architecture-specific.
+//!
+//! This module provides ways to perform such conversions safely:
+//!
+//! - A series of const functions (e.g. [`usize_as_u64`]) supporting safe conversions in const
+//! context. Conversions supported by [`From`] implementations in the standard library are also
+//! covered as the [`From`] trait cannot be used in const context.
+//! - Two extension traits, [`FromSafeCast`] and [`IntoSafeCast`], providing conversion methods
+//! similar to [`From`] and [`Into`] for conversions that are safe to perform in the kernel, but
+//! not supported by the standard library.
+//! - Another series of const functions (e.g. [`u64_into_u8`]) supporting the conversion of a const
+//! value from a larger type into a smaller one, provided the value fits into the destination
+//! type. This is useful if a constant is defined as a larger type, but needs to be used as a
+//! smaller one.
+//! - An [`arch`] sub-module, defining more conversion functions that are only guaranteed to be
+//! lossless for a given pointer size. These can only be used in code that is specific to a
+//! given pointer size.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::num::casts::{self, FromSafeCast, IntoSafeCast};
+//!
+//! // Conversion from const context.
+//! const USIZED_CONST: usize = casts::u8_as_usize(255u8);
+//!
+//! // Non-const conversions.
+//! let a = u64::from_safe_cast(4096usize);
+//! let b: u64 = 4096usize.into_safe_cast();
+//! ```
+
+use crate::prelude::*;
+
+/// Implements safe `as` conversion functions from a given type into a series of target types.
+///
+/// These functions can be used in place of `as`, with the guarantee that they will be lossless.
+macro_rules! impl_safe_as {
+ ($from:ty as { $($into:ty),* }) => {
+ $(
+ $crate::macros::paste! {
+ #[doc = ::core::concat!(
+ "Losslessly converts a [`",
+ ::core::stringify!($from),
+ "`] into a [`",
+ ::core::stringify!($into),
+ "`].")]
+ ///
+ /// This conversion is allowed as it is always lossless. Prefer this over the `as`
+ /// keyword to ensure no lossy casts are performed.
+ ///
+ /// This is for use from a `const` context. For non `const` use, prefer the
+ /// [`FromSafeCast`] and [`IntoSafeCast`] traits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::casts;
+ ///
+ #[doc = ::core::concat!(
+ "assert_eq!(casts::",
+ ::core::stringify!($from),
+ "_as_",
+ ::core::stringify!($into),
+ "(1",
+ ::core::stringify!($from),
+ "), 1",
+ ::core::stringify!($into),
+ ");")]
+ /// ```
+ #[inline]
+ pub const fn [<$from _as_ $into>](value: $from) -> $into {
+ $crate::static_assert!(size_of::<$into>() >= size_of::<$from>());
+
+ value as $into
+ }
+ }
+ )*
+ };
+}
+
+// Valid `Into` transformations.
+impl_safe_as!(u8 as { u16, u32, u64, usize });
+impl_safe_as!(u16 as { u32, u64, usize });
+impl_safe_as!(u32 as { u64 });
+// A `usize` fits into a `u64` on all supported platforms.
+impl_safe_as!(usize as { u64 });
+// A `u32` fits into a `usize` on all supported platforms.
+impl_safe_as!(u32 as { usize });
+
+/// Extension trait providing guaranteed lossless cast to [`Self`] from `T`.
+///
+/// The standard library's [`From`] implementations do not cover conversions that are not portable
+/// or future-proof. For instance, even though it is safe today, [`From<usize>`] is not implemented
+/// for [`u64`] because of the possibility of needing to support larger-than-64bit architectures in
+/// the future.
+///
+/// The workaround is to either deal with the error handling of [`TryFrom`] for an operation that
+/// technically cannot fail, or to use the `as` keyword, which can silently strip data if the
+/// destination type is smaller than the source.
+///
+/// Both options are hardly acceptable for the kernel. It is also a much more architecture
+/// dependent environment, supporting only 32 and 64 bit architectures, with some modules
+/// explicitly depending on a specific bus width that could greatly benefit from infallible
+/// conversion operations.
+///
+/// Thus this extension trait that provides, for all architectures supported by the kernel,
+/// conversion methods between types for which such a cast is lossless.
+///
+/// In other words, this trait is implemented if, for all supported targets and with `t: T`, the
+/// `t as Self` operation is completely lossless.
+///
+/// Prefer this over the `as` keyword to guarantee that no lossy casts are performed.
+///
+/// If you need to perform a conversion in `const` context, use [`u32_as_usize`], [`usize_as_u64`],
+/// etc.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::num::casts::FromSafeCast;
+///
+/// assert_eq!(usize::from_safe_cast(0xf00u32), 0xf00usize);
+/// ```
+pub trait FromSafeCast<T> {
+ /// Create a [`Self`] from `value`. This operation is guaranteed to be lossless.
+ fn from_safe_cast(value: T) -> Self;
+}
+
+// A `usize` fits into a `u64` on all supported platforms.
+impl FromSafeCast<usize> for u64 {
+ #[inline]
+ fn from_safe_cast(value: usize) -> Self {
+ usize_as_u64(value)
+ }
+}
+
+// A `u32` fits into a `usize` on all supported platforms.
+impl FromSafeCast<u32> for usize {
+ #[inline]
+ fn from_safe_cast(value: u32) -> Self {
+ u32_as_usize(value)
+ }
+}
+
+/// Counterpart to the [`FromSafeCast`] trait, i.e. this trait is to [`FromSafeCast`] what [`Into`]
+/// is to [`From`].
+///
+/// See the documentation of [`FromSafeCast`] for the motivation.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::num::casts::IntoSafeCast;
+///
+/// assert_eq!(0xf00usize, 0xf00u32.into_safe_cast());
+/// ```
+pub trait IntoSafeCast<T> {
+ /// Convert `self` into a `T`. This operation is guaranteed to be lossless.
+ fn into_safe_cast(self) -> T;
+}
+
+/// Reverse operation for types implementing [`FromSafeCast`].
+impl<S, T> IntoSafeCast<T> for S
+where
+ T: FromSafeCast<S>,
+{
+ #[inline]
+ fn into_safe_cast(self) -> T {
+ T::from_safe_cast(self)
+ }
+}
+
+/// Implements lossless conversion of a constant from a larger type into a smaller one.
+macro_rules! impl_const_into {
+ ($from:ty => { $($into:ty),* }) => {
+ $(
+ $crate::macros::paste! {
+ #[doc = ::core::concat!(
+ "Performs a build-time safe conversion of a [`",
+ ::core::stringify!($from),
+ "`] constant value into a [`",
+ ::core::stringify!($into),
+ "`].")]
+ ///
+ /// This checks at compile-time that the conversion is lossless, and triggers a build
+ /// error if it isn't.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::casts;
+ ///
+ /// // Succeeds because the value of the source fits into the destination's type.
+ #[doc = ::core::concat!(
+ "assert_eq!(casts::",
+ ::core::stringify!($from),
+ "_into_",
+ ::core::stringify!($into),
+ "::<1",
+ ::core::stringify!($from),
+ ">(), 1",
+ ::core::stringify!($into),
+ ");")]
+ /// ```
+ #[inline]
+ pub const fn [<$from _into_ $into>]<const N: $from>() -> $into {
+ // Make sure that the target type is smaller than the source one.
+ $crate::static_assert!($from::BITS >= $into::BITS);
+ // CAST: we statically enforced above that `$from` is larger than `$into`, so the
+ // `as` conversion will be lossless.
+ $crate::const_assert!(N >= $into::MIN as $from && N <= $into::MAX as $from);
+
+ N as $into
+ }
+ }
+ )*
+ };
+}
+
+impl_const_into!(usize => { u8, u16, u32 });
+impl_const_into!(u64 => { u8, u16, u32 });
+impl_const_into!(u32 => { u8, u16 });
+impl_const_into!(u16 => { u8 });
+
+/// Conversions that are only lossless for the current architecture.
+///
+/// # Portability
+///
+/// Callers of this module become dependent on the setting of `CONFIG_64BIT`. Use with caution, and
+/// never in code that is portable across pointer sizes.
+pub mod arch {
+ /// Trait identical to [`FromSafeCast`](super::FromSafeCast), but for conversions that are not
+ /// available on all architectures.
+ pub trait FromSafeCastArch<T> {
+ /// Create a [`Self`] from `value`. This operation is guaranteed to be lossless.
+ fn from_safe_cast_arch(value: T) -> Self;
+ }
+
+ /// Trait identical to [`IntoSafeCast`](super::IntoSafeCast), but for conversions that are not
+ /// available on all architectures.
+ pub trait IntoSafeCastArch<T> {
+ /// Convert `self` into a `T`. This operation is guaranteed to be lossless.
+ fn into_safe_cast_arch(self) -> T;
+ }
+
+ /// Reverse operation for types implementing [`FromSafeCastArch`].
+ impl<S, T> IntoSafeCastArch<T> for S
+ where
+ T: FromSafeCastArch<S>,
+ {
+ #[inline]
+ fn into_safe_cast_arch(self) -> T {
+ T::from_safe_cast_arch(self)
+ }
+ }
+
+ /// A [`u64`] fits into a [`usize`] on 64-bit platforms.
+ #[cfg(CONFIG_64BIT)]
+ #[inline]
+ pub const fn u64_as_usize(value: u64) -> usize {
+ value as usize
+ }
+
+ #[cfg(CONFIG_64BIT)]
+ impl FromSafeCastArch<u64> for usize {
+ #[inline]
+ fn from_safe_cast_arch(value: u64) -> Self {
+ u64_as_usize(value)
+ }
+ }
+
+ /// A [`usize`] fits into a [`u32`] on 32-bit platforms.
+ #[cfg(not(CONFIG_64BIT))]
+ #[inline]
+ pub const fn usize_as_u32(value: usize) -> u32 {
+ value as u32
+ }
+
+ #[cfg(not(CONFIG_64BIT))]
+ impl FromSafeCastArch<usize> for u32 {
+ #[inline]
+ fn from_safe_cast_arch(value: usize) -> Self {
+ usize_as_u32(value)
+ }
+ }
+}