kernel/cpu.rs
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};
8use safety_macro::safety;
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 #[safety{ValidNum}]
56 #[inline]
57 pub unsafe fn from_i32_unchecked(id: i32) -> Self {
58 debug_assert!(id >= 0);
59 debug_assert!((id as u32) < nr_cpu_ids());
60
61 // INVARIANT: The function safety guarantees `id` is a valid CPU id.
62 Self(id as u32)
63 }
64
65 /// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
66 pub fn from_i32(id: i32) -> Option<Self> {
67 if id < 0 || id as u32 >= nr_cpu_ids() {
68 None
69 } else {
70 // INVARIANT: `id` has just been checked as a valid CPU ID.
71 Some(Self(id as u32))
72 }
73 }
74
75 /// Creates a new [`CpuId`] from the given `id` without checking bounds.
76 ///
77 /// # Safety
78 ///
79 /// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
80 #[safety{ValidNum}]
81 #[inline]
82 pub unsafe fn from_u32_unchecked(id: u32) -> Self {
83 debug_assert!(id < nr_cpu_ids());
84
85 // Ensure the `id` fits in an [`i32`] as it's also representable that way.
86 debug_assert!(id <= i32::MAX as u32);
87
88 // INVARIANT: The function safety guarantees `id` is a valid CPU id.
89 Self(id)
90 }
91
92 /// Creates a new [`CpuId`] from the given `id`, checking that it is valid.
93 pub fn from_u32(id: u32) -> Option<Self> {
94 if id >= nr_cpu_ids() {
95 None
96 } else {
97 // INVARIANT: `id` has just been checked as a valid CPU ID.
98 Some(Self(id))
99 }
100 }
101
102 /// Returns CPU number.
103 #[inline]
104 pub fn as_u32(&self) -> u32 {
105 self.0
106 }
107
108 /// Returns the ID of the CPU the code is currently running on.
109 ///
110 /// The returned value is considered unstable because it may change
111 /// unexpectedly due to preemption or CPU migration. It should only be
112 /// used when the context ensures that the task remains on the same CPU
113 /// or the users could use a stale (yet valid) CPU ID.
114 #[inline]
115 pub fn current() -> Self {
116 // SAFETY: raw_smp_processor_id() always returns a valid CPU ID.
117 unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) }
118 }
119}
120
121impl From<CpuId> for u32 {
122 fn from(id: CpuId) -> Self {
123 id.as_u32()
124 }
125}
126
127impl From<CpuId> for i32 {
128 fn from(id: CpuId) -> Self {
129 id.as_u32() as i32
130 }
131}
132
133/// Creates a new instance of CPU's device.
134///
135/// # Safety
136///
137/// Reference counting is not implemented for the CPU device in the C code. When a CPU is
138/// hot-unplugged, the corresponding CPU device is unregistered, but its associated memory
139/// is not freed.
140///
141/// Callers must ensure that the CPU device is not used after it has been unregistered.
142/// This can be achieved, for example, by registering a CPU hotplug notifier and removing
143/// any references to the CPU device within the notifier's callback.
144#[safety{MayInvalid(Device)}]
145pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> {
146 // SAFETY: It is safe to call `get_cpu_device()` for any CPU.
147 let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) };
148 if ptr.is_null() {
149 return Err(ENODEV);
150 }
151
152 // SAFETY: The pointer returned by `get_cpu_device()`, if not `NULL`, is a valid pointer to
153 // a `struct device` and is never freed by the C code.
154 Ok(unsafe { Device::from_raw(ptr) })
155}