xref: /linux/rust/kernel/cpu.rs (revision f688b599d711d169b22e99f2d055847d66c4e0d3)
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 
7 use crate::{bindings, device::Device, error::Result, prelude::ENODEV};
8 
9 /// Returns the maximum number of possible CPUs in the current system configuration.
10 #[inline]
nr_cpu_ids() -> u3211 pub 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)]
47 pub struct CpuId(u32);
48 
49 impl 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]
from_i32_unchecked(id: i32) -> Self56     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.
from_i32(id: i32) -> Option<Self>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]
from_u32_unchecked(id: u32) -> Self80     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.
from_u32(id: u32) -> Option<Self>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]
as_u32(&self) -> u32102     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.
current() -> Self112     pub fn current() -> Self {
113         // SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
114         unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) }
115     }
116 }
117 
118 impl From<CpuId> for u32 {
from(id: CpuId) -> Self119     fn from(id: CpuId) -> Self {
120         id.as_u32()
121     }
122 }
123 
124 impl From<CpuId> for i32 {
from(id: CpuId) -> Self125     fn from(id: CpuId) -> Self {
126         id.as_u32() as i32
127     }
128 }
129 
130 /// Creates a new instance of CPU's device.
131 ///
132 /// # Safety
133 ///
134 /// Reference counting is not implemented for the CPU device in the C code. When a CPU is
135 /// hot-unplugged, the corresponding CPU device is unregistered, but its associated memory
136 /// is not freed.
137 ///
138 /// Callers must ensure that the CPU device is not used after it has been unregistered.
139 /// This can be achieved, for example, by registering a CPU hotplug notifier and removing
140 /// any references to the CPU device within the notifier's callback.
from_cpu(cpu: CpuId) -> Result<&'static Device>141 pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> {
142     // SAFETY: It is safe to call `get_cpu_device()` for any CPU.
143     let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) };
144     if ptr.is_null() {
145         return Err(ENODEV);
146     }
147 
148     // SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, is a valid pointer to
149     // a `struct device` and is never freed by the C code.
150     Ok(unsafe { Device::as_ref(ptr) })
151 }
152