@@ -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} ;
2022use 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
197266impl < 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
0 commit comments