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 /// - `self.dev` is always a valid pointer to a `struct drm_device`. 171 #[repr(C)] 172 #[pin_data] 173 pub struct Object<T: DriverObject + Send + Sync> { 174 obj: Opaque<bindings::drm_gem_object>, 175 dev: NonNull<drm::Device<T::Driver>>, 176 #[pin] 177 data: T, 178 } 179 180 impl<T: DriverObject> Object<T> { 181 const OBJECT_FUNCS: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs { 182 free: Some(Self::free_callback), 183 open: Some(open_callback::<T>), 184 close: Some(close_callback::<T>), 185 print_info: None, 186 export: None, 187 pin: None, 188 unpin: None, 189 get_sg_table: None, 190 vmap: None, 191 vunmap: None, 192 mmap: None, 193 status: None, 194 vm_ops: core::ptr::null_mut(), 195 evict: None, 196 rss: None, 197 }; 198 199 /// Create a new GEM object. 200 pub fn new(dev: &drm::Device<T::Driver>, size: usize) -> Result<ARef<Self>> { 201 let obj: Pin<KBox<Self>> = KBox::pin_init( 202 try_pin_init!(Self { 203 obj: Opaque::new(bindings::drm_gem_object::default()), 204 data <- T::new(dev, size), 205 // INVARIANT: The drm subsystem guarantees that the `struct drm_device` will live 206 // as long as the GEM object lives. 207 dev: dev.into(), 208 }), 209 GFP_KERNEL, 210 )?; 211 212 // SAFETY: `obj.as_raw()` is guaranteed to be valid by the initialization above. 213 unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS }; 214 215 // SAFETY: The arguments are all valid per the type invariants. 216 to_result(unsafe { bindings::drm_gem_object_init(dev.as_raw(), obj.obj.get(), size) })?; 217 218 // SAFETY: We never move out of `Self`. 219 let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(obj) }); 220 221 // SAFETY: `ptr` comes from `KBox::into_raw` and hence can't be NULL. 222 let ptr = unsafe { NonNull::new_unchecked(ptr) }; 223 224 // SAFETY: We take over the initial reference count from `drm_gem_object_init()`. 225 Ok(unsafe { ARef::from_raw(ptr) }) 226 } 227 228 /// Returns the `Device` that owns this GEM object. 229 pub fn dev(&self) -> &drm::Device<T::Driver> { 230 // SAFETY: The DRM subsystem guarantees that the `struct drm_device` will live as long as 231 // the GEM object lives, hence the pointer must be valid. 232 unsafe { self.dev.as_ref() } 233 } 234 235 fn as_raw(&self) -> *mut bindings::drm_gem_object { 236 self.obj.get() 237 } 238 239 extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) { 240 let ptr: *mut Opaque<bindings::drm_gem_object> = obj.cast(); 241 242 // SAFETY: All of our objects are of type `Object<T>`. 243 let this = unsafe { crate::container_of!(ptr, Self, obj) }; 244 245 // SAFETY: The C code only ever calls this callback with a valid pointer to a `struct 246 // drm_gem_object`. 247 unsafe { bindings::drm_gem_object_release(obj) }; 248 249 // SAFETY: All of our objects are allocated via `KBox`, and we're in the 250 // free callback which guarantees this object has zero remaining references, 251 // so we can drop it. 252 let _ = unsafe { KBox::from_raw(this) }; 253 } 254 } 255 256 // SAFETY: Instances of `Object<T>` are always reference-counted. 257 unsafe impl<T: DriverObject> crate::types::AlwaysRefCounted for Object<T> { 258 fn inc_ref(&self) { 259 // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. 260 unsafe { bindings::drm_gem_object_get(self.as_raw()) }; 261 } 262 263 unsafe fn dec_ref(obj: NonNull<Self>) { 264 // SAFETY: `obj` is a valid pointer to an `Object<T>`. 265 let obj = unsafe { obj.as_ref() }; 266 267 // SAFETY: The safety requirements guarantee that the refcount is non-zero. 268 unsafe { bindings::drm_gem_object_put(obj.as_raw()) } 269 } 270 } 271 272 impl<T: DriverObject> super::private::Sealed for Object<T> {} 273 274 impl<T: DriverObject> Deref for Object<T> { 275 type Target = T; 276 277 fn deref(&self) -> &Self::Target { 278 &self.data 279 } 280 } 281 282 impl<T: DriverObject> AllocImpl for Object<T> { 283 type Driver = T::Driver; 284 285 const ALLOC_OPS: AllocOps = AllocOps { 286 gem_create_object: None, 287 prime_handle_to_fd: None, 288 prime_fd_to_handle: None, 289 gem_prime_import: None, 290 gem_prime_import_sg_table: None, 291 dumb_create: None, 292 dumb_map_offset: None, 293 }; 294 } 295 296 pub(super) const fn create_fops() -> bindings::file_operations { 297 // SAFETY: As by the type invariant, it is safe to initialize `bindings::file_operations` 298 // zeroed. 299 let mut fops: bindings::file_operations = unsafe { core::mem::zeroed() }; 300 301 fops.owner = core::ptr::null_mut(); 302 fops.open = Some(bindings::drm_open); 303 fops.release = Some(bindings::drm_release); 304 fops.unlocked_ioctl = Some(bindings::drm_ioctl); 305 #[cfg(CONFIG_COMPAT)] 306 { 307 fops.compat_ioctl = Some(bindings::drm_compat_ioctl); 308 } 309 fops.poll = Some(bindings::drm_poll); 310 fops.read = Some(bindings::drm_read); 311 fops.llseek = Some(bindings::noop_llseek); 312 fops.mmap = Some(bindings::drm_gem_mmap); 313 fops.fop_flags = bindings::FOP_UNSIGNED_OFFSET; 314 315 fops 316 } 317