Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/rust/kernel/drm/device.rs b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/device.rs
- index 90e0ff6d5915..c5a279e63010 100644
- --- a/rust/kernel/drm/device.rs
- +++ b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/device.rs
- @@ -2,72 +2,194 @@
- //! DRM device.
- //!
- -//! C header: [`include/drm/drm_device.h`](../../../../include/drm/drm_device.h)
- +//! C header: [`include/linux/drm/drm_device.h`](srctree/include/linux/drm/drm_device.h)
- use crate::{
- bindings, device, drm,
- - types::{AlwaysRefCounted, ForeignOwnable},
- + drm::driver::AllocImpl,
- + error::from_err_ptr,
- + error::Result,
- + prelude::*,
- + types::{ARef, AlwaysRefCounted, Opaque},
- };
- -use core::cell::UnsafeCell;
- -use core::marker::PhantomData;
- -use core::ptr::NonNull;
- -
- -/// A typed DRM device with a specific driver. The device is always reference-counted.
- -#[repr(transparent)]
- -pub struct Device<T: drm::drv::Driver> {
- - pub(super) drm: UnsafeCell<bindings::drm_device>,
- - _p: PhantomData<T>,
- +use core::{mem, ops::Deref, ptr, ptr::NonNull};
- +
- +#[cfg(CONFIG_DRM_LEGACY)]
- +macro_rules! drm_legacy_fields {
- + ( $($field:ident: $val:expr),* $(,)? ) => {
- + bindings::drm_driver {
- + $( $field: $val ),*,
- + firstopen: None,
- + preclose: None,
- + dma_ioctl: None,
- + dma_quiescent: None,
- + context_dtor: None,
- + irq_handler: None,
- + irq_preinstall: None,
- + irq_postinstall: None,
- + irq_uninstall: None,
- + get_vblank_counter: None,
- + enable_vblank: None,
- + disable_vblank: None,
- + dev_priv_size: 0,
- + }
- + }
- }
- -impl<T: drm::drv::Driver> Device<T> {
- - #[allow(dead_code, clippy::mut_from_ref)]
- - pub(crate) unsafe fn raw_mut(&self) -> &mut bindings::drm_device {
- - // SAFETY: Depends on safe usage by the caller
- - unsafe { &mut *self.drm.get() }
- +#[cfg(not(CONFIG_DRM_LEGACY))]
- +macro_rules! drm_legacy_fields {
- + ( $($field:ident: $val:expr),* $(,)? ) => {
- + bindings::drm_driver {
- + $( $field: $val ),*
- + }
- }
- +}
- +
- +/// A typed DRM device with a specific `drm::Driver` implementation. The device is always
- +/// reference-counted.
- +#[repr(C)]
- +#[pin_data]
- +pub struct Device<T: drm::Driver> {
- + dev: Opaque<bindings::drm_device>,
- + #[pin]
- + data: T::Data,
- +}
- +
- +impl<T: drm::Driver> Device<T> {
- + const VTABLE: bindings::drm_driver = drm_legacy_fields! {
- + load: None,
- + open: Some(drm::File::<T::File>::open_callback),
- + postclose: Some(drm::File::<T::File>::postclose_callback),
- + unload: None,
- + release: None,
- + master_set: None,
- + master_drop: None,
- + debugfs_init: None,
- + gem_create_object: T::Object::ALLOC_OPS.gem_create_object,
- + prime_handle_to_fd: T::Object::ALLOC_OPS.prime_handle_to_fd,
- + prime_fd_to_handle: T::Object::ALLOC_OPS.prime_fd_to_handle,
- + gem_prime_import: T::Object::ALLOC_OPS.gem_prime_import,
- + gem_prime_import_sg_table: T::Object::ALLOC_OPS.gem_prime_import_sg_table,
- + dumb_create: T::Object::ALLOC_OPS.dumb_create,
- + dumb_map_offset: T::Object::ALLOC_OPS.dumb_map_offset,
- + show_fdinfo: None,
- + fbdev_probe: None,
- +
- + major: T::INFO.major,
- + minor: T::INFO.minor,
- + patchlevel: T::INFO.patchlevel,
- + name: T::INFO.name.as_char_ptr() as *mut _,
- + desc: T::INFO.desc.as_char_ptr() as *mut _,
- - // Not intended to be called externally, except via declare_drm_ioctls!()
- + driver_features: drm::driver::FEAT_GEM,
- + ioctls: T::IOCTLS.as_ptr(),
- + num_ioctls: T::IOCTLS.len() as i32,
- + fops: &Self::GEM_FOPS as _,
- + };
- +
- + const GEM_FOPS: bindings::file_operations = drm::gem::create_fops();
- +
- + /// Create a new `drm::Device` for a `drm::Driver`.
- + pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<ARef<Self>> {
- + // SAFETY:
- + // - `VTABLE`, as a `const` is pinned to the read-only section of the compilation,
- + // - `dev` is valid by its type invarants,
- + let raw_drm: *mut Self = unsafe {
- + bindings::__drm_dev_alloc(
- + dev.as_raw(),
- + &Self::VTABLE,
- + mem::size_of::<Self>(),
- + mem::offset_of!(Self, dev),
- + )
- + }
- + .cast();
- + let raw_drm = NonNull::new(from_err_ptr(raw_drm)?).ok_or(ENOMEM)?;
- +
- + // SAFETY: `raw_drm` is a valid pointer to `Self`.
- + let raw_data = unsafe { ptr::addr_of_mut!((*raw_drm.as_ptr()).data) };
- +
- + // SAFETY:
- + // - `raw_data` is a valid pointer to uninitialized memory.
- + // - `raw_data` will not move until it is dropped.
- + unsafe { data.__pinned_init(raw_data) }.inspect_err(|_| {
- + // SAFETY: `__drm_dev_alloc()` was successful, hence `raw_drm` must be valid and the
- + // refcount must be non-zero.
- + unsafe { bindings::drm_dev_put(ptr::addr_of_mut!((*raw_drm.as_ptr()).dev).cast()) };
- + })?;
- +
- + // SAFETY: The reference count is one, and now we take ownership of that reference as a
- + // `drm::Device`.
- + Ok(unsafe { ARef::from_raw(raw_drm) })
- + }
- +
- + pub(crate) fn as_raw(&self) -> *mut bindings::drm_device {
- + self.dev.get()
- + }
- +
- + /// # Safety
- + ///
- + /// `ptr` must be a valid poiner to a `struct device` embedded in `Self`.
- + unsafe fn from_drm_device(ptr: *const bindings::drm_device) -> *mut Self {
- + // SAFETY: By the safety requirements of this function `ptr` is a valid pointer to a
- + // `struct drm_device` embedded in `Self`.
- + unsafe { crate::container_of!(ptr, Self, dev) }.cast_mut()
- + }
- +
- + /// Not intended to be called externally, except via declare_drm_ioctls!()
- + ///
- + /// # Safety
- + ///
- + /// Callers must ensure that `ptr` is valid, non-null, and has a non-zero reference count,
- + /// i.e. it must be ensured that the reference count of the C `struct drm_device` `ptr` points
- + /// to can't drop to zero, for the duration of this function call and the entire duration when
- + /// the returned reference exists.
- + ///
- + /// Additionally, callers must ensure that the `struct device`, `ptr` is pointing to, is
- + /// embedded in `Self`.
- #[doc(hidden)]
- - pub unsafe fn borrow<'a>(raw: *const bindings::drm_device) -> &'a Self {
- - // SAFETY: Hidden helper, depends on safe usage by the caller
- - unsafe { &*(raw as *const Self) }
- + pub unsafe fn as_ref<'a>(ptr: *const bindings::drm_device) -> &'a Self {
- + // SAFETY: By the safety requirements of this function `ptr` is a valid pointer to a
- + // `struct drm_device` embedded in `Self`.
- + let ptr = unsafe { Self::from_drm_device(ptr) };
- +
- + // SAFETY: `ptr` is valid by the safety requirements of this function.
- + unsafe { &*ptr.cast() }
- }
- +}
- +
- +impl<T: drm::Driver> Deref for Device<T> {
- + type Target = T::Data;
- - /// Returns a borrowed reference to the user data associated with this Device.
- - pub fn data(&self) -> <T::Data as ForeignOwnable>::Borrowed<'_> {
- - // SAFETY: dev_private is guaranteed to be initialized for all
- - // Device objects exposed to users.
- - unsafe { T::Data::borrow((*self.drm.get()).dev_private) }
- + fn deref(&self) -> &Self::Target {
- + &self.data
- }
- }
- // SAFETY: DRM device objects are always reference counted and the get/put functions
- // satisfy the requirements.
- -unsafe impl<T: drm::drv::Driver> AlwaysRefCounted for Device<T> {
- +unsafe impl<T: drm::Driver> AlwaysRefCounted for Device<T> {
- fn inc_ref(&self) {
- - // SAFETY: We already have a reference per the contract.
- - unsafe { bindings::drm_dev_get(&self.drm as *const _ as *mut _) };
- + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
- + unsafe { bindings::drm_dev_get(self.as_raw()) };
- }
- unsafe fn dec_ref(obj: NonNull<Self>) {
- - // SAFETY: The Device<T> type has the same layout as drm_device,
- - // so we can just cast.
- - unsafe { bindings::drm_dev_put(obj.as_ptr() as *mut _) };
- + // SAFETY: The safety requirements guarantee that the refcount is non-zero.
- + unsafe { bindings::drm_dev_put(obj.cast().as_ptr()) };
- }
- }
- -// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
- -unsafe impl<T: drm::drv::Driver> Send for Device<T> {}
- -
- -// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
- -// from any thread.
- -unsafe impl<T: drm::drv::Driver> Sync for Device<T> {}
- -
- -// Make drm::Device work for dev_info!() and friends
- -// SAFETY: dev is initialized by C for all Device objects
- -unsafe impl<T: drm::drv::Driver> device::RawDevice for Device<T> {
- - fn raw_device(&self) -> *mut bindings::device {
- - // SAFETY: dev is initialized by C for all Device objects
- - unsafe { (*self.drm.get()).dev }
- +impl<T: drm::Driver> AsRef<device::Device> for Device<T> {
- + fn as_ref(&self) -> &device::Device {
- + // SAFETY: `bindings::drm_device::dev` is valid as long as the DRM device itself is valid,
- + // which is guaranteed by the type invariant.
- + unsafe { device::Device::as_ref((*self.as_raw()).dev) }
- }
- }
- +
- +// SAFETY: A `drm::Device` can be released from any thread.
- +unsafe impl<T: drm::Driver> Send for Device<T> {}
- +
- +// SAFETY: A `drm::Device` can be shared among threads because all immutable methods are protected
- +// by the synchronization in `struct drm_device`.
- +unsafe impl<T: drm::Driver> Sync for Device<T> {}
- diff --git a/rust/kernel/drm/driver.rs b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/driver.rs
- index fe4441a2c41d..8a571845dad0 100644
- --- a/rust/kernel/drm/driver.rs
- +++ b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/driver.rs
- @@ -2,24 +2,16 @@
- //! DRM driver core.
- //!
- -//! C header: [`include/drm/drm_drv.h`](../../../../include/drm/drm_drv.h)
- +//! C header: [`include/linux/drm/drm_drv.h`](srctree/include/linux/drm/drm_drv.h)
- use crate::{
- - alloc::{box_ext::BoxExt, flags::*},
- - bindings, device, drm,
- - error::code::*,
- - error::from_err_ptr,
- + bindings,
- + devres::Devres,
- + drm,
- error::{Error, Result},
- prelude::*,
- - private::Sealed,
- str::CStr,
- - types::{ARef, ForeignOwnable},
- - ThisModule,
- -};
- -use core::{
- - marker::{PhantomData, PhantomPinned},
- - pin::Pin,
- - ptr::NonNull,
- + types::ARef,
- };
- use macros::vtable;
- @@ -40,8 +32,16 @@
- /// Driver supports the timeline flavor of DRM sync objects for explicit synchronization of command
- /// submission.
- pub const FEAT_SYNCOBJ_TIMELINE: u32 = bindings::drm_driver_feature_DRIVER_SYNCOBJ_TIMELINE;
- -/// Driver uses the GEM GPUVA manager.
- +/// Driver supports compute acceleration devices. This flag is mutually exclusive with `FEAT_RENDER`
- +/// and `FEAT_MODESET`. Devices that support both graphics and compute acceleration should be
- +/// handled by two drivers that are connected using auxiliary bus.
- +pub const FEAT_COMPUTE_ACCEL: u32 = bindings::drm_driver_feature_DRIVER_COMPUTE_ACCEL;
- +/// Driver supports user defined GPU VA bindings for GEM objects.
- pub const FEAT_GEM_GPUVA: u32 = bindings::drm_driver_feature_DRIVER_GEM_GPUVA;
- +/// Driver supports and requires cursor hotspot information in the cursor plane (e.g. cursor plane
- +/// has to actually track the mouse cursor and the clients are required to set hotspot in order for
- +/// the cursor planes to work correctly).
- +pub const FEAT_CURSOR_HOTSPOT: u32 = bindings::drm_driver_feature_DRIVER_CURSOR_HOTSPOT;
- /// Information data for a DRM Driver.
- pub struct DriverInfo {
- @@ -117,18 +117,19 @@ pub struct AllocOps {
- }
- /// Trait for memory manager implementations. Implemented internally.
- -pub trait AllocImpl: Sealed + drm::gem::IntoGEMObject {
- +pub trait AllocImpl: super::private::Sealed + drm::gem::IntoGEMObject {
- /// The C callback operations for this memory manager.
- const ALLOC_OPS: AllocOps;
- }
- -/// A DRM driver implementation.
- +/// The DRM `Driver` trait.
- +///
- +/// This trait must be implemented by drivers in order to create a `struct drm_device` and `struct
- +/// drm_driver` to be registered in the DRM subsystem.
- #[vtable]
- pub trait Driver {
- /// Context data associated with the DRM driver
- - ///
- - /// Determines the type of the context data passed to each of the methods of the trait.
- - type Data: ForeignOwnable + Sync + Send;
- + type Data: Sync + Send;
- /// The type used to manage memory for this driver.
- ///
- @@ -141,193 +142,53 @@ pub trait Driver {
- /// Driver metadata
- const INFO: DriverInfo;
- - /// Feature flags
- - const FEATURES: u32;
- -
- /// IOCTL list. See `kernel::drm::ioctl::declare_drm_ioctls!{}`.
- const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor];
- }
- -/// A registration of a DRM device
- -///
- -/// # Invariants:
- -///
- -/// drm is always a valid pointer to an allocated drm_device
- -pub struct Registration<T: Driver> {
- - drm: ARef<drm::device::Device<T>>,
- - registered: bool,
- - fops: bindings::file_operations,
- - vtable: Pin<Box<bindings::drm_driver>>,
- - _p: PhantomData<T>,
- - _pin: PhantomPinned,
- -}
- -
- -#[cfg(CONFIG_DRM_LEGACY)]
- -macro_rules! drm_legacy_fields {
- - ( $($field:ident: $val:expr),* $(,)? ) => {
- - bindings::drm_driver {
- - $( $field: $val ),*,
- - firstopen: None,
- - preclose: None,
- - dma_ioctl: None,
- - dma_quiescent: None,
- - context_dtor: None,
- - irq_handler: None,
- - irq_preinstall: None,
- - irq_postinstall: None,
- - irq_uninstall: None,
- - get_vblank_counter: None,
- - enable_vblank: None,
- - disable_vblank: None,
- - dev_priv_size: 0,
- - }
- - }
- -}
- -
- -#[cfg(not(CONFIG_DRM_LEGACY))]
- -macro_rules! drm_legacy_fields {
- - ( $($field:ident: $val:expr),* $(,)? ) => {
- - bindings::drm_driver {
- - $( $field: $val ),*
- - }
- - }
- -}
- -
- -/// Registers a DRM device with the rest of the kernel.
- +/// The registration type of a `drm::Device`.
- ///
- -/// It automatically picks up THIS_MODULE.
- -#[allow(clippy::crate_in_macro_def)]
- -#[macro_export]
- -macro_rules! drm_device_register {
- - ($reg:expr, $data:expr, $flags:expr $(,)?) => {{
- - $crate::drm::drv::Registration::register($reg, $data, $flags, &crate::THIS_MODULE)
- - }};
- -}
- +/// Once the `Registration` structure is dropped, the device is unregistered.
- +pub struct Registration<T: Driver>(ARef<drm::Device<T>>);
- impl<T: Driver> Registration<T> {
- - const VTABLE: bindings::drm_driver = drm_legacy_fields! {
- - load: None,
- - open: Some(drm::file::open_callback::<T::File>),
- - postclose: Some(drm::file::postclose_callback::<T::File>),
- - lastclose: None,
- - unload: None,
- - release: None,
- - master_set: None,
- - master_drop: None,
- - debugfs_init: None,
- - gem_create_object: T::Object::ALLOC_OPS.gem_create_object,
- - prime_handle_to_fd: T::Object::ALLOC_OPS.prime_handle_to_fd,
- - prime_fd_to_handle: T::Object::ALLOC_OPS.prime_fd_to_handle,
- - gem_prime_import: T::Object::ALLOC_OPS.gem_prime_import,
- - gem_prime_import_sg_table: T::Object::ALLOC_OPS.gem_prime_import_sg_table,
- - dumb_create: T::Object::ALLOC_OPS.dumb_create,
- - dumb_map_offset: T::Object::ALLOC_OPS.dumb_map_offset,
- - show_fdinfo: None,
- -
- - major: T::INFO.major,
- - minor: T::INFO.minor,
- - patchlevel: T::INFO.patchlevel,
- - name: T::INFO.name.as_char_ptr() as *mut _,
- - desc: T::INFO.desc.as_char_ptr() as *mut _,
- - date: T::INFO.date.as_char_ptr() as *mut _,
- -
- - driver_features: T::FEATURES,
- - ioctls: T::IOCTLS.as_ptr(),
- - num_ioctls: T::IOCTLS.len() as i32,
- - fops: core::ptr::null_mut(),
- - };
- -
- - /// Creates a new [`Registration`] but does not register it yet.
- - ///
- - /// It is allowed to move.
- - pub fn new(parent: &dyn device::RawDevice) -> Result<Self> {
- - let vtable = Pin::new(Box::new(Self::VTABLE, GFP_KERNEL)?);
- - // SAFETY: Safe to call at any time (with valid args)
- - let raw_drm = unsafe { bindings::drm_dev_alloc(&*vtable, parent.raw_device()) };
- - let raw_drm = NonNull::new(from_err_ptr(raw_drm)? as *mut _).ok_or(ENOMEM)?;
- -
- - // SAFETY: The reference count is one, and now we take ownership of that reference as a
- - // drm::device::Device.
- - let drm = unsafe { ARef::from_raw(raw_drm) };
- -
- - Ok(Self {
- - drm,
- - registered: false,
- - vtable,
- - fops: drm::gem::create_fops(),
- - _pin: PhantomPinned,
- - _p: PhantomData,
- - })
- - }
- -
- - /// Registers a DRM device with the rest of the kernel.
- - ///
- - /// Users are encouraged to use the [`drm_device_register!()`] macro because it automatically
- - /// picks up the current module.
- - pub fn register(
- - self: Pin<&mut Self>,
- - data: T::Data,
- - flags: usize,
- - module: &'static ThisModule,
- - ) -> Result {
- - if self.registered {
- - // Already registered.
- - return Err(EINVAL);
- - }
- -
- - // SAFETY: We never move out of `this`.
- - let this = unsafe { self.get_unchecked_mut() };
- - let data_pointer = <T::Data as ForeignOwnable>::into_foreign(data);
- - // SAFETY: This is the only code touching dev_private, so it is safe to upgrade to a
- - // mutable reference.
- - unsafe { this.drm.raw_mut() }.dev_private = data_pointer as *mut _;
- -
- - this.fops.owner = module.0;
- - this.vtable.fops = &this.fops;
- -
- - // SAFETY: The device is now initialized and ready to be registered.
- - let ret = unsafe { bindings::drm_dev_register(this.drm.raw_mut(), flags as u64) };
- + /// Creates a new [`Registration`] and registers it.
- + pub fn new(drm: ARef<drm::Device<T>>, flags: usize) -> Result<Self> {
- + // SAFETY: Safe by the invariants of `drm::Device`.
- + let ret = unsafe { bindings::drm_dev_register(drm.as_raw(), flags) };
- if ret < 0 {
- - // SAFETY: `data_pointer` was returned by `into_foreign` above.
- - unsafe { T::Data::from_foreign(data_pointer) };
- return Err(Error::from_errno(ret));
- }
- - this.registered = true;
- - Ok(())
- + Ok(Self(drm))
- + }
- +
- + /// Same as [`Registration::new`}, but transfers ownership of the [`Registration`] to
- + /// [`Devres`].
- + pub fn new_foreign_owned(drm: ARef<drm::device::Device<T>>, flags: usize) -> Result {
- + let reg = Registration::<T>::new(drm.clone(), flags)?;
- +
- + Devres::new_foreign_owned(drm.as_ref(), reg, GFP_KERNEL)
- }
- /// Returns a reference to the `Device` instance for this registration.
- - pub fn device(&self) -> &drm::device::Device<T> {
- - // TODO: rework this, ensure this only works after registration
- - &self.drm
- + pub fn device(&self) -> &drm::Device<T> {
- + &self.0
- }
- }
- -// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
- -// or CPUs, so it is safe to share it.
- +// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between
- +// threads, hence it's safe to share it.
- unsafe impl<T: Driver> Sync for Registration<T> {}
- -#[allow(clippy::non_send_fields_in_send_ty)]
- -// SAFETY: Registration with and unregistration from the drm subsystem can happen from any thread.
- -// Additionally, `T::Data` (which is dropped during unregistration) is `Send`, so it is ok to move
- -// `Registration` to different threads.
- +// SAFETY: Registration with and unregistration from the DRM subsystem can happen from any thread.
- unsafe impl<T: Driver> Send for Registration<T> {}
- impl<T: Driver> Drop for Registration<T> {
- /// Removes the registration from the kernel if it has completed successfully before.
- fn drop(&mut self) {
- - if self.registered {
- - // Get a pointer to the data stored in device before destroying it.
- - // SAFETY: `drm` is valid per the type invariant
- - let data_pointer = unsafe { self.drm.raw_mut().dev_private };
- -
- - // SAFETY: Since `registered` is true, `self.drm` is both valid and registered.
- - unsafe { bindings::drm_dev_unregister(self.drm.raw_mut()) };
- -
- - // Free data as well.
- - // SAFETY: `data_pointer` was returned by `into_foreign` during registration.
- - unsafe { <T::Data as ForeignOwnable>::from_foreign(data_pointer) };
- - }
- + // SAFETY: Safe by the invariant of `ARef<drm::Device<T>>`. The existence of this
- + // `Registration` also guarantees the this `drm::Device` is actually registered.
- + unsafe { bindings::drm_dev_unregister(self.0.as_raw()) };
- }
- }
- diff --git a/rust/kernel/drm/file.rs b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/file.rs
- index a20ab4b8769b..3b97728f03e0 100644
- --- a/rust/kernel/drm/file.rs
- +++ b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/file.rs
- @@ -2,116 +2,98 @@
- //! DRM File objects.
- //!
- -//! C header: [`include/drm/drm_file.h`](../../../../include/drm/drm_file.h)
- +//! C header: [`include/linux/drm/drm_file.h`](srctree/include/linux/drm/drm_file.h)
- -use crate::{bindings, drm, error::Result};
- -use alloc::boxed::Box;
- +use crate::{bindings, drm, error::Result, prelude::*, types::Opaque};
- use core::marker::PhantomData;
- use core::pin::Pin;
- /// Trait that must be implemented by DRM drivers to represent a DRM File (a client instance).
- pub trait DriverFile {
- /// The parent `Driver` implementation for this `DriverFile`.
- - type Driver: drm::drv::Driver;
- + type Driver: drm::Driver;
- /// Open a new file (called when a client opens the DRM device).
- - fn open(device: &drm::device::Device<Self::Driver>) -> Result<Pin<Box<Self>>>;
- + fn open(device: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>>;
- }
- /// An open DRM File.
- ///
- /// # Invariants
- -/// `raw` is a valid pointer to a `drm_file` struct.
- +///
- +/// `self.0` is always a valid pointer to an open `struct drm_file`.
- #[repr(transparent)]
- -pub struct File<T: DriverFile> {
- - raw: *mut bindings::drm_file,
- - _p: PhantomData<T>,
- -}
- -
- -pub(super) unsafe extern "C" fn open_callback<T: DriverFile>(
- - raw_dev: *mut bindings::drm_device,
- - raw_file: *mut bindings::drm_file,
- -) -> core::ffi::c_int {
- - // SAFETY: The raw_drm arg is always a valid borrowed reference
- - let drm = unsafe { drm::device::Device::borrow(raw_dev) };
- - // SAFETY: This reference won't escape this function
- - let file = unsafe { &mut *raw_file };
- -
- - let inner = match T::open(drm) {
- - Err(e) => {
- - return e.to_errno();
- - }
- - Ok(i) => i,
- - };
- -
- - // SAFETY: This pointer is treated as pinned, and the Drop guarantee is upheld below.
- - file.driver_priv = Box::into_raw(unsafe { Pin::into_inner_unchecked(inner) }) as *mut _;
- -
- - 0
- -}
- -
- -pub(super) unsafe extern "C" fn postclose_callback<T: DriverFile>(
- - _dev: *mut bindings::drm_device,
- - raw_file: *mut bindings::drm_file,
- -) {
- - // SAFETY: This reference won't escape this function
- - let file = unsafe { &*raw_file };
- -
- - // Drop the DriverFile
- - // SAFETY: file.driver_priv is always a Box<T> pointer
- - unsafe { drop(Box::from_raw(file.driver_priv as *mut T)) };
- -}
- +pub struct File<T: DriverFile>(Opaque<bindings::drm_file>, PhantomData<T>);
- impl<T: DriverFile> File<T> {
- - // Not intended to be called externally, except via declare_drm_ioctls!()
- #[doc(hidden)]
- - pub unsafe fn from_raw(raw_file: *mut bindings::drm_file) -> File<T> {
- - File {
- - raw: raw_file,
- - _p: PhantomData,
- - }
- + /// Not intended to be called externally, except via declare_drm_ioctls!()
- + ///
- + /// # Safety
- + ///
- + /// `raw_file` must be a valid pointer to an open `struct drm_file`, opened through `T::open`.
- + pub unsafe fn as_ref<'a>(ptr: *mut bindings::drm_file) -> &'a File<T> {
- + // SAFETY: `raw_file` is valid by the safety requirements of this function.
- + unsafe { &*ptr.cast() }
- }
- - #[allow(dead_code)]
- - /// Return the raw pointer to the underlying `drm_file`.
- - pub(super) fn raw(&self) -> *const bindings::drm_file {
- - self.raw
- + pub(super) fn as_raw(&self) -> *mut bindings::drm_file {
- + self.0.get()
- }
- - /// Return an immutable reference to the raw `drm_file` structure.
- - pub(super) fn file(&self) -> &bindings::drm_file {
- - // SAFETY: The raw pointer is always valid per usage in declare_drm_ioctls!()
- - unsafe { &*self.raw }
- + fn driver_priv(&self) -> *mut T {
- + // SAFETY: By the type invariants of `Self`, `self.as_raw()` is always valid.
- + unsafe { (*self.as_raw()).driver_priv }.cast()
- }
- /// Return a pinned reference to the driver file structure.
- pub fn inner(&self) -> Pin<&T> {
- - // SAFETY: The driver_priv pointer is always a pinned reference to the driver
- - // file structure.
- - unsafe { Pin::new_unchecked(&*(self.file().driver_priv as *const T)) }
- + // SAFETY: By the type invariant the pointer `self.as_raw()` points to a valid and opened
- + // `struct drm_file`, hence `driver_priv` has been properly initialized by `open_callback`.
- + unsafe { Pin::new_unchecked(&*(self.driver_priv())) }
- }
- -}
- -impl<T: DriverFile> crate::private::Sealed for File<T> {}
- + /// The open callback of a `struct drm_file`.
- + pub(crate) extern "C" fn open_callback(
- + raw_dev: *mut bindings::drm_device,
- + raw_file: *mut bindings::drm_file,
- + ) -> core::ffi::c_int {
- + // SAFETY: A callback from `struct drm_driver::open` guarantees that
- + // - `raw_dev` is valid pointer to a `sturct drm_device`,
- + // - the corresponding `sturct drm_device` has been registered.
- + let drm = unsafe { drm::Device::as_ref(raw_dev) };
- +
- + // SAFETY: `raw_file` valid pointer to a `struct drm_file`.
- + let file = unsafe { File::<T>::as_ref(raw_file) };
- +
- + let inner = match T::open(drm) {
- + Err(e) => {
- + return e.to_errno();
- + }
- + Ok(i) => i,
- + };
- +
- + // SAFETY: This pointer is treated as pinned, and the Drop guarantee is upheld in
- + // `postclose_callback()`.
- + let driver_priv = KBox::into_raw(unsafe { Pin::into_inner_unchecked(inner) });
- +
- + // SAFETY: By the type invariants of `Self`, `self.as_raw()` is always valid.
- + unsafe { (*file.as_raw()).driver_priv = driver_priv.cast() };
- +
- + 0
- + }
- -/// Generic trait to allow users that don't care about driver specifics to accept any File<T>.
- -///
- -/// # Safety
- -/// Must only be implemented for File<T> and return the pointer, following the normal invariants
- -/// of that type.
- -pub unsafe trait GenericFile: crate::private::Sealed {
- - /// Returns the raw const pointer to the `struct drm_file`
- - fn raw(&self) -> *const bindings::drm_file;
- - /// Returns the raw mut pointer to the `struct drm_file`
- - fn raw_mut(&mut self) -> *mut bindings::drm_file;
- -}
- + /// The postclose callback of a `struct drm_file`.
- + pub(crate) extern "C" fn postclose_callback(
- + _raw_dev: *mut bindings::drm_device,
- + raw_file: *mut bindings::drm_file,
- + ) {
- + // SAFETY: This reference won't escape this function
- + let file = unsafe { File::<T>::as_ref(raw_file) };
- -// SAFETY: Follows the invariants of the File<T>.
- -unsafe impl<T: DriverFile> GenericFile for File<T> {
- - fn raw(&self) -> *const bindings::drm_file {
- - self.raw
- - }
- - fn raw_mut(&mut self) -> *mut bindings::drm_file {
- - self.raw
- + // SAFETY: `file.driver_priv` has been created in `open_callback` through `KBox::into_raw`.
- + let _ = unsafe { KBox::from_raw(file.driver_priv()) };
- }
- }
- +
- +impl<T: DriverFile> super::private::Sealed for File<T> {}
- diff --git a/rust/kernel/drm/gem/mod.rs b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/gem/mod.rs
- index fdcd415e585f..ec2cdbe79b0e 100644
- --- a/rust/kernel/drm/gem/mod.rs
- +++ b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/gem/mod.rs
- @@ -2,182 +2,135 @@
- //! DRM GEM API
- //!
- -//! C header: [`include/linux/drm/drm_gem.h`](../../../../include/linux/drm/drm_gem.h)
- -
- -#[cfg(CONFIG_DRM_GEM_SHMEM_HELPER = "y")]
- -pub mod shmem;
- -
- -use alloc::boxed::Box;
- +//! C header: [`include/linux/drm/drm_gem.h`](srctree/include/linux/drm/drm_gem.h)
- use crate::{
- alloc::flags::*,
- - bindings,
- - drm::{device, drv, file},
- + bindings, drm,
- + drm::driver::{AllocImpl, AllocOps},
- error::{to_result, Result},
- prelude::*,
- + types::{ARef, Opaque},
- };
- -use core::{marker::PhantomPinned, mem, ops::Deref, ops::DerefMut};
- +use core::{mem, ops::Deref, ptr};
- /// GEM object functions, which must be implemented by drivers.
- pub trait BaseDriverObject<T: BaseObject>: Sync + Send + Sized {
- - /// The return type of the new() function. Should be `impl PinInit<Self, Error>`.
- - /// TODO: Remove this when return_position_impl_trait_in_trait is stable.
- - type Initializer: PinInit<Self, Error>;
- -
- /// Create a new driver data object for a GEM object of a given size.
- - fn new(dev: &device::Device<T::Driver>, size: usize) -> Self::Initializer;
- + 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 drv::Driver>::Object,
- - _file: &file::File<<<T as IntoGEMObject>::Driver as drv::Driver>::File>,
- + _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 drv::Driver>::Object,
- - _file: &file::File<<<T as IntoGEMObject>::Driver as drv::Driver>::File>,
- + _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
- -pub trait IntoGEMObject: Sized + crate::private::Sealed {
- +pub trait IntoGEMObject: Sized + super::private::Sealed {
- /// Owning driver for this type
- - type Driver: drv::Driver;
- + 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 gem_obj(&self) -> &bindings::drm_gem_object;
- + #[allow(clippy::wrong_self_convention)]
- + fn into_gem_obj(&self) -> &Opaque<bindings::drm_gem_object>;
- - /// Returns a reference to the raw `drm_gem_object` structure, which must be valid as long as
- - /// this owning object is valid.
- - fn mut_gem_obj(&mut self) -> &mut bindings::drm_gem_object;
- -
- - /// Converts a pointer to a `drm_gem_object` into a pointer to this type.
- - ///
- - /// # Safety
- - ///
- - /// The argument must an object owned by this Driver.
- - unsafe fn from_gem_obj(obj: *mut bindings::drm_gem_object) -> *mut Self;
- + /// Converts a pointer to a `struct drm_gem_object` into a pointer to `Self`.
- + fn from_gem_obj(obj: *mut bindings::drm_gem_object) -> *mut Self;
- }
- /// Trait which must be implemented by drivers using base GEM objects.
- pub trait DriverObject: BaseDriverObject<Object<Self>> {
- /// Parent `Driver` for this object.
- - type Driver: drv::Driver;
- + type Driver: drm::Driver;
- }
- -unsafe extern "C" fn free_callback<T: DriverObject>(obj: *mut bindings::drm_gem_object) {
- - // SAFETY: All of our objects are Object<T>.
- - let this = unsafe { crate::container_of!(obj, Object<T>, obj) as *mut Object<T> };
- -
- - // SAFETY: The pointer we got has to be valid
- - unsafe { bindings::drm_gem_object_release(obj) };
- -
- - // SAFETY: All of our objects are allocated via Box<>, and we're in the
- - // free callback which guarantees this object has zero remaining references,
- - // so we can drop it
- - unsafe { drop(Box::from_raw(this)) };
- -}
- -
- -unsafe extern "C" fn open_callback<T: BaseDriverObject<U>, U: BaseObject>(
- +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: The file pointer is valid when called from the C side.
- + // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`.
- let file = unsafe {
- - file::File::<<<U as IntoGEMObject>::Driver as drv::Driver>::File>::from_raw(raw_file)
- + drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::as_ref(raw_file)
- };
- - // SAFETY: The object pointer is valid and owned by us when called from the C side.
- - let obj = unsafe {
- - <<<U as IntoGEMObject>::Driver as drv::Driver>::Object as IntoGEMObject>::from_gem_obj(
- + let obj =
- + <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::from_gem_obj(
- raw_obj,
- - )
- - };
- + );
- - // SAFETY: from_gem_obj() returns a valid pointer as long as the type is
- - // correct and the raw_obj we got is valid.
- - match T::open(unsafe { &*obj }, &file) {
- + // SAFETY: `from_gem_obj()` returns a valid pointer as long as the type is correct and the
- + // `raw_obj` we got is valid.
- + match T::open(unsafe { &*obj }, file) {
- Err(e) => e.to_errno(),
- Ok(()) => 0,
- }
- }
- -unsafe extern "C" fn close_callback<T: BaseDriverObject<U>, U: BaseObject>(
- +extern "C" fn close_callback<T: BaseDriverObject<U>, U: BaseObject>(
- raw_obj: *mut bindings::drm_gem_object,
- raw_file: *mut bindings::drm_file,
- ) {
- - // SAFETY: The pointer we got has to be valid.
- + // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`.
- let file = unsafe {
- - file::File::<<<U as IntoGEMObject>::Driver as drv::Driver>::File>::from_raw(raw_file)
- + drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::as_ref(raw_file)
- };
- - // SAFETY: The object pointer is valid and owned by us when called from the C side.
- - let obj = unsafe {
- - <<<U as IntoGEMObject>::Driver as drv::Driver>::Object as IntoGEMObject>::from_gem_obj(
- + let obj =
- + <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::from_gem_obj(
- raw_obj,
- - )
- - };
- + );
- - // SAFETY: from_gem_obj() returns a valid pointer as long as the type is
- - // correct and the raw_obj we got is valid.
- - T::close(unsafe { &*obj }, &file);
- + // SAFETY: `from_gem_obj()` returns a valid pointer as long as the type is correct and the
- + // `raw_obj` we got is valid.
- + T::close(unsafe { &*obj }, file);
- }
- impl<T: DriverObject> IntoGEMObject for Object<T> {
- type Driver = T::Driver;
- - fn gem_obj(&self) -> &bindings::drm_gem_object {
- + fn into_gem_obj(&self) -> &Opaque<bindings::drm_gem_object> {
- &self.obj
- }
- - fn mut_gem_obj(&mut self) -> &mut bindings::drm_gem_object {
- - &mut self.obj
- - }
- -
- - unsafe fn from_gem_obj(obj: *mut bindings::drm_gem_object) -> *mut Object<T> {
- - // SAFETY: Safe as long as the safety invariants of this trait method hold.
- - unsafe { crate::container_of!(obj, Object<T>, obj) as *mut Object<T> }
- + fn from_gem_obj(obj: *mut bindings::drm_gem_object) -> *mut Self {
- + // SAFETY: All of our objects are Object<T>.
- + unsafe { crate::container_of!(obj, Object<T>, obj).cast_mut() }
- }
- }
- /// Base operations shared by all GEM object classes
- -pub trait BaseObject: IntoGEMObject {
- +pub trait BaseObject
- +where
- + Self: crate::types::AlwaysRefCounted + IntoGEMObject,
- +{
- /// Returns the size of the object in bytes.
- fn size(&self) -> usize {
- - self.gem_obj().size
- - }
- -
- - /// Sets the exportable flag, which controls whether the object can be exported via PRIME.
- - fn set_exportable(&mut self, exportable: bool) {
- - self.mut_gem_obj().exportable = exportable;
- - }
- -
- - /// Creates a new reference to the object.
- - fn reference(&self) -> ObjectRef<Self> {
- - // SAFETY: Having a reference to an Object implies holding a GEM reference
- - unsafe {
- - bindings::drm_gem_object_get(self.gem_obj() as *const _ as *mut _);
- - }
- - ObjectRef {
- - ptr: self as *const _,
- - }
- + // SAFETY: `self.into_gem_obj()` is guaranteed to be a pointer to a valid `struct
- + // drm_gem_object`.
- + unsafe { (*self.into_gem_obj().get()).size }
- }
- /// Creates a new handle for the object associated with a given `File`
- /// (or returns an existing one).
- fn create_handle(
- &self,
- - file: &file::File<<<Self as IntoGEMObject>::Driver as drv::Driver>::File>,
- + file: &drm::File<<<Self as IntoGEMObject>::Driver as drm::Driver>::File>,
- ) -> Result<u32> {
- let mut handle: u32 = 0;
- // SAFETY: The arguments are all valid per the type invariants.
- to_result(unsafe {
- bindings::drm_gem_handle_create(
- - file.raw() as *mut _,
- - self.gem_obj() as *const _ as *mut _,
- + file.as_raw().cast(),
- + self.into_gem_obj().get(),
- &mut handle,
- )
- })?;
- @@ -186,58 +139,54 @@ fn create_handle(
- /// Looks up an object by its handle for a given `File`.
- fn lookup_handle(
- - file: &file::File<<<Self as IntoGEMObject>::Driver as drv::Driver>::File>,
- + file: &drm::File<<<Self as IntoGEMObject>::Driver as drm::Driver>::File>,
- handle: u32,
- - ) -> Result<ObjectRef<Self>> {
- + ) -> Result<ARef<Self>> {
- // SAFETY: The arguments are all valid per the type invariants.
- - let ptr = unsafe { bindings::drm_gem_object_lookup(file.raw() as *mut _, handle) };
- -
- - if ptr.is_null() {
- - Err(ENOENT)
- - } else {
- - Ok(ObjectRef {
- - ptr: ptr as *const _,
- - })
- - }
- + let ptr = unsafe { bindings::drm_gem_object_lookup(file.as_raw().cast(), handle) };
- + let ptr = <Self as IntoGEMObject>::from_gem_obj(ptr);
- + let ptr = ptr::NonNull::new(ptr).ok_or(ENOENT)?;
- +
- + // SAFETY: We take ownership of the reference of `drm_gem_object_lookup()`.
- + Ok(unsafe { ARef::from_raw(ptr) })
- }
- /// 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 {
- - // TODO: is this threadsafe?
- - bindings::drm_gem_create_mmap_offset(self.gem_obj() as *const _ as *mut _)
- - })?;
- - // SAFETY: Safe to call on vma_node (which is guaranteed to be valid after the above)
- + to_result(unsafe { bindings::drm_gem_create_mmap_offset(self.into_gem_obj().get()) })?;
- +
- + // SAFETY: The arguments are valid per the type invariant.
- Ok(unsafe {
- - bindings::drm_vma_node_offset_addr(&self.gem_obj().vma_node as *const _ as *mut _)
- + bindings::drm_vma_node_offset_addr(ptr::addr_of_mut!(
- + (*self.into_gem_obj().get()).vma_node
- + ))
- })
- }
- }
- -impl<T: IntoGEMObject> BaseObject for T {}
- +impl<T> BaseObject for T where Self: crate::types::AlwaysRefCounted + IntoGEMObject {}
- /// A base GEM object.
- +///
- +/// Invariants
- +///
- +/// `self.dev` is always a valid pointer to a `struct drm_device`.
- #[repr(C)]
- #[pin_data]
- -pub struct Object<T: DriverObject> {
- - obj: bindings::drm_gem_object,
- - dev: *const bindings::drm_device,
- +pub struct Object<T: DriverObject + Send + Sync> {
- + obj: Opaque<bindings::drm_gem_object>,
- + dev: ptr::NonNull<bindings::drm_device>,
- #[pin]
- - inner: T,
- - #[pin]
- - _p: PhantomPinned,
- + data: T,
- }
- -// SAFETY: This struct is safe to zero-initialize
- -unsafe impl init::Zeroable for bindings::drm_gem_object {}
- -
- impl<T: DriverObject> Object<T> {
- /// The size of this object's structure.
- pub const SIZE: usize = mem::size_of::<Self>();
- const OBJECT_FUNCS: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs {
- - free: Some(free_callback::<T>),
- + free: Some(Self::free_callback),
- open: Some(open_callback::<T, Object<T>>),
- close: Some(close_callback::<T, Object<T>>),
- print_info: None,
- @@ -249,174 +198,124 @@ impl<T: DriverObject> Object<T> {
- vunmap: None,
- mmap: None,
- status: None,
- - rss: None,
- vm_ops: core::ptr::null_mut(),
- evict: None,
- + rss: None,
- };
- /// Create a new GEM object.
- - pub fn new(dev: &device::Device<T::Driver>, size: usize) -> Result<Pin<UniqueObjectRef<Self>>> {
- - let obj: Pin<Box<Self>> = Box::try_pin_init(
- + pub fn new(dev: &drm::Device<T::Driver>, size: usize) -> Result<ARef<Self>> {
- + let obj: Pin<KBox<Self>> = KBox::pin_init(
- try_pin_init!(Self {
- - // SAFETY: This struct is expected to be zero-initialized
- - obj: bindings::drm_gem_object {
- - funcs: &Self::OBJECT_FUNCS,
- - ..Default::default()
- - },
- - inner <- T::new(dev, size),
- - dev: dev.drm.get(),
- - _p: PhantomPinned
- + obj: Opaque::zeroed(),
- + data <- T::new(dev, size),
- + // INVARIANT: The drm subsystem guarantees that the `struct drm_device` will live
- + // as long as the GEM object lives.
- + //
- + // SAFETY: By the type invariants of `drm::Device`, `dev.as_raw()` must be valid.
- + dev: unsafe { ptr::NonNull::new_unchecked(dev.as_raw()) },
- }),
- GFP_KERNEL,
- )?;
- - // SAFETY: Safe to call as long as the pointer is a properly allocated GEM object
- - to_result(unsafe {
- - bindings::drm_gem_object_init(dev.raw_mut(), &obj.obj as *const _ as *mut _, size)
- - })?;
- + // SAFETY: `obj.as_raw()` is guaranteed to be valid by the initialization above.
- + unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS };
- - // SAFETY: We never move out of self
- - let obj_ref = unsafe {
- - Pin::new_unchecked(UniqueObjectRef {
- - // SAFETY: We never move out of the Box
- - ptr: Box::leak(Pin::into_inner_unchecked(obj)),
- - _p: PhantomPinned,
- - })
- - };
- + // 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 { ptr::NonNull::new_unchecked(ptr) };
- - Ok(obj_ref)
- + // 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.
- - pub fn dev(&self) -> &device::Device<T::Driver> {
- - // SAFETY: The drm subsystem guarantees that the drm_device will live as long as
- + pub fn 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, so we can just borrow from the raw pointer.
- - unsafe { device::Device::borrow(self.dev) }
- - }
- -}
- -
- -impl<T: DriverObject> crate::private::Sealed for Object<T> {}
- -
- -impl<T: DriverObject> Deref for Object<T> {
- - type Target = T;
- -
- - fn deref(&self) -> &Self::Target {
- - &self.inner
- + unsafe { drm::Device::as_ref(self.dev.as_ptr()) }
- }
- -}
- -impl<T: DriverObject> DerefMut for Object<T> {
- - fn deref_mut(&mut self) -> &mut Self::Target {
- - &mut self.inner
- + fn as_raw(&self) -> *mut bindings::drm_gem_object {
- + self.obj.get()
- }
- -}
- -impl<T: DriverObject> drv::AllocImpl for Object<T> {
- - const ALLOC_OPS: drv::AllocOps = drv::AllocOps {
- - gem_create_object: None,
- - prime_handle_to_fd: None,
- - prime_fd_to_handle: None,
- - gem_prime_import: None,
- - gem_prime_import_sg_table: None,
- - dumb_create: None,
- - dumb_map_offset: None,
- - };
- -}
- -
- -/// A reference-counted shared reference to a base GEM object.
- -pub struct ObjectRef<T: IntoGEMObject> {
- - // Invariant: the pointer is valid and initialized, and this ObjectRef owns a reference to it.
- - ptr: *const T,
- -}
- + extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
- + // SAFETY: All of our objects are of type `Object<T>`.
- + let this = unsafe { crate::container_of!(obj, Self, obj) }.cast_mut();
- -/// SAFETY: GEM object references are safe to share between threads.
- -unsafe impl<T: IntoGEMObject> Send for ObjectRef<T> {}
- -/// SAFETY: GEM object references are safe to share between threads.
- -unsafe impl<T: IntoGEMObject> Sync for ObjectRef<T> {}
- + // 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) };
- -impl<T: IntoGEMObject> Clone for ObjectRef<T> {
- - fn clone(&self) -> Self {
- - self.reference()
- + // 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: IntoGEMObject> Drop for ObjectRef<T> {
- - fn drop(&mut self) {
- - // SAFETY: Having an ObjectRef implies holding a GEM reference.
- - // The free callback will take care of deallocation.
- - unsafe {
- - bindings::drm_gem_object_put((*self.ptr).gem_obj() as *const _ as *mut _);
- - }
- +// SAFETY: Instances of `Object<T>` are always reference-counted.
- +unsafe impl<T: DriverObject> crate::types::AlwaysRefCounted for Object<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()) };
- }
- -}
- -impl<T: IntoGEMObject> Deref for ObjectRef<T> {
- - type Target = T;
- + unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
- + // SAFETY: `obj` is a valid pointer to an `Object<T>`.
- + let obj = unsafe { obj.as_ref() };
- - fn deref(&self) -> &Self::Target {
- - // SAFETY: The pointer is valid per the invariant
- - unsafe { &*self.ptr }
- + // SAFETY: The safety requirements guarantee that the refcount is non-zero.
- + unsafe { bindings::drm_gem_object_put(obj.as_raw()) }
- }
- }
- -/// A unique reference to a base GEM object.
- -pub struct UniqueObjectRef<T: IntoGEMObject> {
- - // Invariant: the pointer is valid and initialized, and this ObjectRef owns the only reference
- - // to it.
- - ptr: *mut T,
- - _p: PhantomPinned,
- -}
- +impl<T: DriverObject> super::private::Sealed for Object<T> {}
- -impl<T: IntoGEMObject> UniqueObjectRef<T> {
- - /// Downgrade this reference to a shared reference.
- - pub fn into_ref(self) -> ObjectRef<T> {
- - let ptr = self.ptr as *const _;
- - core::mem::forget(self);
- -
- - ObjectRef { ptr }
- - }
- -}
- -
- -impl<T: IntoGEMObject> Drop for UniqueObjectRef<T> {
- - fn drop(&mut self) {
- - // SAFETY: Having a UniqueObjectRef implies holding a GEM
- - // reference. The free callback will take care of deallocation.
- - unsafe {
- - bindings::drm_gem_object_put((*self.ptr).gem_obj() as *const _ as *mut _);
- - }
- - }
- -}
- -
- -impl<T: IntoGEMObject> Deref for UniqueObjectRef<T> {
- +impl<T: DriverObject> Deref for Object<T> {
- type Target = T;
- fn deref(&self) -> &Self::Target {
- - // SAFETY: The pointer is valid per the invariant
- - unsafe { &*self.ptr }
- + &self.data
- }
- }
- -impl<T: IntoGEMObject> DerefMut for UniqueObjectRef<T> {
- - fn deref_mut(&mut self) -> &mut Self::Target {
- - // SAFETY: The pointer is valid per the invariant
- - unsafe { &mut *self.ptr }
- - }
- +impl<T: DriverObject> AllocImpl for Object<T> {
- + const ALLOC_OPS: AllocOps = AllocOps {
- + gem_create_object: None,
- + prime_handle_to_fd: None,
- + prime_fd_to_handle: None,
- + gem_prime_import: None,
- + gem_prime_import_sg_table: None,
- + dumb_create: None,
- + dumb_map_offset: None,
- + };
- }
- -pub(super) fn create_fops() -> bindings::file_operations {
- - bindings::file_operations {
- - owner: core::ptr::null_mut(),
- - open: Some(bindings::drm_open),
- - release: Some(bindings::drm_release),
- - unlocked_ioctl: Some(bindings::drm_ioctl),
- - #[cfg(CONFIG_COMPAT)]
- - compat_ioctl: Some(bindings::drm_compat_ioctl),
- - #[cfg(not(CONFIG_COMPAT))]
- - compat_ioctl: None,
- - poll: Some(bindings::drm_poll),
- - read: Some(bindings::drm_read),
- - llseek: Some(bindings::noop_llseek),
- - mmap: Some(bindings::drm_gem_mmap),
- - ..Default::default()
- +pub(super) const fn create_fops() -> bindings::file_operations {
- + // SAFETY: As by the type invariant, it is safe to initialize `bindings::file_operations`
- + // zeroed.
- + let mut fops: bindings::file_operations = unsafe { core::mem::zeroed() };
- +
- + fops.owner = core::ptr::null_mut();
- + fops.open = Some(bindings::drm_open);
- + fops.release = Some(bindings::drm_release);
- + fops.unlocked_ioctl = Some(bindings::drm_ioctl);
- + #[cfg(CONFIG_COMPAT)]
- + {
- + fops.compat_ioctl = Some(bindings::drm_compat_ioctl);
- }
- + fops.poll = Some(bindings::drm_poll);
- + fops.read = Some(bindings::drm_read);
- + fops.llseek = Some(bindings::noop_llseek);
- + fops.mmap = Some(bindings::drm_gem_mmap);
- + fops.fop_flags = bindings::FOP_UNSIGNED_OFFSET;
- +
- + fops
- }
- diff --git a/rust/kernel/drm/ioctl.rs b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/ioctl.rs
- index 39846cd35da2..fe4ce0373d33 100644
- --- a/rust/kernel/drm/ioctl.rs
- +++ b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/ioctl.rs
- @@ -1,33 +1,36 @@
- // SPDX-License-Identifier: GPL-2.0 OR MIT
- -#![allow(non_snake_case)]
- //! DRM IOCTL definitions.
- //!
- -//! C header: [`include/drm/drm_ioctl.h`](../../../../include/drm/drm_ioctl.h)
- +//! C header: [`include/linux/drm/drm_ioctl.h`](srctree/include/linux/drm/drm_ioctl.h)
- use crate::ioctl;
- -const BASE: u32 = bindings::DRM_IOCTL_BASE as u32;
- +const BASE: u32 = uapi::DRM_IOCTL_BASE as u32;
- /// Construct a DRM ioctl number with no argument.
- +#[allow(non_snake_case)]
- #[inline(always)]
- pub const fn IO(nr: u32) -> u32 {
- ioctl::_IO(BASE, nr)
- }
- /// Construct a DRM ioctl number with a read-only argument.
- +#[allow(non_snake_case)]
- #[inline(always)]
- pub const fn IOR<T>(nr: u32) -> u32 {
- ioctl::_IOR::<T>(BASE, nr)
- }
- /// Construct a DRM ioctl number with a write-only argument.
- +#[allow(non_snake_case)]
- #[inline(always)]
- pub const fn IOW<T>(nr: u32) -> u32 {
- ioctl::_IOW::<T>(BASE, nr)
- }
- /// Construct a DRM ioctl number with a read-write argument.
- +#[allow(non_snake_case)]
- #[inline(always)]
- pub const fn IOWR<T>(nr: u32) -> u32 {
- ioctl::_IOWR::<T>(BASE, nr)
- @@ -49,8 +52,8 @@ pub const fn IOWR<T>(nr: u32) -> u32 {
- /// Anything that could potentially wreak a master file descriptor needs to have this flag set.
- ///
- -/// Current that’s only for the SETMASTER and DROPMASTER ioctl, which e.g. logind can call to force
- -/// a non-behaving master (display compositor) into compliance.
- +/// Current that’s only for the SETMASTER and DROPMASTER ioctl, which e.g. logind can call to
- +/// force a non-behaving master (display compositor) into compliance.
- ///
- /// This is equivalent to callers with the SYSADMIN capability.
- pub const ROOT_ONLY: u32 = bindings::drm_ioctl_flags_DRM_ROOT_ONLY;
- @@ -61,7 +64,7 @@ pub const fn IOWR<T>(nr: u32) -> u32 {
- /// DRM_AUTH because they do not require authentication.
- pub const RENDER_ALLOW: u32 = bindings::drm_ioctl_flags_DRM_RENDER_ALLOW;
- -/// Internal structures used by the [`declare_drm_ioctls!{}`] macro. Do not use directly.
- +/// Internal structures used by the `declare_drm_ioctls!{}` macro. Do not use directly.
- #[doc(hidden)]
- pub mod internal {
- pub use bindings::drm_device;
- @@ -78,17 +81,17 @@ pub mod internal {
- /// `argument_type` is the type name within the `bindings` crate.
- /// `user_callback` should have the following prototype:
- ///
- -/// ```
- -/// fn foo(device: &kernel::drm::device::Device<Self>,
- +/// ```ignore
- +/// fn foo(device: &kernel::drm::Device<Self>,
- /// data: &mut bindings::argument_type,
- -/// file: &kernel::drm::file::File<Self::File>,
- +/// file: &kernel::drm::File<Self::File>,
- /// )
- /// ```
- /// where `Self` is the drm::drv::Driver implementation these ioctls are being declared within.
- ///
- /// # Examples
- ///
- -/// ```
- +/// ```ignore
- /// kernel::declare_drm_ioctls! {
- /// (FOO_GET_PARAM, drm_foo_get_param, ioctl::RENDER_ALLOW, my_get_param_handler),
- /// }
- @@ -102,11 +105,12 @@ macro_rules! declare_drm_ioctls {
- const _:() = {
- let i: u32 = $crate::uapi::DRM_COMMAND_BASE;
- // Assert that all the IOCTLs are in the right order and there are no gaps,
- - // and that the sizeof of the specified type is correct.
- + // and that the size of the specified type is correct.
- $(
- let cmd: u32 = $crate::macros::concat_idents!(DRM_IOCTL_, $cmd);
- ::core::assert!(i == $crate::ioctl::_IOC_NR(cmd));
- - ::core::assert!(core::mem::size_of::<$crate::uapi::$struct>() == $crate::ioctl::_IOC_SIZE(cmd));
- + ::core::assert!(core::mem::size_of::<$crate::uapi::$struct>() ==
- + $crate::ioctl::_IOC_SIZE(cmd));
- let i: u32 = i + 1;
- )*
- };
- @@ -119,24 +123,28 @@ macro_rules! declare_drm_ioctls {
- unsafe extern "C" fn $cmd(
- raw_dev: *mut $crate::drm::ioctl::internal::drm_device,
- raw_data: *mut ::core::ffi::c_void,
- - raw_file_priv: *mut $crate::drm::ioctl::internal::drm_file,
- + raw_file: *mut $crate::drm::ioctl::internal::drm_file,
- ) -> core::ffi::c_int {
- - // SAFETY: The DRM core ensures the device lives while callbacks are
- - // being called.
- + // SAFETY:
- + // - The DRM core ensures the device lives while callbacks are being
- + // called.
- + // - The DRM device must have been registered when we're called through
- + // an IOCTL.
- //
- // FIXME: Currently there is nothing enforcing that the types of the
- // dev/file match the current driver these ioctls are being declared
- // for, and it's not clear how to enforce this within the type system.
- - let dev = $crate::drm::device::Device::borrow(raw_dev);
- - // SAFETY: This is just the ioctl argument, which hopefully has the right type
- - // (we've done our best checking the size).
- + let dev = $crate::drm::device::Device::as_ref(raw_dev);
- + // SAFETY: This is just the ioctl argument, which hopefully has the
- + // right type (we've done our best checking the size).
- let data = unsafe { &mut *(raw_data as *mut $crate::uapi::$struct) };
- // SAFETY: This is just the DRM file structure
- - let file = unsafe { $crate::drm::file::File::from_raw(raw_file_priv) };
- + let file = unsafe { $crate::drm::File::as_ref(raw_file) };
- - match $func(dev, data, &file) {
- + match $func(dev, data, file) {
- Err(e) => e.to_errno(),
- - Ok(i) => i.try_into().unwrap_or(code::ERANGE.to_errno()),
- + Ok(i) => i.try_into()
- + .unwrap_or($crate::error::code::ERANGE.to_errno()),
- }
- }
- Some($cmd)
- diff --git a/rust/kernel/drm/mod.rs b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/mod.rs
- index 50d1bb9139dc..1b82b6945edf 100644
- --- a/rust/kernel/drm/mod.rs
- +++ b/home/danilo/projects/linux/drm-misc/drm-misc-next/rust/kernel/drm/mod.rs
- @@ -3,12 +3,17 @@
- //! DRM subsystem abstractions.
- pub mod device;
- -pub mod drv;
- +pub mod driver;
- pub mod file;
- pub mod gem;
- -#[cfg(CONFIG_DRM_GPUVM = "y")]
- -pub mod gpuvm;
- pub mod ioctl;
- -pub mod mm;
- -pub mod sched;
- -pub mod syncobj;
- +
- +pub use self::device::Device;
- +pub use self::driver::Driver;
- +pub use self::driver::DriverInfo;
- +pub use self::driver::Registration;
- +pub use self::file::File;
- +
- +pub(crate) mod private {
- + pub trait Sealed {}
- +}
Add Comment
Please, Sign In to add comment