[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251009-bounded_ints-v2-0-ff3d7fee3ffd@nvidia.com>
Date: Thu, 09 Oct 2025 21:37:07 +0900
From: Alexandre Courbot <acourbot@...dia.com>
To: Danilo Krummrich <dakr@...nel.org>,
Joel Fernandes <joelagnelf@...dia.com>, Yury Norov <yury.norov@...il.com>,
Jesung Yang <y.j3ms.n@...il.com>, Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>, Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>, Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>, Trevor Gross <tmgross@...ch.edu>
Cc: nouveau@...ts.freedesktop.org, linux-kernel@...r.kernel.org,
rust-for-linux@...r.kernel.org, Alexandre Courbot <acourbot@...dia.com>,
Edwin Peer <epeer@...dia.com>
Subject: [RFC PATCH v2 0/3] rust: bounded integer types and use in register
macro
Second revision, much more complete, of the RFC/PoC for an idea I
submitted a bit earlier [1] regarding how to handle truncated bits in
the register/bitfield macro field setters.
Currently, the register macro allows to define fields that are shorter
than the primitive type used to set them. For instance, in the following
register:
register!(NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase[0x00000128] {
8:0 base as u16;
});
The `base` field is 9 bits long, but is set using the following
setter method:
fn set_base(self, value: u16) -> Self
which discards bits of `value` higher than 9 without any error or
warning if some happen to be set. And so you happily start a DMA
transfer from the wrong base address...
While this behavior is not UB, this can also be a source of bugs.
Several ideas have been submitted to not let these unnoticed, including
making the register setters fallible, or panicking or printing a warning
whenever extra bits are discarded. These solutions are either too
risky (like panicking), or add extra code and checks on what can be a
critical path as registers are commonly accessed in interrupt handlers.
In pure Rust fashion, we would prefer to guarantee at compile-time,
whenever possible, that no bits are discarded when setting register
fields with a non-round number of bits.
This PoC proposes a possible solution for that. It introduces a new
`BoundedInt` type that wraps a primitive integer type and, using a const
generic parameter, limits the number of bits that can actually be used
within it. This is similar in spirit to `NonZero` or `Alignment` in that
it provides a static guarantee that the value it contains is limited to
a certain subset of the possible values of its primitive type.
Instances of `BoundedInt` can be constructed infallibly when the
compiler is able to guarantee that the passed value fits within the
allowed bounds, or fallibly using `try_new(primitive)`.
This type is then used by the register/bitfield macros to let the fields
getter and (more importantly) setter methods work with the exact number
of bits they can handle. For instance, the above method would become:
fn set_base(self, value: impl Into<BoundedInt<u32, 9>>) -> Self
which guarantees that no bits are ever discarded by the setter, since
the type of `value` carries an invariant that only the 9 lowest bits can
ever be set.
It is then the responsibility of the caller to build the adequate
`BoundedInt`, which very often can be done infallibly, but all the cases
that require a fallible operation are cases that the caller should have
checked anyway (lest you beam out the wrong memory region on your DMA
transfer!).
Compared to v1, this version of the RFC is much more complete. It
notably provides many `From` implementations for conversions from/to
bounded types that cannot fail, which removes a lot of the friction one
would expect when introducing new integer types.
Another side effect of this is that the bitfield definitions are
considerably simplified, since their type can now be automatically
inferred. This means that
8:0 base as u16;
could become simply
8:0 base;
And the getter/setters would work with a `BoundedInt<u32, 9>` (provided
the bitfield type is backed by a `u32`).
For convenience, this PoC is based on drm-rust-next. If we decide to
proceed with it, we would do it after the patchset extracting and moving
the bitfield logic [2] lands, as the two would conflict heavily.
Patch 1 is a pre-requisite that should be merged to nova-core, but can
be considered external to this series.
Patch 2 is the `BoundedInt` implementation.
Patch 3 makes nova-core use `BoundedInt` for its register macro, and
serves to illustrate how callers of the register field accessors are
affected by the change (rather minimally imho).
Feedback is welcome! If there is no pushback I will remove the RFC tag
for the next revision as I think the `BoundedInt` implementation is
already rather exhaustive.
[1] https://lore.kernel.org/rust-for-linux/DD5D59FH4JTT.2G5WEXF3RBCQJ@nvidia.com/
[2] https://lore.kernel.org/rust-for-linux/DD68A3TZD9CV.2CL7R7K4UAICU@kernel.org/T/
Signed-off-by: Alexandre Courbot <acourbot@...dia.com>
---
Changes in v2:
- Thorough implementation of `BoundedInt`.
- nova-core fully adapted to use `BoundedInt`.
- Link to v1: https://lore.kernel.org/r/20251002-bounded_ints-v1-0-dd60f5804ea4@nvidia.com
---
Alexandre Courbot (3):
gpu: nova-core: register: use field type for Into implementation
rust: kernel: add bounded integer types
gpu: nova-core: use BoundedInt
drivers/gpu/nova-core/falcon.rs | 118 ++++---
drivers/gpu/nova-core/falcon/hal/ga102.rs | 5 +-
drivers/gpu/nova-core/fb/hal/ga100.rs | 3 +-
drivers/gpu/nova-core/gpu.rs | 9 +-
drivers/gpu/nova-core/regs.rs | 139 ++++-----
drivers/gpu/nova-core/regs/macros.rs | 264 ++++++++--------
rust/kernel/lib.rs | 1 +
rust/kernel/num.rs | 499 ++++++++++++++++++++++++++++++
8 files changed, 783 insertions(+), 255 deletions(-)
---
base-commit: 299eb32863e584cfff7c6b667c3e92ae7d4d2bf9
change-id: 20251001-bounded_ints-1d0457d9ae26
Best regards,
--
Alexandre Courbot <acourbot@...dia.com>
Powered by blists - more mailing lists