xref: /linux/rust/kernel/io/resource.rs (revision 22c5696e3fe029f4fc2decbe7cc6663b5d281223)
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 
8 use core::ops::Deref;
9 use core::ptr::NonNull;
10 
11 use crate::prelude::*;
12 use crate::str::{CStr, CString};
13 use 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.
19 pub 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`.
27 pub 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 
35 impl Deref for Region {
36     type Target = Resource;
37 
deref(&self) -> &Self::Target38     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 
44 impl Drop for Region {
drop(&mut self)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.
64 unsafe 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.
68 unsafe 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)]
76 pub struct Resource(Opaque<bindings::resource>);
77 
78 impl 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.
from_raw<'a>(ptr: *mut bindings::resource) -> &'a Self88     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.
request_region( &self, start: ResourceSize, size: ResourceSize, name: CString, flags: Flags, ) -> Option<Region>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.
size(&self) -> ResourceSize127     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.
start(&self) -> ResourceSize134     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.
name(&self) -> Option<&CStr>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.
flags(&self) -> Flags159     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.
170 unsafe 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.
174 unsafe 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)]
183 pub struct Flags(c_ulong);
184 
185 impl Flags {
186     /// Check whether `flags` is contained in `self`.
contains(self, flags: Flags) -> bool187     pub fn contains(self, flags: Flags) -> bool {
188         (self & flags) == flags
189     }
190 }
191 
192 impl core::ops::BitOr for Flags {
193     type Output = Self;
bitor(self, rhs: Self) -> Self::Output194     fn bitor(self, rhs: Self) -> Self::Output {
195         Self(self.0 | rhs.0)
196     }
197 }
198 
199 impl core::ops::BitAnd for Flags {
200     type Output = Self;
bitand(self, rhs: Self) -> Self::Output201     fn bitand(self, rhs: Self) -> Self::Output {
202         Self(self.0 & rhs.0)
203     }
204 }
205 
206 impl core::ops::Not for Flags {
207     type Output = Self;
not(self) -> Self::Output208     fn not(self) -> Self::Output {
209         Self(!self.0)
210     }
211 }
212 
213 impl 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 
new(value: u32) -> Self226     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 }
231