public inbox for rust-for-linux@vger.kernel.org
 help / color / mirror / Atom feed
From: Lyude Paul <lyude@redhat.com>
To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	rust-for-linux@vger.kernel.org,
	Danilo Krummrich <dakr@kernel.org>
Cc: nouveau@lists.freedesktop.org,
	Daniel Almeida <daniel.almeida@collabora.com>,
	Gary Guo <gary@garyguo.net>, Benno Lossin <lossin@kernel.org>,
	Alexandre Courbot <acourbot@nvidia.com>,
	Janne Grunau <j@jannau.net>
Subject: [PATCH v7 7/7] rust: drm/gem: Add vmap functions to shmem bindings
Date: Fri,  6 Feb 2026 17:34:31 -0500	[thread overview]
Message-ID: <20260206223431.693765-8-lyude@redhat.com> (raw)
In-Reply-To: <20260206223431.693765-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>

---
V7:
* Switch over to the new iosys map bindings that use the Io trait

 rust/kernel/drm/gem/shmem.rs | 170 ++++++++++++++++++++++++++++++++++-
 rust/kernel/iosys_map.rs     |   3 +-
 2 files changed, 170 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs
index e511a9b6710e0..604fb10325d1e 100644
--- a/rust/kernel/drm/gem/shmem.rs
+++ b/rust/kernel/drm/gem/shmem.rs
@@ -21,6 +21,7 @@
         from_err_ptr,
         to_result, //
     },
+    iosys_map::*,
     prelude::*,
     scatterlist,
     types::{
@@ -29,13 +30,18 @@
     }, //
 };
 use core::{
+    mem::{
+        self,
+        MaybeUninit, //
+    },
     ops::{
         Deref,
         DerefMut, //
     },
-    ptr::NonNull,
+    ptr::NonNull, //
 };
 use gem::{
+    BaseObject,
     BaseObjectPrivate,
     DriverObject,
     IntoGEMObject, //
@@ -216,6 +222,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<const SIZE: usize>(&self) -> Result<RawIoSysMap<SIZE>> {
+        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::<SIZE>::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<const SIZE: usize>(&self, map: &mut RawIoSysMap<SIZE>) {
+        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<const SIZE: usize>(&self) -> Result<VMapRef<'_, T, SIZE>> {
+        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::<SIZE>::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<const SIZE: usize>(&self) -> Result<VMap<T, SIZE>> {
+        // INVARIANT: We verify here that the mapping is at least of SIZE bytes.
+        if self.size() < SIZE {
+            return Err(EINVAL);
+        }
+
+        Ok(VMap {
+            map: self.raw_vmap()?,
+            owner: self.into(),
+        })
+    }
 }
 
 impl<T: DriverObject> Deref for Object<T> {
@@ -267,6 +339,102 @@ 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, const SIZE: usize = 0> {
+    map: IoSysMapRef<'a, SIZE>,
+    owner: &'a Object<D>,
+}
+
+impl<'a, D: DriverObject, const SIZE: usize> Clone for VMapRef<'a, D, SIZE> {
+    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, const SIZE: usize> Deref for VMapRef<'a, D, SIZE> {
+    type Target = IoSysMapRef<'a, SIZE>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.map
+    }
+}
+
+impl<'a, D: DriverObject, const SIZE: usize> DerefMut for VMapRef<'a, D, SIZE> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.map
+    }
+}
+
+impl<'a, D: DriverObject, const SIZE: usize> Drop for VMapRef<'a, D, SIZE> {
+    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.raw_map) };
+    }
+}
+
+/// An owned reference to a virtual mapping for a shmem-based GEM object in kernel address space.
+///
+/// # Invariants
+///
+/// - The size of `owner` is >= SIZE.
+/// - 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, const SIZE: usize = 0> {
+    map: RawIoSysMap<SIZE>,
+    owner: ARef<Object<D>>,
+}
+
+impl<D: DriverObject, const SIZE: usize> Clone for VMap<D, SIZE> {
+    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, const SIZE: usize> From<VMapRef<'a, D, SIZE>> for VMap<D, SIZE> {
+    fn from(value: VMapRef<'a, D, SIZE>) -> Self {
+        let this = Self {
+            map: value.map.raw_map.clone(),
+            owner: value.owner.into(),
+        };
+
+        mem::forget(value);
+        this
+    }
+}
+
+impl<D: DriverObject, const SIZE: usize> VMap<D, SIZE> {
+    /// Return a reference to the iosys map for this `VMap`.
+    #[inline]
+    pub fn get(&self) -> IoSysMapRef<'_, SIZE> {
+        // SAFETY:
+        // - The size of the iosys_map is equivalent to the size of the gem object.
+        // - `size` is >= SIZE according to our type invariants, ensuring that we can never pass an
+        //   invalid `size` to `IoSysMapRef::new().
+        unsafe {
+            IoSysMapRef::new(self.map.clone(), self.owner.size()).unwrap_unchecked()
+        }
+    }
+
+    /// Borrows a reference to the object that owns this virtual mapping.
+    pub fn owner(&self) -> &Object<D> {
+        &self.owner
+    }
+}
+
+impl<D: DriverObject, const SIZE: usize> Drop for VMap<D, SIZE> {
+    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, const SIZE: usize> Send for VMap<D, SIZE> {}
+/// SAFETY: `iosys_map` objects are safe to send across threads.
+unsafe impl<D: DriverObject, const SIZE: usize> Sync for VMap<D, SIZE> {}
+
 /// 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 2070f0fb42cb8..b649d2de83093 100644
--- a/rust/kernel/iosys_map.rs
+++ b/rust/kernel/iosys_map.rs
@@ -33,7 +33,7 @@
 
 impl<const SIZE: usize> RawIoSysMap<SIZE> {
     /// Convert from a raw `bindings::iosys_map`.
-    #[expect(unused)]
+    #[allow(unused)]
     #[inline]
     pub(crate) fn from_raw(val: bindings::iosys_map) -> Self {
         Self(val)
@@ -139,7 +139,6 @@ impl<'a, const SIZE: usize> IoSysMapRef<'a, SIZE> {
     ///
     /// - The caller guarantees that the mapping is of at least `size` bytes.
     /// - The caller guarantees that the mapping remains valid for the lifetime of `'a`.
-    #[expect(unused)]
     pub(crate) unsafe fn new(map: RawIoSysMap<SIZE>, size: usize) -> Result<Self> {
         if size < SIZE {
             return Err(EINVAL);
-- 
2.53.0


      parent reply	other threads:[~2026-02-06 22:35 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-06 22:34 [PATCH v7 0/7] Rust bindings for gem shmem + iosys_map Lyude Paul
2026-02-06 22:34 ` [PATCH v7 1/7] rust: drm: gem: Add raw_dma_resv() function Lyude Paul
2026-02-09 12:40   ` Alice Ryhl
2026-02-09 12:47     ` Janne Grunau
2026-02-06 22:34 ` [PATCH v7 2/7] rust: helpers: Add bindings/wrappers for dma_resv_lock Lyude Paul
2026-02-06 22:34 ` [PATCH v7 3/7] rust: gem: Introduce DriverObject::Args Lyude Paul
2026-02-06 22:34 ` [PATCH v7 4/7] rust: drm: gem: shmem: Add DRM shmem helper abstraction Lyude Paul
2026-02-17 19:38   ` Daniel Almeida
2026-02-06 22:34 ` [PATCH v7 5/7] rust: drm: gem: Introduce shmem::SGTable Lyude Paul
2026-02-17 19:53   ` Daniel Almeida
2026-02-06 22:34 ` [PATCH v7 6/7] rust: Introduce iosys_map bindings Lyude Paul
2026-02-09 11:17   ` Danilo Krummrich
2026-02-13  1:59   ` Deborah Brouwer
2026-03-04 22:59     ` lyude
2026-03-06 20:59       ` Deborah Brouwer
2026-02-06 22:34 ` 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=20260206223431.693765-8-lyude@redhat.com \
    --to=lyude@redhat.com \
    --cc=acourbot@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gary@garyguo.net \
    --cc=j@jannau.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=nouveau@lists.freedesktop.org \
    --cc=rust-for-linux@vger.kernel.org \
    /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