kernel/io/
resource.rs

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