Re: [PATCH v5 13/20] rust: io: add projection macro and methods

"Alexandre Courbot" <[email protected]>
Newsgroups org.kernel.vger.linux-pwm,dev.linux.lists.driver-core,dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci,org.kernel.vger.rust-for-linux
Message-ID <[email protected]>
On Fri Jun 26, 2026 at 11:45 PM JST, Gary Guo wrote:
> Add an `io_project!()` macro allows projection from `Io` to a subview of

nit: "to allow projection"?

> it, using the pointer projection mechanism to perform compile-time checks.
>
> For cases where type-casting is required, the `try_cast()` function may be
> used where the size and alignment checks are performed at runtime.
>
> Signed-off-by: Gary Guo <[email protected]>
> ---
>  rust/kernel/io.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 124 insertions(+)
>
> diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
> index 0746b0d209ef..96962498af77 100644
> --- a/rust/kernel/io.rs
> +++ b/rust/kernel/io.rs
> @@ -49,6 +49,7 @@
>  /// - Size of the region is at least as large as the `SIZE` generic parameter.
>  /// - Size of the region is multiple of 4.
>  #[repr(C, align(4))]
> +#[derive(FromBytes)]
>  pub struct Region<const SIZE: usize = 0> {
>      inner: [u8],
>  }
> @@ -90,6 +91,16 @@ fn size(p: *const Self) -> usize {
>      }
>  }
>  
> +// SAFETY: Values read from I/O are always treated as initialized.
> +//
> +// This cannot be derived as `derive(IntoBytes)` does not know that this type is padding free (given
> +// `repr(align(4))`).

In that case the `SAFETY` comment should probably also justify that
there is no padding by citing the invariant of `Region` (which will also
allow us to remove the second paragraph).

> +unsafe impl<const SIZE: usize> IntoBytes for Region<SIZE> {
> +    #[inline]
> +    #[allow(unused)] // Rust 1.87+ stops requiring this and will emit unused warnings.
> +    fn only_derive_is_allowed_to_implement_this_trait() {}
> +}
> +
>  /// Raw representation of an MMIO region.
>  ///
>  /// `MmioRaw<T>` is equivalent to `T __iomem *` in C.
> @@ -339,6 +350,49 @@ fn size(self) -> usize {
>          KnownSize::size(Self::Backend::as_ptr(self.as_view()))
>      }
>  
> +    /// Try to convert into a different typed I/O view.
> +    ///
> +    /// The target type must be of same or smaller size to current type, and the current view must
> +    /// be properly aligned for the target type.

Maybe "Returns `EINVAL` if the target type..." to make it clear this is
runtime-checked and not a static requirement.

> +    ///
> +    /// # Examples
> +    ///
> +    /// ```no_run
> +    /// use kernel::io::{
> +    ///     io_project,
> +    ///     Mmio,
> +    ///     Io,
> +    ///     Region,
> +    /// };
> +    /// #[derive(FromBytes, IntoBytes)]
> +    /// struct MyStruct { field: u32, }

Do we want to make this `#[repr(C)]` to give the right example to
driver authors looking for inspiration here?

> +    ///
> +    /// # fn test(mmio: &Mmio<'_, Region>) -> Result {
> +    /// // let mmio: Mmio<'_, Region>;
> +    /// let whole: Mmio<'_, MyStruct> = mmio.try_cast()?;
> +    /// # Ok::<(), Error>(()) }
> +    /// ```
> +    #[inline]
> +    fn try_cast<U>(self) -> Result<<Self::Backend as IoBackend>::View<'a, U>>
> +    where
> +        Self::Target: FromBytes + IntoBytes,
> +        U: FromBytes + IntoBytes,
> +    {
> +        let view = self.as_view();
> +        let ptr = Self::Backend::as_ptr(view);
> +
> +        if size_of::<U>() > KnownSize::size(ptr) {
> +            return Err(EINVAL);
> +        }
> +
> +        if ptr.addr() % align_of::<U>() != 0 {
> +            return Err(EINVAL);
> +        }
> +
> +        // SAFETY: We have checked bounds and alignment, so this is a valid projection.
> +        Ok(unsafe { Self::Backend::project_view(view, ptr.cast()) })
> +    }
> +
>      /// Fallible 8-bit read with runtime bounds check.
>      #[inline(always)]
>      fn try_read8(self, offset: usize) -> Result<u8>
> @@ -979,3 +1033,73 @@ pub fn relaxed(self) -> RelaxedMmio<'a, T> {
>  // MMIO regions on 64-bit systems also support 64-bit accesses.
>  #[cfg(CONFIG_64BIT)]
>  impl_mmio_io_capable!(RelaxedMmioBackend, u64, readq_relaxed, writeq_relaxed);
> +
> +// This helper turns associated functions to methods so it can be invoked in macro.
> +// Used by `io_project!()` only.
> +#[doc(hidden)]
> +#[derive(Clone, Copy)]
> +pub struct ProjectHelper<T>(pub T);
> +
> +impl<'a, T> ProjectHelper<T>
> +where
> +    T: Io<'a, Backend: IoBackend<View<'a, T::Target> = T>>,
> +{
> +    // These helper methods must not have symbols present in binary to avoid confusion.

nit: "in the binary", lest the reader thinks we are talking about
symbols spelled with 0s and 1s. :)

> +    #[inline(always)]
> +    pub fn as_ptr(self) -> *mut T::Target {
> +        T::Backend::as_ptr(self.0)
> +    }
> +
> +    /// # Safety
> +    ///
> +    /// Same as `IoBackend::project_view`
> +    #[inline(always)]
> +    pub unsafe fn project_view<U: ?Sized + KnownSize>(
> +        self,
> +        ptr: *mut U,
> +    ) -> <T::Backend as IoBackend>::View<'a, U> {
> +        // SAFETY: Per safety requirement.
> +        unsafe { T::Backend::project_view::<T::Target, _>(self.0, ptr) }
> +    }
> +}
> +
> +/// Project an I/O type to a subview of it.
> +///
> +/// 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!).
> +///
> +/// In addition to projecting from [`Io`], you may also project from a [`View`] of an [`Io`].
> +///
> +/// # Examples
> +///
> +/// ```
> +/// use kernel::io::{
> +///     io_project,
> +///     Mmio,
> +/// };
> +/// struct MyStruct { field: u32, }

Same remark about `#[repr(C)]`.

With these considered,

Reviewed-by: Alexandre Courbot <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.