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::{
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 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}