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