diff options
Diffstat (limited to 'rust/kernel')
| -rw-r--r-- | rust/kernel/alloc/kvec.rs | 3 | ||||
| -rw-r--r-- | rust/kernel/auxiliary.rs | 360 | ||||
| -rw-r--r-- | rust/kernel/configfs.rs | 1049 | ||||
| -rw-r--r-- | rust/kernel/device.rs | 109 | ||||
| -rw-r--r-- | rust/kernel/devres.rs | 56 | ||||
| -rw-r--r-- | rust/kernel/dma.rs | 14 | ||||
| -rw-r--r-- | rust/kernel/drm/device.rs | 200 | ||||
| -rw-r--r-- | rust/kernel/drm/driver.rs | 166 | ||||
| -rw-r--r-- | rust/kernel/drm/file.rs | 99 | ||||
| -rw-r--r-- | rust/kernel/drm/gem/mod.rs | 328 | ||||
| -rw-r--r-- | rust/kernel/drm/ioctl.rs | 162 | ||||
| -rw-r--r-- | rust/kernel/drm/mod.rs | 19 | ||||
| -rw-r--r-- | rust/kernel/firmware.rs | 8 | ||||
| -rw-r--r-- | rust/kernel/lib.rs | 6 | ||||
| -rw-r--r-- | rust/kernel/list.rs | 3 | ||||
| -rw-r--r-- | rust/kernel/net/phy.rs | 1 | ||||
| -rw-r--r-- | rust/kernel/pci.rs | 55 | ||||
| -rw-r--r-- | rust/kernel/platform.rs | 54 | ||||
| -rw-r--r-- | rust/kernel/revocable.rs | 28 | ||||
| -rw-r--r-- | rust/kernel/str.rs | 46 | ||||
| -rw-r--r-- | rust/kernel/sync/rcu.rs | 5 | ||||
| -rw-r--r-- | rust/kernel/types.rs | 8 | 
22 files changed, 2687 insertions, 92 deletions
| diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs index ae9d072741ce..87a71fd40c3c 100644 --- a/rust/kernel/alloc/kvec.rs +++ b/rust/kernel/alloc/kvec.rs @@ -2,6 +2,9 @@  //! Implementation of [`Vec`]. +// May not be needed in Rust 1.87.0 (pending beta backport). +#![allow(clippy::ptr_eq)] +  use super::{      allocator::{KVmalloc, Kmalloc, Vmalloc},      layout::ArrayLayout, diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs new file mode 100644 index 000000000000..5c072960dee0 --- /dev/null +++ b/rust/kernel/auxiliary.rs @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Abstractions for the auxiliary bus. +//! +//! C header: [`include/linux/auxiliary_bus.h`](srctree/include/linux/auxiliary_bus.h) + +use crate::{ +    bindings, container_of, device, +    device_id::RawDeviceId, +    driver, +    error::{to_result, Result}, +    prelude::*, +    str::CStr, +    types::{ForeignOwnable, Opaque}, +    ThisModule, +}; +use core::{ +    marker::PhantomData, +    ptr::{addr_of_mut, NonNull}, +}; + +/// An adapter for the registration of auxiliary drivers. +pub struct Adapter<T: Driver>(T); + +// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// a preceding call to `register` has been successful. +unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { +    type RegType = bindings::auxiliary_driver; + +    unsafe fn register( +        adrv: &Opaque<Self::RegType>, +        name: &'static CStr, +        module: &'static ThisModule, +    ) -> Result { +        // SAFETY: It's safe to set the fields of `struct auxiliary_driver` on initialization. +        unsafe { +            (*adrv.get()).name = name.as_char_ptr(); +            (*adrv.get()).probe = Some(Self::probe_callback); +            (*adrv.get()).remove = Some(Self::remove_callback); +            (*adrv.get()).id_table = T::ID_TABLE.as_ptr(); +        } + +        // SAFETY: `adrv` is guaranteed to be a valid `RegType`. +        to_result(unsafe { +            bindings::__auxiliary_driver_register(adrv.get(), module.0, name.as_char_ptr()) +        }) +    } + +    unsafe fn unregister(adrv: &Opaque<Self::RegType>) { +        // SAFETY: `adrv` is guaranteed to be a valid `RegType`. +        unsafe { bindings::auxiliary_driver_unregister(adrv.get()) } +    } +} + +impl<T: Driver + 'static> Adapter<T> { +    extern "C" fn probe_callback( +        adev: *mut bindings::auxiliary_device, +        id: *const bindings::auxiliary_device_id, +    ) -> kernel::ffi::c_int { +        // SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a +        // `struct auxiliary_device`. +        // +        // INVARIANT: `adev` is valid for the duration of `probe_callback()`. +        let adev = unsafe { &*adev.cast::<Device<device::Core>>() }; + +        // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id` +        // and does not add additional invariants, so it's safe to transmute. +        let id = unsafe { &*id.cast::<DeviceId>() }; +        let info = T::ID_TABLE.info(id.index()); + +        match T::probe(adev, info) { +            Ok(data) => { +                // Let the `struct auxiliary_device` own a reference of the driver's private data. +                // SAFETY: By the type invariant `adev.as_raw` returns a valid pointer to a +                // `struct auxiliary_device`. +                unsafe { bindings::auxiliary_set_drvdata(adev.as_raw(), data.into_foreign()) }; +            } +            Err(err) => return Error::to_errno(err), +        } + +        0 +    } + +    extern "C" fn remove_callback(adev: *mut bindings::auxiliary_device) { +        // SAFETY: The auxiliary bus only ever calls the remove callback with a valid pointer to a +        // `struct auxiliary_device`. +        let ptr = unsafe { bindings::auxiliary_get_drvdata(adev) }; + +        // SAFETY: `remove_callback` is only ever called after a successful call to +        // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized +        // `KBox<T>` pointer created through `KBox::into_foreign`. +        drop(unsafe { KBox::<T>::from_foreign(ptr) }); +    } +} + +/// Declares a kernel module that exposes a single auxiliary driver. +#[macro_export] +macro_rules! module_auxiliary_driver { +    ($($f:tt)*) => { +        $crate::module_driver!(<T>, $crate::auxiliary::Adapter<T>, { $($f)* }); +    }; +} + +/// Abstraction for `bindings::auxiliary_device_id`. +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct DeviceId(bindings::auxiliary_device_id); + +impl DeviceId { +    /// Create a new [`DeviceId`] from name. +    pub const fn new(modname: &'static CStr, name: &'static CStr) -> Self { +        let name = name.as_bytes_with_nul(); +        let modname = modname.as_bytes_with_nul(); + +        // TODO: Replace with `bindings::auxiliary_device_id::default()` once stabilized for +        // `const`. +        // +        // SAFETY: FFI type is valid to be zero-initialized. +        let mut id: bindings::auxiliary_device_id = unsafe { core::mem::zeroed() }; + +        let mut i = 0; +        while i < modname.len() { +            id.name[i] = modname[i]; +            i += 1; +        } + +        // Reuse the space of the NULL terminator. +        id.name[i - 1] = b'.'; + +        let mut j = 0; +        while j < name.len() { +            id.name[i] = name[j]; +            i += 1; +            j += 1; +        } + +        Self(id) +    } +} + +// SAFETY: +// * `DeviceId` is a `#[repr(transparent)`] wrapper of `auxiliary_device_id` and does not add +//   additional invariants, so it's safe to transmute to `RawType`. +// * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. +unsafe impl RawDeviceId for DeviceId { +    type RawType = bindings::auxiliary_device_id; + +    const DRIVER_DATA_OFFSET: usize = +        core::mem::offset_of!(bindings::auxiliary_device_id, driver_data); + +    fn index(&self) -> usize { +        self.0.driver_data +    } +} + +/// IdTable type for auxiliary drivers. +pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>; + +/// Create a auxiliary `IdTable` with its alias for modpost. +#[macro_export] +macro_rules! auxiliary_device_table { +    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { +        const $table_name: $crate::device_id::IdArray< +            $crate::auxiliary::DeviceId, +            $id_info_type, +            { $table_data.len() }, +        > = $crate::device_id::IdArray::new($table_data); + +        $crate::module_device_table!("auxiliary", $module_table_name, $table_name); +    }; +} + +/// The auxiliary driver trait. +/// +/// Drivers must implement this trait in order to get an auxiliary driver registered. +pub trait Driver { +    /// The type holding information about each device id supported by the driver. +    /// +    /// TODO: Use associated_type_defaults once stabilized: +    /// +    /// type IdInfo: 'static = (); +    type IdInfo: 'static; + +    /// The table of device ids supported by the driver. +    const ID_TABLE: IdTable<Self::IdInfo>; + +    /// Auxiliary driver probe. +    /// +    /// Called when an auxiliary device is matches a corresponding driver. +    fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>; +} + +/// The auxiliary device representation. +/// +/// This structure represents the Rust abstraction for a C `struct auxiliary_device`. The +/// implementation abstracts the usage of an already existing C `struct auxiliary_device` within +/// Rust code that we get passed from the C side. +/// +/// # Invariants +/// +/// A [`Device`] instance represents a valid `struct auxiliary_device` created by the C portion of +/// the kernel. +#[repr(transparent)] +pub struct Device<Ctx: device::DeviceContext = device::Normal>( +    Opaque<bindings::auxiliary_device>, +    PhantomData<Ctx>, +); + +impl<Ctx: device::DeviceContext> Device<Ctx> { +    fn as_raw(&self) -> *mut bindings::auxiliary_device { +        self.0.get() +    } + +    /// Returns the auxiliary device' id. +    pub fn id(&self) -> u32 { +        // SAFETY: By the type invariant `self.as_raw()` is a valid pointer to a +        // `struct auxiliary_device`. +        unsafe { (*self.as_raw()).id } +    } + +    /// Returns a reference to the parent [`device::Device`], if any. +    pub fn parent(&self) -> Option<&device::Device> { +        let ptr: *const Self = self; +        // CAST: `Device<Ctx: DeviceContext>` types are transparent to each other. +        let ptr: *const Device = ptr.cast(); +        // SAFETY: `ptr` was derived from `&self`. +        let this = unsafe { &*ptr }; + +        this.as_ref().parent() +    } +} + +impl Device { +    extern "C" fn release(dev: *mut bindings::device) { +        // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device` +        // embedded in `struct auxiliary_device`. +        let adev = unsafe { container_of!(dev, bindings::auxiliary_device, dev) }.cast_mut(); + +        // SAFETY: `adev` points to the memory that has been allocated in `Registration::new`, via +        // `KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)`. +        let _ = unsafe { KBox::<Opaque<bindings::auxiliary_device>>::from_raw(adev.cast()) }; +    } +} + +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); +kernel::impl_device_context_into_aref!(Device); + +// SAFETY: Instances of `Device` are always reference-counted. +unsafe impl crate::types::AlwaysRefCounted for Device { +    fn inc_ref(&self) { +        // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. +        unsafe { bindings::get_device(self.as_ref().as_raw()) }; +    } + +    unsafe fn dec_ref(obj: NonNull<Self>) { +        // CAST: `Self` a transparent wrapper of `bindings::auxiliary_device`. +        let adev: *mut bindings::auxiliary_device = obj.cast().as_ptr(); + +        // SAFETY: By the type invariant of `Self`, `adev` is a pointer to a valid +        // `struct auxiliary_device`. +        let dev = unsafe { addr_of_mut!((*adev).dev) }; + +        // SAFETY: The safety requirements guarantee that the refcount is non-zero. +        unsafe { bindings::put_device(dev) } +    } +} + +impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { +    fn as_ref(&self) -> &device::Device<Ctx> { +        // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid +        // `struct auxiliary_device`. +        let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; + +        // SAFETY: `dev` points to a valid `struct device`. +        unsafe { device::Device::as_ref(dev) } +    } +} + +// SAFETY: A `Device` is always reference-counted and can be released from any thread. +unsafe impl Send for Device {} + +// SAFETY: `Device` can be shared among threads because all methods of `Device` +// (i.e. `Device<Normal>) are thread safe. +unsafe impl Sync for Device {} + +/// The registration of an auxiliary device. +/// +/// This type represents the registration of a [`struct auxiliary_device`]. When an instance of this +/// type is dropped, its respective auxiliary device will be unregistered from the system. +/// +/// # Invariants +/// +/// `self.0` always holds a valid pointer to an initialized and registered +/// [`struct auxiliary_device`]. +pub struct Registration(NonNull<bindings::auxiliary_device>); + +impl Registration { +    /// Create and register a new auxiliary device. +    pub fn new(parent: &device::Device, name: &CStr, id: u32, modname: &CStr) -> Result<Self> { +        let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?; +        let adev = boxed.get(); + +        // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. +        unsafe { +            (*adev).dev.parent = parent.as_raw(); +            (*adev).dev.release = Some(Device::release); +            (*adev).name = name.as_char_ptr(); +            (*adev).id = id; +        } + +        // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, +        // which has not been initialized yet. +        unsafe { bindings::auxiliary_device_init(adev) }; + +        // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be freed +        // by `Device::release` when the last reference to the `struct auxiliary_device` is dropped. +        let _ = KBox::into_raw(boxed); + +        // SAFETY: +        // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which has +        //   been initialialized, +        // - `modname.as_char_ptr()` is a NULL terminated string. +        let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; +        if ret != 0 { +            // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, +            // which has been initialialized. +            unsafe { bindings::auxiliary_device_uninit(adev) }; + +            return Err(Error::from_errno(ret)); +        } + +        // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated successfully. +        // +        // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is called, +        // which happens in `Self::drop()`. +        Ok(Self(unsafe { NonNull::new_unchecked(adev) })) +    } +} + +impl Drop for Registration { +    fn drop(&mut self) { +        // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered +        // `struct auxiliary_device`. +        unsafe { bindings::auxiliary_device_delete(self.0.as_ptr()) }; + +        // This drops the reference we acquired through `auxiliary_device_init()`. +        // +        // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered +        // `struct auxiliary_device`. +        unsafe { bindings::auxiliary_device_uninit(self.0.as_ptr()) }; +    } +} + +// SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread. +unsafe impl Send for Registration {} + +// SAFETY: `Registration` does not expose any methods or fields that need synchronization. +unsafe impl Sync for Registration {} diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs new file mode 100644 index 000000000000..b93ac7b0bebc --- /dev/null +++ b/rust/kernel/configfs.rs @@ -0,0 +1,1049 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! configfs interface: Userspace-driven Kernel Object Configuration +//! +//! configfs is an in-memory pseudo file system for configuration of kernel +//! modules. Please see the [C documentation] for details and intended use of +//! configfs. +//! +//! This module does not support the following configfs features: +//! +//! - Items. All group children are groups. +//! - Symlink support. +//! - `disconnect_notify` hook. +//! - Default groups. +//! +//! See the [`rust_configfs.rs`] sample for a full example use of this module. +//! +//! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h) +//! +//! # Example +//! +//! ```ignore +//! use kernel::alloc::flags; +//! use kernel::c_str; +//! use kernel::configfs_attrs; +//! use kernel::configfs; +//! use kernel::new_mutex; +//! use kernel::page::PAGE_SIZE; +//! use kernel::sync::Mutex; +//! use kernel::ThisModule; +//! +//! #[pin_data] +//! struct RustConfigfs { +//!     #[pin] +//!     config: configfs::Subsystem<Configuration>, +//! } +//! +//! impl kernel::InPlaceModule for RustConfigfs { +//!     fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> { +//!         pr_info!("Rust configfs sample (init)\n"); +//! +//!         let item_type = configfs_attrs! { +//!             container: configfs::Subsystem<Configuration>, +//!             data: Configuration, +//!             attributes: [ +//!                 message: 0, +//!                 bar: 1, +//!             ], +//!         }; +//! +//!         try_pin_init!(Self { +//!             config <- configfs::Subsystem::new( +//!                 c_str!("rust_configfs"), item_type, Configuration::new() +//!             ), +//!         }) +//!     } +//! } +//! +//! #[pin_data] +//! struct Configuration { +//!     message: &'static CStr, +//!     #[pin] +//!     bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>, +//! } +//! +//! impl Configuration { +//!     fn new() -> impl PinInit<Self, Error> { +//!         try_pin_init!(Self { +//!             message: c_str!("Hello World\n"), +//!             bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)), +//!         }) +//!     } +//! } +//! +//! #[vtable] +//! impl configfs::AttributeOperations<0> for Configuration { +//!     type Data = Configuration; +//! +//!     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> { +//!         pr_info!("Show message\n"); +//!         let data = container.message; +//!         page[0..data.len()].copy_from_slice(data); +//!         Ok(data.len()) +//!     } +//! } +//! +//! #[vtable] +//! impl configfs::AttributeOperations<1> for Configuration { +//!     type Data = Configuration; +//! +//!     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> { +//!         pr_info!("Show bar\n"); +//!         let guard = container.bar.lock(); +//!         let data = guard.0.as_slice(); +//!         let len = guard.1; +//!         page[0..len].copy_from_slice(&data[0..len]); +//!         Ok(len) +//!     } +//! +//!     fn store(container: &Configuration, page: &[u8]) -> Result { +//!         pr_info!("Store bar\n"); +//!         let mut guard = container.bar.lock(); +//!         guard.0[0..page.len()].copy_from_slice(page); +//!         guard.1 = page.len(); +//!         Ok(()) +//!     } +//! } +//! ``` +//! +//! [C documentation]: srctree/Documentation/filesystems/configfs.rst +//! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs + +use crate::alloc::flags; +use crate::container_of; +use crate::page::PAGE_SIZE; +use crate::prelude::*; +use crate::str::CString; +use crate::sync::Arc; +use crate::sync::ArcBorrow; +use crate::types::Opaque; +use core::cell::UnsafeCell; +use core::marker::PhantomData; + +/// A configfs subsystem. +/// +/// This is the top level entrypoint for a configfs hierarchy. To register +/// with configfs, embed a field of this type into your kernel module struct. +#[pin_data(PinnedDrop)] +pub struct Subsystem<Data> { +    #[pin] +    subsystem: Opaque<bindings::configfs_subsystem>, +    #[pin] +    data: Data, +} + +// SAFETY: We do not provide any operations on `Subsystem`. +unsafe impl<Data> Sync for Subsystem<Data> {} + +// SAFETY: Ownership of `Subsystem` can safely be transferred to other threads. +unsafe impl<Data> Send for Subsystem<Data> {} + +impl<Data> Subsystem<Data> { +    /// Create an initializer for a [`Subsystem`]. +    /// +    /// The subsystem will appear in configfs as a directory name given by +    /// `name`. The attributes available in directory are specified by +    /// `item_type`. +    pub fn new( +        name: &'static CStr, +        item_type: &'static ItemType<Subsystem<Data>, Data>, +        data: impl PinInit<Data, Error>, +    ) -> impl PinInit<Self, Error> { +        try_pin_init!(Self { +            subsystem <- pin_init::zeroed().chain( +                |place: &mut Opaque<bindings::configfs_subsystem>| { +                    // SAFETY: We initialized the required fields of `place.group` above. +                    unsafe { +                        bindings::config_group_init_type_name( +                            &mut (*place.get()).su_group, +                            name.as_ptr(), +                            item_type.as_ptr(), +                        ) +                    }; + +                    // SAFETY: `place.su_mutex` is valid for use as a mutex. +                    unsafe { +                        bindings::__mutex_init( +                            &mut (*place.get()).su_mutex, +                            kernel::optional_name!().as_char_ptr(), +                            kernel::static_lock_class!().as_ptr(), +                        ) +                    } +                    Ok(()) +                } +            ), +            data <- data, +        }) +        .pin_chain(|this| { +            crate::error::to_result( +                // SAFETY: We initialized `this.subsystem` according to C API contract above. +                unsafe { bindings::configfs_register_subsystem(this.subsystem.get()) }, +            ) +        }) +    } +} + +#[pinned_drop] +impl<Data> PinnedDrop for Subsystem<Data> { +    fn drop(self: Pin<&mut Self>) { +        // SAFETY: We registered `self.subsystem` in the initializer returned by `Self::new`. +        unsafe { bindings::configfs_unregister_subsystem(self.subsystem.get()) }; +        // SAFETY: We initialized the mutex in `Subsystem::new`. +        unsafe { bindings::mutex_destroy(&raw mut (*self.subsystem.get()).su_mutex) }; +    } +} + +/// Trait that allows offset calculations for structs that embed a +/// `bindings::config_group`. +/// +/// Users of the configfs API should not need to implement this trait. +/// +/// # Safety +/// +/// - Implementers of this trait must embed a `bindings::config_group`. +/// - Methods must be implemented according to method documentation. +pub unsafe trait HasGroup<Data> { +    /// Return the address of the `bindings::config_group` embedded in [`Self`]. +    /// +    /// # Safety +    /// +    /// - `this` must be a valid allocation of at least the size of [`Self`]. +    unsafe fn group(this: *const Self) -> *const bindings::config_group; + +    /// Return the address of the [`Self`] that `group` is embedded in. +    /// +    /// # Safety +    /// +    /// - `group` must point to the `bindings::config_group` that is embedded in +    ///   [`Self`]. +    unsafe fn container_of(group: *const bindings::config_group) -> *const Self; +} + +// SAFETY: `Subsystem<Data>` embeds a field of type `bindings::config_group` +// within the `subsystem` field. +unsafe impl<Data> HasGroup<Data> for Subsystem<Data> { +    unsafe fn group(this: *const Self) -> *const bindings::config_group { +        // SAFETY: By impl and function safety requirement this projection is in bounds. +        unsafe { &raw const (*(*this).subsystem.get()).su_group } +    } + +    unsafe fn container_of(group: *const bindings::config_group) -> *const Self { +        // SAFETY: By impl and function safety requirement this projection is in bounds. +        let c_subsys_ptr = unsafe { container_of!(group, bindings::configfs_subsystem, su_group) }; +        let opaque_ptr = c_subsys_ptr.cast::<Opaque<bindings::configfs_subsystem>>(); +        // SAFETY: By impl and function safety requirement, `opaque_ptr` and the +        // pointer it returns, are within the same allocation. +        unsafe { container_of!(opaque_ptr, Subsystem<Data>, subsystem) } +    } +} + +/// A configfs group. +/// +/// To add a subgroup to configfs, pass this type as `ctype` to +/// [`crate::configfs_attrs`] when creating a group in [`GroupOperations::make_group`]. +#[pin_data] +pub struct Group<Data> { +    #[pin] +    group: Opaque<bindings::config_group>, +    #[pin] +    data: Data, +} + +impl<Data> Group<Data> { +    /// Create an initializer for a new group. +    /// +    /// When instantiated, the group will appear as a directory with the name +    /// given by `name` and it will contain attributes specified by `item_type`. +    pub fn new( +        name: CString, +        item_type: &'static ItemType<Group<Data>, Data>, +        data: impl PinInit<Data, Error>, +    ) -> impl PinInit<Self, Error> { +        try_pin_init!(Self { +            group <- pin_init::zeroed().chain(|v: &mut Opaque<bindings::config_group>| { +                let place = v.get(); +                let name = name.as_bytes_with_nul().as_ptr(); +                // SAFETY: It is safe to initialize a group once it has been zeroed. +                unsafe { +                    bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr()) +                }; +                Ok(()) +            }), +            data <- data, +        }) +    } +} + +// SAFETY: `Group<Data>` embeds a field of type `bindings::config_group` +// within the `group` field. +unsafe impl<Data> HasGroup<Data> for Group<Data> { +    unsafe fn group(this: *const Self) -> *const bindings::config_group { +        Opaque::raw_get( +            // SAFETY: By impl and function safety requirements this field +            // projection is within bounds of the allocation. +            unsafe { &raw const (*this).group }, +        ) +    } + +    unsafe fn container_of(group: *const bindings::config_group) -> *const Self { +        let opaque_ptr = group.cast::<Opaque<bindings::config_group>>(); +        // SAFETY: By impl and function safety requirement, `opaque_ptr` and +        // pointer it returns will be in the same allocation. +        unsafe { container_of!(opaque_ptr, Self, group) } +    } +} + +/// # Safety +/// +/// `this` must be a valid pointer. +/// +/// If `this` does not represent the root group of a configfs subsystem, +/// `this` must be a pointer to a `bindings::config_group` embedded in a +/// `Group<Parent>`. +/// +/// Otherwise, `this` must be a pointer to a `bindings::config_group` that +/// is embedded in a `bindings::configfs_subsystem` that is embedded in a +/// `Subsystem<Parent>`. +unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent { +    // SAFETY: `this` is a valid pointer. +    let is_root = unsafe { (*this).cg_subsys.is_null() }; + +    if !is_root { +        // SAFETY: By C API contact,`this` was returned from a call to +        // `make_group`. The pointer is known to be embedded within a +        // `Group<Parent>`. +        unsafe { &(*Group::<Parent>::container_of(this)).data } +    } else { +        // SAFETY: By C API contract, `this` is a pointer to the +        // `bindings::config_group` field within a `Subsystem<Parent>`. +        unsafe { &(*Subsystem::container_of(this)).data } +    } +} + +struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>); + +impl<Parent, Child> GroupOperationsVTable<Parent, Child> +where +    Parent: GroupOperations<Child = Child>, +    Child: 'static, +{ +    /// # Safety +    /// +    /// `this` must be a valid pointer. +    /// +    /// If `this` does not represent the root group of a configfs subsystem, +    /// `this` must be a pointer to a `bindings::config_group` embedded in a +    /// `Group<Parent>`. +    /// +    /// Otherwise, `this` must be a pointer to a `bindings::config_group` that +    /// is embedded in a `bindings::configfs_subsystem` that is embedded in a +    /// `Subsystem<Parent>`. +    /// +    /// `name` must point to a null terminated string. +    unsafe extern "C" fn make_group( +        this: *mut bindings::config_group, +        name: *const kernel::ffi::c_char, +    ) -> *mut bindings::config_group { +        // SAFETY: By function safety requirements of this function, this call +        // is safe. +        let parent_data = unsafe { get_group_data(this) }; + +        let group_init = match Parent::make_group( +            parent_data, +            // SAFETY: By function safety requirements, name points to a null +            // terminated string. +            unsafe { CStr::from_char_ptr(name) }, +        ) { +            Ok(init) => init, +            Err(e) => return e.to_ptr(), +        }; + +        let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init( +            group_init, +            flags::GFP_KERNEL, +        ); + +        match child_group { +            Ok(child_group) => { +                let child_group_ptr = child_group.into_raw(); +                // SAFETY: We allocated the pointee of `child_ptr` above as a +                // `Group<Child>`. +                unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut() +            } +            Err(e) => e.to_ptr(), +        } +    } + +    /// # Safety +    /// +    /// If `this` does not represent the root group of a configfs subsystem, +    /// `this` must be a pointer to a `bindings::config_group` embedded in a +    /// `Group<Parent>`. +    /// +    /// Otherwise, `this` must be a pointer to a `bindings::config_group` that +    /// is embedded in a `bindings::configfs_subsystem` that is embedded in a +    /// `Subsystem<Parent>`. +    /// +    /// `item` must point to a `bindings::config_item` within a +    /// `bindings::config_group` within a `Group<Child>`. +    unsafe extern "C" fn drop_item( +        this: *mut bindings::config_group, +        item: *mut bindings::config_item, +    ) { +        // SAFETY: By function safety requirements of this function, this call +        // is safe. +        let parent_data = unsafe { get_group_data(this) }; + +        // SAFETY: By function safety requirements, `item` is embedded in a +        // `config_group`. +        let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) }; +        // SAFETY: By function safety requirements, `c_child_group_ptr` is +        // embedded within a `Group<Child>`. +        let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) }; + +        if Parent::HAS_DROP_ITEM { +            // SAFETY: We called `into_raw` to produce `r_child_group_ptr` in +            // `make_group`. +            let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) }; + +            Parent::drop_item(parent_data, arc.as_arc_borrow()); +            arc.into_raw(); +        } + +        // SAFETY: By C API contract, we are required to drop a refcount on +        // `item`. +        unsafe { bindings::config_item_put(item) }; +    } + +    const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations { +        make_item: None, +        make_group: Some(Self::make_group), +        disconnect_notify: None, +        drop_item: Some(Self::drop_item), +        is_visible: None, +        is_bin_visible: None, +    }; + +    const fn vtable_ptr() -> *const bindings::configfs_group_operations { +        &Self::VTABLE as *const bindings::configfs_group_operations +    } +} + +struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>); + +impl<Data> ItemOperationsVTable<Group<Data>, Data> +where +    Data: 'static, +{ +    /// # Safety +    /// +    /// `this` must be a pointer to a `bindings::config_group` embedded in a +    /// `Group<Parent>`. +    /// +    /// This function will destroy the pointee of `this`. The pointee of `this` +    /// must not be accessed after the function returns. +    unsafe extern "C" fn release(this: *mut bindings::config_item) { +        // SAFETY: By function safety requirements, `this` is embedded in a +        // `config_group`. +        let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) }; +        // SAFETY: By function safety requirements, `c_group_ptr` is +        // embedded within a `Group<Data>`. +        let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) }; + +        // SAFETY: We called `into_raw` on `r_group_ptr` in +        // `make_group`. +        let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) }; +        drop(pin_self); +    } + +    const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations { +        release: Some(Self::release), +        allow_link: None, +        drop_link: None, +    }; + +    const fn vtable_ptr() -> *const bindings::configfs_item_operations { +        &Self::VTABLE as *const bindings::configfs_item_operations +    } +} + +impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> { +    const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations { +        release: None, +        allow_link: None, +        drop_link: None, +    }; + +    const fn vtable_ptr() -> *const bindings::configfs_item_operations { +        &Self::VTABLE as *const bindings::configfs_item_operations +    } +} + +/// Operations implemented by configfs groups that can create subgroups. +/// +/// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`]. +#[vtable] +pub trait GroupOperations { +    /// The child data object type. +    /// +    /// This group will create subgroups (subdirectories) backed by this kind of +    /// object. +    type Child: 'static; + +    /// Creates a new subgroup. +    /// +    /// The kernel will call this method in response to `mkdir(2)` in the +    /// directory representing `this`. +    /// +    /// To accept the request to create a group, implementations should +    /// return an initializer of a `Group<Self::Child>`. To prevent creation, +    /// return a suitable error. +    fn make_group(&self, name: &CStr) -> Result<impl PinInit<Group<Self::Child>, Error>>; + +    /// Prepares the group for removal from configfs. +    /// +    /// The kernel will call this method before the directory representing `_child` is removed from +    /// configfs. +    /// +    /// Implementations can use this method to do house keeping before configfs drops its +    /// reference to `Child`. +    /// +    /// NOTE: "drop" in the name of this function is not related to the Rust drop term. Rather, the +    /// name is inherited from the callback name in the underlying C code. +    fn drop_item(&self, _child: ArcBorrow<'_, Group<Self::Child>>) { +        kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR) +    } +} + +/// A configfs attribute. +/// +/// An attribute appears as a file in configfs, inside a folder that represent +/// the group that the attribute belongs to. +#[repr(transparent)] +pub struct Attribute<const ID: u64, O, Data> { +    attribute: Opaque<bindings::configfs_attribute>, +    _p: PhantomData<(O, Data)>, +} + +// SAFETY: We do not provide any operations on `Attribute`. +unsafe impl<const ID: u64, O, Data> Sync for Attribute<ID, O, Data> {} + +// SAFETY: Ownership of `Attribute` can safely be transferred to other threads. +unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {} + +impl<const ID: u64, O, Data> Attribute<ID, O, Data> +where +    O: AttributeOperations<ID, Data = Data>, +{ +    /// # Safety +    /// +    /// `item` must be embedded in a `bindings::config_group`. +    /// +    /// If `item` does not represent the root group of a configfs subsystem, +    /// the group must be embedded in a `Group<Data>`. +    /// +    /// Otherwise, the group must be a embedded in a +    /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`. +    /// +    /// `page` must point to a writable buffer of size at least [`PAGE_SIZE`]. +    unsafe extern "C" fn show( +        item: *mut bindings::config_item, +        page: *mut kernel::ffi::c_char, +    ) -> isize { +        let c_group: *mut bindings::config_group = +            // SAFETY: By function safety requirements, `item` is embedded in a +            // `config_group`. +            unsafe { container_of!(item, bindings::config_group, cg_item) }.cast_mut(); + +        // SAFETY: The function safety requirements for this function satisfy +        // the conditions for this call. +        let data: &Data = unsafe { get_group_data(c_group) }; + +        // SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`. +        let ret = O::show(data, unsafe { &mut *(page as *mut [u8; PAGE_SIZE]) }); + +        match ret { +            Ok(size) => size as isize, +            Err(err) => err.to_errno() as isize, +        } +    } + +    /// # Safety +    /// +    /// `item` must be embedded in a `bindings::config_group`. +    /// +    /// If `item` does not represent the root group of a configfs subsystem, +    /// the group must be embedded in a `Group<Data>`. +    /// +    /// Otherwise, the group must be a embedded in a +    /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`. +    /// +    /// `page` must point to a readable buffer of size at least `size`. +    unsafe extern "C" fn store( +        item: *mut bindings::config_item, +        page: *const kernel::ffi::c_char, +        size: usize, +    ) -> isize { +        let c_group: *mut bindings::config_group = +        // SAFETY: By function safety requirements, `item` is embedded in a +        // `config_group`. +            unsafe { container_of!(item, bindings::config_group, cg_item) }.cast_mut(); + +        // SAFETY: The function safety requirements for this function satisfy +        // the conditions for this call. +        let data: &Data = unsafe { get_group_data(c_group) }; + +        let ret = O::store( +            data, +            // SAFETY: By function safety requirements, `page` is readable +            // for at least `size`. +            unsafe { core::slice::from_raw_parts(page.cast(), size) }, +        ); + +        match ret { +            Ok(()) => size as isize, +            Err(err) => err.to_errno() as isize, +        } +    } + +    /// Create a new attribute. +    /// +    /// The attribute will appear as a file with name given by `name`. +    pub const fn new(name: &'static CStr) -> Self { +        Self { +            attribute: Opaque::new(bindings::configfs_attribute { +                ca_name: name.as_char_ptr(), +                ca_owner: core::ptr::null_mut(), +                ca_mode: 0o660, +                show: Some(Self::show), +                store: if O::HAS_STORE { +                    Some(Self::store) +                } else { +                    None +                }, +            }), +            _p: PhantomData, +        } +    } +} + +/// Operations supported by an attribute. +/// +/// Implement this trait on type and pass that type as generic parameter when +/// creating an [`Attribute`]. The type carrying the implementation serve no +/// purpose other than specifying the attribute operations. +/// +/// This trait must be implemented on the `Data` type of for types that +/// implement `HasGroup<Data>`. The trait must be implemented once for each +/// attribute of the group. The constant type parameter `ID` maps the +/// implementation to a specific `Attribute`. `ID` must be passed when declaring +/// attributes via the [`kernel::configfs_attrs`] macro, to tie +/// `AttributeOperations` implementations to concrete named attributes. +#[vtable] +pub trait AttributeOperations<const ID: u64 = 0> { +    /// The type of the object that contains the field that is backing the +    /// attribute for this operation. +    type Data; + +    /// Renders the value of an attribute. +    /// +    /// This function is called by the kernel to read the value of an attribute. +    /// +    /// Implementations should write the rendering of the attribute to `page` +    /// and return the number of bytes written. +    fn show(data: &Self::Data, page: &mut [u8; PAGE_SIZE]) -> Result<usize>; + +    /// Stores the value of an attribute. +    /// +    /// This function is called by the kernel to update the value of an attribute. +    /// +    /// Implementations should parse the value from `page` and update internal +    /// state to reflect the parsed value. +    fn store(_data: &Self::Data, _page: &[u8]) -> Result { +        kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR) +    } +} + +/// A list of attributes. +/// +/// This type is used to construct a new [`ItemType`]. It represents a list of +/// [`Attribute`] that will appear in the directory representing a [`Group`]. +/// Users should not directly instantiate this type, rather they should use the +/// [`kernel::configfs_attrs`] macro to declare a static set of attributes for a +/// group. +/// +/// # Note +/// +/// Instances of this type are constructed statically at compile by the +/// [`kernel::configfs_attrs`] macro. +#[repr(transparent)] +pub struct AttributeList<const N: usize, Data>( +    /// Null terminated Array of pointers to [`Attribute`]. The type is [`c_void`] +    /// to conform to the C API. +    UnsafeCell<[*mut kernel::ffi::c_void; N]>, +    PhantomData<Data>, +); + +// SAFETY: Ownership of `AttributeList` can safely be transferred to other threads. +unsafe impl<const N: usize, Data> Send for AttributeList<N, Data> {} + +// SAFETY: We do not provide any operations on `AttributeList` that need synchronization. +unsafe impl<const N: usize, Data> Sync for AttributeList<N, Data> {} + +impl<const N: usize, Data> AttributeList<N, Data> { +    /// # Safety +    /// +    /// This function must only be called by the [`kernel::configfs_attrs`] +    /// macro. +    #[doc(hidden)] +    pub const unsafe fn new() -> Self { +        Self(UnsafeCell::new([core::ptr::null_mut(); N]), PhantomData) +    } + +    /// # Safety +    /// +    /// The caller must ensure that there are no other concurrent accesses to +    /// `self`. That is, the caller has exclusive access to `self.` +    #[doc(hidden)] +    pub const unsafe fn add<const I: usize, const ID: u64, O>( +        &'static self, +        attribute: &'static Attribute<ID, O, Data>, +    ) where +        O: AttributeOperations<ID, Data = Data>, +    { +        // We need a space at the end of our list for a null terminator. +        const { assert!(I < N - 1, "Invalid attribute index") }; + +        // SAFETY: By function safety requirements, we have exclusive access to +        // `self` and the reference created below will be exclusive. +        unsafe { +            (&mut *self.0.get())[I] = (attribute as *const Attribute<ID, O, Data>) +                .cast_mut() +                .cast() +        }; +    } +} + +/// A representation of the attributes that will appear in a [`Group`] or +/// [`Subsystem`]. +/// +/// Users should not directly instantiate objects of this type. Rather, they +/// should use the [`kernel::configfs_attrs`] macro to statically declare the +/// shape of a [`Group`] or [`Subsystem`]. +#[pin_data] +pub struct ItemType<Container, Data> { +    #[pin] +    item_type: Opaque<bindings::config_item_type>, +    _p: PhantomData<(Container, Data)>, +} + +// SAFETY: We do not provide any operations on `ItemType` that need synchronization. +unsafe impl<Container, Data> Sync for ItemType<Container, Data> {} + +// SAFETY: Ownership of `ItemType` can safely be transferred to other threads. +unsafe impl<Container, Data> Send for ItemType<Container, Data> {} + +macro_rules! impl_item_type { +    ($tpe:ty) => { +        impl<Data> ItemType<$tpe, Data> { +            #[doc(hidden)] +            pub const fn new_with_child_ctor<const N: usize, Child>( +                owner: &'static ThisModule, +                attributes: &'static AttributeList<N, Data>, +            ) -> Self +            where +                Data: GroupOperations<Child = Child>, +                Child: 'static, +            { +                Self { +                    item_type: Opaque::new(bindings::config_item_type { +                        ct_owner: owner.as_ptr(), +                        ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(), +                        ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(), +                        ct_attrs: (attributes as *const AttributeList<N, Data>) +                            .cast_mut() +                            .cast(), +                        ct_bin_attrs: core::ptr::null_mut(), +                    }), +                    _p: PhantomData, +                } +            } + +            #[doc(hidden)] +            pub const fn new<const N: usize>( +                owner: &'static ThisModule, +                attributes: &'static AttributeList<N, Data>, +            ) -> Self { +                Self { +                    item_type: Opaque::new(bindings::config_item_type { +                        ct_owner: owner.as_ptr(), +                        ct_group_ops: core::ptr::null_mut(), +                        ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(), +                        ct_attrs: (attributes as *const AttributeList<N, Data>) +                            .cast_mut() +                            .cast(), +                        ct_bin_attrs: core::ptr::null_mut(), +                    }), +                    _p: PhantomData, +                } +            } +        } +    }; +} + +impl_item_type!(Subsystem<Data>); +impl_item_type!(Group<Data>); + +impl<Container, Data> ItemType<Container, Data> { +    fn as_ptr(&self) -> *const bindings::config_item_type { +        self.item_type.get() +    } +} + +/// Define a list of configfs attributes statically. +/// +/// Invoking the macro in the following manner: +/// +/// ```ignore +/// let item_type = configfs_attrs! { +///     container: configfs::Subsystem<Configuration>, +///     data: Configuration, +///     child: Child, +///     attributes: [ +///         message: 0, +///         bar: 1, +///     ], +/// }; +/// ``` +/// +/// Expands the following output: +/// +/// ```ignore +/// let item_type = { +///     static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute< +///         0, +///         Configuration, +///         Configuration, +///     > = unsafe { +///         kernel::configfs::Attribute::new({ +///             const S: &str = "message\u{0}"; +///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul( +///                 S.as_bytes() +///             ) { +///                 Ok(v) => v, +///                 Err(_) => { +///                     core::panicking::panic_fmt(core::const_format_args!( +///                         "string contains interior NUL" +///                     )); +///                 } +///             }; +///             C +///         }) +///     }; +/// +///     static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute< +///             1, +///             Configuration, +///             Configuration +///     > = unsafe { +///         kernel::configfs::Attribute::new({ +///             const S: &str = "bar\u{0}"; +///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul( +///                 S.as_bytes() +///             ) { +///                 Ok(v) => v, +///                 Err(_) => { +///                     core::panicking::panic_fmt(core::const_format_args!( +///                         "string contains interior NUL" +///                     )); +///                 } +///             }; +///             C +///         }) +///     }; +/// +///     const N: usize = (1usize + (1usize + 0usize)) + 1usize; +/// +///     static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> = +///         unsafe { kernel::configfs::AttributeList::new() }; +/// +///     { +///         const N: usize = 0usize; +///         unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) }; +///     } +/// +///     { +///         const N: usize = (1usize + 0usize); +///         unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) }; +///     } +/// +///     static CONFIGURATION_TPE: +///       kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration> +///         = kernel::configfs::ItemType::< +///                 configfs::Subsystem<Configuration>, +///                 Configuration +///                 >::new_with_child_ctor::<N,Child>( +///             &THIS_MODULE, +///             &CONFIGURATION_ATTRS +///         ); +/// +///     &CONFIGURATION_TPE +/// } +/// ``` +#[macro_export] +macro_rules! configfs_attrs { +    ( +        container: $container:ty, +        data: $data:ty, +        attributes: [ +            $($name:ident: $attr:literal),* $(,)? +        ] $(,)? +    ) => { +        $crate::configfs_attrs!( +            count: +            @container($container), +            @data($data), +            @child(), +            @no_child(x), +            @attrs($($name $attr)*), +            @eat($($name $attr,)*), +            @assign(), +            @cnt(0usize), +        ) +    }; +    ( +        container: $container:ty, +        data: $data:ty, +        child: $child:ty, +        attributes: [ +            $($name:ident: $attr:literal),* $(,)? +        ] $(,)? +    ) => { +        $crate::configfs_attrs!( +            count: +            @container($container), +            @data($data), +            @child($child), +            @no_child(), +            @attrs($($name $attr)*), +            @eat($($name $attr,)*), +            @assign(), +            @cnt(0usize), +        ) +    }; +    (count: +     @container($container:ty), +     @data($data:ty), +     @child($($child:ty)?), +     @no_child($($no_child:ident)?), +     @attrs($($aname:ident $aattr:literal)*), +     @eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*), +     @assign($($assign:block)*), +     @cnt($cnt:expr), +    ) => { +        $crate::configfs_attrs!( +            count: +            @container($container), +            @data($data), +            @child($($child)?), +            @no_child($($no_child)?), +            @attrs($($aname $aattr)*), +            @eat($($rname $rattr,)*), +            @assign($($assign)* { +                const N: usize = $cnt; +                // The following macro text expands to a call to `Attribute::add`. + +                // SAFETY: By design of this macro, the name of the variable we +                // invoke the `add` method on below, is not visible outside of +                // the macro expansion. The macro does not operate concurrently +                // on this variable, and thus we have exclusive access to the +                // variable. +                unsafe { +                    $crate::macros::paste!( +                        [< $data:upper _ATTRS >] +                            .add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >]) +                    ) +                }; +            }), +            @cnt(1usize + $cnt), +        ) +    }; +    (count: +     @container($container:ty), +     @data($data:ty), +     @child($($child:ty)?), +     @no_child($($no_child:ident)?), +     @attrs($($aname:ident $aattr:literal)*), +     @eat(), +     @assign($($assign:block)*), +     @cnt($cnt:expr), +    ) => +    { +        $crate::configfs_attrs!( +            final: +            @container($container), +            @data($data), +            @child($($child)?), +            @no_child($($no_child)?), +            @attrs($($aname $aattr)*), +            @assign($($assign)*), +            @cnt($cnt), +        ) +    }; +    (final: +     @container($container:ty), +     @data($data:ty), +     @child($($child:ty)?), +     @no_child($($no_child:ident)?), +     @attrs($($name:ident $attr:literal)*), +     @assign($($assign:block)*), +     @cnt($cnt:expr), +    ) => +    { +        $crate::macros::paste!{ +            { +                $( +                    // SAFETY: We are expanding `configfs_attrs`. +                    static [< $data:upper _ $name:upper _ATTR >]: +                        $crate::configfs::Attribute<$attr, $data, $data> = +                            unsafe { +                                $crate::configfs::Attribute::new(c_str!(::core::stringify!($name))) +                            }; +                )* + + +                // We need space for a null terminator. +                const N: usize = $cnt + 1usize; + +                // SAFETY: We are expanding `configfs_attrs`. +                static [< $data:upper _ATTRS >]: +                $crate::configfs::AttributeList<N, $data> = +                    unsafe { $crate::configfs::AttributeList::new() }; + +                $($assign)* + +                $( +                    const [<$no_child:upper>]: bool = true; + +                    static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data>  = +                        $crate::configfs::ItemType::<$container, $data>::new::<N>( +                            &THIS_MODULE, &[<$ data:upper _ATTRS >] +                        ); +                )? + +                $( +                    static [< $data:upper _TPE >]: +                        $crate::configfs::ItemType<$container, $data>  = +                            $crate::configfs::ItemType::<$container, $data>:: +                            new_with_child_ctor::<N, $child>( +                                &THIS_MODULE, &[<$ data:upper _ATTRS >] +                            ); +                )? + +                & [< $data:upper _TPE >] +            } +        } +    }; + +} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 21b343a1dc4d..f08583fa39c9 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -9,7 +9,7 @@ use crate::{      str::CStr,      types::{ARef, Opaque},  }; -use core::{fmt, ptr}; +use core::{fmt, marker::PhantomData, ptr};  #[cfg(CONFIG_PRINTK)]  use crate::c_str; @@ -42,7 +42,7 @@ use crate::c_str;  /// `bindings::device::release` is valid to be called from any thread, hence `ARef<Device>` can be  /// dropped from any thread.  #[repr(transparent)] -pub struct Device(Opaque<bindings::device>); +pub struct Device<Ctx: DeviceContext = Normal>(Opaque<bindings::device>, PhantomData<Ctx>);  impl Device {      /// Creates a new reference-counted abstraction instance of an existing `struct device` pointer. @@ -59,12 +59,33 @@ impl Device {          // SAFETY: By the safety requirements ptr is valid          unsafe { Self::as_ref(ptr) }.into()      } +} +impl<Ctx: DeviceContext> Device<Ctx> {      /// Obtain the raw `struct device *`.      pub(crate) fn as_raw(&self) -> *mut bindings::device {          self.0.get()      } +    /// Returns a reference to the parent device, if any. +    #[cfg_attr(not(CONFIG_AUXILIARY_BUS), expect(dead_code))] +    pub(crate) fn parent(&self) -> Option<&Self> { +        // SAFETY: +        // - By the type invariant `self.as_raw()` is always valid. +        // - The parent device is only ever set at device creation. +        let parent = unsafe { (*self.as_raw()).parent }; + +        if parent.is_null() { +            None +        } else { +            // SAFETY: +            // - Since `parent` is not NULL, it must be a valid pointer to a `struct device`. +            // - `parent` is valid for the lifetime of `self`, since a `struct device` holds a +            //   reference count of its parent. +            Some(unsafe { Self::as_ref(parent) }) +        } +    } +      /// Convert a raw C `struct device` pointer to a `&'a Device`.      ///      /// # Safety @@ -189,6 +210,11 @@ impl Device {      }  } +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); +kernel::impl_device_context_into_aref!(Device); +  // SAFETY: Instances of `Device` are always reference-counted.  unsafe impl crate::types::AlwaysRefCounted for Device {      fn inc_ref(&self) { @@ -225,16 +251,95 @@ pub struct Normal;  /// any of the bus callbacks, such as `probe()`.  pub struct Core; +/// The [`Bound`] context is the context of a bus specific device reference when it is guaranteed to +/// be bound for the duration of its lifetime. +pub struct Bound; +  mod private {      pub trait Sealed {} +    impl Sealed for super::Bound {}      impl Sealed for super::Core {}      impl Sealed for super::Normal {}  } +impl DeviceContext for Bound {}  impl DeviceContext for Core {}  impl DeviceContext for Normal {} +/// # Safety +/// +/// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the +/// generic argument of `$device`. +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_device_context_deref { +    (unsafe { $device:ident, $src:ty => $dst:ty }) => { +        impl ::core::ops::Deref for $device<$src> { +            type Target = $device<$dst>; + +            fn deref(&self) -> &Self::Target { +                let ptr: *const Self = self; + +                // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the +                // safety requirement of the macro. +                let ptr = ptr.cast::<Self::Target>(); + +                // SAFETY: `ptr` was derived from `&self`. +                unsafe { &*ptr } +            } +        } +    }; +} + +/// Implement [`core::ops::Deref`] traits for allowed [`DeviceContext`] conversions of a (bus +/// specific) device. +/// +/// # Safety +/// +/// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the +/// generic argument of `$device`. +#[macro_export] +macro_rules! impl_device_context_deref { +    (unsafe { $device:ident }) => { +        // SAFETY: This macro has the exact same safety requirement as +        // `__impl_device_context_deref!`. +        ::kernel::__impl_device_context_deref!(unsafe { +            $device, +            $crate::device::Core => $crate::device::Bound +        }); + +        // SAFETY: This macro has the exact same safety requirement as +        // `__impl_device_context_deref!`. +        ::kernel::__impl_device_context_deref!(unsafe { +            $device, +            $crate::device::Bound => $crate::device::Normal +        }); +    }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_device_context_into_aref { +    ($src:ty, $device:tt) => { +        impl ::core::convert::From<&$device<$src>> for $crate::types::ARef<$device> { +            fn from(dev: &$device<$src>) -> Self { +                (&**dev).into() +            } +        } +    }; +} + +/// Implement [`core::convert::From`], such that all `&Device<Ctx>` can be converted to an +/// `ARef<Device>`. +#[macro_export] +macro_rules! impl_device_context_into_aref { +    ($device:tt) => { +        ::kernel::__impl_device_context_into_aref!($crate::device::Core, $device); +        ::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device); +    }; +} +  #[doc(hidden)]  #[macro_export]  macro_rules! dev_printk { diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index ddb1ce4a78d9..0f79a2ec9474 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -8,7 +8,7 @@  use crate::{      alloc::Flags,      bindings, -    device::Device, +    device::{Bound, Device},      error::{Error, Result},      ffi::c_void,      prelude::*, @@ -45,7 +45,7 @@ struct DevresInner<T> {  /// # Example  ///  /// ```no_run -/// # use kernel::{bindings, c_str, device::Device, devres::Devres, io::{Io, IoRaw}}; +/// # use kernel::{bindings, c_str, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}};  /// # use core::ops::Deref;  ///  /// // See also [`pci::Bar`] for a real example. @@ -83,13 +83,10 @@ struct DevresInner<T> {  ///         unsafe { Io::from_raw(&self.0) }  ///    }  /// } -/// # fn no_run() -> Result<(), Error> { -/// # // SAFETY: Invalid usage; just for the example to get an `ARef<Device>` instance. -/// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) }; -/// +/// # fn no_run(dev: &Device<Bound>) -> Result<(), Error> {  /// // SAFETY: Invalid usage for example purposes.  /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; -/// let devres = Devres::new(&dev, iomem, GFP_KERNEL)?; +/// let devres = Devres::new(dev, iomem, GFP_KERNEL)?;  ///  /// let res = devres.try_access().ok_or(ENXIO)?;  /// res.write8(0x42, 0x0); @@ -99,7 +96,7 @@ struct DevresInner<T> {  pub struct Devres<T>(Arc<DevresInner<T>>);  impl<T> DevresInner<T> { -    fn new(dev: &Device, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> { +    fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> {          let inner = Arc::pin_init(              pin_init!( DevresInner {                  dev: dev.into(), @@ -171,7 +168,7 @@ impl<T> DevresInner<T> {  impl<T> Devres<T> {      /// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the      /// returned `Devres` instance' `data` will be revoked once the device is detached. -    pub fn new(dev: &Device, data: T, flags: Flags) -> Result<Self> { +    pub fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Self> {          let inner = DevresInner::new(dev, data, flags)?;          Ok(Devres(inner)) @@ -179,11 +176,50 @@ impl<T> Devres<T> {      /// Same as [`Devres::new`], but does not return a `Devres` instance. Instead the given `data`      /// is owned by devres and will be revoked / dropped, once the device is detached. -    pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result { +    pub fn new_foreign_owned(dev: &Device<Bound>, data: T, flags: Flags) -> Result {          let _ = DevresInner::new(dev, data, flags)?;          Ok(())      } + +    /// Obtain `&'a T`, bypassing the [`Revocable`]. +    /// +    /// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting +    /// a `&'a Device<Bound>` of the same [`Device`] this [`Devres`] instance has been created with. +    /// +    /// # Errors +    /// +    /// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance +    /// has been created with. +    /// +    /// # Example +    /// +    /// ```no_run +    /// # #![cfg(CONFIG_PCI)] +    /// # use kernel::{device::Core, devres::Devres, pci}; +    /// +    /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result { +    ///     let bar = devres.access(dev.as_ref())?; +    /// +    ///     let _ = bar.read32(0x0); +    /// +    ///     // might_sleep() +    /// +    ///     bar.write32(0x42, 0x0); +    /// +    ///     Ok(()) +    /// } +    /// ``` +    pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> { +        if self.0.dev.as_raw() != dev.as_raw() { +            return Err(EINVAL); +        } + +        // SAFETY: `dev` being the same device as the device this `Devres` has been created for +        // proves that `self.0.data` hasn't been revoked and is guaranteed to not be revoked as +        // long as `dev` lives; `dev` lives at least as long as `self`. +        Ok(unsafe { self.deref().access() }) +    }  }  impl<T> Deref for Devres<T> { diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 8cdc76043ee7..605e01e35715 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -6,7 +6,7 @@  use crate::{      bindings, build_assert, -    device::Device, +    device::{Bound, Device},      error::code::*,      error::Result,      transmute::{AsBytes, FromBytes}, @@ -22,10 +22,10 @@ use crate::{  /// # Examples  ///  /// ``` -/// use kernel::device::Device; +/// # use kernel::device::{Bound, Device};  /// use kernel::dma::{attrs::*, CoherentAllocation};  /// -/// # fn test(dev: &Device) -> Result { +/// # fn test(dev: &Device<Bound>) -> Result {  /// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;  /// let c: CoherentAllocation<u64> =  ///     CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?; @@ -143,16 +143,16 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {      /// # Examples      ///      /// ``` -    /// use kernel::device::Device; +    /// # use kernel::device::{Bound, Device};      /// use kernel::dma::{attrs::*, CoherentAllocation};      /// -    /// # fn test(dev: &Device) -> Result { +    /// # fn test(dev: &Device<Bound>) -> Result {      /// let c: CoherentAllocation<u64> =      ///     CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;      /// # Ok::<(), Error>(()) }      /// ```      pub fn alloc_attrs( -        dev: &Device, +        dev: &Device<Bound>,          count: usize,          gfp_flags: kernel::alloc::Flags,          dma_attrs: Attrs, @@ -194,7 +194,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {      /// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the      /// `dma_attrs` is 0 by default.      pub fn alloc_coherent( -        dev: &Device, +        dev: &Device<Bound>,          count: usize,          gfp_flags: kernel::alloc::Flags,      ) -> Result<CoherentAllocation<T>> { diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs new file mode 100644 index 000000000000..74c9a3dd719e --- /dev/null +++ b/rust/kernel/drm/device.rs @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM device. +//! +//! C header: [`include/linux/drm/drm_device.h`](srctree/include/linux/drm/drm_device.h) + +use crate::{ +    bindings, device, drm, +    drm::driver::AllocImpl, +    error::from_err_ptr, +    error::Result, +    prelude::*, +    types::{ARef, AlwaysRefCounted, Opaque}, +}; +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, +        } +    } +} + +#[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. +/// +/// # Invariants +/// +/// `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, +} + +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 _, + +        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 pointer 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 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; + +    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::Driver> AlwaysRefCounted for Device<T> { +    fn inc_ref(&self) { +        // 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 safety requirements guarantee that the refcount is non-zero. +        unsafe { bindings::drm_dev_put(obj.cast().as_ptr()) }; +    } +} + +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/rust/kernel/drm/driver.rs new file mode 100644 index 000000000000..acb638086131 --- /dev/null +++ b/rust/kernel/drm/driver.rs @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM driver core. +//! +//! C header: [`include/linux/drm/drm_drv.h`](srctree/include/linux/drm/drm_drv.h) + +use crate::{ +    bindings, device, +    devres::Devres, +    drm, +    error::{to_result, Result}, +    prelude::*, +    str::CStr, +    types::ARef, +}; +use macros::vtable; + +/// Driver use the GEM memory manager. This should be set for all modern drivers. +pub(crate) const FEAT_GEM: u32 = bindings::drm_driver_feature_DRIVER_GEM; + +/// Information data for a DRM Driver. +pub struct DriverInfo { +    /// Driver major version. +    pub major: i32, +    /// Driver minor version. +    pub minor: i32, +    /// Driver patchlevel version. +    pub patchlevel: i32, +    /// Driver name. +    pub name: &'static CStr, +    /// Driver description. +    pub desc: &'static CStr, +} + +/// Internal memory management operation set, normally created by memory managers (e.g. GEM). +pub struct AllocOps { +    pub(crate) gem_create_object: Option< +        unsafe extern "C" fn( +            dev: *mut bindings::drm_device, +            size: usize, +        ) -> *mut bindings::drm_gem_object, +    >, +    pub(crate) prime_handle_to_fd: Option< +        unsafe extern "C" fn( +            dev: *mut bindings::drm_device, +            file_priv: *mut bindings::drm_file, +            handle: u32, +            flags: u32, +            prime_fd: *mut core::ffi::c_int, +        ) -> core::ffi::c_int, +    >, +    pub(crate) prime_fd_to_handle: Option< +        unsafe extern "C" fn( +            dev: *mut bindings::drm_device, +            file_priv: *mut bindings::drm_file, +            prime_fd: core::ffi::c_int, +            handle: *mut u32, +        ) -> core::ffi::c_int, +    >, +    pub(crate) gem_prime_import: Option< +        unsafe extern "C" fn( +            dev: *mut bindings::drm_device, +            dma_buf: *mut bindings::dma_buf, +        ) -> *mut bindings::drm_gem_object, +    >, +    pub(crate) gem_prime_import_sg_table: Option< +        unsafe extern "C" fn( +            dev: *mut bindings::drm_device, +            attach: *mut bindings::dma_buf_attachment, +            sgt: *mut bindings::sg_table, +        ) -> *mut bindings::drm_gem_object, +    >, +    pub(crate) dumb_create: Option< +        unsafe extern "C" fn( +            file_priv: *mut bindings::drm_file, +            dev: *mut bindings::drm_device, +            args: *mut bindings::drm_mode_create_dumb, +        ) -> core::ffi::c_int, +    >, +    pub(crate) dumb_map_offset: Option< +        unsafe extern "C" fn( +            file_priv: *mut bindings::drm_file, +            dev: *mut bindings::drm_device, +            handle: u32, +            offset: *mut u64, +        ) -> core::ffi::c_int, +    >, +} + +/// Trait for memory manager implementations. Implemented internally. +pub trait AllocImpl: super::private::Sealed + drm::gem::IntoGEMObject { +    /// The C callback operations for this memory manager. +    const ALLOC_OPS: AllocOps; +} + +/// 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 +    type Data: Sync + Send; + +    /// The type used to manage memory for this driver. +    type Object: AllocImpl; + +    /// The type used to represent a DRM File (client) +    type File: drm::file::DriverFile; + +    /// Driver metadata +    const INFO: DriverInfo; + +    /// IOCTL list. See `kernel::drm::ioctl::declare_drm_ioctls!{}`. +    const IOCTLS: &'static [drm::ioctl::DrmIoctlDescriptor]; +} + +/// The registration type of a `drm::Device`. +/// +/// Once the `Registration` structure is dropped, the device is unregistered. +pub struct Registration<T: Driver>(ARef<drm::Device<T>>); + +impl<T: Driver> Registration<T> { +    /// Creates a new [`Registration`] and registers it. +    fn new(drm: &drm::Device<T>, flags: usize) -> Result<Self> { +        // SAFETY: `drm.as_raw()` is valid by the invariants of `drm::Device`. +        to_result(unsafe { bindings::drm_dev_register(drm.as_raw(), flags) })?; + +        Ok(Self(drm.into())) +    } + +    /// Same as [`Registration::new`}, but transfers ownership of the [`Registration`] to +    /// [`Devres`]. +    pub fn new_foreign_owned( +        drm: &drm::Device<T>, +        dev: &device::Device<device::Bound>, +        flags: usize, +    ) -> Result { +        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) +    } + +    /// Returns a reference to the `Device` instance for this registration. +    pub fn device(&self) -> &drm::Device<T> { +        &self.0 +    } +} + +// 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> {} + +// 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> { +    fn drop(&mut self) { +        // 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/rust/kernel/drm/file.rs new file mode 100644 index 000000000000..b9527705e551 --- /dev/null +++ b/rust/kernel/drm/file.rs @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM File objects. +//! +//! C header: [`include/linux/drm/drm_file.h`](srctree/include/linux/drm/drm_file.h) + +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::Driver; + +    /// Open a new file (called when a client opens the DRM device). +    fn open(device: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>>; +} + +/// An open DRM File. +/// +/// # Invariants +/// +/// `self.0` is a valid instance of a `struct drm_file`. +#[repr(transparent)] +pub struct File<T: DriverFile>(Opaque<bindings::drm_file>, PhantomData<T>); + +impl<T: DriverFile> File<T> { +    #[doc(hidden)] +    /// 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() } +    } + +    pub(super) fn as_raw(&self) -> *mut bindings::drm_file { +        self.0.get() +    } + +    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: 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())) } +    } + +    /// 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 `struct drm_device`, +        // - the corresponding `struct drm_device` has been registered. +        let drm = unsafe { drm::Device::as_ref(raw_dev) }; + +        // SAFETY: `raw_file` is a 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 +    } + +    /// 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: `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/rust/kernel/drm/gem/mod.rs new file mode 100644 index 000000000000..d8765e61c6c2 --- /dev/null +++ b/rust/kernel/drm/gem/mod.rs @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM GEM API +//! +//! C header: [`include/linux/drm/drm_gem.h`](srctree/include/linux/drm/drm_gem.h) + +use crate::{ +    alloc::flags::*, +    bindings, drm, +    drm::driver::{AllocImpl, AllocOps}, +    error::{to_result, Result}, +    prelude::*, +    types::{ARef, AlwaysRefCounted, Opaque}, +}; +use core::{mem, ops::Deref, ptr::NonNull}; + +/// GEM object functions, which must be implemented by drivers. +pub trait BaseDriverObject<T: BaseObject>: Sync + Send + Sized { +    /// Create a new driver data object for a GEM object of a given size. +    fn new(dev: &drm::Device<T::Driver>, size: usize) -> impl PinInit<Self, Error>; + +    /// Open a new handle to an existing object, associated with a File. +    fn open( +        _obj: &<<T as IntoGEMObject>::Driver as drm::Driver>::Object, +        _file: &drm::File<<<T as IntoGEMObject>::Driver as drm::Driver>::File>, +    ) -> Result { +        Ok(()) +    } + +    /// Close a handle to an existing object, associated with a File. +    fn close( +        _obj: &<<T as IntoGEMObject>::Driver as drm::Driver>::Object, +        _file: &drm::File<<<T as IntoGEMObject>::Driver as drm::Driver>::File>, +    ) { +    } +} + +/// Trait that represents a GEM object subtype +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; + +    /// Converts a pointer to a `struct drm_gem_object` into a reference to `Self`. +    /// +    /// # Safety +    /// +    /// - `self_ptr` must be a valid pointer to `Self`. +    /// - The caller promises that holding the immutable reference returned by this function does +    ///   not violate rust's data aliasing rules and remains valid throughout the lifetime of `'a`. +    unsafe fn as_ref<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self; +} + +// SAFETY: All gem objects are refcounted. +unsafe impl<T: IntoGEMObject> AlwaysRefCounted for T { +    fn inc_ref(&self) { +        // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. +        unsafe { bindings::drm_gem_object_get(self.as_raw()) }; +    } + +    unsafe fn dec_ref(obj: NonNull<Self>) { +        // SAFETY: We either hold the only refcount on `obj`, or one of many - meaning that no one +        // else could possibly hold a mutable reference to `obj` and thus this immutable reference +        // is safe. +        let obj = unsafe { obj.as_ref() }.as_raw(); + +        // SAFETY: +        // - The safety requirements guarantee that the refcount is non-zero. +        // - We hold no references to `obj` now, making it safe for us to potentially deallocate it. +        unsafe { bindings::drm_gem_object_put(obj) }; +    } +} + +/// Trait which must be implemented by drivers using base GEM objects. +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>( +    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>::as_ref(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) +    }; + +    match T::open(obj, file) { +        Err(e) => e.to_errno(), +        Ok(()) => 0, +    } +} + +extern "C" fn close_callback<T: BaseDriverObject<U>, U: BaseObject>( +    raw_obj: *mut bindings::drm_gem_object, +    raw_file: *mut bindings::drm_file, +) { +    // SAFETY: `open_callback` is only ever called with a valid pointer to a `struct drm_file`. +    let file = unsafe { +        drm::File::<<<U as IntoGEMObject>::Driver as drm::Driver>::File>::as_ref(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) +    }; + +    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() +    } + +    unsafe fn as_ref<'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) } +    } +} + +/// Base operations shared by all GEM object classes +pub trait BaseObject: IntoGEMObject { +    /// Returns the size of the object in bytes. +    fn size(&self) -> usize { +        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `struct drm_gem_object`. +        unsafe { (*self.as_raw()).size } +    } + +    /// Creates a new handle for the object associated with a given `File` +    /// (or returns an existing one). +    fn create_handle( +        &self, +        file: &drm::File<<<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.as_raw().cast(), self.as_raw(), &mut handle) +        })?; +        Ok(handle) +    } + +    /// Looks up an object by its handle for a given `File`. +    fn lookup_handle( +        file: &drm::File<<<Self as IntoGEMObject>::Driver as drm::Driver>::File>, +        handle: u32, +    ) -> Result<ARef<Self>> { +        // SAFETY: The arguments are all valid per the type invariants. +        let ptr = unsafe { bindings::drm_gem_object_lookup(file.as_raw().cast(), handle) }; +        if ptr.is_null() { +            return Err(ENOENT); +        } + +        // SAFETY: +        // - A `drm::Driver` can only have a single `File` implementation. +        // - `file` uses the same `drm::Driver` as `Self`. +        // - Therefore, we're guaranteed that `ptr` must be a gem object embedded within `Self`. +        // - And we check if the pointer is null befoe calling as_ref(), ensuring that `ptr` is a +        //   valid pointer to an initialized `Self`. +        let obj = unsafe { Self::as_ref(ptr) }; + +        // SAFETY: +        // - We take ownership of the reference of `drm_gem_object_lookup()`. +        // - Our `NonNull` comes from an immutable reference, thus ensuring it is a valid pointer to +        //   `Self`. +        Ok(unsafe { ARef::from_raw(obj.into()) }) +    } + +    /// Creates an mmap offset to map the object from userspace. +    fn create_mmap_offset(&self) -> Result<u64> { +        // SAFETY: The arguments are valid per the type invariant. +        to_result(unsafe { bindings::drm_gem_create_mmap_offset(self.as_raw()) })?; + +        // SAFETY: The arguments are valid per the type invariant. +        Ok(unsafe { bindings::drm_vma_node_offset_addr(&raw mut (*self.as_raw()).vma_node) }) +    } +} + +impl<T: IntoGEMObject> BaseObject for T {} + +/// A base GEM object. +/// +/// Invariants +/// +/// - `self.obj` is a valid instance of a `struct drm_gem_object`. +/// - `self.dev` is always a valid pointer to a `struct drm_device`. +#[repr(C)] +#[pin_data] +pub struct Object<T: DriverObject + Send + Sync> { +    obj: Opaque<bindings::drm_gem_object>, +    dev: NonNull<drm::Device<T::Driver>>, +    #[pin] +    data: T, +} + +impl<T: DriverObject> Object<T> { +    /// The size of this object's structure. +    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>>), +        print_info: None, +        export: None, +        pin: None, +        unpin: None, +        get_sg_table: None, +        vmap: None, +        vunmap: None, +        mmap: None, +        status: None, +        vm_ops: core::ptr::null_mut(), +        evict: None, +        rss: None, +    }; + +    /// Create a new GEM object. +    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 { +                obj: Opaque::new(bindings::drm_gem_object::default()), +                data <- T::new(dev, size), +                // INVARIANT: The drm subsystem guarantees that the `struct drm_device` will live +                // as long as the GEM object lives. +                dev: dev.into(), +            }), +            GFP_KERNEL, +        )?; + +        // SAFETY: `obj.as_raw()` is guaranteed to be valid by the initialization above. +        unsafe { (*obj.as_raw()).funcs = &Self::OBJECT_FUNCS }; + +        // SAFETY: The arguments are all valid per the type invariants. +        to_result(unsafe { bindings::drm_gem_object_init(dev.as_raw(), obj.obj.get(), size) })?; + +        // SAFETY: We never move out of `Self`. +        let ptr = KBox::into_raw(unsafe { Pin::into_inner_unchecked(obj) }); + +        // SAFETY: `ptr` comes from `KBox::into_raw` and hence can't be NULL. +        let ptr = unsafe { NonNull::new_unchecked(ptr) }; + +        // SAFETY: We take over the initial reference count from `drm_gem_object_init()`. +        Ok(unsafe { ARef::from_raw(ptr) }) +    } + +    /// Returns the `Device` that owns this GEM object. +    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, hence the pointer must be valid. +        unsafe { self.dev.as_ref() } +    } + +    fn as_raw(&self) -> *mut bindings::drm_gem_object { +        self.obj.get() +    } + +    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: The C code only ever calls this callback with a valid pointer to a `struct +        // drm_gem_object`. +        unsafe { bindings::drm_gem_object_release(obj) }; + +        // SAFETY: All of our objects are allocated via `KBox`, and we're in the +        // free callback which guarantees this object has zero remaining references, +        // so we can drop it. +        let _ = unsafe { KBox::from_raw(this) }; +    } +} + +impl<T: DriverObject> super::private::Sealed for Object<T> {} + +impl<T: DriverObject> Deref for Object<T> { +    type Target = T; + +    fn deref(&self) -> &Self::Target { +        &self.data +    } +} + +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) 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/rust/kernel/drm/ioctl.rs new file mode 100644 index 000000000000..445639404fb7 --- /dev/null +++ b/rust/kernel/drm/ioctl.rs @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM IOCTL definitions. +//! +//! C header: [`include/linux/drm/drm_ioctl.h`](srctree/include/linux/drm/drm_ioctl.h) + +use crate::ioctl; + +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) +} + +/// Descriptor type for DRM ioctls. Use the `declare_drm_ioctls!{}` macro to construct them. +pub type DrmIoctlDescriptor = bindings::drm_ioctl_desc; + +/// This is for ioctl which are used for rendering, and require that the file descriptor is either +/// for a render node, or if it’s a legacy/primary node, then it must be authenticated. +pub const AUTH: u32 = bindings::drm_ioctl_flags_DRM_AUTH; + +/// This must be set for any ioctl which can change the modeset or display state. Userspace must +/// call the ioctl through a primary node, while it is the active master. +/// +/// Note that read-only modeset ioctl can also be called by unauthenticated clients, or when a +/// master is not the currently active one. +pub const MASTER: u32 = bindings::drm_ioctl_flags_DRM_MASTER; + +/// 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. +/// +/// This is equivalent to callers with the SYSADMIN capability. +pub const ROOT_ONLY: u32 = bindings::drm_ioctl_flags_DRM_ROOT_ONLY; + +/// This is used for all ioctl needed for rendering only, for drivers which support render nodes. +/// This should be all new render drivers, and hence it should be always set for any ioctl with +/// `AUTH` set. Note though that read-only query ioctl might have this set, but have not set +/// 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. +#[doc(hidden)] +pub mod internal { +    pub use bindings::drm_device; +    pub use bindings::drm_file; +    pub use bindings::drm_ioctl_desc; +} + +/// Declare the DRM ioctls for a driver. +/// +/// Each entry in the list should have the form: +/// +/// `(ioctl_number, argument_type, flags, user_callback),` +/// +/// `argument_type` is the type name within the `bindings` crate. +/// `user_callback` should have the following prototype: +/// +/// ```ignore +/// fn foo(device: &kernel::drm::Device<Self>, +///        data: &Opaque<uapi::argument_type>, +///        file: &kernel::drm::File<Self::File>, +/// ) -> Result<u32> +/// ``` +/// 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), +/// } +/// ``` +/// +#[macro_export] +macro_rules! declare_drm_ioctls { +    ( $(($cmd:ident, $struct:ident, $flags:expr, $func:expr)),* $(,)? ) => { +        const IOCTLS: &'static [$crate::drm::ioctl::DrmIoctlDescriptor] = { +            use $crate::uapi::*; +            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 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)); +                    let i: u32 = i + 1; +                )* +            }; + +            let ioctls = &[$( +                $crate::drm::ioctl::internal::drm_ioctl_desc { +                    cmd: $crate::macros::concat_idents!(DRM_IOCTL_, $cmd) as u32, +                    func: { +                        #[allow(non_snake_case)] +                        unsafe extern "C" fn $cmd( +                                raw_dev: *mut $crate::drm::ioctl::internal::drm_device, +                                raw_data: *mut ::core::ffi::c_void, +                                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. +                            // - 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::as_ref(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. +                            let data = unsafe { +                                &*(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) }; + +                            match $func(dev, data, file) { +                                Err(e) => e.to_errno(), +                                Ok(i) => i.try_into() +                                            .unwrap_or($crate::error::code::ERANGE.to_errno()), +                            } +                        } +                        Some($cmd) +                    }, +                    flags: $flags, +                    name: $crate::c_str!(::core::stringify!($cmd)).as_char_ptr(), +                } +            ),*]; +            ioctls +        }; +    }; +} diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs new file mode 100644 index 000000000000..1b82b6945edf --- /dev/null +++ b/rust/kernel/drm/mod.rs @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +//! DRM subsystem abstractions. + +pub mod device; +pub mod driver; +pub mod file; +pub mod gem; +pub mod ioctl; + +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 {} +} diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs index f04b058b09b2..2494c96e105f 100644 --- a/rust/kernel/firmware.rs +++ b/rust/kernel/firmware.rs @@ -4,7 +4,7 @@  //!  //! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.h) -use crate::{bindings, device::Device, error::Error, error::Result, str::CStr}; +use crate::{bindings, device::Device, error::Error, error::Result, ffi, str::CStr};  use core::ptr::NonNull;  /// # Invariants @@ -12,7 +12,11 @@ use core::ptr::NonNull;  /// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,  /// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.  struct FwFunc( -    unsafe extern "C" fn(*mut *const bindings::firmware, *const u8, *mut bindings::device) -> i32, +    unsafe extern "C" fn( +        *mut *const bindings::firmware, +        *const ffi::c_char, +        *mut bindings::device, +    ) -> i32,  );  impl FwFunc { diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index de07aadd1ff5..1cf1bd5b73fc 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -38,16 +38,22 @@ extern crate self as kernel;  pub use ffi;  pub mod alloc; +#[cfg(CONFIG_AUXILIARY_BUS)] +pub mod auxiliary;  #[cfg(CONFIG_BLOCK)]  pub mod block;  #[doc(hidden)]  pub mod build_assert; +#[cfg(CONFIG_CONFIGFS_FS)] +pub mod configfs;  pub mod cred;  pub mod device;  pub mod device_id;  pub mod devres;  pub mod dma;  pub mod driver; +#[cfg(CONFIG_DRM = "y")] +pub mod drm;  pub mod error;  pub mod faux;  #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs index a335c3b1ff5e..2054682c5724 100644 --- a/rust/kernel/list.rs +++ b/rust/kernel/list.rs @@ -4,6 +4,9 @@  //! A linked list implementation. +// May not be needed in Rust 1.87.0 (pending beta backport). +#![allow(clippy::ptr_eq)] +  use crate::sync::ArcBorrow;  use crate::types::Opaque;  use core::iter::{DoubleEndedIterator, FusedIterator}; diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index a59469c785e3..32ea43ece646 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -421,6 +421,7 @@ impl<T: Driver> Adapter<T> {      /// `phydev` must be passed by the corresponding callback in `phy_driver`.      unsafe extern "C" fn match_phy_device_callback(          phydev: *mut bindings::phy_device, +        _phydrv: *const bindings::phy_driver,      ) -> crate::ffi::c_int {          // SAFETY: This callback is called only in contexts          // where we hold `phy_device->lock`, so the accessors on diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index c97d6d470b28..38fc8d5ffbf9 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -6,7 +6,7 @@  use crate::{      alloc::flags::*, -    bindings, device, +    bindings, container_of, device,      device_id::RawDeviceId,      devres::Devres,      driver, @@ -360,11 +360,13 @@ impl<const SIZE: usize> Deref for Bar<SIZE> {      }  } -impl Device { +impl<Ctx: device::DeviceContext> Device<Ctx> {      fn as_raw(&self) -> *mut bindings::pci_dev {          self.0.get()      } +} +impl Device {      /// Returns the PCI vendor ID.      pub fn vendor_id(&self) -> u16 {          // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. @@ -388,7 +390,9 @@ impl Device {          // - by its type invariant `self.as_raw` is always a valid pointer to a `struct pci_dev`.          Ok(unsafe { bindings::pci_resource_len(self.as_raw(), bar.try_into()?) })      } +} +impl Device<device::Bound> {      /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks      /// can be performed on compile time for offsets (plus the requested type size) < SIZE.      pub fn iomap_region_sized<const SIZE: usize>( @@ -422,25 +426,10 @@ impl Device<device::Core> {      }  } -impl Deref for Device<device::Core> { -    type Target = Device; - -    fn deref(&self) -> &Self::Target { -        let ptr: *const Self = self; - -        // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::pci_dev>`. -        let ptr = ptr.cast::<Device>(); - -        // SAFETY: `ptr` was derived from `&self`. -        unsafe { &*ptr } -    } -} - -impl From<&Device<device::Core>> for ARef<Device> { -    fn from(dev: &Device<device::Core>) -> Self { -        (&**dev).into() -    } -} +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); +kernel::impl_device_context_into_aref!(Device);  // SAFETY: Instances of `Device` are always reference-counted.  unsafe impl crate::types::AlwaysRefCounted for Device { @@ -455,8 +444,8 @@ unsafe impl crate::types::AlwaysRefCounted for Device {      }  } -impl AsRef<device::Device> for Device { -    fn as_ref(&self) -> &device::Device { +impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { +    fn as_ref(&self) -> &device::Device<Ctx> {          // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid          // `struct pci_dev`.          let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; @@ -466,6 +455,26 @@ impl AsRef<device::Device> for Device {      }  } +impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &Device<Ctx> { +    type Error = kernel::error::Error; + +    fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> { +        // SAFETY: By the type invariant of `Device`, `dev.as_raw()` is a valid pointer to a +        // `struct device`. +        if !unsafe { bindings::dev_is_pci(dev.as_raw()) } { +            return Err(EINVAL); +        } + +        // SAFETY: We've just verified that the bus type of `dev` equals `bindings::pci_bus_type`, +        // hence `dev` must be embedded in a valid `struct pci_dev` as guaranteed by the +        // corresponding C code. +        let pdev = unsafe { container_of!(dev.as_raw(), bindings::pci_dev, dev) }; + +        // SAFETY: `pdev` is a valid pointer to a `struct pci_dev`. +        Ok(unsafe { &*pdev.cast() }) +    } +} +  // SAFETY: A `Device` is always reference-counted and can be released from any thread.  unsafe impl Send for Device {} diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 4917cb34e2fe..08849d92c074 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -5,18 +5,17 @@  //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h)  use crate::{ -    bindings, device, driver, +    bindings, container_of, device, driver,      error::{to_result, Result},      of,      prelude::*,      str::CStr, -    types::{ARef, ForeignOwnable, Opaque}, +    types::{ForeignOwnable, Opaque},      ThisModule,  };  use core::{      marker::PhantomData, -    ops::Deref,      ptr::{addr_of_mut, NonNull},  }; @@ -184,31 +183,16 @@ pub struct Device<Ctx: device::DeviceContext = device::Normal>(      PhantomData<Ctx>,  ); -impl Device { +impl<Ctx: device::DeviceContext> Device<Ctx> {      fn as_raw(&self) -> *mut bindings::platform_device {          self.0.get()      }  } -impl Deref for Device<device::Core> { -    type Target = Device; - -    fn deref(&self) -> &Self::Target { -        let ptr: *const Self = self; - -        // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::platform_device>`. -        let ptr = ptr.cast::<Device>(); - -        // SAFETY: `ptr` was derived from `&self`. -        unsafe { &*ptr } -    } -} - -impl From<&Device<device::Core>> for ARef<Device> { -    fn from(dev: &Device<device::Core>) -> Self { -        (&**dev).into() -    } -} +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); +kernel::impl_device_context_into_aref!(Device);  // SAFETY: Instances of `Device` are always reference-counted.  unsafe impl crate::types::AlwaysRefCounted for Device { @@ -223,8 +207,8 @@ unsafe impl crate::types::AlwaysRefCounted for Device {      }  } -impl AsRef<device::Device> for Device { -    fn as_ref(&self) -> &device::Device { +impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { +    fn as_ref(&self) -> &device::Device<Ctx> {          // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid          // `struct platform_device`.          let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; @@ -234,6 +218,26 @@ impl AsRef<device::Device> for Device {      }  } +impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &Device<Ctx> { +    type Error = kernel::error::Error; + +    fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> { +        // SAFETY: By the type invariant of `Device`, `dev.as_raw()` is a valid pointer to a +        // `struct device`. +        if !unsafe { bindings::dev_is_platform(dev.as_raw()) } { +            return Err(EINVAL); +        } + +        // SAFETY: We've just verified that the bus type of `dev` equals +        // `bindings::platform_bus_type`, hence `dev` must be embedded in a valid +        // `struct platform_device` as guaranteed by the corresponding C code. +        let pdev = unsafe { container_of!(dev.as_raw(), bindings::platform_device, dev) }; + +        // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. +        Ok(unsafe { &*pdev.cast() }) +    } +} +  // SAFETY: A `Device` is always reference-counted and can be released from any thread.  unsafe impl Send for Device {} diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs index 1e5a9d25c21b..db4aa46bb121 100644 --- a/rust/kernel/revocable.rs +++ b/rust/kernel/revocable.rs @@ -123,6 +123,34 @@ impl<T> Revocable<T> {          }      } +    /// Tries to access the wrapped object and run a closure on it while the guard is held. +    /// +    /// This is a convenience method to run short non-sleepable code blocks while ensuring the +    /// guard is dropped afterwards. [`Self::try_access`] carries the risk that the caller will +    /// forget to explicitly drop that returned guard before calling sleepable code; this method +    /// adds an extra safety to make sure it doesn't happen. +    /// +    /// Returns [`None`] if the object has been revoked and is therefore no longer accessible, or +    /// the result of the closure wrapped in [`Some`]. If the closure returns a [`Result`] then the +    /// return type becomes `Option<Result<>>`, which can be inconvenient. Users are encouraged to +    /// define their own macro that turns the [`Option`] into a proper error code and flattens the +    /// inner result into it if it makes sense within their subsystem. +    pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R> { +        self.try_access().map(|t| f(&*t)) +    } + +    /// Directly access the revocable wrapped object. +    /// +    /// # Safety +    /// +    /// The caller must ensure this [`Revocable`] instance hasn't been revoked and won't be revoked +    /// as long as the returned `&T` lives. +    pub unsafe fn access(&self) -> &T { +        // SAFETY: By the safety requirement of this function it is guaranteed that +        // `self.data.get()` is a valid pointer to an instance of `T`. +        unsafe { &*self.data.get() } +    } +      /// # Safety      ///      /// Callers must ensure that there are no more concurrent users of the revocable object. diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 878111cb77bc..fb61ce81ea28 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -73,7 +73,7 @@ impl fmt::Display for BStr {                  b'\r' => f.write_str("\\r")?,                  // Printable characters.                  0x20..=0x7e => f.write_char(b as char)?, -                _ => write!(f, "\\x{:02x}", b)?, +                _ => write!(f, "\\x{b:02x}")?,              }          }          Ok(()) @@ -109,7 +109,7 @@ impl fmt::Debug for BStr {                  b'\\' => f.write_str("\\\\")?,                  // Printable characters.                  0x20..=0x7e => f.write_char(b as char)?, -                _ => write!(f, "\\x{:02x}", b)?, +                _ => write!(f, "\\x{b:02x}")?,              }          }          f.write_char('"') @@ -447,7 +447,7 @@ impl fmt::Display for CStr {                  // Printable character.                  f.write_char(c as char)?;              } else { -                write!(f, "\\x{:02x}", c)?; +                write!(f, "\\x{c:02x}")?;              }          }          Ok(()) @@ -479,7 +479,7 @@ impl fmt::Debug for CStr {                  // Printable characters.                  b'\"' => f.write_str("\\\"")?,                  0x20..=0x7e => f.write_char(c as char)?, -                _ => write!(f, "\\x{:02x}", c)?, +                _ => write!(f, "\\x{c:02x}")?,              }          }          f.write_str("\"") @@ -641,13 +641,13 @@ mod tests {      #[test]      fn test_cstr_display() {          let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0").unwrap(); -        assert_eq!(format!("{}", hello_world), "hello, world!"); +        assert_eq!(format!("{hello_world}"), "hello, world!");          let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0").unwrap(); -        assert_eq!(format!("{}", non_printables), "\\x01\\x09\\x0a"); +        assert_eq!(format!("{non_printables}"), "\\x01\\x09\\x0a");          let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0").unwrap(); -        assert_eq!(format!("{}", non_ascii), "d\\xe9j\\xe0 vu"); +        assert_eq!(format!("{non_ascii}"), "d\\xe9j\\xe0 vu");          let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0").unwrap(); -        assert_eq!(format!("{}", good_bytes), "\\xf0\\x9f\\xa6\\x80"); +        assert_eq!(format!("{good_bytes}"), "\\xf0\\x9f\\xa6\\x80");      }      #[test] @@ -658,47 +658,47 @@ mod tests {              bytes[i as usize] = i.wrapping_add(1);          }          let cstr = CStr::from_bytes_with_nul(&bytes).unwrap(); -        assert_eq!(format!("{}", cstr), ALL_ASCII_CHARS); +        assert_eq!(format!("{cstr}"), ALL_ASCII_CHARS);      }      #[test]      fn test_cstr_debug() {          let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0").unwrap(); -        assert_eq!(format!("{:?}", hello_world), "\"hello, world!\""); +        assert_eq!(format!("{hello_world:?}"), "\"hello, world!\"");          let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0").unwrap(); -        assert_eq!(format!("{:?}", non_printables), "\"\\x01\\x09\\x0a\""); +        assert_eq!(format!("{non_printables:?}"), "\"\\x01\\x09\\x0a\"");          let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0").unwrap(); -        assert_eq!(format!("{:?}", non_ascii), "\"d\\xe9j\\xe0 vu\""); +        assert_eq!(format!("{non_ascii:?}"), "\"d\\xe9j\\xe0 vu\"");          let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0").unwrap(); -        assert_eq!(format!("{:?}", good_bytes), "\"\\xf0\\x9f\\xa6\\x80\""); +        assert_eq!(format!("{good_bytes:?}"), "\"\\xf0\\x9f\\xa6\\x80\"");      }      #[test]      fn test_bstr_display() {          let hello_world = BStr::from_bytes(b"hello, world!"); -        assert_eq!(format!("{}", hello_world), "hello, world!"); +        assert_eq!(format!("{hello_world}"), "hello, world!");          let escapes = BStr::from_bytes(b"_\t_\n_\r_\\_\'_\"_"); -        assert_eq!(format!("{}", escapes), "_\\t_\\n_\\r_\\_'_\"_"); +        assert_eq!(format!("{escapes}"), "_\\t_\\n_\\r_\\_'_\"_");          let others = BStr::from_bytes(b"\x01"); -        assert_eq!(format!("{}", others), "\\x01"); +        assert_eq!(format!("{others}"), "\\x01");          let non_ascii = BStr::from_bytes(b"d\xe9j\xe0 vu"); -        assert_eq!(format!("{}", non_ascii), "d\\xe9j\\xe0 vu"); +        assert_eq!(format!("{non_ascii}"), "d\\xe9j\\xe0 vu");          let good_bytes = BStr::from_bytes(b"\xf0\x9f\xa6\x80"); -        assert_eq!(format!("{}", good_bytes), "\\xf0\\x9f\\xa6\\x80"); +        assert_eq!(format!("{good_bytes}"), "\\xf0\\x9f\\xa6\\x80");      }      #[test]      fn test_bstr_debug() {          let hello_world = BStr::from_bytes(b"hello, world!"); -        assert_eq!(format!("{:?}", hello_world), "\"hello, world!\""); +        assert_eq!(format!("{hello_world:?}"), "\"hello, world!\"");          let escapes = BStr::from_bytes(b"_\t_\n_\r_\\_\'_\"_"); -        assert_eq!(format!("{:?}", escapes), "\"_\\t_\\n_\\r_\\\\_'_\\\"_\""); +        assert_eq!(format!("{escapes:?}"), "\"_\\t_\\n_\\r_\\\\_'_\\\"_\"");          let others = BStr::from_bytes(b"\x01"); -        assert_eq!(format!("{:?}", others), "\"\\x01\""); +        assert_eq!(format!("{others:?}"), "\"\\x01\"");          let non_ascii = BStr::from_bytes(b"d\xe9j\xe0 vu"); -        assert_eq!(format!("{:?}", non_ascii), "\"d\\xe9j\\xe0 vu\""); +        assert_eq!(format!("{non_ascii:?}"), "\"d\\xe9j\\xe0 vu\"");          let good_bytes = BStr::from_bytes(b"\xf0\x9f\xa6\x80"); -        assert_eq!(format!("{:?}", good_bytes), "\"\\xf0\\x9f\\xa6\\x80\""); +        assert_eq!(format!("{good_bytes:?}"), "\"\\xf0\\x9f\\xa6\\x80\"");      }  } diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs index b51d9150ffe2..a32bef6e490b 100644 --- a/rust/kernel/sync/rcu.rs +++ b/rust/kernel/sync/rcu.rs @@ -17,6 +17,7 @@ pub struct Guard(NotThreadSafe);  impl Guard {      /// Acquires the RCU read side lock and returns a guard. +    #[inline]      pub fn new() -> Self {          // SAFETY: An FFI call with no additional requirements.          unsafe { bindings::rcu_read_lock() }; @@ -25,16 +26,19 @@ impl Guard {      }      /// Explicitly releases the RCU read side lock. +    #[inline]      pub fn unlock(self) {}  }  impl Default for Guard { +    #[inline]      fn default() -> Self {          Self::new()      }  }  impl Drop for Guard { +    #[inline]      fn drop(&mut self) {          // SAFETY: By the type invariants, the RCU read side is locked, so it is ok to unlock it.          unsafe { bindings::rcu_read_unlock() }; @@ -42,6 +46,7 @@ impl Drop for Guard {  }  /// Acquires the RCU read side lock. +#[inline]  pub fn read_lock() -> Guard {      Guard::new()  } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9d0471afc964..eee387727d1a 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -329,6 +329,14 @@ impl<T> Opaque<T> {          }      } +    /// Creates a new zeroed opaque value. +    pub const fn zeroed() -> Self { +        Self { +            value: UnsafeCell::new(MaybeUninit::zeroed()), +            _pin: PhantomPinned, +        } +    } +      /// Create an opaque pin-initializer from the given pin-initializer.      pub fn pin_init(slot: impl PinInit<T>) -> impl PinInit<Self> {          Self::ffi_init(|ptr: *mut T| { | 
