// 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, ptr::NonNull, //};use crate::{ prelude::*, str::CString, types::Opaque, //};pub use super::{ PhysAddr, ResourceSize, //};/// 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: PhysAddr, 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) -> PhysAddr { 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); // Always inline to optimize out error path of `build_assert`. #[inline(always)] const fn new(value: u32) -> Self { build_assert!(value as u64 <= c_ulong::MAX as u64); Flags(value as c_ulong) }}
// 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,
ptr::NonNull, //
};
use crate::{
prelude::*,
str::CString,
types::Opaque, //
};
pub use super::{
PhysAddr,
ResourceSize, //
};
/// 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: PhysAddr,
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) -> PhysAddr {
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);
// Always inline to optimize out error path of `build_assert`.
#[inline(always)]
const fn new(value: u32) -> Self {
build_assert!(value as u64 <= c_ulong::MAX as u64);
Flags(value as c_ulong)
}
}