public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Eliot Courtney" <ecourtney@nvidia.com>
To: "Alexandre Courbot" <acourbot@nvidia.com>,
	"Joel Fernandes" <joelagnelf@nvidia.com>,
	"Yury Norov" <yury.norov@gmail.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>
Cc: "John Hubbard" <jhubbard@nvidia.com>,
	"Alistair Popple" <apopple@nvidia.com>,
	"Timur Tabi" <ttabi@nvidia.com>, "Zhi Wang" <zhiw@nvidia.com>,
	"Eliot Courtney" <ecourtney@nvidia.com>,
	<linux-kernel@vger.kernel.org>, <rust-for-linux@vger.kernel.org>,
	<driver-core@lists.linux.dev>, <dri-devel@lists.freedesktop.org>
Subject: Re: [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!`
Date: Mon, 13 Apr 2026 11:29:47 +0900	[thread overview]
Message-ID: <DHRO963VKBJG.1RNNN4EJ791PP@nvidia.com> (raw)
In-Reply-To: <20260409-bitfield-v2-1-23ac400071cb@nvidia.com>

On Thu Apr 9, 2026 at 11:58 PM JST, Alexandre Courbot wrote:
> 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.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  MAINTAINERS                |   8 +
>  rust/kernel/bitfield.rs    | 491 +++++++++++++++++++++++++++++++++++++++++++++
>  rust/kernel/io/register.rs | 246 +----------------------
>  rust/kernel/lib.rs         |   1 +
>  4 files changed, 502 insertions(+), 244 deletions(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b01791963e25..77f2617ade5d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23186,6 +23186,14 @@ F:	scripts/*rust*
>  F:	tools/testing/selftests/rust/
>  K:	\b(?i:rust)\b
>  
> +RUST [BITFIELD]
> +M:	Alexandre Courbot <acourbot@nvidia.com>
> +M:	Joel Fernandes <joelagnelf@nvidia.com>
> +R:	Yury Norov <yury.norov@gmail.com>
> +L:	rust-for-linux@vger.kernel.org
> +S:	Maintained
> +F:	rust/kernel/bitfield.rs
> +
>  RUST [ALLOC]
>  M:	Danilo Krummrich <dakr@kernel.org>
>  R:	Lorenzo Stoakes <ljs@kernel.org>

nit: Should this be kept in alphabetical order (e.g. with ALLOC here
below?).

> diff --git a/rust/kernel/bitfield.rs b/rust/kernel/bitfield.rs
> new file mode 100644
> index 000000000000..f5948eec8a76
> --- /dev/null
> +++ b/rust/kernel/bitfield.rs
> @@ -0,0 +1,491 @@
> +// 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 integer type (`u8`, `u16`, `u32`, `u64`).
> +//! - `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:
> +//!
> +//! - `with_field(value)` — infallible setter; the argument type must be statically known to fit
> +//!   the field 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.
> +//!
> +//! # 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));
> +//! ```
> +//!
> +//! [`Bounded`]: kernel::num::Bounded

In the nova version of bitfield we had @check_field_bounds. If we put
in the bit numbers the wrong way around, this patch gives a compile
error like:

```
attempt to compute `4_u32 - 7_u32`, which would overflow
```

The original nova version looks like it used build_assert, but I think
we can do it with const assert!, so we should be able to get a better
build error message for this case:

```
const _: () = assert!($hi >= $lo, "bitfield: hi bit must be >= lo bit");
```

With just that we get an extra build error, although it still spams the
confusing build error. We could also consider adding a function like:

```
pub const fn bitfield_width(hi: u32, lo: u32) -> u32 {
  assert!(hi >= lo, "bitfield: hi bit must be >= lo bit");
  hi + 1 - lo
}
```

Using this instead gets rid of some confusing build errors since we can
also use it in type bounds. But to get rid of all of them we would need
to do it for the mask etc and others.

WDYT?

  reply	other threads:[~2026-04-13  2:29 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-09 14:58 [PATCH v2 0/3] rust: add `bitfield!` macro Alexandre Courbot
2026-04-09 14:58 ` [PATCH v2 1/3] rust: extract `bitfield!` macro from `register!` Alexandre Courbot
2026-04-13  2:29   ` Eliot Courtney [this message]
2026-04-09 14:58 ` [PATCH v2 2/3] rust: bitfield: Add KUNIT tests for bitfield Alexandre Courbot
2026-04-13  2:28   ` Eliot Courtney
2026-04-09 14:58 ` [PATCH v2 3/3] gpu: nova-core: switch to kernel bitfield macro Alexandre Courbot
2026-04-13  2:01   ` Eliot Courtney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DHRO963VKBJG.1RNNN4EJ791PP@nvidia.com \
    --to=ecourtney@nvidia.com \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=apopple@nvidia.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=driver-core@lists.linux.dev \
    --cc=gary@garyguo.net \
    --cc=jhubbard@nvidia.com \
    --cc=joelagnelf@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tmgross@umich.edu \
    --cc=ttabi@nvidia.com \
    --cc=yury.norov@gmail.com \
    --cc=zhiw@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox