rust: extract bitfield! macro from register!

Extract the bitfield-defining part of the `register!` macro into an
independent macro used to define bitfield types with bounds-checked
accessors.

Each field is represented as a `Bounded` of the appropriate bit width,
ensuring field values are never silently truncated.

Fields can optionally be converted to/from custom types, either fallibly
or infallibly.

Appropriate documentation is also added, and a MAINTAINERS entry created
for the new module.

Two minor fixups are also applied: the private accessors are inlined,
and a couple of missing fully qualified types in the macro are fixed.

Acked-by: Yury Norov <ynorov@nvidia.com>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Yury Norov <ynorov@nvidia.com>
Link: https://patch.msgid.link/20260606-bitfield-v5-1-b92188820914@nvidia.com
[ Added some more intra-doc links. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
Alexandre Courbot
2026-06-06 21:43:04 +09:00
committed by Miguel Ojeda
parent 09699b2419
commit b7b8b4ccda
3 changed files with 556 additions and 0 deletions

View File

@@ -23422,6 +23422,13 @@ T: git https://github.com/Rust-for-Linux/linux.git alloc-next
F: rust/kernel/alloc.rs
F: rust/kernel/alloc/
RUST [BITFIELD]
M: Alexandre Courbot <acourbot@nvidia.com>
R: Yury Norov <yury.norov@gmail.com>
L: rust-for-linux@vger.kernel.org
S: Maintained
F: rust/kernel/bitfield.rs
RUST [INTEROP]
M: Joel Fernandes <joelagnelf@nvidia.com>
M: Alexandre Courbot <acourbot@nvidia.com>

548
rust/kernel/bitfield.rs Normal file
View File

@@ -0,0 +1,548 @@
// SPDX-License-Identifier: GPL-2.0
//! Support for defining bitfields as Rust structures.
//!
//! The [`bitfield!`](kernel::bitfield!) macro declares integer types that are split into distinct
//! bit fields of arbitrary length. Each field is typed using [`Bounded`](kernel::num::Bounded) to
//! ensure values are properly validated and to avoid implicit data loss.
//!
//! # Example
//!
//! ```rust
//! use kernel::bitfield;
//! use kernel::num::Bounded;
//!
//! bitfield! {
//! pub struct Rgb(u16) {
//! 15:11 blue;
//! 10:5 green;
//! 4:0 red;
//! }
//! }
//!
//! // Valid value for the `blue` field.
//! let blue = Bounded::<u16, 5>::new::<0x18>();
//!
//! // Setters can be chained. Values ranges are checked at compile-time.
//! let color = Rgb::zeroed()
//! // Compile-time bounds check of constant value.
//! .with_const_red::<0x10>()
//! .with_const_green::<0x1f>()
//! // A `Bounded` can also be passed.
//! .with_blue(blue);
//!
//! assert_eq!(color.red(), 0x10);
//! assert_eq!(color.green(), 0x1f);
//! assert_eq!(color.blue(), 0x18);
//! assert_eq!(
//! color.into_raw(),
//! (0x18 << Rgb::BLUE_SHIFT) + (0x1f << Rgb::GREEN_SHIFT) + 0x10,
//! );
//!
//! // Convert to/from the backing storage type.
//! let raw: u16 = color.into();
//! assert_eq!(Rgb::from(raw), color);
//! ```
//!
//! # Syntax
//!
//! ```text
//! bitfield! {
//! #[attributes]
//! // Documentation for `Name`.
//! pub struct Name(storage_type) {
//! // `field_1` documentation.
//! hi:lo field_1;
//! // `field_2` documentation.
//! hi:lo field_2 => ConvertedType;
//! // `field_3` documentation.
//! hi:lo field_3 ?=> ConvertedType;
//! ...
//! }
//! }
//! ```
//!
//! - `storage_type`: The underlying unsigned integer type ([`u8`], [`u16`], [`u32`], [`u64`]).
//! Signed integer storage types are not supported.
//! - `hi:lo`: Bit range (inclusive), where `hi >= lo`.
//! - `=> Type`: Optional infallible conversion (see [below](#infallible-conversion-)).
//! - `?=> Type`: Optional fallible conversion (see [below](#fallible-conversion-)).
//! - Documentation strings and attributes are optional.
//!
//! # Generated code
//!
//! Each field is internally represented as a [`Bounded`] parameterized by its bit width. Field
//! values can either be set/retrieved directly, or converted from/to another type.
//!
//! The use of [`Bounded`] for each field enforces bounds-checking (at build time or runtime) of
//! every value assigned to a field. This ensures that data is never accidentally truncated.
//!
//! The macro generates the bitfield type, [`From`] and [`Into`] implementations for its storage
//! type, as well as [`Debug`] and [`Zeroable`](pin_init::Zeroable) implementations.
//!
//! For each field, it also generates:
//!
//! - `field()`: Getter method for the field value.
//! - `with_field(value)`: Infallible setter; the argument type must fit within the field's width.
//! - `with_const_field::<VALUE>()`: `const` setter; the value is validated at compile time.
//! Usually shorter to use than `with_field` for constant values as it doesn't require
//! constructing a [`Bounded`].
//! - `try_with_field(value)`: Fallible setter. Returns an error if the value is out of range.
//! - `FIELD_MASK`, `FIELD_SHIFT`, `FIELD_RANGE`: Constants for manual bit manipulation.
//!
//! # Reserved names for field identifiers
//!
//! Field identifiers are used to generate methods and associated constants on the bitfield type.
//! For a field named `field`, the macro may generate methods named `field`, `with_field`,
//! `with_const_field`, `try_with_field`, `__field` and `__with_field`, as well as constants named
//! `FIELD_MASK`, `FIELD_SHIFT` and `FIELD_RANGE`.
//!
//! Therefore, field identifiers must not use names that would collide with generated items for
//! any field in the same bitfield. The following prefixes are thus reserved for field identifiers:
//!
//! - `with_`
//! - `const_`
//! - `try_with_`
//! - `__`
//!
//! The field identifiers `from_raw`, `into_raw`, and `into` are also reserved.
//!
//! In addition, field identifiers should follow Rust `snake_case` conventions, since the associated
//! constants are generated by uppercasing the field name.
//!
//! # Implicit conversions
//!
//! Types that fit entirely within a field's bit width can be used directly with setters. For
//! example, [`bool`] works with single-bit fields, and [`u8`] works with 8-bit fields:
//!
//! ```rust
//! use kernel::bitfield;
//!
//! bitfield! {
//! pub struct Flags(u32) {
//! 15:8 byte_field;
//! 0:0 flag;
//! }
//! }
//!
//! let flags = Flags::zeroed()
//! .with_byte_field(0x42_u8)
//! .with_flag(true);
//!
//! assert_eq!(flags.into_raw(), (0x42 << Flags::BYTE_FIELD_SHIFT) | 1);
//! ```
//!
//! # Runtime bounds checking
//!
//! When a value is not known at compile time, use `try_with_field()` to check bounds at runtime:
//!
//! ```rust
//! use kernel::bitfield;
//!
//! bitfield! {
//! pub struct Config(u8) {
//! 3:0 nibble;
//! }
//! }
//!
//! fn set_nibble(config: Config, value: u8) -> Result<Config, Error> {
//! // Returns `EOVERFLOW` if `value > 0xf`.
//! config.try_with_nibble(value)
//! }
//! # Ok::<(), Error>(())
//! ```
//!
//! # Type conversion
//!
//! Fields can be automatically converted to/from a custom type using `=>` (infallible) or `?=>`
//! (fallible). The custom type must implement the appropriate [`From`] or [`TryFrom`] traits with
//! [`Bounded`].
//!
//! ## Infallible conversion (`=>`)
//!
//! Use this when all possible bit patterns of a field map to valid values:
//!
//! ```rust
//! use kernel::bitfield;
//! use kernel::num::Bounded;
//!
//! #[derive(Debug, Clone, Copy, PartialEq)]
//! enum Power {
//! Off,
//! On,
//! }
//!
//! impl From<Bounded<u32, 1>> for Power {
//! fn from(v: Bounded<u32, 1>) -> Self {
//! match *v {
//! 0 => Power::Off,
//! _ => Power::On,
//! }
//! }
//! }
//!
//! impl From<Power> for Bounded<u32, 1> {
//! fn from(p: Power) -> Self {
//! (p as u32 != 0).into()
//! }
//! }
//!
//! bitfield! {
//! pub struct Control(u32) {
//! 0:0 power => Power;
//! }
//! }
//!
//! let ctrl = Control::zeroed().with_power(Power::On);
//! assert_eq!(ctrl.power(), Power::On);
//! ```
//!
//! ## Fallible conversion (`?=>`)
//!
//! Use this when some bit patterns of a field are invalid. The getter returns a [`Result`]:
//!
//! ```rust
//! use kernel::bitfield;
//! use kernel::num::Bounded;
//!
//! #[derive(Debug, Clone, Copy, PartialEq)]
//! enum Mode {
//! Low = 0,
//! High = 1,
//! Auto = 2,
//! // 3 is invalid
//! }
//!
//! impl TryFrom<Bounded<u32, 2>> for Mode {
//! type Error = u32;
//!
//! fn try_from(v: Bounded<u32, 2>) -> Result<Self, u32> {
//! match *v {
//! 0 => Ok(Mode::Low),
//! 1 => Ok(Mode::High),
//! 2 => Ok(Mode::Auto),
//! n => Err(n),
//! }
//! }
//! }
//!
//! impl From<Mode> for Bounded<u32, 2> {
//! fn from(m: Mode) -> Self {
//! match m {
//! Mode::Low => Bounded::<u32, _>::new::<0>(),
//! Mode::High => Bounded::<u32, _>::new::<1>(),
//! Mode::Auto => Bounded::<u32, _>::new::<2>(),
//! }
//! }
//! }
//!
//! bitfield! {
//! pub struct Config(u32) {
//! 1:0 mode ?=> Mode;
//! }
//! }
//!
//! let cfg = Config::zeroed().with_mode(Mode::Auto);
//! assert_eq!(cfg.mode(), Ok(Mode::Auto));
//!
//! // Invalid bit pattern returns an error.
//! assert_eq!(Config::from(0b11).mode(), Err(3));
//! ```
//!
//! # Bits outside of declared fields
//!
//! Bits of the storage type that are not part of any declared field are preserved by the setter
//! methods, and can only be modified through `from_raw` or the [`From`] implementation from the
//! storage type.
//!
//! ```rust
//! use kernel::bitfield;
//!
//! bitfield! {
//! pub struct Sparse(u8) {
//! 7:6 high;
//! // Bits 5:1 are not covered by any field.
//! 0:0 low;
//! }
//! }
//!
//! // Set the gap bits via `from_raw`, then mutate the declared fields.
//! let val = Sparse::from_raw(0b0010_1010)
//! .with_const_high::<0b11>()
//! .with_low(true);
//!
//! // Bits 5:1 are unchanged.
//! assert_eq!(val.into_raw(), 0b1110_1011);
//! ```
//!
//! # Signed field values
//!
//! Bitfield storage types are unsigned. Since field getter methods return a [`Bounded`] of the
//! storage type, fields are also unsigned by default.
//!
//! If a field needs to encode a signed value, use a custom conversion type with `=>` or `?=>` to
//! perform the sign interpretation explicitly.
//!
//! [`Bounded`]: kernel::num::Bounded
/// Defines a bitfield struct with bounds-checked accessors for individual bit ranges.
///
/// See the [`mod@kernel::bitfield`] module for full documentation and examples.
#[macro_export]
macro_rules! bitfield {
// Entry point defining the bitfield struct, its implementations and its field accessors.
(
$(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* }
) => {
$crate::bitfield!(@core
#[allow(non_camel_case_types)]
$(#[$attr])* $vis $name $storage
);
$crate::bitfield!(@fields $vis $name $storage { $($fields)* });
};
// All rules below are helpers.
// Defines the wrapper `$name` type and its conversions from/to the storage type.
(@core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {
$(#[$attr])*
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
$vis struct $name {
inner: $storage,
}
#[allow(dead_code)]
impl $name {
/// Creates a bitfield from a raw value.
#[inline(always)]
$vis const fn from_raw(value: $storage) -> Self {
Self{ inner: value }
}
/// Turns this bitfield into its raw value.
///
/// This is similar to the [`From`] implementation, but is shorter to invoke in
/// most cases.
#[inline(always)]
$vis const fn into_raw(self) -> $storage {
self.inner
}
}
// SAFETY: `$storage` is `Zeroable` and `$name` is transparent.
unsafe impl ::pin_init::Zeroable for $name {}
impl ::core::convert::From<$name> for $storage {
#[inline(always)]
fn from(val: $name) -> $storage {
val.into_raw()
}
}
impl ::core::convert::From<$storage> for $name {
#[inline(always)]
fn from(val: $storage) -> $name {
Self::from_raw(val)
}
}
};
// Definitions requiring knowledge of individual fields: private and public field accessors,
// and `Debug` implementation.
(@fields $vis:vis $name:ident $storage:ty {
$($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident
$(?=> $try_into_type:ty)?
$(=> $into_type:ty)?
;
)*
}
) => {
#[allow(dead_code)]
impl $name {
$(
$crate::bitfield!(@private_field_accessors $vis $name $storage : $hi:$lo $field);
$crate::bitfield!(
@public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field
$(?=> $try_into_type)?
$(=> $into_type)?
);
)*
}
$crate::bitfield!(@debug $name { $($field;)* });
};
// Private field accessors working with the exact `Bounded` type for the field.
(
@private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident
) => {
::kernel::macros::paste!(
$vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
$vis const [<$field:upper _MASK>]: $storage =
((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
$vis const [<$field:upper _SHIFT>]: u32 = $lo;
);
::kernel::macros::paste!(
#[inline(always)]
fn [<__ $field>](self) ->
::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {
// Left shift to align the field's MSB with the storage MSB.
const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);
// Right shift to move the top-aligned field to bit 0 of the storage.
const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;
// Extract the field using two shifts. `Bounded::shr` produces the correctly-sized
// output type.
let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(
self.inner << ALIGN_TOP
);
val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()
}
#[inline(always)]
const fn [<__with_ $field>](
mut self,
value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,
) -> Self
{
const MASK: $storage = <$name>::[<$field:upper _MASK>];
const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];
let value = value.get() << SHIFT;
self.inner = (self.inner & !MASK) | value;
self
}
);
};
// Public accessors for fields infallibly (`=>`) converted to a type.
(
@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
$hi:literal:$lo:literal $field:ident => $into_type:ty
) => {
::kernel::macros::paste!(
$(#[doc = $doc])*
#[doc = "Returns the value of this field."]
#[inline(always)]
$vis fn $field(self) -> $into_type
{
self.[<__ $field>]().into()
}
$(#[doc = $doc])*
#[doc = "Sets this field to the given `value`."]
#[inline(always)]
$vis fn [<with_ $field>](self, value: $into_type) -> Self
{
self.[<__with_ $field>](value.into())
}
);
};
// Public accessors for fields fallibly (`?=>`) converted to a type.
(
@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
$hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty
) => {
::kernel::macros::paste!(
$(#[doc = $doc])*
#[doc = "Returns the value of this field."]
#[inline(always)]
$vis fn $field(self) ->
::core::result::Result<
$try_into_type,
<$try_into_type as ::core::convert::TryFrom<
::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
>>::Error
>
{
self.[<__ $field>]().try_into()
}
$(#[doc = $doc])*
#[doc = "Sets this field to the given `value`."]
#[inline(always)]
$vis fn [<with_ $field>](self, value: $try_into_type) -> Self
{
self.[<__with_ $field>](value.into())
}
);
};
// Public accessors for fields not converted to a type.
(
@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
$hi:tt:$lo:tt $field:ident
) => {
::kernel::macros::paste!(
$(#[doc = $doc])*
#[doc = "Returns the value of this field."]
#[inline(always)]
$vis fn $field(self) ->
::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
{
self.[<__ $field>]()
}
$(#[doc = $doc])*
#[doc = "Sets this field to the compile-time constant `VALUE`."]
#[inline(always)]
$vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {
self.[<__with_ $field>](
::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()
)
}
$(#[doc = $doc])*
#[doc = "Sets this field to the given `value`."]
#[inline(always)]
$vis fn [<with_ $field>]<T>(
self,
value: T,
) -> Self
where T: ::core::convert::Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,
{
self.[<__with_ $field>](value.into())
}
$(#[doc = $doc])*
#[doc = "Tries to set this field to `value`, returning an error if it is out of range."]
#[inline(always)]
$vis fn [<try_with_ $field>]<T>(
self,
value: T,
) -> ::kernel::error::Result<Self>
where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,
{
Ok(
self.[<__with_ $field>](
value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?
)
)
}
);
};
// `Debug` implementation.
(@debug $name:ident { $($field:ident;)* }) => {
impl ::kernel::fmt::Debug for $name {
fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
f.debug_struct(stringify!($name))
.field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner))
$(
.field(stringify!($field), &self.$field())
)*
.finish()
}
}
};
}

View File

@@ -44,6 +44,7 @@
pub mod alloc;
#[cfg(CONFIG_AUXILIARY_BUS)]
pub mod auxiliary;
pub mod bitfield;
pub mod bitmap;
pub mod bits;
#[cfg(CONFIG_BLOCK)]