Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  resource.rs   Sprache: unbekannt

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

[ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge