235 lines · 6.8 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 //! Abstractions for [system//! resources](https://docs.kernel.org/core-api/kernel-api.html#resources-management).//!//! C header: [`include/linux/ioport.h`](srctree/include/linux/ioport.h) use core::{    ops::Deref,    ptr::NonNull, //}; use crate::{    prelude::*,    str::CString,    types::Opaque, //}; pub use super::{    PhysAddr,    ResourceSize, //}; /// A region allocated from a parent [`Resource`].////// # Invariants////// - `self.0` points to a valid `bindings::resource` that was obtained through///   `bindings::__request_region`.pub struct Region {    /// The resource returned when the region was requested.    resource: NonNull<bindings::resource>,    /// The name that was passed in when the region was requested. We need to    /// store it for ownership reasons.    _name: CString,} impl Deref for Region {    type Target = Resource;     fn deref(&self) -> &Self::Target {        // SAFETY: Safe as per the invariant of `Region`.        unsafe { Resource::from_raw(self.resource.as_ptr()) }    }} impl Drop for Region {    fn drop(&mut self) {        let (flags, start, size) = {            let res = &**self;            (res.flags(), res.start(), res.size())        };         let release_fn = if flags.contains(Flags::IORESOURCE_MEM) {            bindings::release_mem_region        } else {            bindings::release_region        };         // SAFETY: Safe as per the invariant of `Region`.        unsafe { release_fn(start, size) };    }} // SAFETY: `Region` only holds a pointer to a C `struct resource`, which is safe to be used from// any thread.unsafe impl Send for Region {} // SAFETY: `Region` only holds a pointer to a C `struct resource`, references to which are// safe to be used from any thread.unsafe impl Sync for Region {} /// A resource abstraction.////// # Invariants////// [`Resource`] is a transparent wrapper around a valid `bindings::resource`.#[repr(transparent)]pub struct Resource(Opaque<bindings::resource>); impl Resource {    /// Creates a reference to a [`Resource`] from a valid pointer.    ///    /// # Safety    ///    /// The caller must ensure that for the duration of 'a, the pointer will    /// point at a valid `bindings::resource`.    ///    /// The caller must also ensure that the [`Resource`] is only accessed via the    /// returned reference for the duration of 'a.    pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::resource) -> &'a Self {        // SAFETY: Self is a transparent wrapper around `Opaque<bindings::resource>`.        unsafe { &*ptr.cast() }    }     /// Requests a resource region.    ///    /// Exclusive access will be given and the region will be marked as busy.    /// Further calls to [`Self::request_region`] will return [`None`] if    /// the region, or a part of it, is already in use.    pub fn request_region(        &self,        start: PhysAddr,        size: ResourceSize,        name: CString,        flags: Flags,    ) -> Option<Region> {        // SAFETY:        // - Safe as per the invariant of `Resource`.        // - `__request_region` will store a reference to the name, but that is        // safe as we own it and it will not be dropped until the `Region` is        // dropped.        let region = unsafe {            bindings::__request_region(                self.0.get(),                start,                size,                name.as_char_ptr(),                flags.0 as c_int,            )        };         Some(Region {            resource: NonNull::new(region)?,            _name: name,        })    }     /// Returns the size of the resource.    pub fn size(&self) -> ResourceSize {        let inner = self.0.get();        // SAFETY: Safe as per the invariants of `Resource`.        unsafe { bindings::resource_size(inner) }    }     /// Returns the start address of the resource.    pub fn start(&self) -> PhysAddr {        let inner = self.0.get();        // SAFETY: Safe as per the invariants of `Resource`.        unsafe { (*inner).start }    }     /// Returns the name of the resource.    pub fn name(&self) -> Option<&CStr> {        let inner = self.0.get();         // SAFETY: Safe as per the invariants of `Resource`.        let name = unsafe { (*inner).name };         if name.is_null() {            return None;        }         // SAFETY: In the C code, `resource::name` either contains a null        // pointer or points to a valid NUL-terminated C string, and at this        // point we know it is not null, so we can safely convert it to a        // `CStr`.        Some(unsafe { CStr::from_char_ptr(name) })    }     /// Returns the flags associated with the resource.    pub fn flags(&self) -> Flags {        let inner = self.0.get();        // SAFETY: Safe as per the invariants of `Resource`.        let flags = unsafe { (*inner).flags };         Flags(flags)    }} // SAFETY: `Resource` only holds a pointer to a C `struct resource`, which is// safe to be used from any thread.unsafe impl Send for Resource {} // SAFETY: `Resource` only holds a pointer to a C `struct resource`, references// to which are safe to be used from any thread.unsafe impl Sync for Resource {} /// Resource flags as stored in the C `struct resource::flags` field.////// They can be combined with the operators `|`, `&`, and `!`.////// Values can be used from the associated constants such as/// [`Flags::IORESOURCE_IO`].#[derive(Clone, Copy, PartialEq)]pub struct Flags(c_ulong); impl Flags {    /// Check whether `flags` is contained in `self`.    pub fn contains(self, flags: Flags) -> bool {        (self & flags) == flags    }} impl core::ops::BitOr for Flags {    type Output = Self;    fn bitor(self, rhs: Self) -> Self::Output {        Self(self.0 | rhs.0)    }} impl core::ops::BitAnd for Flags {    type Output = Self;    fn bitand(self, rhs: Self) -> Self::Output {        Self(self.0 & rhs.0)    }} impl core::ops::Not for Flags {    type Output = Self;    fn not(self) -> Self::Output {        Self(!self.0)    }} impl Flags {    /// PCI/ISA I/O ports.    pub const IORESOURCE_IO: Flags = Flags::new(bindings::IORESOURCE_IO);     /// Resource is software muxed.    pub const IORESOURCE_MUXED: Flags = Flags::new(bindings::IORESOURCE_MUXED);     /// Resource represents a memory region.    pub const IORESOURCE_MEM: Flags = Flags::new(bindings::IORESOURCE_MEM);     /// Resource represents a memory region that must be ioremaped using `ioremap_np`.    pub const IORESOURCE_MEM_NONPOSTED: Flags = Flags::new(bindings::IORESOURCE_MEM_NONPOSTED);     // Always inline to optimize out error path of `build_assert`.    #[inline(always)]    const fn new(value: u32) -> Self {        build_assert!(value as u64 <= c_ulong::MAX as u64);        Flags(value as c_ulong)    }}