[PATCH v2 10/16] rust: io: register: make register have a typed base

From: Gary Guo

Date: Wed Aug 05 2026 - 12:43:53 EST


Previously `register!` defined registers can be used on any untyped I/O
regions. With all users specifying their desired register type now,
propagate the specified type and restrict I/O access only when type
matches.

Also, add an `io_project!` example which is enabled by this change.

Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
---
rust/kernel/io.rs | 13 ++++++++++
rust/kernel/io/register.rs | 64 +++++++++++++++++++---------------------------
2 files changed, 40 insertions(+), 37 deletions(-)

diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index d92e0b6adc99..d56c8faa7d7c 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -1798,21 +1798,34 @@ pub fn project_loc<U, L>(self, location: L) -> <T::Backend as IoBackend>::View<'
/// The syntax is of form `io_project!(io, proj)` where `io` is an expression to a type that
/// implements [`Io`] and `proj` is a [projection specification](kernel::ptr::project!).
///
+/// `io_project!` can also project to subview of registers defined with [`register!`] macro.
+/// Register projection has syntax `io_project!(io, try: REGISTER)` for fallible projection and
+/// `io_project!(io, build: REGISTER)` for infallible projection.
+///
/// # Examples
///
/// ```
/// use kernel::io::{
/// io_project,
+/// register,
/// Mmio,
/// };
/// #[repr(C)]
/// struct MyStruct { field: u32, }
///
+/// register! {
+/// base: MyStruct;
+/// FIELD(u32) @ 0 {
+/// 31:0 val;
+/// }
+/// }
+///
/// # fn test(mmio: Mmio<'_, [MyStruct]>) -> Result {
/// // let mmio: Mmio<[MyStruct]>;
/// let field: Mmio<'_, u32> = io_project!(mmio, [try: 1].field);
/// let whole: Mmio<'_, MyStruct> = io_project!(mmio, [try: 2]);
/// let nested: Mmio<'_, u32> = io_project!(whole, .field);
+/// let reg: Mmio<'_, FIELD> = io_project!(whole, build: FIELD);
/// # Ok::<(), Error>(()) }
/// ```
#[macro_export]
diff --git a/rust/kernel/io/register.rs b/rust/kernel/io/register.rs
index 7dca2437b551..dc800fc71172 100644
--- a/rust/kernel/io/register.rs
+++ b/rust/kernel/io/register.rs
@@ -121,10 +121,11 @@
io::IoLoc, //
};

-use super::Region;
-
/// Trait implemented by all registers.
pub trait Register: Sized {
+ /// Base type for this register.
+ type Base: ?Sized;
+
/// Start offset of the register.
///
/// The interpretation of this offset depends on the type of the register.
@@ -136,9 +137,9 @@ pub trait FixedRegister: Register {}

/// Allows `()` to be used as the `location` parameter of [`Io::write`](super::Io::write) when
/// passing a [`FixedRegister`] value.
-impl<const SIZE: usize, T> IoLoc<Region<SIZE>, T> for ()
+impl<Base: ?Sized, T> IoLoc<Base, T> for ()
where
- T: FixedRegister,
+ T: FixedRegister<Base = Base>,
{
#[inline(always)]
fn offset(self) -> usize {
@@ -148,9 +149,9 @@ fn offset(self) -> usize {

/// A [`FixedRegister`] carries its location in its type. Thus `FixedRegister` values can be used
/// as an [`IoLoc`].
-impl<const SIZE: usize, T> IoLoc<Region<SIZE>, T> for T
+impl<Base: ?Sized, T> IoLoc<Base, T> for T
where
- T: FixedRegister,
+ T: FixedRegister<Base = Base>,
{
#[inline(always)]
fn offset(self) -> usize {
@@ -171,9 +172,9 @@ pub const fn new() -> Self {
}
}

-impl<const SIZE: usize, T> IoLoc<Region<SIZE>, T> for FixedRegisterLoc<T>
+impl<Base: ?Sized, T> IoLoc<Base, T> for FixedRegisterLoc<T>
where
- T: FixedRegister,
+ T: FixedRegister<Base = Base>,
{
#[inline(always)]
fn offset(self) -> usize {
@@ -240,9 +241,9 @@ const fn offset(self) -> usize {
}
}

-impl<const SIZE: usize, T, B> IoLoc<Region<SIZE>, T> for RelativeRegisterLoc<T, B>
+impl<SuperBase: ?Sized, T, B> IoLoc<SuperBase, T> for RelativeRegisterLoc<T, B>
where
- T: RelativeRegister,
+ T: RelativeRegister<Base = SuperBase>,
B: RegisterBase<T::BaseFamily> + ?Sized,
{
#[inline(always)]
@@ -282,9 +283,9 @@ pub fn try_new(idx: usize) -> Option<Self> {
}
}

-impl<const SIZE: usize, T> IoLoc<Region<SIZE>, T> for RegisterArrayLoc<T>
+impl<Base: ?Sized, T> IoLoc<Base, T> for RegisterArrayLoc<T>
where
- T: RegisterArray,
+ T: RegisterArray<Base = Base>,
{
#[inline(always)]
fn offset(self) -> usize {
@@ -367,9 +368,9 @@ pub fn try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>> {
}
}

-impl<const SIZE: usize, T, B> IoLoc<Region<SIZE>, T> for RelativeRegisterArrayLoc<T, B>
+impl<SuperBase: ?Sized, T, B> IoLoc<SuperBase, T> for RelativeRegisterArrayLoc<T, B>
where
- T: RelativeRegisterArray,
+ T: RelativeRegisterArray<Base = SuperBase>,
B: RegisterBase<T::BaseFamily> + ?Sized,
{
#[inline(always)]
@@ -393,9 +394,9 @@ pub trait LocatedRegister<Base: ?Sized> {
fn into_io_op(self) -> (Self::Location, Self::Value);
}

-impl<const SIZE: usize, T> LocatedRegister<Region<SIZE>> for T
+impl<Base: ?Sized, T> LocatedRegister<Base> for T
where
- T: FixedRegister,
+ T: FixedRegister<Base = Base>,
{
type Location = FixedRegisterLoc<Self::Value>;
type Value = T;
@@ -823,12 +824,7 @@ fn into_io_op(self) -> (FixedRegisterLoc<T>, T) {
/// ```
#[macro_export]
macro_rules! register {
- (base: $reg_base:ty;) => {
- const _: () = {
- #[allow(unused)]
- type Base = $reg_base;
- };
- };
+ (base: $reg_base:ty;) => {};

// Creates a register at a fixed offset of the MMIO space.
//
@@ -843,7 +839,7 @@ macro_rules! register {
$($rest:tt)*
) => {
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
- $crate::register!(@io_base $name
+ $crate::register!(@io_base $reg_base; $name
@ $crate::register!(@offset $(@ $offset)? $(=> $alias $([$alias_idx])?)?)
);
$crate::register!(@io_fixed $(#[$attr])* $vis $name);
@@ -858,7 +854,7 @@ macro_rules! register {
$($rest:tt)*
) => {
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
- $crate::register!(@io_base $name @ $offset);
+ $crate::register!(@io_base $reg_base; $name @ $offset);
$crate::register!(@io_relative $vis $name @ $base);
$crate::register!(base: $reg_base; $($rest)*);
};
@@ -871,7 +867,7 @@ macro_rules! register {
$($rest:tt)*
) => {
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
- $crate::register!(@io_base $name @ $crate::register!(@offset => $alias));
+ $crate::register!(@io_base $reg_base; $name @ $crate::register!(@offset => $alias));
$crate::register!(@io_relative $vis $name @ $base);
$crate::register!(base: $reg_base; $($rest)*);
};
@@ -884,7 +880,7 @@ macro_rules! register {
$($rest:tt)*
) => {
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
- $crate::register!(@io_base $name @ $offset);
+ $crate::register!(@io_base $reg_base; $name @ $offset);
$crate::register!(@io_array $vis $name
[ $size, stride = $crate::register!(@stride $storage $(, $stride)?) ]
);
@@ -900,7 +896,7 @@ macro_rules! register {
$($rest:tt)*
) => {
$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
- $crate::register!(@io_base $name @ $offset);
+ $crate::register!(@io_base $reg_base; $name @ $offset);
$crate::register!(@io_relative_array $vis $name
[ $size, stride = $crate::register!(@stride $storage $(, $stride)?) ] @ $base + $offset
);
@@ -920,7 +916,7 @@ macro_rules! register {
);

$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
- $crate::register!(@io_base $name @ $crate::register!(@offset => $alias [$idx]));
+ $crate::register!(@io_base $reg_base; $name @ $crate::register!(@offset => $alias [$idx]));
$crate::register!(@io_relative $vis $name @ $base);
$crate::register!(base: $reg_base; $($rest)*);
};
@@ -960,8 +956,10 @@ macro_rules! register {
(@stride $ty: ty) => { ::core::mem::size_of::<$ty>() };

// Implementations shared by all registers types.
- (@io_base $name:ident @ $offset:expr) => {
+ (@io_base $reg_base:ty; $name:ident @ $offset:expr) => {
impl $crate::io::register::Register for $name {
+ type Base = $reg_base;
+
const OFFSET: usize = $offset;
}
};
@@ -1010,12 +1008,4 @@ impl $crate::io::register::RegisterArray for $name {

impl $crate::io::register::RelativeRegisterArray for $name {}
};
-
- // Compatibility rule when base is not specified.
- ($($rest:tt)*) => {
- $crate::register!(
- base: $crate::io::Region;
- $($rest)*
- );
- }
}

--
2.54.0