Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/io/resource.rs
49082 views
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
// Always inline to optimize out error path of `build_assert`.
230
#[inline(always)]
231
const fn new(value: u32) -> Self {
232
crate::build_assert!(value as u64 <= c_ulong::MAX as u64);
233
Flags(value as c_ulong)
234
}
235
}
236
237