xref: /linux/rust/kernel/io/resource.rs (revision b61104e7a6349bd2c2b3e2fb3260d87f15eda8f4)
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::{
9     ops::Deref,
10     ptr::NonNull, //
11 };
12 
13 use crate::{
14     prelude::*,
15     str::CString,
16     types::Opaque, //
17 };
18 
19 pub 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`.
30 pub 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 
38 impl 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 
47 impl 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.
67 unsafe 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.
71 unsafe 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)]
79 pub struct Resource(Opaque<bindings::resource>);
80 
81 impl 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.
173 unsafe 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.
177 unsafe 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)]
186 pub struct Flags(c_ulong);
187 
188 impl Flags {
189     /// Check whether `flags` is contained in `self`.
190     pub fn contains(self, flags: Flags) -> bool {
191         (self & flags) == flags
192     }
193 }
194 
195 impl 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 
202 impl 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 
209 impl core::ops::Not for Flags {
210     type Output = Self;
211     fn not(self) -> Self::Output {
212         Self(!self.0)
213     }
214 }
215 
216 impl 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     const fn new(value: u32) -> Self {
230         crate::build_assert!(value as u64 <= c_ulong::MAX as u64);
231         Flags(value as c_ulong)
232     }
233 }
234