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