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