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