diff options
Diffstat (limited to 'rust/kernel/drm')
-rw-r--r-- | rust/kernel/drm/device.rs | 46 | ||||
-rw-r--r-- | rust/kernel/drm/driver.rs | 14 | ||||
-rw-r--r-- | rust/kernel/drm/file.rs | 8 | ||||
-rw-r--r-- | rust/kernel/drm/gem/mod.rs | 20 | ||||
-rw-r--r-- | rust/kernel/drm/ioctl.rs | 4 |
5 files changed, 54 insertions, 38 deletions
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs index 14c1aa402951..d29c477e89a8 100644 --- a/rust/kernel/drm/device.rs +++ b/rust/kernel/drm/device.rs @@ -5,6 +5,7 @@ //! C header: [`include/linux/drm/drm_device.h`](srctree/include/linux/drm/drm_device.h) use crate::{ + alloc::allocator::Kmalloc, bindings, device, drm, drm::driver::AllocImpl, error::from_err_ptr, @@ -12,7 +13,7 @@ use crate::{ prelude::*, types::{ARef, AlwaysRefCounted, 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 +54,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,19 +82,23 @@ 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() as *mut _, - desc: T::INFO.desc.as_char_ptr() as *mut _, + name: T::INFO.name.as_char_ptr().cast_mut(), + desc: T::INFO.desc.as_char_ptr().cast_mut(), driver_features: drm::driver::FEAT_GEM, ioctls: T::IOCTLS.as_ptr(), num_ioctls: T::IOCTLS.len() as i32, - fops: &Self::GEM_FOPS as _, + fops: &Self::GEM_FOPS, }; 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>> { + // `__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 +106,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 +120,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 @@ -135,11 +142,17 @@ impl<T: drm::Driver> Device<T> { /// /// `ptr` must be a valid pointer to a `struct device` embedded in `Self`. unsafe fn from_drm_device(ptr: *const bindings::drm_device) -> *mut Self { - let ptr: *const Opaque<bindings::drm_device> = ptr.cast(); - // 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() + 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!() @@ -154,7 +167,7 @@ impl<T: drm::Driver> Device<T> { /// Additionally, callers must ensure that the `struct device`, `ptr` is pointing to, is /// embedded in `Self`. #[doc(hidden)] - pub unsafe fn as_ref<'a>(ptr: *const bindings::drm_device) -> &'a Self { + pub unsafe fn from_raw<'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) }; @@ -191,8 +204,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) }; } } @@ -200,7 +216,7 @@ 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) } + unsafe { device::Device::from_raw((*self.as_raw()).dev) } } } diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs index af93d46d03d3..fe7e8d06961a 100644 --- a/rust/kernel/drm/driver.rs +++ b/rust/kernel/drm/driver.rs @@ -5,9 +5,7 @@ //! C header: [`include/linux/drm/drm_drv.h`](srctree/include/linux/drm/drm_drv.h) use crate::{ - bindings, device, - devres::Devres, - drm, + bindings, device, devres, drm, error::{to_result, Result}, prelude::*, types::ARef, @@ -129,18 +127,22 @@ impl<T: Driver> Registration<T> { } /// Same as [`Registration::new`}, but transfers ownership of the [`Registration`] to - /// [`Devres`]. + /// [`devres::register`]. pub fn new_foreign_owned( drm: &drm::Device<T>, dev: &device::Device<device::Bound>, flags: usize, - ) -> Result { + ) -> Result + where + T: 'static, + { if drm.as_ref().as_raw() != dev.as_raw() { return Err(EINVAL); } let reg = Registration::<T>::new(drm, flags)?; - Devres::new_foreign_owned(dev, reg, GFP_KERNEL) + + devres::register(dev, reg, GFP_KERNEL) } /// Returns a reference to the `Device` instance for this registration. diff --git a/rust/kernel/drm/file.rs b/rust/kernel/drm/file.rs index b9527705e551..e8789c9110d6 100644 --- a/rust/kernel/drm/file.rs +++ b/rust/kernel/drm/file.rs @@ -32,7 +32,7 @@ impl<T: DriverFile> File<T> { /// # 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> { + pub unsafe fn from_raw<'a>(ptr: *mut bindings::drm_file) -> &'a File<T> { // SAFETY: `raw_file` is valid by the safety requirements of this function. unsafe { &*ptr.cast() } } @@ -61,10 +61,10 @@ impl<T: DriverFile> File<T> { // SAFETY: A callback from `struct drm_driver::open` guarantees that // - `raw_dev` is valid pointer to a `struct drm_device`, // - the corresponding `struct drm_device` has been registered. - let drm = unsafe { drm::Device::as_ref(raw_dev) }; + let drm = unsafe { drm::Device::from_raw(raw_dev) }; // SAFETY: `raw_file` is a valid pointer to a `struct drm_file`. - let file = unsafe { File::<T>::as_ref(raw_file) }; + let file = unsafe { File::<T>::from_raw(raw_file) }; let inner = match T::open(drm) { Err(e) => { @@ -89,7 +89,7 @@ impl<T: DriverFile> File<T> { raw_file: *mut bindings::drm_file, ) { // SAFETY: This reference won't escape this function - let file = unsafe { File::<T>::as_ref(raw_file) }; + let file = unsafe { File::<T>::from_raw(raw_file) }; // SAFETY: `file.driver_priv` has been created in `open_callback` through `KBox::into_raw`. let _ = unsafe { KBox::from_raw(file.driver_priv()) }; diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs index 4cd69fa84318..b71821cfb5ea 100644 --- a/rust/kernel/drm/gem/mod.rs +++ b/rust/kernel/drm/gem/mod.rs @@ -51,7 +51,7 @@ pub trait IntoGEMObject: Sized + super::private::Sealed + AlwaysRefCounted { /// - `self_ptr` must be a valid pointer to `Self`. /// - The caller promises that holding the immutable reference returned by this function does /// not violate rust's data aliasing rules and remains valid throughout the lifetime of `'a`. - unsafe fn as_ref<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self; + unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self; } // SAFETY: All gem objects are refcounted. @@ -86,12 +86,12 @@ extern "C" fn open_callback<T: BaseDriverObject<U>, U: BaseObject>( ) -> 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>::as_ref(raw_file) + 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>::as_ref(raw_obj) + <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) }; match T::open(obj, file) { @@ -106,12 +106,12 @@ extern "C" fn close_callback<T: BaseDriverObject<U>, U: BaseObject>( ) { // 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>::as_ref(raw_file) + drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::from_raw(raw_file) }; // SAFETY: `close_callback` is specified in the AllocOps structure for `Object<T>`, ensuring // that `raw_obj` is indeed contained within a `Object<T>`. let obj = unsafe { - <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::as_ref(raw_obj) + <<<U as IntoGEMObject>::Driver as drm::Driver>::Object as IntoGEMObject>::from_raw(raw_obj) }; T::close(obj, file); @@ -124,12 +124,10 @@ impl<T: DriverObject> IntoGEMObject for Object<T> { self.obj.get() } - unsafe fn as_ref<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self { - let self_ptr: *mut Opaque<bindings::drm_gem_object> = self_ptr.cast(); - + unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self { // SAFETY: `obj` is guaranteed to be in an `Object<T>` via the safety contract of this // function - unsafe { &*crate::container_of!(self_ptr, Object<T>, obj) } + unsafe { &*crate::container_of!(Opaque::cast_from(self_ptr), Object<T>, obj) } } } @@ -170,9 +168,9 @@ pub trait BaseObject: IntoGEMObject { // - A `drm::Driver` can only have a single `File` implementation. // - `file` uses the same `drm::Driver` as `Self`. // - Therefore, we're guaranteed that `ptr` must be a gem object embedded within `Self`. - // - And we check if the pointer is null befoe calling as_ref(), ensuring that `ptr` is a + // - And we check if the pointer is null befoe calling from_raw(), ensuring that `ptr` is a // valid pointer to an initialized `Self`. - let obj = unsafe { Self::as_ref(ptr) }; + let obj = unsafe { Self::from_raw(ptr) }; // SAFETY: // - We take ownership of the reference of `drm_gem_object_lookup()`. diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs index 445639404fb7..fdec01c37168 100644 --- a/rust/kernel/drm/ioctl.rs +++ b/rust/kernel/drm/ioctl.rs @@ -134,7 +134,7 @@ macro_rules! declare_drm_ioctls { // 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::as_ref(raw_dev); + let dev = $crate::drm::device::Device::from_raw(raw_dev); // 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. @@ -142,7 +142,7 @@ macro_rules! declare_drm_ioctls { &*(raw_data as *const $crate::types::Opaque<$crate::uapi::$struct>) }; // SAFETY: This is just the DRM file structure - let file = unsafe { $crate::drm::File::as_ref(raw_file) }; + let file = unsafe { $crate::drm::File::from_raw(raw_file) }; match $func(dev, data, file) { Err(e) => e.to_errno(), |