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