Skip to content

Commit eb42153

Browse files
Lyudejannau
authored andcommitted
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@redhat.com>
1 parent a6d63d6 commit eb42153

2 files changed

Lines changed: 160 additions & 2 deletions

File tree

rust/kernel/drm/gem/shmem.rs

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,18 @@ use crate::{
1313
container_of,
1414
drm::{device, driver, gem, private::Sealed},
1515
error::{from_err_ptr, to_result},
16+
iosys_map::*,
1617
prelude::*,
1718
scatterlist,
19+
transmute::*,
1820
types::{ARef, Opaque},
1921
};
2022
use core::{
23+
mem::{self, MaybeUninit},
2124
ops::{Deref, DerefMut},
2225
ptr::NonNull,
2326
};
24-
use gem::{BaseObjectPrivate, DriverObject, IntoGEMObject};
27+
use gem::{BaseObject, BaseObjectPrivate, DriverObject, IntoGEMObject};
2528

2629
/// A struct for controlling the creation of shmem-backed GEM objects.
2730
///
@@ -192,6 +195,72 @@ impl<T: DriverObject> Object<T> {
192195
_owner: self.into(),
193196
})
194197
}
198+
199+
/// Attempt to create a [`RawIoSysMap`] from the gem object.
200+
fn raw_vmap<U: AsBytes + FromBytes>(&self) -> Result<RawIoSysMap<U>> {
201+
build_assert!(
202+
mem::size_of::<U>() > 0,
203+
"It doesn't make sense for the mapping type to be a ZST"
204+
);
205+
206+
let mut map: MaybeUninit<bindings::iosys_map> = MaybeUninit::uninit();
207+
208+
// SAFETY: drm_gem_shmem_vmap can be called with the DMA reservation lock held
209+
to_result(unsafe {
210+
// TODO: see top of file
211+
bindings::dma_resv_lock(self.raw_dma_resv(), core::ptr::null_mut());
212+
let ret = bindings::drm_gem_shmem_vmap_locked(self.as_shmem(), map.as_mut_ptr());
213+
bindings::dma_resv_unlock(self.raw_dma_resv());
214+
ret
215+
})?;
216+
217+
// SAFETY: if drm_gem_shmem_vmap did not fail, map is initialized now
218+
Ok(unsafe { RawIoSysMap::from_raw(map.assume_init()) })
219+
}
220+
221+
/// Unmap a [`RawIoSysMap`] from the gem object.
222+
///
223+
/// # Safety
224+
///
225+
/// - The caller promises that `map` came from a prior call to [`Self::raw_vmap`] on this gem
226+
/// object.
227+
/// - The caller promises that the memory pointed to by `map` will no longer be accesed through
228+
/// this instance.
229+
unsafe fn raw_vunmap<U: AsBytes + FromBytes>(&self, map: &mut RawIoSysMap<U>) {
230+
let resv = self.raw_dma_resv();
231+
232+
// SAFETY:
233+
// - This function is safe to call with the DMA reservation lock held
234+
// - Our `ARef` is proof that the underlying gem object here is initialized and thus safe to
235+
// dereference.
236+
unsafe {
237+
// TODO: see top of file
238+
bindings::dma_resv_lock(resv, core::ptr::null_mut());
239+
bindings::drm_gem_shmem_vunmap_locked(self.as_shmem(), map.as_raw_mut());
240+
bindings::dma_resv_unlock(resv);
241+
}
242+
}
243+
244+
/// Creates and returns a virtual kernel memory mapping for this object.
245+
pub fn vmap<U: AsBytes + FromBytes>(&self) -> Result<VMapRef<'_, T, U>> {
246+
let map = self.raw_vmap()?;
247+
248+
Ok(VMapRef {
249+
// SAFETY:
250+
// - The size of the vmap is the same as the size of the gem
251+
// - The vmap will remain alive until this object is dropped.
252+
map: unsafe { IoSysMapRef::new(map, self.size()) },
253+
owner: self,
254+
})
255+
}
256+
257+
/// Creates and returns an owned reference to a virtual kernel memory mapping for this object.
258+
pub fn owned_vmap<U: AsBytes + FromBytes>(&self) -> Result<VMap<T, U>> {
259+
Ok(VMap {
260+
map: self.raw_vmap()?,
261+
owner: self.into(),
262+
})
263+
}
195264
}
196265

197266
impl<T: DriverObject> Deref for Object<T> {
@@ -243,6 +312,95 @@ impl<T: DriverObject> driver::AllocImpl for Object<T> {
243312
};
244313
}
245314

315+
/// A borrowed reference to a virtual mapping for a shmem-based GEM object in kernel address space.
316+
pub struct VMapRef<'a, D: DriverObject, T: AsBytes + FromBytes> {
317+
map: IoSysMapRef<'a, T>,
318+
owner: &'a Object<D>,
319+
}
320+
321+
impl<'a, D: DriverObject, T: AsBytes + FromBytes> Clone for VMapRef<'a, D, T> {
322+
fn clone(&self) -> Self {
323+
// SAFETY: We have a successful vmap already, so this can't fail
324+
unsafe { self.owner.vmap().unwrap_unchecked() }
325+
}
326+
}
327+
328+
impl<'a, D: DriverObject, T: AsBytes + FromBytes> Deref for VMapRef<'a, D, T> {
329+
type Target = IoSysMapRef<'a, T>;
330+
331+
fn deref(&self) -> &Self::Target {
332+
&self.map
333+
}
334+
}
335+
336+
impl<'a, D: DriverObject, T: AsBytes + FromBytes> DerefMut for VMapRef<'a, D, T> {
337+
fn deref_mut(&mut self) -> &mut Self::Target {
338+
&mut self.map
339+
}
340+
}
341+
342+
impl<'a, D: DriverObject, T: AsBytes + FromBytes> Drop for VMapRef<'a, D, T> {
343+
fn drop(&mut self) {
344+
// SAFETY: Our existence is proof that this map was previously created using self.owner.
345+
unsafe { self.owner.raw_vunmap(&mut self.map) };
346+
}
347+
}
348+
349+
/// An owned reference to a virtual mapping for a shmem-based GEM object in kernel address space.
350+
///
351+
/// # Invariants
352+
///
353+
/// - The memory pointed to by `map` is at least as large as `T`.
354+
/// - The memory pointed to by `map` remains valid at least until this object is dropped.
355+
pub struct VMap<D: DriverObject, T: AsBytes + FromBytes> {
356+
map: RawIoSysMap<T>,
357+
owner: ARef<Object<D>>,
358+
}
359+
360+
impl<D: DriverObject, T: AsBytes + FromBytes> Clone for VMap<D, T> {
361+
fn clone(&self) -> Self {
362+
// SAFETY: We have a successful vmap already, so this can't fail
363+
unsafe { self.owner.owned_vmap().unwrap_unchecked() }
364+
}
365+
}
366+
367+
impl<'a, D: DriverObject, T: AsBytes + FromBytes> From<VMapRef<'a, D, T>> for VMap<D, T> {
368+
fn from(value: VMapRef<'a, D, T>) -> Self {
369+
let this = Self {
370+
map: value.map.clone(),
371+
owner: value.owner.into(),
372+
};
373+
374+
mem::forget(value);
375+
this
376+
}
377+
}
378+
379+
impl<D: DriverObject, T: AsBytes + FromBytes> VMap<D, T> {
380+
/// Return a reference to the iosys map for this `VMap`.
381+
pub fn get(&self) -> IoSysMapRef<'_, T> {
382+
// SAFETY: The size of the iosys_map is equivalent to the size of the gem object.
383+
unsafe { IoSysMapRef::new(self.map.clone(), self.owner.size()) }
384+
}
385+
386+
/// Borrows a reference to the object that owns this virtual mapping.
387+
pub fn owner(&self) -> &Object<D> {
388+
&self.owner
389+
}
390+
}
391+
392+
impl<D: DriverObject, T: AsBytes + FromBytes> Drop for VMap<D, T> {
393+
fn drop(&mut self) {
394+
// SAFETY: Our existence is proof that this map was previously created using self.owner
395+
unsafe { self.owner.raw_vunmap(&mut self.map) };
396+
}
397+
}
398+
399+
/// SAFETY: `iosys_map` objects are safe to send across threads.
400+
unsafe impl<D: DriverObject, T: AsBytes + FromBytes> Send for VMap<D, T> {}
401+
/// SAFETY: `iosys_map` objects are safe to send across threads.
402+
unsafe impl<D: DriverObject, T: AsBytes + FromBytes> Sync for VMap<D, T> {}
403+
246404
/// An owned reference to a scatter-gather table of DMA address spans for a GEM shmem object.
247405
///
248406
/// This object holds an owned reference to the underlying GEM shmem object, ensuring that the

rust/kernel/iosys_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub struct RawIoSysMap<T: AsBytes + FromBytes>(bindings::iosys_map, PhantomData<
3131

3232
impl<T: AsBytes + FromBytes> RawIoSysMap<T> {
3333
/// Convert from a raw `bindings::iosys_map`.
34-
#[expect(unused)]
34+
#[allow(unused)]
3535
#[inline]
3636
pub(crate) fn from_raw(val: bindings::iosys_map) -> Self {
3737
Self(val, PhantomData)

0 commit comments

Comments
 (0)