Re: [PATCH 2/8] rust: io: generalize `Mmio` to arbitrary type

From: Alexandre Courbot

Date: Sun Apr 05 2026 - 10:56:01 EST


On Tue Mar 24, 2026 at 12:37 AM JST, Gary Guo wrote:
> From: Gary Guo <gary@xxxxxxxxxxx>
>
> Currently, `io::Mmio` always represent an untyped region of a compile-time
> known minimum size, which is roughly equivalent to `void __iomem*` (but
> with bound checks). However, it is useful to also be to represent I/O
> memory of a specific type, e.g. `u32 __iomem*` or `struct foo __iomem*`.
>
> Thus, make `Mmio` generic on arbitrary `T`, where `T` is a sized type, or a
> DST that implements `KnownSize`. Similar to the `MmioRaw` change, the
> existing behaviour is preserved in the form of `Mmio<Region<SIZE>>`. This
> change brings the MMIO closer to the DMA coherent allocation types that we
> have, which is already typed.

You probably noticed, but the regular `read8`, `read16` remain available
irrespective of the `T` parameter, allowing the `Mmio` to be accessed
using both the structured type and arbitrary primitives with an offset.
I cannot find a reason to label this as unsound, but it might be
confusing as it makes projection an additional capability on top of the
existing raw I/O methods. This might be worth mentioning in the
documentation, or maybe the primitive accessors should only be made
available to `Io<Region>`?

>
> To be able to implement `IoKnownSize`, add a `MIN_SIZE` constant to
> `KnownSize` trait to represent compile-time known minimum size of a
> specific type.
>
> Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
> ---
> rust/kernel/devres.rs | 2 +-
> rust/kernel/io.rs | 63 ++++++++++++++++++++++----------------
> rust/kernel/io/mem.rs | 4 +--
> rust/kernel/io/poll.rs | 6 ++--
> rust/kernel/io/register.rs | 19 +++++++-----
> rust/kernel/pci/io.rs | 2 +-
> rust/kernel/ptr.rs | 7 +++++
> 7 files changed, 64 insertions(+), 39 deletions(-)
>
> diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
> index 65a4082122af..3e22c63efb98 100644
> --- a/rust/kernel/devres.rs
> +++ b/rust/kernel/devres.rs
> @@ -106,7 +106,7 @@ struct Inner<T> {
> /// }
> ///
> /// impl<const SIZE: usize> Deref for IoMem<SIZE> {
> -/// type Target = Mmio<SIZE>;
> +/// type Target = Mmio<Region<SIZE>>;
> ///
> /// fn deref(&self) -> &Self::Target {
> /// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`.
> diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
> index d7f2145fa9b9..5a26b1e7e533 100644
> --- a/rust/kernel/io.rs
> +++ b/rust/kernel/io.rs
> @@ -44,6 +44,8 @@ pub struct Region<const SIZE: usize = 0> {
> }
>
> impl<const SIZE: usize> KnownSize for Region<SIZE> {
> + const MIN_SIZE: usize = SIZE;
> +
> #[inline(always)]
> fn size(p: *const Self) -> usize {
> (p as *const [u8]).len()
> @@ -169,7 +171,7 @@ pub fn size(&self) -> usize {
> /// }
> ///
> /// impl<const SIZE: usize> Deref for IoMem<SIZE> {
> -/// type Target = Mmio<SIZE>;
> +/// type Target = Mmio<Region<SIZE>>;
> ///
> /// fn deref(&self) -> &Self::Target {
> /// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`.
> @@ -187,7 +189,7 @@ pub fn size(&self) -> usize {
> /// # }
> /// ```
> #[repr(transparent)]
> -pub struct Mmio<const SIZE: usize = 0>(MmioRaw<Region<SIZE>>);
> +pub struct Mmio<T: ?Sized>(MmioRaw<T>);
>
> /// Checks whether an access of type `U` at the given `offset`
> /// is valid within this region.
> @@ -462,9 +464,10 @@ fn write64(&self, value: u64, offset: usize)
> /// use kernel::io::{
> /// Io,
> /// Mmio,
> + /// Region,
> /// };
> ///
> - /// fn do_reads(io: &Mmio) -> Result {
> + /// fn do_reads(io: &Mmio<Region<0>>) -> Result {

This can be `&Mmio<Region>`, and probably should be as it is closer to
the original code which also used a size of `0` by default (applies to
the other examples as well).

<snip>
> -impl<const SIZE: usize> Mmio<SIZE> {
> +impl<T: ?Sized + KnownSize> Mmio<T> {
> /// Converts an `MmioRaw` into an `Mmio` instance, providing the accessors to the MMIO mapping.
> ///
> /// # Safety
> ///
> /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size
> - /// `maxsize`.
> - pub unsafe fn from_raw(raw: &MmioRaw<Region<SIZE>>) -> &Self {
> + /// `addr.size()`.

That probably shouldn't be fixed by this patch, but there are is `addr`
parameter for this method.