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 { - pub(super) drm: UnsafeCell, - _p: PhantomData, +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 Device { - #[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 { + dev: Opaque, + #[pin] + data: T::Data, +} + +impl Device { + const VTABLE: bindings::drm_driver = drm_legacy_fields! { + load: None, + open: Some(drm::File::::open_callback), + postclose: Some(drm::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) -> Result> { + // 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::(), + 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 Deref for Device { + type Target = T::Data; - /// Returns a borrowed reference to the user data associated with this Device. - pub fn data(&self) -> ::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 AlwaysRefCounted for Device { +unsafe impl AlwaysRefCounted for Device { 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) { - // SAFETY: The Device 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 Send for Device {} - -// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used -// from any thread. -unsafe impl Sync for Device {} - -// Make drm::Device work for dev_info!() and friends -// SAFETY: dev is initialized by C for all Device objects -unsafe impl device::RawDevice for Device { - fn raw_device(&self) -> *mut bindings::device { - // SAFETY: dev is initialized by C for all Device objects - unsafe { (*self.drm.get()).dev } +impl AsRef for Device { + 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 Send for Device {} + +// SAFETY: A `drm::Device` can be shared among threads because all immutable methods are protected +// by the synchronization in `struct drm_device`. +unsafe impl Sync for Device {} 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 { - drm: ARef>, - registered: bool, - fops: bindings::file_operations, - vtable: Pin>, - _p: PhantomData, - _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(ARef>); impl Registration { - const VTABLE: bindings::drm_driver = drm_legacy_fields! { - load: None, - open: Some(drm::file::open_callback::), - postclose: Some(drm::file::postclose_callback::), - 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 { - 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 = ::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>, flags: usize) -> Result { + // 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>, flags: usize) -> Result { + let reg = Registration::::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 { - // TODO: rework this, ensure this only works after registration - &self.drm + pub fn device(&self) -> &drm::Device { + &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 Sync for Registration {} -#[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 Send for Registration {} impl Drop for Registration { /// 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 { ::from_foreign(data_pointer) }; - } + // SAFETY: Safe by the invariant of `ARef>`. 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) -> Result>>; + fn open(device: &drm::Device) -> Result>>; } /// 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 { - raw: *mut bindings::drm_file, - _p: PhantomData, -} - -pub(super) unsafe extern "C" fn open_callback( - 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( - _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 pointer - unsafe { drop(Box::from_raw(file.driver_priv as *mut T)) }; -} +pub struct File(Opaque, PhantomData); impl File { - // 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 { - 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 { + // 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 crate::private::Sealed for File {} + /// 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::::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. -/// -/// # Safety -/// Must only be implemented for File 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::::as_ref(raw_file) }; -// SAFETY: Follows the invariants of the File. -unsafe impl GenericFile for File { - 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 super::private::Sealed for File {} 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: Sync + Send + Sized { - /// The return type of the new() function. Should be `impl PinInit`. - /// TODO: Remove this when return_position_impl_trait_in_trait is stable. - type Initializer: PinInit; - /// Create a new driver data object for a GEM object of a given size. - fn new(dev: &device::Device, size: usize) -> Self::Initializer; + fn new(dev: &drm::Device, size: usize) -> impl PinInit; /// Open a new handle to an existing object, associated with a File. fn open( - _obj: &<::Driver as drv::Driver>::Object, - _file: &file::File<<::Driver as drv::Driver>::File>, + _obj: &<::Driver as drm::Driver>::Object, + _file: &drm::File<<::Driver as drm::Driver>::File>, ) -> Result { Ok(()) } /// Close a handle to an existing object, associated with a File. fn close( - _obj: &<::Driver as drv::Driver>::Object, - _file: &file::File<<::Driver as drv::Driver>::File>, + _obj: &<::Driver as drm::Driver>::Object, + _file: &drm::File<<::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; - /// 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> { /// Parent `Driver` for this object. - type Driver: drv::Driver; + type Driver: drm::Driver; } -unsafe extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) { - // SAFETY: All of our objects are Object. - let this = unsafe { crate::container_of!(obj, Object, obj) as *mut Object }; - - // 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, U: BaseObject>( +extern "C" fn open_callback, 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::<<::Driver as drv::Driver>::File>::from_raw(raw_file) + drm::File::<<::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 { - <<::Driver as drv::Driver>::Object as IntoGEMObject>::from_gem_obj( + let obj = + <<::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, U: BaseObject>( +extern "C" fn close_callback, 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::<<::Driver as drv::Driver>::File>::from_raw(raw_file) + drm::File::<<::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 { - <<::Driver as drv::Driver>::Object as IntoGEMObject>::from_gem_obj( + let obj = + <<::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 IntoGEMObject for Object { type Driver = T::Driver; - fn gem_obj(&self) -> &bindings::drm_gem_object { + fn into_gem_obj(&self) -> &Opaque { &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 { - // SAFETY: Safe as long as the safety invariants of this trait method hold. - unsafe { crate::container_of!(obj, Object, obj) as *mut Object } + fn from_gem_obj(obj: *mut bindings::drm_gem_object) -> *mut Self { + // SAFETY: All of our objects are Object. + unsafe { crate::container_of!(obj, Object, 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 { - // 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<<::Driver as drv::Driver>::File>, + file: &drm::File<<::Driver as drm::Driver>::File>, ) -> Result { 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<<::Driver as drv::Driver>::File>, + file: &drm::File<<::Driver as drm::Driver>::File>, handle: u32, - ) -> Result> { + ) -> Result> { // 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 = ::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 { // 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 BaseObject for T {} +impl 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 { - obj: bindings::drm_gem_object, - dev: *const bindings::drm_device, +pub struct Object { + obj: Opaque, + dev: ptr::NonNull, #[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 Object { /// The size of this object's structure. pub const SIZE: usize = mem::size_of::(); const OBJECT_FUNCS: bindings::drm_gem_object_funcs = bindings::drm_gem_object_funcs { - free: Some(free_callback::), + free: Some(Self::free_callback), open: Some(open_callback::>), close: Some(close_callback::>), print_info: None, @@ -249,174 +198,124 @@ impl Object { 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, size: usize) -> Result>> { - let obj: Pin> = Box::try_pin_init( + pub fn new(dev: &drm::Device, size: usize) -> Result> { + let obj: Pin> = 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 { - // SAFETY: The drm subsystem guarantees that the drm_device will live as long as + pub fn dev(&self) -> &drm::Device { + // 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 crate::private::Sealed for Object {} - -impl Deref for Object { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.inner + unsafe { drm::Device::as_ref(self.dev.as_ptr()) } } -} -impl DerefMut for Object { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner + fn as_raw(&self) -> *mut bindings::drm_gem_object { + self.obj.get() } -} -impl drv::AllocImpl for Object { - 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 { - // 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`. + let this = unsafe { crate::container_of!(obj, Self, obj) }.cast_mut(); -/// SAFETY: GEM object references are safe to share between threads. -unsafe impl Send for ObjectRef {} -/// SAFETY: GEM object references are safe to share between threads. -unsafe impl Sync for ObjectRef {} + // 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 Clone for ObjectRef { - 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 Drop for ObjectRef { - 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` are always reference-counted. +unsafe impl crate::types::AlwaysRefCounted for Object { + 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 Deref for ObjectRef { - type Target = T; + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: `obj` is a valid pointer to an `Object`. + 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 { - // Invariant: the pointer is valid and initialized, and this ObjectRef owns the only reference - // to it. - ptr: *mut T, - _p: PhantomPinned, -} +impl super::private::Sealed for Object {} -impl UniqueObjectRef { - /// Downgrade this reference to a shared reference. - pub fn into_ref(self) -> ObjectRef { - let ptr = self.ptr as *const _; - core::mem::forget(self); - - ObjectRef { ptr } - } -} - -impl Drop for UniqueObjectRef { - 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 Deref for UniqueObjectRef { +impl Deref for Object { type Target = T; fn deref(&self) -> &Self::Target { - // SAFETY: The pointer is valid per the invariant - unsafe { &*self.ptr } + &self.data } } -impl DerefMut for UniqueObjectRef { - fn deref_mut(&mut self) -> &mut Self::Target { - // SAFETY: The pointer is valid per the invariant - unsafe { &mut *self.ptr } - } +impl AllocImpl for Object { + 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(nr: u32) -> u32 { ioctl::_IOR::(BASE, nr) } /// Construct a DRM ioctl number with a write-only argument. +#[allow(non_snake_case)] #[inline(always)] pub const fn IOW(nr: u32) -> u32 { ioctl::_IOW::(BASE, nr) } /// Construct a DRM ioctl number with a read-write argument. +#[allow(non_snake_case)] #[inline(always)] pub const fn IOWR(nr: u32) -> u32 { ioctl::_IOWR::(BASE, nr) @@ -49,8 +52,8 @@ pub const fn IOWR(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(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, +/// ```ignore +/// fn foo(device: &kernel::drm::Device, /// data: &mut bindings::argument_type, -/// file: &kernel::drm::file::File, +/// file: &kernel::drm::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 {} +}