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