[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251016210955.2813186-10-lyude@redhat.com>
Date: Thu, 16 Oct 2025 17:08:22 -0400
From: Lyude Paul <lyude@...hat.com>
To: dri-devel@...ts.freedesktop.org,
rust-for-linux@...r.kernel.org,
Daniel Almeida <daniel.almeida@...labora.com>,
Alice Ryhl <aliceryhl@...gle.com>
Cc: David Airlie <airlied@...il.com>,
Simona Vetter <simona@...ll.ch>,
Danilo Krummrich <dakr@...nel.org>,
Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>,
Andreas Hindborg <a.hindborg@...nel.org>,
Trevor Gross <tmgross@...ch.edu>,
Asahi Lina <lina+kernel@...hilina.net>,
linux-kernel@...r.kernel.org (open list)
Subject: [PATCH v4 9/9] rust: drm/gem: Add vmap functions to shmem bindings
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@...hat.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 5c2fb2d5481cf..01b4a2e9e17ae 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.
///
@@ -187,6 +190,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> {
@@ -237,6 +306,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 2986d98414457..84dcc3cc52c80 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
Powered by blists - more mailing lists