File Index
Files and directories
Sign in
FILE

resource.rs

File preview with syntax highlighting.

linux-6.19.14/rust/kernel/io/resource.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3//! Abstractions for [system
  4//! resources](https://docs.kernel.org/core-api/kernel-api.html#resources-management).
  5//!
  6//! C header: [`include/linux/ioport.h`](srctree/include/linux/ioport.h)
  7
  8use core::{
  9    ops::Deref,
 10    ptr::NonNull, //
 11};
 12
 13use crate::{
 14    prelude::*,
 15    str::CString,
 16    types::Opaque, //
 17};
 18
 19pub use super::{
 20    PhysAddr,
 21    ResourceSize, //
 22};
 23
 24/// A region allocated from a parent [`Resource`].
 25///
 26/// # Invariants
 27///
 28/// - `self.0` points to a valid `bindings::resource` that was obtained through
 29///   `bindings::__request_region`.
 30pub struct Region {
 31    /// The resource returned when the region was requested.
 32    resource: NonNull<bindings::resource>,
 33    /// The name that was passed in when the region was requested. We need to
 34    /// store it for ownership reasons.
 35    _name: CString,
 36}
 37
 38impl Deref for Region {
 39    type Target = Resource;
 40
 41    fn deref(&self) -> &Self::Target {
 42        // SAFETY: Safe as per the invariant of `Region`.
 43        unsafe { Resource::from_raw(self.resource.as_ptr()) }
 44    }
 45}
 46
 47impl Drop for Region {
 48    fn drop(&mut self) {
 49        let (flags, start, size) = {
 50            let res = &**self;
 51            (res.flags(), res.start(), res.size())
 52        };
 53
 54        let release_fn = if flags.contains(Flags::IORESOURCE_MEM) {
 55            bindings::release_mem_region
 56        } else {
 57            bindings::release_region
 58        };
 59
 60        // SAFETY: Safe as per the invariant of `Region`.
 61        unsafe { release_fn(start, size) };
 62    }
 63}
 64
 65// SAFETY: `Region` only holds a pointer to a C `struct resource`, which is safe to be used from
 66// any thread.
 67unsafe impl Send for Region {}
 68
 69// SAFETY: `Region` only holds a pointer to a C `struct resource`, references to which are
 70// safe to be used from any thread.
 71unsafe impl Sync for Region {}
 72
 73/// A resource abstraction.
 74///
 75/// # Invariants
 76///
 77/// [`Resource`] is a transparent wrapper around a valid `bindings::resource`.
 78#[repr(transparent)]
 79pub struct Resource(Opaque<bindings::resource>);
 80
 81impl Resource {
 82    /// Creates a reference to a [`Resource`] from a valid pointer.
 83    ///
 84    /// # Safety
 85    ///
 86    /// The caller must ensure that for the duration of 'a, the pointer will
 87    /// point at a valid `bindings::resource`.
 88    ///
 89    /// The caller must also ensure that the [`Resource`] is only accessed via the
 90    /// returned reference for the duration of 'a.
 91    pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::resource) -> &'a Self {
 92        // SAFETY: Self is a transparent wrapper around `Opaque<bindings::resource>`.
 93        unsafe { &*ptr.cast() }
 94    }
 95
 96    /// Requests a resource region.
 97    ///
 98    /// Exclusive access will be given and the region will be marked as busy.
 99    /// Further calls to [`Self::request_region`] will return [`None`] if
100    /// the region, or a part of it, is already in use.
101    pub fn request_region(
102        &self,
103        start: PhysAddr,
104        size: ResourceSize,
105        name: CString,
106        flags: Flags,
107    ) -> Option<Region> {
108        // SAFETY:
109        // - Safe as per the invariant of `Resource`.
110        // - `__request_region` will store a reference to the name, but that is
111        // safe as we own it and it will not be dropped until the `Region` is
112        // dropped.
113        let region = unsafe {
114            bindings::__request_region(
115                self.0.get(),
116                start,
117                size,
118                name.as_char_ptr(),
119                flags.0 as c_int,
120            )
121        };
122
123        Some(Region {
124            resource: NonNull::new(region)?,
125            _name: name,
126        })
127    }
128
129    /// Returns the size of the resource.
130    pub fn size(&self) -> ResourceSize {
131        let inner = self.0.get();
132        // SAFETY: Safe as per the invariants of `Resource`.
133        unsafe { bindings::resource_size(inner) }
134    }
135
136    /// Returns the start address of the resource.
137    pub fn start(&self) -> PhysAddr {
138        let inner = self.0.get();
139        // SAFETY: Safe as per the invariants of `Resource`.
140        unsafe { (*inner).start }
141    }
142
143    /// Returns the name of the resource.
144    pub fn name(&self) -> Option<&CStr> {
145        let inner = self.0.get();
146
147        // SAFETY: Safe as per the invariants of `Resource`.
148        let name = unsafe { (*inner).name };
149
150        if name.is_null() {
151            return None;
152        }
153
154        // SAFETY: In the C code, `resource::name` either contains a null
155        // pointer or points to a valid NUL-terminated C string, and at this
156        // point we know it is not null, so we can safely convert it to a
157        // `CStr`.
158        Some(unsafe { CStr::from_char_ptr(name) })
159    }
160
161    /// Returns the flags associated with the resource.
162    pub fn flags(&self) -> Flags {
163        let inner = self.0.get();
164        // SAFETY: Safe as per the invariants of `Resource`.
165        let flags = unsafe { (*inner).flags };
166
167        Flags(flags)
168    }
169}
170
171// SAFETY: `Resource` only holds a pointer to a C `struct resource`, which is
172// safe to be used from any thread.
173unsafe impl Send for Resource {}
174
175// SAFETY: `Resource` only holds a pointer to a C `struct resource`, references
176// to which are safe to be used from any thread.
177unsafe impl Sync for Resource {}
178
179/// Resource flags as stored in the C `struct resource::flags` field.
180///
181/// They can be combined with the operators `|`, `&`, and `!`.
182///
183/// Values can be used from the associated constants such as
184/// [`Flags::IORESOURCE_IO`].
185#[derive(Clone, Copy, PartialEq)]
186pub struct Flags(c_ulong);
187
188impl Flags {
189    /// Check whether `flags` is contained in `self`.
190    pub fn contains(self, flags: Flags) -> bool {
191        (self & flags) == flags
192    }
193}
194
195impl core::ops::BitOr for Flags {
196    type Output = Self;
197    fn bitor(self, rhs: Self) -> Self::Output {
198        Self(self.0 | rhs.0)
199    }
200}
201
202impl core::ops::BitAnd for Flags {
203    type Output = Self;
204    fn bitand(self, rhs: Self) -> Self::Output {
205        Self(self.0 & rhs.0)
206    }
207}
208
209impl core::ops::Not for Flags {
210    type Output = Self;
211    fn not(self) -> Self::Output {
212        Self(!self.0)
213    }
214}
215
216impl Flags {
217    /// PCI/ISA I/O ports.
218    pub const IORESOURCE_IO: Flags = Flags::new(bindings::IORESOURCE_IO);
219
220    /// Resource is software muxed.
221    pub const IORESOURCE_MUXED: Flags = Flags::new(bindings::IORESOURCE_MUXED);
222
223    /// Resource represents a memory region.
224    pub const IORESOURCE_MEM: Flags = Flags::new(bindings::IORESOURCE_MEM);
225
226    /// Resource represents a memory region that must be ioremaped using `ioremap_np`.
227    pub const IORESOURCE_MEM_NONPOSTED: Flags = Flags::new(bindings::IORESOURCE_MEM_NONPOSTED);
228
229    // Always inline to optimize out error path of `build_assert`.
230    #[inline(always)]
231    const fn new(value: u32) -> Self {
232        crate::build_assert!(value as u64 <= c_ulong::MAX as u64);
233        Flags(value as c_ulong)
234    }
235}
~/ Read-only file preview.