From: Lyude Paul <lyude@redhat.com>
To: dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org,
Alice Ryhl <aliceryhl@google.com>,
Daniel Almeida <daniel.almeida@collabora.com>,
Danilo Krummrich <dakr@kernel.org>,
linux-kernel@vger.kernel.org
Cc: "David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Asahi Lina" <lina+kernel@asahilina.net>
Subject: [PATCH v5 8/8] rust: drm/gem: Add vmap functions to shmem bindings
Date: Thu, 23 Oct 2025 17:22:10 -0400 [thread overview]
Message-ID: <20251023212540.1141999-9-lyude@redhat.com> (raw)
In-Reply-To: <20251023212540.1141999-1-lyude@redhat.com>
One of the more obvious use cases for gem shmem objects is the ability to
create mappings into their contents, specifically iosys mappings. Now that
we've added iosys_map rust bindings to the kernel, let's hook these up in
gem shmem.
Similar to how we handle SGTables, we make sure there's two different types
of mappings: owned mappings (kernel::drm::gem::shmem::VMap) and borrowed
mappings (kernel::drm::gem::shmem::VMapRef).
One last note: we change the #[expect(unused)] for RawIoSysMap::from_raw()
to an #[allow(unused)]. Normally we would simply remove the lint assertion,
however - since shmem is conditionally built, we need allow to avoid
hitting warnings in certain kernel configurations.
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
rust/kernel/drm/gem/shmem.rs | 160 ++++++++++++++++++++++++++++++++++-
rust/kernel/iosys_map.rs | 2 +-
2 files changed, 160 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index 21ccb6c1824be..62a2c12b9fe2a 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -13,15 +13,18 @@
container_of,
drm::{device, driver, gem, private::Sealed},
error::{from_err_ptr, to_result},
+ iosys_map::*,
prelude::*,
scatterlist,
+ transmute::*,
types::{ARef, Opaque},
};
use core::{
+ mem::{self, MaybeUninit},
ops::{Deref, DerefMut},
ptr::NonNull,
};
-use gem::{BaseObjectPrivate, DriverObject, IntoGEMObject};
+use gem::{BaseObject, BaseObjectPrivate, DriverObject, IntoGEMObject};
/// A struct for controlling the creation of shmem-backed GEM objects.
///
@@ -192,6 +195,72 @@ pub fn owned_sg_table(&self) -> Result<SGTable<T>> {
_owner: self.into(),
})
}
+
+ /// Attempt to create a [`RawIoSysMap`] from the gem object.
+ fn raw_vmap<U: AsBytes + FromBytes>(&self) -> Result<RawIoSysMap<U>> {
+ build_assert!(
+ mem::size_of::<U>() > 0,
+ "It doesn't make sense for the mapping type to be a ZST"
+ );
+
+ let mut map: MaybeUninit<bindings::iosys_map> = MaybeUninit::uninit();
+
+ // SAFETY: drm_gem_shmem_vmap can be called with the DMA reservation lock held
+ to_result(unsafe {
+ // TODO: see top of file
+ bindings::dma_resv_lock(self.raw_dma_resv(), core::ptr::null_mut());
+ let ret = bindings::drm_gem_shmem_vmap_locked(self.as_shmem(), map.as_mut_ptr());
+ bindings::dma_resv_unlock(self.raw_dma_resv());
+ ret
+ })?;
+
+ // SAFETY: if drm_gem_shmem_vmap did not fail, map is initialized now
+ Ok(unsafe { RawIoSysMap::from_raw(map.assume_init()) })
+ }
+
+ /// Unmap a [`RawIoSysMap`] from the gem object.
+ ///
+ /// # Safety
+ ///
+ /// - The caller promises that `map` came from a prior call to [`Self::raw_vmap`] on this gem
+ /// object.
+ /// - The caller promises that the memory pointed to by `map` will no longer be accesed through
+ /// this instance.
+ unsafe fn raw_vunmap<U: AsBytes + FromBytes>(&self, map: &mut RawIoSysMap<U>) {
+ let resv = self.raw_dma_resv();
+
+ // SAFETY:
+ // - This function is safe to call with the DMA reservation lock held
+ // - Our `ARef` is proof that the underlying gem object here is initialized and thus safe to
+ // dereference.
+ unsafe {
+ // TODO: see top of file
+ bindings::dma_resv_lock(resv, core::ptr::null_mut());
+ bindings::drm_gem_shmem_vunmap_locked(self.as_shmem(), map.as_raw_mut());
+ bindings::dma_resv_unlock(resv);
+ }
+ }
+
+ /// Creates and returns a virtual kernel memory mapping for this object.
+ pub fn vmap<U: AsBytes + FromBytes>(&self) -> Result<VMapRef<'_, T, U>> {
+ let map = self.raw_vmap()?;
+
+ Ok(VMapRef {
+ // SAFETY:
+ // - The size of the vmap is the same as the size of the gem
+ // - The vmap will remain alive until this object is dropped.
+ map: unsafe { IoSysMapRef::new(map, self.size()) },
+ owner: self,
+ })
+ }
+
+ /// Creates and returns an owned reference to a virtual kernel memory mapping for this object.
+ pub fn owned_vmap<U: AsBytes + FromBytes>(&self) -> Result<VMap<T, U>> {
+ Ok(VMap {
+ map: self.raw_vmap()?,
+ owner: self.into(),
+ })
+ }
}
impl<T: DriverObject> Deref for Object<T> {
@@ -243,6 +312,95 @@ impl<T: DriverObject> driver::AllocImpl for Object<T> {
};
}
+/// A borrowed reference to a virtual mapping for a shmem-based GEM object in kernel address space.
+pub struct VMapRef<'a, D: DriverObject, T: AsBytes + FromBytes> {
+ map: IoSysMapRef<'a, T>,
+ owner: &'a Object<D>,
+}
+
+impl<'a, D: DriverObject, T: AsBytes + FromBytes> Clone for VMapRef<'a, D, T> {
+ fn clone(&self) -> Self {
+ // SAFETY: We have a successful vmap already, so this can't fail
+ unsafe { self.owner.vmap().unwrap_unchecked() }
+ }
+}
+
+impl<'a, D: DriverObject, T: AsBytes + FromBytes> Deref for VMapRef<'a, D, T> {
+ type Target = IoSysMapRef<'a, T>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.map
+ }
+}
+
+impl<'a, D: DriverObject, T: AsBytes + FromBytes> DerefMut for VMapRef<'a, D, T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.map
+ }
+}
+
+impl<'a, D: DriverObject, T: AsBytes + FromBytes> Drop for VMapRef<'a, D, T> {
+ fn drop(&mut self) {
+ // SAFETY: Our existence is proof that this map was previously created using self.owner.
+ unsafe { self.owner.raw_vunmap(&mut self.map) };
+ }
+}
+
+/// An owned reference to a virtual mapping for a shmem-based GEM object in kernel address space.
+///
+/// # Invariants
+///
+/// - The memory pointed to by `map` is at least as large as `T`.
+/// - The memory pointed to by `map` remains valid at least until this object is dropped.
+pub struct VMap<D: DriverObject, T: AsBytes + FromBytes> {
+ map: RawIoSysMap<T>,
+ owner: ARef<Object<D>>,
+}
+
+impl<D: DriverObject, T: AsBytes + FromBytes> Clone for VMap<D, T> {
+ fn clone(&self) -> Self {
+ // SAFETY: We have a successful vmap already, so this can't fail
+ unsafe { self.owner.owned_vmap().unwrap_unchecked() }
+ }
+}
+
+impl<'a, D: DriverObject, T: AsBytes + FromBytes> From<VMapRef<'a, D, T>> for VMap<D, T> {
+ fn from(value: VMapRef<'a, D, T>) -> Self {
+ let this = Self {
+ map: value.map.clone(),
+ owner: value.owner.into(),
+ };
+
+ mem::forget(value);
+ this
+ }
+}
+
+impl<D: DriverObject, T: AsBytes + FromBytes> VMap<D, T> {
+ /// Return a reference to the iosys map for this `VMap`.
+ pub fn get(&self) -> IoSysMapRef<'_, T> {
+ // SAFETY: The size of the iosys_map is equivalent to the size of the gem object.
+ unsafe { IoSysMapRef::new(self.map.clone(), self.owner.size()) }
+ }
+
+ /// Borrows a reference to the object that owns this virtual mapping.
+ pub fn owner(&self) -> &Object<D> {
+ &self.owner
+ }
+}
+
+impl<D: DriverObject, T: AsBytes + FromBytes> Drop for VMap<D, T> {
+ fn drop(&mut self) {
+ // SAFETY: Our existence is proof that this map was previously created using self.owner
+ unsafe { self.owner.raw_vunmap(&mut self.map) };
+ }
+}
+
+/// SAFETY: `iosys_map` objects are safe to send across threads.
+unsafe impl<D: DriverObject, T: AsBytes + FromBytes> Send for VMap<D, T> {}
+/// SAFETY: `iosys_map` objects are safe to send across threads.
+unsafe impl<D: DriverObject, T: AsBytes + FromBytes> Sync for VMap<D, T> {}
+
/// An owned reference to a scatter-gather table of DMA address spans for a GEM shmem object.
///
/// This object holds an owned reference to the underlying GEM shmem object, ensuring that the
diff --git a/rust/kernel/iosys_map.rs b/rust/kernel/iosys_map.rs
index 4da0ab57cf35c..e7540139ada01 100644
--- a/rust/kernel/iosys_map.rs
+++ b/rust/kernel/iosys_map.rs
@@ -32,7 +32,7 @@
impl<T: AsBytes + FromBytes> RawIoSysMap<T> {
/// Convert from a raw `bindings::iosys_map`.
- #[expect(unused)]
+ #[allow(unused)]
#[inline]
pub(crate) fn from_raw(val: bindings::iosys_map) -> Self {
Self(val, PhantomData)
--
2.51.0
prev parent reply other threads:[~2025-10-23 21:27 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-23 21:22 [PATCH v5 0/8] Rust bindings for gem shmem + iosys_map Lyude Paul
2025-10-23 21:22 ` [PATCH v5 1/8] rust/drm: Add gem::impl_aref_for_gem_obj! Lyude Paul
2025-11-24 15:23 ` Daniel Almeida
2025-10-23 21:22 ` [PATCH v5 2/8] rust: helpers: Add bindings/wrappers for dma_resv_lock Lyude Paul
2025-10-23 21:22 ` [PATCH v5 3/8] rust: drm: gem: Add raw_dma_resv() function Lyude Paul
2025-10-23 21:22 ` [PATCH v5 4/8] rust: gem: Introduce DriverObject::Args Lyude Paul
2025-11-04 20:41 ` Deborah Brouwer
2025-11-24 15:25 ` Daniel Almeida
2025-10-23 21:22 ` [PATCH v5 5/8] rust: drm: gem: shmem: Add DRM shmem helper abstraction Lyude Paul
2025-11-24 15:41 ` Daniel Almeida
2025-12-02 22:01 ` Lyude Paul
2025-10-23 21:22 ` [PATCH v5 6/8] rust: drm: gem: Introduce shmem::SGTable Lyude Paul
2025-11-24 15:42 ` Daniel Almeida
2025-10-23 21:22 ` [PATCH v5 7/8] rust: Introduce iosys_map bindings Lyude Paul
2025-10-23 21:22 ` Lyude Paul [this message]
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=20251023212540.1141999-9-lyude@redhat.com \
--to=lyude@redhat.com \
--cc=a.hindborg@kernel.org \
--cc=airlied@gmail.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=lina+kernel@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--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;
as well as URLs for NNTP newsgroup(s).