Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/io/resource.rs
29266 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::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
38
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 {
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.
88
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.
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.
127
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.
134
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.
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.
159
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`.
187
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;
194
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;
201
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;
208
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
226
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
232