File Index
Files and directories
Sign in
FILE

cpu.rs

File preview with syntax highlighting.

linux-6.19.14/rust/kernel/cpu.rs RUST
  1// SPDX-License-Identifier: GPL-2.0
  2
  3//! Generic CPU definitions.
  4//!
  5//! C header: [`include/linux/cpu.h`](srctree/include/linux/cpu.h)
  6
  7use crate::{bindings, device::Device, error::Result, prelude::ENODEV};
  8
  9/// Returns the maximum number of possible CPUs in the current system configuration.
 10#[inline]
 11pub fn nr_cpu_ids() -> u32 {
 12    #[cfg(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS))]
 13    {
 14        bindings::NR_CPUS
 15    }
 16
 17    #[cfg(not(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS)))]
 18    // SAFETY: `nr_cpu_ids` is a valid global provided by the kernel.
 19    unsafe {
 20        bindings::nr_cpu_ids
 21    }
 22}
 23
 24/// The CPU ID.
 25///
 26/// Represents a CPU identifier as a wrapper around an [`u32`].
 27///
 28/// # Invariants
 29///
 30/// The CPU ID lies within the range `[0, nr_cpu_ids())`.
 31///
 32/// # Examples
 33///
 34/// ```
 35/// use kernel::cpu::CpuId;
 36///
 37/// let cpu = 0;
 38///
 39/// // SAFETY: 0 is always a valid CPU number.
 40/// let id = unsafe { CpuId::from_u32_unchecked(cpu) };
 41///
 42/// assert_eq!(id.as_u32(), cpu);
 43/// assert!(CpuId::from_i32(0).is_some());
 44/// assert!(CpuId::from_i32(-1).is_none());
 45/// ```
 46#[derive(Copy, Clone, PartialEq, Eq, Debug)]
 47pub struct CpuId(u32);
 48
 49impl CpuId {
 50    /// Creates a new [`CpuId`] from the given `id` without checking bounds.
 51    ///
 52    /// # Safety
 53    ///
 54    /// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
 55    #[inline]
 56    pub unsafe fn from_i32_unchecked(id: i32) -> Self {
 57        debug_assert!(id >= 0);
 58        debug_assert!((id as u32) < nr_cpu_ids());
 59
 60        // INVARIANT: The function safety guarantees `id` is a valid CPU id.
 61        Self(id as u32)
 62    }
 63
 64    /// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
 65    pub fn from_i32(id: i32) -> Option<Self> {
 66        if id < 0 || id as u32 >= nr_cpu_ids() {
 67            None
 68        } else {
 69            // INVARIANT: `id` has just been checked as a valid CPU ID.
 70            Some(Self(id as u32))
 71        }
 72    }
 73
 74    /// Creates a new [`CpuId`] from the given `id` without checking bounds.
 75    ///
 76    /// # Safety
 77    ///
 78    /// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
 79    #[inline]
 80    pub unsafe fn from_u32_unchecked(id: u32) -> Self {
 81        debug_assert!(id < nr_cpu_ids());
 82
 83        // Ensure the `id` fits in an [`i32`] as it's also representable that way.
 84        debug_assert!(id <= i32::MAX as u32);
 85
 86        // INVARIANT: The function safety guarantees `id` is a valid CPU id.
 87        Self(id)
 88    }
 89
 90    /// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
 91    pub fn from_u32(id: u32) -> Option<Self> {
 92        if id >= nr_cpu_ids() {
 93            None
 94        } else {
 95            // INVARIANT: `id` has just been checked as a valid CPU ID.
 96            Some(Self(id))
 97        }
 98    }
 99
100    /// Returns CPU number.
101    #[inline]
102    pub fn as_u32(&self) -> u32 {
103        self.0
104    }
105
106    /// Returns the ID of the CPU the code is currently running on.
107    ///
108    /// The returned value is considered unstable because it may change
109    /// unexpectedly due to preemption or CPU migration. It should only be
110    /// used when the context ensures that the task remains on the same CPU
111    /// or the users could use a stale (yet valid) CPU ID.
112    #[inline]
113    pub fn current() -> Self {
114        // SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
115        unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) }
116    }
117}
118
119impl From<CpuId> for u32 {
120    fn from(id: CpuId) -> Self {
121        id.as_u32()
122    }
123}
124
125impl From<CpuId> for i32 {
126    fn from(id: CpuId) -> Self {
127        id.as_u32() as i32
128    }
129}
130
131/// Creates a new instance of CPU's device.
132///
133/// # Safety
134///
135/// Reference counting is not implemented for the CPU device in the C code. When a CPU is
136/// hot-unplugged, the corresponding CPU device is unregistered, but its associated memory
137/// is not freed.
138///
139/// Callers must ensure that the CPU device is not used after it has been unregistered.
140/// This can be achieved, for example, by registering a CPU hotplug notifier and removing
141/// any references to the CPU device within the notifier's callback.
142pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> {
143    // SAFETY: It is safe to call `get_cpu_device()` for any CPU.
144    let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) };
145    if ptr.is_null() {
146        return Err(ENODEV);
147    }
148
149    // SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, is a valid pointer to
150    // a `struct device` and is never freed by the C code.
151    Ok(unsafe { Device::from_raw(ptr) })
152}
~/ Read-only file preview.