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)
}
}