/// GEM object functions, which must be implemented by drivers. pubtrait BaseDriverObject<T: BaseObject>: Sync + Send + Sized { /// Create a new driver data object for a GEM object of a given size. fn new(dev: &drm::Device<T::Driver>, size: usize) -> impl PinInit<Self, Error>;
/// Open a new handle to an existing object, associated with a File. fn open(
_obj: &<<T as IntoGEMObject>::Driver as drm::Driver>::Object,
_file: &drm::File<<<T as IntoGEMObject>::Driver as drm::Driver>::File>,
) -> Result {
Ok(())
}
/// Close a handle to an existing object, associated with a File. fn close(
_obj: &<<T as IntoGEMObject>::Driver as drm::Driver>::Object,
_file: &drm::File<<<T as IntoGEMObject>::Driver as drm::Driver>::File>,
) {
}
}
/// Trait that represents a GEM object subtype pubtrait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted { /// Owning driver for this type type Driver: drm::Driver;
/// Returns a reference to the raw `drm_gem_object` structure, which must be valid as long as /// this owning object is valid. fn as_raw(&self) -> *mut bindings::drm_gem_object;
/// Converts a pointer to a `struct drm_gem_object` into a reference to `Self`. /// /// # Safety /// /// - `self_ptr` must be a valid pointer to `Self`. /// - The caller promises that holding the immutable reference returned by this function does /// not violate rust's data aliasing rules and remains valid throughout the lifetime of `'a`. unsafefn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self;
}
// SAFETY: All gem objects are refcounted. unsafeimpl<T: IntoGEMObject> AlwaysRefCounted for T { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. unsafe { bindings::drm_gem_object_get(self.as_raw()) };
}
unsafefn dec_ref(obj: NonNull<Self>) { // SAFETY: We either hold the only refcount on `obj`, or one of many - meaning that no one // else could possibly hold a mutable reference to `obj` and thus this immutable reference // is safe. let obj = unsafe { obj.as_ref() }.as_raw();
// SAFETY: // - The safety requirements guarantee that the refcount is non-zero. // - We hold no references to `obj` now, making it safe for us to potentially deallocate it. unsafe { bindings::drm_gem_object_put(obj) };
}
}
/// Trait which must be implemented by drivers using base GEM objects. pubtrait DriverObject: BaseDriverObject<Object<Self>> { /// Parent `Driver` for this object. type Driver: drm::Driver;
}
extern"C"fn open_callback<T: BaseDriverObject<U>, U: BaseObject>(
raw_obj: *mut bindings::drm_gem_object,
raw_file: *mut bindings::drm_file,
) -> core::ffi::c_int { // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. let file = unsafe {
drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::from_raw(raw_file)
}; // SAFETY: `open_callback` is specified in the AllocOps structure for `Object<T>`, ensuring that // `raw_obj` is indeed contained within a `Object<T>`. let obj = unsafe {
<<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj)
};
extern"C"fn close_callback<T: BaseDriverObject<U>, U: BaseObject>(
raw_obj: *mut bindings::drm_gem_object,
raw_file: *mut bindings::drm_file,
) { // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. let file = unsafe {
drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::from_raw(raw_file)
}; // SAFETY: `close_callback` is specified in the AllocOps structure for `Object<T>`, ensuring // that `raw_obj` is indeed contained within a `Object<T>`. let obj = unsafe {
<<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj)
};
T::close(obj, file);
}
impl<T: DriverObject> IntoGEMObject for Object<T> { type Driver = T::Driver;
unsafefn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self { // SAFETY: `obj` is guaranteed to be in an `Object<T>` via the safety contract of this // function unsafe { &*crate::container_of!(Opaque::cast_from(self_ptr), Object<T>, obj) }
}
}
/// Base operations shared by all GEM object classes pubtrait BaseObject: IntoGEMObject { /// Returns the size of the object in bytes. fn size(&self) -> usize { // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`. unsafe { (*self.as_raw()).size }
}
/// Creates a new handle for the object associated with a given `File` /// (or returns an existing one). fn create_handle(
&self,
file: &drm::File<<<Selfas IntoGEMObject>::Driver as drm::Driver>::File>,
) -> Result<u32> { letmut handle: u32 = 0; // SAFETY: The arguments are all valid per the type invariants.
to_result(unsafe {
bindings::drm_gem_handle_create(file.as_raw().cast(), self.as_raw(), &mut handle)
})?;
Ok(handle)
}
/// Looks up an object by its handle for a given `File`. fn lookup_handle(
file: &drm::File<<<Selfas IntoGEMObject>::Driver as drm::Driver>::File>,
handle: u32,
) -> Result<ARef<Self>> { // SAFETY: The arguments are all valid per the type invariants. let ptr = unsafe { bindings::drm_gem_object_lookup(file.as_raw().cast(), handle) }; if ptr.is_null() { return Err(ENOENT);
}
// SAFETY: // - A `drm::Driver` can only have a single `File` implementation. // - `file` uses the same `drm::Driver` as `Self`. // - Therefore, we're guaranteed that `ptr` must be a gem object embedded within `Self`. // - And we check if the pointer is null befoe calling from_raw(), ensuring that `ptr` is a // valid pointer to an initialized `Self`. let obj = unsafe { Self::from_raw(ptr) };
// SAFETY: // - We take ownership of the reference of `drm_gem_object_lookup()`. // - Our `NonNull` comes from an immutable reference, thus ensuring it is a valid pointer to // `Self`.
Ok(unsafe { ARef::from_raw(obj.into()) })
}
/// Creates an mmap offset to map the object from userspace. fn create_mmap_offset(&self) -> Result<u64> { // SAFETY: The arguments are valid per the type invariant.
to_result(unsafe { bindings::drm_gem_create_mmap_offset(self.as_raw()) })?;
// SAFETY: The arguments are valid per the type invariant.
Ok(unsafe { bindings::drm_vma_node_offset_addr(&raw mut (*self.as_raw()).vma_node) })
}
}
impl<T: IntoGEMObject> BaseObject for T {}
/// A base GEM object. /// /// Invariants /// /// - `self.obj` is a valid instance of a `struct drm_gem_object`. /// - `self.dev` is always a valid pointer to a `struct drm_device`. #[repr(C)] #[pin_data] pubstruct Object<T: DriverObject + Send + Sync> {
obj: Opaque<bindings::drm_gem_object>,
dev: NonNull<drm::Device<T::Driver>>, #[pin]
data: T,
}
impl<T: DriverObject> Object<T> { /// The size of this object's structure. pubconst SIZE: usize = mem::size_of::<Self>();
/// Create a new GEM object. pubfn new(dev: &drm::Device<T::Driver>, size: usize) -> Result<ARef<Self>> { let obj: Pin<KBox<Self>> = KBox::pin_init(
try_pin_init!(Self {
obj: Opaque::new(bindings::drm_gem_object::default()),
data <- T::new(dev, size), // INVARIANT: The drm subsystem guarantees that the `struct drm_device` will live // as long as the GEM object lives.
dev: dev.into(),
}),
GFP_KERNEL,
)?;
// SAFETY: `obj.as_raw()` is guaranteed to be valid by the initialization above. unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS };
// SAFETY: The arguments are all valid per the type invariants.
to_result(unsafe { bindings::drm_gem_object_init(dev.as_raw(), obj.obj.get(), size) })?;
// SAFETY: We never move out of `Self`. let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(obj) });
// SAFETY: `ptr` comes from `KBox::into_raw` and hence can't be NULL. let ptr = unsafe { NonNull::new_unchecked(ptr) };
// SAFETY: We take over the initial reference count from `drm_gem_object_init()`.
Ok(unsafe { ARef::from_raw(ptr) })
}
/// Returns the `Device` that owns this GEM object. pubfn dev(&self) -> &drm::Device<T::Driver> { // SAFETY: The DRM subsystem guarantees that the `struct drm_device` will live as long as // the GEM object lives, hence the pointer must be valid. unsafe { self.dev.as_ref() }
}
// SAFETY: All of our objects are of type `Object<T>`. let this = unsafe { crate::container_of!(ptr, Self, obj) };
// SAFETY: The C code only ever calls this callback with a valid pointer to a `struct // drm_gem_object`. unsafe { bindings::drm_gem_object_release(obj) };
// SAFETY: All of our objects are allocated via `KBox`, and we're in the // free callback which guarantees this object has zero remaining references, // so we can drop it. let _ = unsafe { KBox::from_raw(this) };
}
}
impl<T: DriverObject> super::private::Sealed for Object<T> {}
impl<T: DriverObject> Deref for Object<T> { type Target = T;
pub(super) constfn create_fops() -> bindings::file_operations { // SAFETY: As by the type invariant, it is safe to initialize `bindings::file_operations` // zeroed. letmut fops: bindings::file_operations = unsafe { core::mem::zeroed() };
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.