[PATCH v7 06/10] rust: io: use generic read/write accessors for primitive accesses

From: Alexandre Courbot

Date: Tue Feb 24 2026 - 09:23:45 EST


By providing the required `IoLoc` implementations on `usize`, we can
leverage the generic accessors and reduce the number of unsafe blocks in
the module.

Signed-off-by: Alexandre Courbot <acourbot@xxxxxxxxxx>
---
rust/kernel/io.rs | 103 +++++++++++++++++++-----------------------------------
1 file changed, 35 insertions(+), 68 deletions(-)

diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index fdd2549d8e13..256eba16ccc8 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -275,6 +275,25 @@ fn try_init_default<F, E>(self, f: F) -> Result<IoWrite<T, Self>, E>
}
}

+/// Implements [`IoLoc<$ty>`] for [`usize`], allowing to use `usize` as a parameter of
+/// [`Io::read`] and [`Io::write`].
+macro_rules! impl_usize_ioloc {
+ ($($ty:ty),*) => {
+ $(
+ impl IoLoc<$ty> for usize {
+ type IoType = $ty;
+
+ fn offset(self) -> usize {
+ self
+ }
+ }
+ )*
+ }
+}
+
+// Provide the ability to read any primitive type from a [`usize`].
+impl_usize_ioloc!(u8, u16, u32, u64);
+
/// A pending I/O write operation, bundling a value with the [`IoLoc`] it should be written to.
///
/// Created by [`IoLoc::set`], [`IoLoc::zeroed`], [`IoLoc::default`], [`IoLoc::init`], or
@@ -369,10 +388,7 @@ fn try_read8(&self, offset: usize) -> Result<u8>
where
Self: IoCapable<u8>,
{
- let address = self.io_addr::<u8>(offset)?;
-
- // SAFETY: `address` has been validated by `io_addr`.
- Ok(unsafe { self.io_read(address) })
+ self.try_read(offset)
}

/// Fallible 16-bit read with runtime bounds check.
@@ -381,10 +397,7 @@ fn try_read16(&self, offset: usize) -> Result<u16>
where
Self: IoCapable<u16>,
{
- let address = self.io_addr::<u16>(offset)?;
-
- // SAFETY: `address` has been validated by `io_addr`.
- Ok(unsafe { self.io_read(address) })
+ self.try_read(offset)
}

/// Fallible 32-bit read with runtime bounds check.
@@ -393,10 +406,7 @@ fn try_read32(&self, offset: usize) -> Result<u32>
where
Self: IoCapable<u32>,
{
- let address = self.io_addr::<u32>(offset)?;
-
- // SAFETY: `address` has been validated by `io_addr`.
- Ok(unsafe { self.io_read(address) })
+ self.try_read(offset)
}

/// Fallible 64-bit read with runtime bounds check.
@@ -405,10 +415,7 @@ fn try_read64(&self, offset: usize) -> Result<u64>
where
Self: IoCapable<u64>,
{
- let address = self.io_addr::<u64>(offset)?;
-
- // SAFETY: `address` has been validated by `io_addr`.
- Ok(unsafe { self.io_read(address) })
+ self.try_read(offset)
}

/// Fallible 8-bit write with runtime bounds check.
@@ -417,11 +424,7 @@ fn try_write8(&self, value: u8, offset: usize) -> Result
where
Self: IoCapable<u8>,
{
- let address = self.io_addr::<u8>(offset)?;
-
- // SAFETY: `address` has been validated by `io_addr`.
- unsafe { self.io_write(value, address) };
- Ok(())
+ self.try_write(offset.set(value))
}

/// Fallible 16-bit write with runtime bounds check.
@@ -430,11 +433,7 @@ fn try_write16(&self, value: u16, offset: usize) -> Result
where
Self: IoCapable<u16>,
{
- let address = self.io_addr::<u16>(offset)?;
-
- // SAFETY: `address` has been validated by `io_addr`.
- unsafe { self.io_write(value, address) };
- Ok(())
+ self.try_write(offset.set(value))
}

/// Fallible 32-bit write with runtime bounds check.
@@ -443,11 +442,7 @@ fn try_write32(&self, value: u32, offset: usize) -> Result
where
Self: IoCapable<u32>,
{
- let address = self.io_addr::<u32>(offset)?;
-
- // SAFETY: `address` has been validated by `io_addr`.
- unsafe { self.io_write(value, address) };
- Ok(())
+ self.try_write(offset.set(value))
}

/// Fallible 64-bit write with runtime bounds check.
@@ -456,11 +451,7 @@ fn try_write64(&self, value: u64, offset: usize) -> Result
where
Self: IoCapable<u64>,
{
- let address = self.io_addr::<u64>(offset)?;
-
- // SAFETY: `address` has been validated by `io_addr`.
- unsafe { self.io_write(value, address) };
- Ok(())
+ self.try_write(offset.set(value))
}

/// Infallible 8-bit read with compile-time bounds check.
@@ -469,10 +460,7 @@ fn read8(&self, offset: usize) -> u8
where
Self: IoKnownSize + IoCapable<u8>,
{
- let address = self.io_addr_assert::<u8>(offset);
-
- // SAFETY: `address` has been validated by `io_addr_assert`.
- unsafe { self.io_read(address) }
+ self.read(offset)
}

/// Infallible 16-bit read with compile-time bounds check.
@@ -481,10 +469,7 @@ fn read16(&self, offset: usize) -> u16
where
Self: IoKnownSize + IoCapable<u16>,
{
- let address = self.io_addr_assert::<u16>(offset);
-
- // SAFETY: `address` has been validated by `io_addr_assert`.
- unsafe { self.io_read(address) }
+ self.read(offset)
}

/// Infallible 32-bit read with compile-time bounds check.
@@ -493,10 +478,7 @@ fn read32(&self, offset: usize) -> u32
where
Self: IoKnownSize + IoCapable<u32>,
{
- let address = self.io_addr_assert::<u32>(offset);
-
- // SAFETY: `address` has been validated by `io_addr_assert`.
- unsafe { self.io_read(address) }
+ self.read(offset)
}

/// Infallible 64-bit read with compile-time bounds check.
@@ -505,10 +487,7 @@ fn read64(&self, offset: usize) -> u64
where
Self: IoKnownSize + IoCapable<u64>,
{
- let address = self.io_addr_assert::<u64>(offset);
-
- // SAFETY: `address` has been validated by `io_addr_assert`.
- unsafe { self.io_read(address) }
+ self.read(offset)
}

/// Infallible 8-bit write with compile-time bounds check.
@@ -517,10 +496,7 @@ fn write8(&self, value: u8, offset: usize)
where
Self: IoKnownSize + IoCapable<u8>,
{
- let address = self.io_addr_assert::<u8>(offset);
-
- // SAFETY: `address` has been validated by `io_addr_assert`.
- unsafe { self.io_write(value, address) }
+ self.write(offset.set(value))
}

/// Infallible 16-bit write with compile-time bounds check.
@@ -529,10 +505,7 @@ fn write16(&self, value: u16, offset: usize)
where
Self: IoKnownSize + IoCapable<u16>,
{
- let address = self.io_addr_assert::<u16>(offset);
-
- // SAFETY: `address` has been validated by `io_addr_assert`.
- unsafe { self.io_write(value, address) }
+ self.write(offset.set(value))
}

/// Infallible 32-bit write with compile-time bounds check.
@@ -541,10 +514,7 @@ fn write32(&self, value: u32, offset: usize)
where
Self: IoKnownSize + IoCapable<u32>,
{
- let address = self.io_addr_assert::<u32>(offset);
-
- // SAFETY: `address` has been validated by `io_addr_assert`.
- unsafe { self.io_write(value, address) }
+ self.write(offset.set(value))
}

/// Infallible 64-bit write with compile-time bounds check.
@@ -553,10 +523,7 @@ fn write64(&self, value: u64, offset: usize)
where
Self: IoKnownSize + IoCapable<u64>,
{
- let address = self.io_addr_assert::<u64>(offset);
-
- // SAFETY: `address` has been validated by `io_addr_assert`.
- unsafe { self.io_write(value, address) }
+ self.write(offset.set(value))
}

/// Generic fallible read with runtime bounds check.

--
2.53.0