diff options
Diffstat (limited to 'rust/kernel/drm')
| -rw-r--r-- | rust/kernel/drm/device.rs | 41 | ||||
| -rw-r--r-- | rust/kernel/drm/driver.rs | 7 | ||||
| -rw-r--r-- | rust/kernel/drm/file.rs | 2 | ||||
| -rw-r--r-- | rust/kernel/drm/gem/mod.rs | 98 | ||||
| -rw-r--r-- | rust/kernel/drm/ioctl.rs | 13 | 
5 files changed, 88 insertions, 73 deletions
| diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index 3bb7c83966cf..3ce8f62a0056 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -2,17 +2,19 @@  //! DRM device.  //! -//! C header: [`include/linux/drm/drm_device.h`](srctree/include/linux/drm/drm_device.h) +//! C header: [`include/drm/drm_device.h`](srctree/include/drm/drm_device.h)  use crate::{ +    alloc::allocator::Kmalloc,      bindings, device, drm,      drm::driver::AllocImpl,      error::from_err_ptr,      error::Result,      prelude::*, -    types::{ARef, AlwaysRefCounted, Opaque}, +    sync::aref::{ARef, AlwaysRefCounted}, +    types::Opaque,  }; -use core::{mem, ops::Deref, ptr, ptr::NonNull}; +use core::{alloc::Layout, mem, ops::Deref, ptr, ptr::NonNull};  #[cfg(CONFIG_DRM_LEGACY)]  macro_rules! drm_legacy_fields { @@ -53,10 +55,8 @@ macro_rules! drm_legacy_fields {  ///  /// `self.dev` is a valid instance of a `struct device`.  #[repr(C)] -#[pin_data]  pub struct Device<T: drm::Driver> {      dev: Opaque<bindings::drm_device>, -    #[pin]      data: T::Data,  } @@ -83,8 +83,8 @@ impl<T: drm::Driver> Device<T> {          major: T::INFO.major,          minor: T::INFO.minor,          patchlevel: T::INFO.patchlevel, -        name: T::INFO.name.as_char_ptr().cast_mut(), -        desc: T::INFO.desc.as_char_ptr().cast_mut(), +        name: crate::str::as_char_ptr_in_const_context(T::INFO.name).cast_mut(), +        desc: crate::str::as_char_ptr_in_const_context(T::INFO.desc).cast_mut(),          driver_features: drm::driver::FEAT_GEM,          ioctls: T::IOCTLS.as_ptr(), @@ -96,6 +96,10 @@ impl<T: drm::Driver> Device<T> {      /// Create a new `drm::Device` for a `drm::Driver`.      pub fn new(dev: &device::Device, data: impl PinInit<T::Data, Error>) -> Result<ARef<Self>> { +        // `__drm_dev_alloc` uses `kmalloc()` to allocate memory, hence ensure a `kmalloc()` +        // compatible `Layout`. +        let layout = Kmalloc::aligned_layout(Layout::new::<Self>()); +          // SAFETY:          // - `VTABLE`, as a `const` is pinned to the read-only section of the compilation,          // - `dev` is valid by its type invarants, @@ -103,7 +107,7 @@ impl<T: drm::Driver> Device<T> {              bindings::__drm_dev_alloc(                  dev.as_raw(),                  &Self::VTABLE, -                mem::size_of::<Self>(), +                layout.size(),                  mem::offset_of!(Self, dev),              )          } @@ -117,9 +121,13 @@ impl<T: drm::Driver> Device<T> {          // - `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 +            // SAFETY: `raw_drm` is a valid pointer to `Self`, given that `__drm_dev_alloc` was +            // successful. +            let drm_dev = unsafe { Self::into_drm_device(raw_drm) }; + +            // SAFETY: `__drm_dev_alloc()` was successful, hence `drm_dev` 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()) }; +            unsafe { bindings::drm_dev_put(drm_dev) };          })?;          // SAFETY: The reference count is one, and now we take ownership of that reference as a @@ -140,6 +148,14 @@ impl<T: drm::Driver> Device<T> {          unsafe { crate::container_of!(Opaque::cast_from(ptr), Self, dev) }.cast_mut()      } +    /// # Safety +    /// +    /// `ptr` must be a valid pointer to `Self`. +    unsafe fn into_drm_device(ptr: NonNull<Self>) -> *mut bindings::drm_device { +        // SAFETY: By the safety requirements of this function, `ptr` is a valid pointer to `Self`. +        unsafe { &raw mut (*ptr.as_ptr()).dev }.cast() +    } +      /// Not intended to be called externally, except via declare_drm_ioctls!()      ///      /// # Safety @@ -189,8 +205,11 @@ unsafe impl<T: drm::Driver> AlwaysRefCounted for Device<T> {      }      unsafe fn dec_ref(obj: NonNull<Self>) { +        // SAFETY: `obj` is a valid pointer to `Self`. +        let drm_dev = unsafe { Self::into_drm_device(obj) }; +          // SAFETY: The safety requirements guarantee that the refcount is non-zero. -        unsafe { bindings::drm_dev_put(obj.cast().as_ptr()) }; +        unsafe { bindings::drm_dev_put(drm_dev) };      }  } diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs index fe7e8d06961a..f30ee4c6245c 100644 --- a/rust/kernel/drm/driver.rs +++ b/rust/kernel/drm/driver.rs @@ -2,13 +2,13 @@  //! DRM driver core.  //! -//! C header: [`include/linux/drm/drm_drv.h`](srctree/include/linux/drm/drm_drv.h) +//! C header: [`include/drm/drm_drv.h`](srctree/include/drm/drm_drv.h)  use crate::{      bindings, device, devres, drm,      error::{to_result, Result},      prelude::*, -    types::ARef, +    sync::aref::ARef,  };  use macros::vtable; @@ -86,6 +86,9 @@ pub struct AllocOps {  /// Trait for memory manager implementations. Implemented internally.  pub trait AllocImpl: super::private::Sealed + drm::gem::IntoGEMObject { +    /// The [`Driver`] implementation for this [`AllocImpl`]. +    type Driver: drm::Driver; +      /// The C callback operations for this memory manager.      const ALLOC_OPS: AllocOps;  } diff --git a/rust/kernel/drm/file.rs b/rust/kernel/drm/file.rs index e8789c9110d6..8c46f8d51951 100644 --- a/rust/kernel/drm/file.rs +++ b/rust/kernel/drm/file.rs @@ -2,7 +2,7 @@  //! DRM File objects.  //! -//! C header: [`include/linux/drm/drm_file.h`](srctree/include/linux/drm/drm_file.h) +//! C header: [`include/drm/drm_file.h`](srctree/include/drm/drm_file.h)  use crate::{bindings, drm, error::Result, prelude::*, types::Opaque};  use core::marker::PhantomData; diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs index b71821cfb5ea..30c853988b94 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -2,7 +2,7 @@  //! DRM GEM API  //! -//! C header: [`include/linux/drm/drm_gem.h`](srctree/include/linux/drm/drm_gem.h) +//! C header: [`include/drm/drm_gem.h`](srctree/include/drm/drm_gem.h)  use crate::{      alloc::flags::*, @@ -10,36 +10,37 @@ use crate::{      drm::driver::{AllocImpl, AllocOps},      error::{to_result, Result},      prelude::*, -    types::{ARef, AlwaysRefCounted, Opaque}, +    sync::aref::{ARef, AlwaysRefCounted}, +    types::Opaque,  }; -use core::{mem, ops::Deref, ptr::NonNull}; +use core::{ops::Deref, ptr::NonNull}; + +/// A type alias for retrieving a [`Driver`]s [`DriverFile`] implementation from its +/// [`DriverObject`] implementation. +/// +/// [`Driver`]: drm::Driver +/// [`DriverFile`]: drm::file::DriverFile +pub type DriverFile<T> = drm::File<<<T as DriverObject>::Driver as drm::Driver>::File>;  /// GEM object functions, which must be implemented by drivers. -pub trait BaseDriverObject<T: BaseObject>: Sync + Send + Sized { +pub trait DriverObject: Sync + Send + Sized { +    /// Parent `Driver` for this object. +    type Driver: drm::Driver; +      /// Create a new driver data object for a GEM object of a given size. -    fn new(dev: &drm::Device<T::Driver>, size: usize) -> impl PinInit<Self, Error>; +    fn new(dev: &drm::Device<Self::Driver>, size: usize) -> impl PinInit<Self, Error>;      /// Open a new handle to an existing object, associated with a File. -    fn open( -        _obj: &<<T as IntoGEMObject>::Driver as drm::Driver>::Object, -        _file: &drm::File<<<T as IntoGEMObject>::Driver as drm::Driver>::File>, -    ) -> Result { +    fn open(_obj: &<Self::Driver as drm::Driver>::Object, _file: &DriverFile<Self>) -> Result {          Ok(())      }      /// Close a handle to an existing object, associated with a File. -    fn close( -        _obj: &<<T as IntoGEMObject>::Driver as drm::Driver>::Object, -        _file: &drm::File<<<T as IntoGEMObject>::Driver as drm::Driver>::File>, -    ) { -    } +    fn close(_obj: &<Self::Driver as drm::Driver>::Object, _file: &DriverFile<Self>) {}  }  /// Trait that represents a GEM object subtype  pub trait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted { -    /// Owning driver for this type -    type Driver: drm::Driver; -      /// Returns a reference to the raw `drm_gem_object` structure, which must be valid as long as      /// this owning object is valid.      fn as_raw(&self) -> *mut bindings::drm_gem_object; @@ -74,25 +75,16 @@ unsafe impl<T: IntoGEMObject> AlwaysRefCounted for T {      }  } -/// Trait which must be implemented by drivers using base GEM objects. -pub trait DriverObject: BaseDriverObject<Object<Self>> { -    /// Parent `Driver` for this object. -    type Driver: drm::Driver; -} - -extern "C" fn open_callback<T: BaseDriverObject<U>, U: BaseObject>( +extern "C" fn open_callback<T: DriverObject>(      raw_obj: *mut bindings::drm_gem_object,      raw_file: *mut bindings::drm_file,  ) -> core::ffi::c_int {      // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. -    let file = unsafe { -        drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::from_raw(raw_file) -    }; -    // SAFETY: `open_callback` is specified in the AllocOps structure for `Object<T>`, ensuring that -    // `raw_obj` is indeed contained within a `Object<T>`. -    let obj = unsafe { -        <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) -    }; +    let file = unsafe { DriverFile::<T>::from_raw(raw_file) }; + +    // SAFETY: `open_callback` is specified in the AllocOps structure for `DriverObject<T>`, +    // ensuring that `raw_obj` is contained within a `DriverObject<T>` +    let obj = unsafe { <<T::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) };      match T::open(obj, file) {          Err(e) => e.to_errno(), @@ -100,26 +92,21 @@ extern "C" fn open_callback<T: BaseDriverObject<U>, U: BaseObject>(      }  } -extern "C" fn close_callback<T: BaseDriverObject<U>, U: BaseObject>( +extern "C" fn close_callback<T: DriverObject>(      raw_obj: *mut bindings::drm_gem_object,      raw_file: *mut bindings::drm_file,  ) {      // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. -    let file = unsafe { -        drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::from_raw(raw_file) -    }; +    let file = unsafe { DriverFile::<T>::from_raw(raw_file) }; +      // SAFETY: `close_callback` is specified in the AllocOps structure for `Object<T>`, ensuring      // that `raw_obj` is indeed contained within a `Object<T>`. -    let obj = unsafe { -        <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) -    }; +    let obj = unsafe { <<T::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) };      T::close(obj, file);  }  impl<T: DriverObject> IntoGEMObject for Object<T> { -    type Driver = T::Driver; -      fn as_raw(&self) -> *mut bindings::drm_gem_object {          self.obj.get()      } @@ -141,10 +128,12 @@ pub trait BaseObject: IntoGEMObject {      /// Creates a new handle for the object associated with a given `File`      /// (or returns an existing one). -    fn create_handle( -        &self, -        file: &drm::File<<<Self as IntoGEMObject>::Driver as drm::Driver>::File>, -    ) -> Result<u32> { +    fn create_handle<D, F>(&self, file: &drm::File<F>) -> Result<u32> +    where +        Self: AllocImpl<Driver = D>, +        D: drm::Driver<Object = Self, File = F>, +        F: drm::file::DriverFile<Driver = D>, +    {          let mut handle: u32 = 0;          // SAFETY: The arguments are all valid per the type invariants.          to_result(unsafe { @@ -154,10 +143,12 @@ pub trait BaseObject: IntoGEMObject {      }      /// Looks up an object by its handle for a given `File`. -    fn lookup_handle( -        file: &drm::File<<<Self as IntoGEMObject>::Driver as drm::Driver>::File>, -        handle: u32, -    ) -> Result<ARef<Self>> { +    fn lookup_handle<D, F>(file: &drm::File<F>, handle: u32) -> Result<ARef<Self>> +    where +        Self: AllocImpl<Driver = D>, +        D: drm::Driver<Object = Self, File = F>, +        F: drm::file::DriverFile<Driver = D>, +    {          // SAFETY: The arguments are all valid per the type invariants.          let ptr = unsafe { bindings::drm_gem_object_lookup(file.as_raw().cast(), handle) };          if ptr.is_null() { @@ -207,13 +198,10 @@ pub struct Object<T: DriverObject + Send + Sync> {  }  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(Self::free_callback), -        open: Some(open_callback::<T, Object<T>>), -        close: Some(close_callback::<T, Object<T>>), +        open: Some(open_callback::<T>), +        close: Some(close_callback::<T>),          print_info: None,          export: None,          pin: None, @@ -296,6 +284,8 @@ impl<T: DriverObject> Deref for Object<T> {  }  impl<T: DriverObject> AllocImpl for Object<T> { +    type Driver = T::Driver; +      const ALLOC_OPS: AllocOps = AllocOps {          gem_create_object: None,          prime_handle_to_fd: None, diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs index fdec01c37168..69efbdb4c85a 100644 --- a/rust/kernel/drm/ioctl.rs +++ b/rust/kernel/drm/ioctl.rs @@ -2,7 +2,7 @@  //! DRM IOCTL definitions.  //! -//! C header: [`include/linux/drm/drm_ioctl.h`](srctree/include/linux/drm/drm_ioctl.h) +//! C header: [`include/drm/drm_ioctl.h`](srctree/include/drm/drm_ioctl.h)  use crate::ioctl; @@ -83,7 +83,7 @@ pub mod internal {  ///  /// ```ignore  /// fn foo(device: &kernel::drm::Device<Self>, -///        data: &Opaque<uapi::argument_type>, +///        data: &mut uapi::argument_type,  ///        file: &kernel::drm::File<Self::File>,  /// ) -> Result<u32>  /// ``` @@ -138,9 +138,12 @@ macro_rules! declare_drm_ioctls {                              // SAFETY: The ioctl argument has size `_IOC_SIZE(cmd)`, which we                              // asserted above matches the size of this type, and all bit patterns of                              // UAPI structs must be valid. -                            let data = unsafe { -                                &*(raw_data as *const $crate::types::Opaque<$crate::uapi::$struct>) -                            }; +                            // The `ioctl` argument is exclusively owned by the handler +                            // and guaranteed by the C implementation (`drm_ioctl()`) to remain +                            // valid for the entire lifetime of the reference taken here. +                            // There is no concurrent access or aliasing; no other references +                            // to this object exist during this call. +                            let data = unsafe { &mut *(raw_data.cast::<$crate::uapi::$struct>()) };                              // SAFETY: This is just the DRM file structure                              let file = unsafe { $crate::drm::File::from_raw(raw_file) }; | 
