1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 3 //! DRM GEM API 4 //! 5 //! C header: [`include/drm/drm_gem.h`](srctree/include/drm/drm_gem.h) 6 7 use crate::{ 8 bindings, 9 drm::{ 10 self, 11 driver::{ 12 AllocImpl, 13 AllocOps, // 14 }, 15 }, 16 error::to_result, 17 prelude::*, 18 sync::aref::{ 19 ARef, 20 AlwaysRefCounted, // 21 }, 22 types::Opaque, 23 }; 24 use core::{ 25 ops::Deref, 26 ptr::NonNull, // 27 }; 28 29 #[cfg(CONFIG_RUST_DRM_GEM_SHMEM_HELPER)] 30 pub mod shmem; 31 32 /// A macro for implementing [`AlwaysRefCounted`] for any GEM object type. 33 /// 34 /// Since all GEM objects use the same refcounting scheme. 35 #[macro_export] 36 macro_rules! impl_aref_for_gem_obj { 37 ( 38 impl $( <$( $tparam_id:ident ),+> )? for $type:ty 39 $( 40 where 41 $( $bind_param:path : $bind_trait:path ),+ 42 )? 43 ) => { 44 // SAFETY: All GEM objects are refcounted. 45 unsafe impl $( <$( $tparam_id ),+> )? $crate::sync::aref::AlwaysRefCounted for $type 46 where 47 Self: IntoGEMObject, 48 $( $( $bind_param : $bind_trait ),+ )? 49 { 50 fn inc_ref(&self) { 51 // SAFETY: The existence of a shared reference guarantees that the refcount is 52 // non-zero. 53 unsafe { bindings::drm_gem_object_get(self.as_raw()) }; 54 } 55 56 unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) { 57 // SAFETY: `obj` is a valid pointer to an `Object<T>`. 58 let obj = unsafe { obj.as_ref() }.as_raw(); 59 60 // SAFETY: The safety requirements guarantee that the refcount is non-zero. 61 unsafe { bindings::drm_gem_object_put(obj) }; 62 } 63 } 64 }; 65 } 66 #[cfg_attr(not(CONFIG_RUST_DRM_GEM_SHMEM_HELPER), allow(unused))] 67 pub(crate) use impl_aref_for_gem_obj; 68 69 /// A type alias for retrieving a [`Driver`]s [`DriverFile`] implementation from its 70 /// [`DriverObject`] implementation. 71 /// 72 /// [`Driver`]: drm::Driver 73 /// [`DriverFile`]: drm::file::DriverFile 74 pub type DriverFile<T> = drm::File<<<T as DriverObject>::Driver as drm::Driver>::File>; 75 76 /// GEM object functions, which must be implemented by drivers. 77 pub trait DriverObject: Sync + Send + Sized { 78 /// Parent `Driver` for this object. 79 type Driver: drm::Driver; 80 81 /// The data type to use for passing arguments to [`DriverObject::new`]. 82 type Args; 83 84 /// Create a new driver data object for a GEM object of a given size. 85 fn new( 86 dev: &drm::Device<Self::Driver>, 87 size: usize, 88 args: Self::Args, 89 ) -> impl PinInit<Self, Error>; 90 91 /// Open a new handle to an existing object, associated with a File. 92 fn open(_obj: &<Self::Driver as drm::Driver>::Object, _file: &DriverFile<Self>) -> Result { 93 Ok(()) 94 } 95 96 /// Close a handle to an existing object, associated with a File. 97 fn close(_obj: &<Self::Driver as drm::Driver>::Object, _file: &DriverFile<Self>) {} 98 } 99 100 /// Trait that represents a GEM object subtype 101 pub trait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted { 102 /// Returns a reference to the raw `drm_gem_object` structure, which must be valid as long as 103 /// this owning object is valid. 104 fn as_raw(&self) -> *mut bindings::drm_gem_object; 105 106 /// Converts a pointer to a `struct drm_gem_object` into a reference to `Self`. 107 /// 108 /// # Safety 109 /// 110 /// - `self_ptr` must be a valid pointer to `Self`. 111 /// - The caller promises that holding the immutable reference returned by this function does 112 /// not violate rust's data aliasing rules and remains valid throughout the lifetime of `'a`. 113 unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self; 114 } 115 116 extern "C" fn open_callback<T: DriverObject>( 117 raw_obj: *mut bindings::drm_gem_object, 118 raw_file: *mut bindings::drm_file, 119 ) -> core::ffi::c_int { 120 // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. 121 let file = unsafe { DriverFile::<T>::from_raw(raw_file) }; 122 123 // SAFETY: `open_callback` is specified in the AllocOps structure for `DriverObject<T>`, 124 // ensuring that `raw_obj` is contained within a `DriverObject<T>` 125 let obj = unsafe { <<T::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) }; 126 127 match T::open(obj, file) { 128 Err(e) => e.to_errno(), 129 Ok(()) => 0, 130 } 131 } 132 133 extern "C" fn close_callback<T: DriverObject>( 134 raw_obj: *mut bindings::drm_gem_object, 135 raw_file: *mut bindings::drm_file, 136 ) { 137 // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. 138 let file = unsafe { DriverFile::<T>::from_raw(raw_file) }; 139 140 // SAFETY: `close_callback` is specified in the AllocOps structure for `Object<T>`, ensuring 141 // that `raw_obj` is indeed contained within a `Object<T>`. 142 let obj = unsafe { <<T::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) }; 143 144 T::close(obj, file); 145 } 146 147 impl<T: DriverObject> IntoGEMObject for Object<T> { 148 fn as_raw(&self) -> *mut bindings::drm_gem_object { 149 self.obj.get() 150 } 151 152 unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self { 153 // SAFETY: `obj` is guaranteed to be in an `Object<T>` via the safety contract of this 154 // function 155 unsafe { &*crate::container_of!(Opaque::cast_from(self_ptr), Object<T>, obj) } 156 } 157 } 158 159 /// Base operations shared by all GEM object classes 160 pub trait BaseObject: IntoGEMObject { 161 /// Returns the size of the object in bytes. 162 fn size(&self) -> usize { 163 // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`. 164 unsafe { (*self.as_raw()).size } 165 } 166 167 /// Creates a new handle for the object associated with a given `File` 168 /// (or returns an existing one). 169 fn create_handle<D, F>(&self, file: &drm::File<F>) -> Result<u32> 170 where 171 Self: AllocImpl<Driver = D>, 172 D: drm::Driver<Object = Self, File = F>, 173 F: drm::file::DriverFile<Driver = D>, 174 { 175 let mut handle: u32 = 0; 176 // SAFETY: The arguments are all valid per the type invariants. 177 to_result(unsafe { 178 bindings::drm_gem_handle_create(file.as_raw().cast(), self.as_raw(), &mut handle) 179 })?; 180 Ok(handle) 181 } 182 183 /// Looks up an object by its handle for a given `File`. 184 fn lookup_handle<D, F>(file: &drm::File<F>, handle: u32) -> Result<ARef<Self>> 185 where 186 Self: AllocImpl<Driver = D>, 187 D: drm::Driver<Object = Self, File = F>, 188 F: drm::file::DriverFile<Driver = D>, 189 { 190 // SAFETY: The arguments are all valid per the type invariants. 191 let ptr = unsafe { bindings::drm_gem_object_lookup(file.as_raw().cast(), handle) }; 192 if ptr.is_null() { 193 return Err(ENOENT); 194 } 195 196 // SAFETY: 197 // - A `drm::Driver` can only have a single `File` implementation. 198 // - `file` uses the same `drm::Driver` as `Self`. 199 // - Therefore, we're guaranteed that `ptr` must be a gem object embedded within `Self`. 200 // - And we check if the pointer is null befoe calling from_raw(), ensuring that `ptr` is a 201 // valid pointer to an initialized `Self`. 202 let obj = unsafe { Self::from_raw(ptr) }; 203 204 // SAFETY: 205 // - We take ownership of the reference of `drm_gem_object_lookup()`. 206 // - Our `NonNull` comes from an immutable reference, thus ensuring it is a valid pointer to 207 // `Self`. 208 Ok(unsafe { ARef::from_raw(obj.into()) }) 209 } 210 211 /// Creates an mmap offset to map the object from userspace. 212 fn create_mmap_offset(&self) -> Result<u64> { 213 // SAFETY: The arguments are valid per the type invariant. 214 to_result(unsafe { bindings::drm_gem_create_mmap_offset(self.as_raw()) })?; 215 216 // SAFETY: The arguments are valid per the type invariant. 217 Ok(unsafe { bindings::drm_vma_node_offset_addr(&raw mut (*self.as_raw()).vma_node) }) 218 } 219 } 220 221 impl<T: IntoGEMObject> BaseObject for T {} 222 223 /// Crate-private base operations shared by all GEM object classes. 224 #[cfg_attr(not(CONFIG_RUST_DRM_GEM_SHMEM_HELPER), expect(unused))] 225 pub(crate) trait BaseObjectPrivate: IntoGEMObject { 226 /// Return a pointer to this object's dma_resv. 227 fn raw_dma_resv(&self) -> *mut bindings::dma_resv { 228 // SAFETY: `self.as_raw()` always returns a valid pointer to the base DRM GEM object. 229 unsafe { (*self.as_raw()).resv } 230 } 231 } 232 233 impl<T: IntoGEMObject> BaseObjectPrivate for T {} 234 235 /// A base GEM object. 236 /// 237 /// # Invariants 238 /// 239 /// - `self.obj` is a valid instance of a `struct drm_gem_object`. 240 #[repr(C)] 241 #[pin_data] 242 pub struct Object<T: DriverObject + Send + Sync> { 243 obj: Opaque<bindings::drm_gem_object>, 244 #[pin] 245 data: T, 246 } 247 248 impl<T: DriverObject> Object<T> { 249 const OBJECT_FUNCS: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs { 250 free: Some(Self::free_callback), 251 open: Some(open_callback::<T>), 252 close: Some(close_callback::<T>), 253 print_info: None, 254 export: None, 255 pin: None, 256 unpin: None, 257 get_sg_table: None, 258 vmap: None, 259 vunmap: None, 260 mmap: None, 261 status: None, 262 vm_ops: core::ptr::null_mut(), 263 evict: None, 264 rss: None, 265 }; 266 267 /// Create a new GEM object. 268 pub fn new(dev: &drm::Device<T::Driver>, size: usize, args: T::Args) -> Result<ARef<Self>> { 269 let obj: Pin<KBox<Self>> = KBox::pin_init( 270 try_pin_init!(Self { 271 obj: Opaque::new(bindings::drm_gem_object::default()), 272 data <- T::new(dev, size, args), 273 }), 274 GFP_KERNEL, 275 )?; 276 277 // SAFETY: `obj.as_raw()` is guaranteed to be valid by the initialization above. 278 unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS }; 279 280 // SAFETY: The arguments are all valid per the type invariants. 281 to_result(unsafe { bindings::drm_gem_object_init(dev.as_raw(), obj.obj.get(), size) })?; 282 283 // SAFETY: We will never move out of `Self` as `ARef<Self>` is always treated as pinned. 284 let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(obj) }); 285 286 // SAFETY: `ptr` comes from `KBox::into_raw` and hence can't be NULL. 287 let ptr = unsafe { NonNull::new_unchecked(ptr) }; 288 289 // SAFETY: We take over the initial reference count from `drm_gem_object_init()`. 290 Ok(unsafe { ARef::from_raw(ptr) }) 291 } 292 293 /// Returns the `Device` that owns this GEM object. 294 pub fn dev(&self) -> &drm::Device<T::Driver> { 295 // SAFETY: 296 // - `struct drm_gem_object.dev` is initialized and valid for as long as the GEM 297 // object lives. 298 // - The device we used for creating the gem object is passed as &drm::Device<T::Driver> to 299 // Object::<T>::new(), so we know that `T::Driver` is the right generic parameter to use 300 // here. 301 unsafe { drm::Device::from_raw((*self.as_raw()).dev) } 302 } 303 304 fn as_raw(&self) -> *mut bindings::drm_gem_object { 305 self.obj.get() 306 } 307 308 extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) { 309 let ptr: *mut Opaque<bindings::drm_gem_object> = obj.cast(); 310 311 // SAFETY: All of our objects are of type `Object<T>`. 312 let this = unsafe { crate::container_of!(ptr, Self, obj) }; 313 314 // SAFETY: The C code only ever calls this callback with a valid pointer to a `struct 315 // drm_gem_object`. 316 unsafe { bindings::drm_gem_object_release(obj) }; 317 318 // SAFETY: All of our objects are allocated via `KBox`, and we're in the 319 // free callback which guarantees this object has zero remaining references, 320 // so we can drop it. 321 let _ = unsafe { KBox::from_raw(this) }; 322 } 323 } 324 325 impl_aref_for_gem_obj!(impl<T> for Object<T> where T: DriverObject); 326 327 impl<T: DriverObject> super::private::Sealed for Object<T> {} 328 329 impl<T: DriverObject> Deref for Object<T> { 330 type Target = T; 331 332 fn deref(&self) -> &Self::Target { 333 &self.data 334 } 335 } 336 337 impl<T: DriverObject> AllocImpl for Object<T> { 338 type Driver = T::Driver; 339 340 const ALLOC_OPS: AllocOps = AllocOps { 341 gem_create_object: None, 342 prime_handle_to_fd: None, 343 prime_fd_to_handle: None, 344 gem_prime_import: None, 345 gem_prime_import_sg_table: None, 346 dumb_create: None, 347 dumb_map_offset: None, 348 }; 349 } 350 351 pub(super) const fn create_fops() -> bindings::file_operations { 352 let mut fops: bindings::file_operations = pin_init::zeroed(); 353 354 fops.owner = core::ptr::null_mut(); 355 fops.open = Some(bindings::drm_open); 356 fops.release = Some(bindings::drm_release); 357 fops.unlocked_ioctl = Some(bindings::drm_ioctl); 358 #[cfg(CONFIG_COMPAT)] 359 { 360 fops.compat_ioctl = Some(bindings::drm_compat_ioctl); 361 } 362 fops.poll = Some(bindings::drm_poll); 363 fops.read = Some(bindings::drm_read); 364 fops.llseek = Some(bindings::noop_llseek); 365 fops.mmap = Some(bindings::drm_gem_mmap); 366 fops.fop_flags = bindings::FOP_UNSIGNED_OFFSET; 367 368 fops 369 } 370