From: Gary Guo <gary@kernel.org>
To: "Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>
Cc: rust-for-linux@vger.kernel.org, driver-core@lists.linux.dev,
linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org
Subject: [PATCH 1/8] rust: io: generalize `MmioRaw` to pointer to arbitrary type
Date: Mon, 23 Mar 2026 15:37:53 +0000 [thread overview]
Message-ID: <20260323153807.1360705-2-gary@kernel.org> (raw)
In-Reply-To: <20260323153807.1360705-1-gary@kernel.org>
From: Gary Guo <gary@garyguo.net>
Conceptually, `MmioRaw` is just `__iomem *`, so it should work for any
types. The existing use case where it represents a region of compile-time
known minimum size and run-time known actual size is moved to a custom
dynamic-sized type `Region<SIZE>` instead. The `maxsize` method is also
renamed to `size` to reflect that it is the actual size (not a bound) of
the region.
Signed-off-by: Gary Guo <gary@garyguo.net>
---
rust/kernel/devres.rs | 7 ++--
rust/kernel/io.rs | 84 +++++++++++++++++++++++++++++++++----------
rust/kernel/io/mem.rs | 4 +--
rust/kernel/pci/io.rs | 4 +--
4 files changed, 74 insertions(+), 25 deletions(-)
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 9e5f93aed20c..65a4082122af 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -71,14 +71,15 @@ struct Inner<T> {
/// IoKnownSize,
/// Mmio,
/// MmioRaw,
-/// PhysAddr, //
+/// PhysAddr,
+/// Region, //
/// },
/// prelude::*,
/// };
/// use core::ops::Deref;
///
/// // See also [`pci::Bar`] for a real example.
-/// struct IoMem<const SIZE: usize>(MmioRaw<SIZE>);
+/// struct IoMem<const SIZE: usize>(MmioRaw<Region<SIZE>>);
///
/// impl<const SIZE: usize> IoMem<SIZE> {
/// /// # Safety
@@ -93,7 +94,7 @@ struct Inner<T> {
/// return Err(ENOMEM);
/// }
///
-/// Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?))
+/// Ok(IoMem(MmioRaw::new_region(addr as usize, SIZE)?))
/// }
/// }
///
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index fcc7678fd9e3..d7f2145fa9b9 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -6,7 +6,8 @@
use crate::{
bindings,
- prelude::*, //
+ prelude::*,
+ ptr::KnownSize, //
};
pub mod mem;
@@ -31,39 +32,85 @@
/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.
pub type ResourceSize = bindings::resource_size_t;
+/// Untyped I/O region.
+///
+/// This type can be used when an I/O region without known type information has a compile-time known
+/// minimum size (and a runtime known actual size).
+///
+/// The `SIZE` generic parameter indicate the minimum size of the region.
+#[repr(transparent)]
+pub struct Region<const SIZE: usize = 0> {
+ inner: [u8],
+}
+
+impl<const SIZE: usize> KnownSize for Region<SIZE> {
+ #[inline(always)]
+ fn size(p: *const Self) -> usize {
+ (p as *const [u8]).len()
+ }
+}
+
/// Raw representation of an MMIO region.
///
+/// `MmioRaw<T>` is equivalent to `T __iomem *` in C.
+///
/// By itself, the existence of an instance of this structure does not provide any guarantees that
/// the represented MMIO region does exist or is properly mapped.
///
/// Instead, the bus specific MMIO implementation must convert this raw representation into an
/// `Mmio` instance providing the actual memory accessors. Only by the conversion into an `Mmio`
/// structure any guarantees are given.
-pub struct MmioRaw<const SIZE: usize = 0> {
- addr: usize,
- maxsize: usize,
+pub struct MmioRaw<T: ?Sized> {
+ /// Pointer is in I/O address space.
+ ///
+ /// The provenance does not matter, only the address and metadata do.
+ addr: *mut T,
}
-impl<const SIZE: usize> MmioRaw<SIZE> {
- /// Returns a new `MmioRaw` instance on success, an error otherwise.
- pub fn new(addr: usize, maxsize: usize) -> Result<Self> {
- if maxsize < SIZE {
+// SAFETY: `MmioRaw` is just an address, so is thread-safe.
+unsafe impl<T: ?Sized> Send for MmioRaw<T> {}
+// SAFETY: `MmioRaw` is just an address, so is thread-safe.
+unsafe impl<T: ?Sized> Sync for MmioRaw<T> {}
+
+impl<T> MmioRaw<T> {
+ /// Create a `MmioRaw` from address.
+ #[inline]
+ pub fn new(addr: usize) -> Self {
+ Self {
+ addr: core::ptr::without_provenance_mut(addr),
+ }
+ }
+}
+
+impl<const SIZE: usize> MmioRaw<Region<SIZE>> {
+ /// Create a `MmioRaw` representing a I/O region with given size.
+ ///
+ /// The size is checked against the minimum size specified via const generics.
+ #[inline]
+ pub fn new_region(addr: usize, size: usize) -> Result<Self> {
+ if size < SIZE {
return Err(EINVAL);
}
- Ok(Self { addr, maxsize })
+ let addr = core::ptr::slice_from_raw_parts_mut::<u8>(
+ core::ptr::without_provenance_mut(addr),
+ size,
+ ) as *mut Region<SIZE>;
+ Ok(Self { addr })
}
+}
+impl<T: ?Sized + KnownSize> MmioRaw<T> {
/// Returns the base address of the MMIO region.
#[inline]
pub fn addr(&self) -> usize {
- self.addr
+ self.addr.addr()
}
- /// Returns the maximum size of the MMIO region.
+ /// Returns the size of the MMIO region.
#[inline]
- pub fn maxsize(&self) -> usize {
- self.maxsize
+ pub fn size(&self) -> usize {
+ KnownSize::size(self.addr)
}
}
@@ -89,12 +136,13 @@ pub fn maxsize(&self) -> usize {
/// Mmio,
/// MmioRaw,
/// PhysAddr,
+/// Region,
/// },
/// };
/// use core::ops::Deref;
///
/// // See also `pci::Bar` for a real example.
-/// struct IoMem<const SIZE: usize>(MmioRaw<SIZE>);
+/// struct IoMem<const SIZE: usize>(MmioRaw<Region<SIZE>>);
///
/// impl<const SIZE: usize> IoMem<SIZE> {
/// /// # Safety
@@ -109,7 +157,7 @@ pub fn maxsize(&self) -> usize {
/// return Err(ENOMEM);
/// }
///
-/// Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?))
+/// Ok(IoMem(MmioRaw::new_region(addr as usize, SIZE)?))
/// }
/// }
///
@@ -139,7 +187,7 @@ pub fn maxsize(&self) -> usize {
/// # }
/// ```
#[repr(transparent)]
-pub struct Mmio<const SIZE: usize = 0>(MmioRaw<SIZE>);
+pub struct Mmio<const SIZE: usize = 0>(MmioRaw<Region<SIZE>>);
/// Checks whether an access of type `U` at the given `offset`
/// is valid within this region.
@@ -767,7 +815,7 @@ fn addr(&self) -> usize {
/// Returns the maximum size of this mapping.
#[inline]
fn maxsize(&self) -> usize {
- self.0.maxsize()
+ self.0.size()
}
}
@@ -782,7 +830,7 @@ impl<const SIZE: usize> Mmio<SIZE> {
///
/// 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<SIZE>) -> &Self {
+ pub unsafe fn from_raw(raw: &MmioRaw<Region<SIZE>>) -> &Self {
// SAFETY: `Mmio` is a transparent wrapper around `MmioRaw`.
unsafe { &*core::ptr::from_ref(raw).cast() }
}
diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs
index 7dc78d547f7a..9117d417f99c 100644
--- a/rust/kernel/io/mem.rs
+++ b/rust/kernel/io/mem.rs
@@ -231,7 +231,7 @@ fn deref(&self) -> &Self::Target {
/// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the
/// start of the I/O memory mapped region.
pub struct IoMem<const SIZE: usize = 0> {
- io: MmioRaw<SIZE>,
+ io: MmioRaw<super::Region<SIZE>>,
}
impl<const SIZE: usize> IoMem<SIZE> {
@@ -266,7 +266,7 @@ fn ioremap(resource: &Resource) -> Result<Self> {
return Err(ENOMEM);
}
- let io = MmioRaw::new(addr as usize, size)?;
+ let io = MmioRaw::new_region(addr as usize, size)?;
let io = IoMem { io };
Ok(io)
diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
index ae78676c927f..0335b5068f69 100644
--- a/rust/kernel/pci/io.rs
+++ b/rust/kernel/pci/io.rs
@@ -148,7 +148,7 @@ impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> {
/// memory mapped PCI BAR and its size.
pub struct Bar<const SIZE: usize = 0> {
pdev: ARef<Device>,
- io: MmioRaw<SIZE>,
+ io: MmioRaw<crate::io::Region<SIZE>>,
num: i32,
}
@@ -184,7 +184,7 @@ pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> {
return Err(ENOMEM);
}
- let io = match MmioRaw::new(ioptr, len as usize) {
+ let io = match MmioRaw::new_region(ioptr, len as usize) {
Ok(io) => io,
Err(err) => {
// SAFETY:
--
2.51.2
next prev parent reply other threads:[~2026-03-23 15:38 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <OxgMwl1EcYLh4AqdBa-FaFap0ODNxpID-Hnns6odQVjvPTXqh6VoXM01bZmoVkAOF_5udNfKuCP8YJoW4UE5Fg==@protonmail.internalid>
2026-03-23 15:37 ` [PATCH 0/8] I/O type generalization and projection Gary Guo
2026-03-23 15:37 ` Gary Guo [this message]
2026-03-26 12:53 ` [PATCH 1/8] rust: io: generalize `MmioRaw` to pointer to arbitrary type Andreas Hindborg
2026-03-26 14:31 ` Gary Guo
2026-03-23 15:37 ` [PATCH 2/8] rust: io: generalize `Mmio` " Gary Guo
2026-03-26 13:04 ` Andreas Hindborg
2026-03-26 14:32 ` Gary Guo
2026-03-26 18:23 ` Andreas Hindborg
2026-03-23 15:37 ` [PATCH 3/8] rust: io: use pointer types instead of address Gary Guo
2026-03-26 14:20 ` Andreas Hindborg
2026-03-26 14:35 ` Gary Guo
2026-03-27 10:11 ` Miguel Ojeda
2026-03-23 15:37 ` [PATCH 4/8] rust: io: add view type Gary Guo
2026-03-26 14:31 ` Andreas Hindborg
2026-03-23 15:37 ` [PATCH 5/8] rust: dma: add methods to unsafely create reference from subview Gary Guo
2026-03-26 14:37 ` Andreas Hindborg
2026-03-26 14:44 ` Gary Guo
2026-03-23 15:37 ` [PATCH 6/8] rust: io: add `read_val` and `write_val` function on I/O view Gary Guo
2026-03-27 8:21 ` Andreas Hindborg
2026-03-27 12:19 ` Gary Guo
2026-03-23 15:37 ` [PATCH 7/8] gpu: nova-core: use I/O projection for cleaner encapsulation Gary Guo
2026-03-23 15:38 ` [PATCH 8/8] rust: dma: drop `dma_read!` and `dma_write!` API Gary Guo
2026-03-27 8:25 ` Andreas Hindborg
2026-03-25 11:11 ` [PATCH 0/8] I/O type generalization and projection Andreas Hindborg
2026-03-25 11:19 ` Miguel Ojeda
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260323153807.1360705-2-gary@kernel.org \
--to=gary@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=aliceryhl@google.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=driver-core@lists.linux.dev \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox