ostd/cpu/id.rs
1// SPDX-License-Identifier: MPL-2.0
2
3//! CPU identification numbers.
4
5pub use current::PinCurrentCpu;
6pub use set::{AtomicCpuSet, CpuSet};
7
8use crate::util::id_set::Id;
9
10/// The ID of a CPU in the system.
11///
12/// If converting from/to an integer, the integer must start from 0 and be less
13/// than the number of CPUs.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct CpuId(u32);
16
17impl CpuId {
18 /// Creates a new instance.
19 ///
20 /// # Panics
21 ///
22 /// The given number must be smaller than the total number of CPUs
23 /// (`ostd::cpu::num_cpus()`).
24 pub fn new(raw_id: u32) -> Self {
25 assert!(raw_id < num_cpus() as u32);
26 // SAFETY: The raw ID is smaller than `num_cpus()`.
27 unsafe { Self::new_unchecked(raw_id) }
28 }
29
30 /// Returns the CPU ID of the bootstrap processor (BSP).
31 ///
32 /// The number for the BSP is always zero.
33 pub const fn bsp() -> Self {
34 // BSP's `CURRENT_CPU` is assigned a value of 0.
35 let bsp_raw_cpu_id = 0;
36 // SAFETY: There is at least one CPU.
37 Self(bsp_raw_cpu_id)
38 }
39}
40
41impl From<CpuId> for u32 {
42 fn from(cpu_id: CpuId) -> Self {
43 cpu_id.0
44 }
45}
46
47/// The error type returned when converting an out-of-range integer to [`CpuId`].
48#[derive(Debug, Clone, Copy)]
49pub struct CpuIdFromIntError;
50
51impl TryFrom<usize> for CpuId {
52 type Error = CpuIdFromIntError;
53
54 fn try_from(raw_id: usize) -> Result<Self, Self::Error> {
55 if raw_id < num_cpus() {
56 // SAFETY: The raw ID is smaller than `num_cpus()`.
57 let new_self = unsafe { CpuId::new_unchecked(raw_id as u32) };
58 Ok(new_self)
59 } else {
60 Err(CpuIdFromIntError)
61 }
62 }
63}
64
65/// Returns the number of CPUs.
66pub fn num_cpus() -> usize {
67 // SAFETY: As far as the safe APIs are concerned, `NUM_CPUS` is
68 // read-only, so it is always valid to read.
69 (unsafe { NUM_CPUS }) as usize
70}
71
72static mut NUM_CPUS: u32 = 1;
73
74/// Returns an iterator over all CPUs.
75pub fn all_cpus() -> impl Iterator<Item = CpuId> {
76 (0..num_cpus()).map(|raw_id| {
77 // SAFETY: The raw ID is smaller than `num_cpus()`.
78 unsafe { CpuId::new_unchecked(raw_id as u32) }
79 })
80}
81
82mod set {
83 use super::{CpuId, num_cpus};
84 use crate::util::id_set::{AtomicIdSet, Id, IdSet};
85
86 /// A set of CPU IDs.
87 pub type CpuSet = IdSet<CpuId>;
88
89 /// A set of CPU IDs, with support for concurrent access.
90 pub type AtomicCpuSet = AtomicIdSet<CpuId>;
91
92 // SAFETY: `CpuId`s and the integers within 0 to `num_cpus` (exclusive)
93 // have 1:1 mapping.
94 unsafe impl Id for CpuId {
95 unsafe fn new_unchecked(raw_id: u32) -> Self {
96 Self(raw_id)
97 }
98
99 fn cardinality() -> u32 {
100 num_cpus() as u32
101 }
102 }
103}
104
105mod current {
106 //! The current CPU ID.
107
108 use super::CpuId;
109 use crate::{cpu_local_cell, task::atomic_mode::InAtomicMode, util::id_set::Id};
110
111 /// A marker trait for guard types that can "pin" the current task to the
112 /// current CPU.
113 ///
114 /// Such guard types include [`DisabledLocalIrqGuard`] and
115 /// [`DisabledPreemptGuard`]. When such guards exist, the CPU executing the
116 /// current task is pinned. So getting the current CPU ID or CPU-local
117 /// variables are safe.
118 ///
119 /// # Safety
120 ///
121 /// The implementor must ensure that the current task is pinned to the current
122 /// CPU while any one of the instances of the implemented structure exists.
123 ///
124 /// [`DisabledLocalIrqGuard`]: crate::irq::DisabledLocalIrqGuard
125 /// [`DisabledPreemptGuard`]: crate::task::DisabledPreemptGuard
126 pub unsafe trait PinCurrentCpu {
127 /// Returns the ID of the current CPU.
128 fn current_cpu(&self) -> CpuId {
129 CpuId::current_racy()
130 }
131 }
132
133 // SAFETY: A guard that enforces the atomic mode requires disabling any
134 // context switching. So naturally, the current task is pinned on the CPU.
135 unsafe impl<T: InAtomicMode> PinCurrentCpu for T {}
136 unsafe impl PinCurrentCpu for dyn InAtomicMode + '_ {}
137
138 impl CpuId {
139 /// Returns the ID of the current CPU.
140 ///
141 /// This function is safe to call, but is vulnerable to races. The returned CPU
142 /// ID may be outdated if the task migrates to another CPU.
143 ///
144 /// To ensure that the CPU ID is up-to-date, do it under any guards that
145 /// implement the [`PinCurrentCpu`] trait.
146 pub fn current_racy() -> Self {
147 #[cfg(debug_assertions)]
148 assert!(IS_CURRENT_CPU_INITED.load());
149
150 let current_raw_id = CURRENT_CPU.load();
151 // SAFETY: The CPU-local value is initialized to a correct one.
152 unsafe { Self::new_unchecked(current_raw_id) }
153 }
154 }
155
156 /// Initializes the module on the current CPU.
157 ///
158 /// Note that this method will use the current CPU's CPU-local storage.
159 ///
160 /// # Safety
161 ///
162 /// The caller must ensure:
163 /// 1. This method is called on each CPU in the boot context.
164 /// 2. The CPU ID for the current CPU is correct.
165 pub(super) unsafe fn init_on_cpu(current_cpu_id: u32) {
166 // FIXME: If there are safe APIs that rely on the correctness of
167 // the CPU ID for soundness, we'd better make the CPU ID a global
168 // invariant and initialize it before entering `ap_early_entry`.
169 CURRENT_CPU.store(current_cpu_id);
170
171 #[cfg(debug_assertions)]
172 IS_CURRENT_CPU_INITED.store(true);
173 }
174
175 cpu_local_cell! {
176 /// The current CPU ID.
177 pub(super) static CURRENT_CPU: u32 = 0;
178 /// The initialization state of the current CPU ID.
179 #[cfg(debug_assertions)]
180 pub(super) static IS_CURRENT_CPU_INITED: bool = false;
181 }
182}
183
184/// Initializes the CPU ID module (the BSP part).
185///
186/// Note that this method will use the BSP's CPU-local storage.
187///
188/// # Safety
189///
190/// The caller must ensure that
191/// 1. We're in the boot context of the BSP and APs have not yet booted.
192/// 2. The number of CPUs is correct.
193pub(super) unsafe fn init_on_bsp(num_cpus: u32) {
194 // SAFETY:
195 // 1. We're in the boot context of the BSP.
196 // 2. The CPU ID of BSP has a value of zero.
197 unsafe { current::init_on_cpu(0) };
198
199 // SAFETY:
200 // 1. We're in the boot context of the BSP and APs have not yet booted.
201 // 2. The number of CPUs is correct.
202 unsafe { init_num_cpus(num_cpus) };
203}
204
205/// Initializes the number of CPUs.
206///
207/// The number of CPUs is a fixed value,
208/// since we don't support CPU hot-plugging.
209///
210/// # Safety
211///
212/// The caller must ensure that
213/// 1. We're in the boot context of the BSP and APs have not yet booted.
214/// 2. The number of CPUs is correct.
215unsafe fn init_num_cpus(num_cpus: u32) {
216 // Thanks to this assertion,
217 // it's only legal to call this function to
218 // increase the number of CPUs from one (the initial value)
219 // to the actual number of CPUs.
220 assert!(num_cpus >= 1);
221
222 // SAFETY: It is safe to mutate this global variable because we
223 // are in the boot context.
224 unsafe { NUM_CPUS = num_cpus };
225}
226
227/// Initializes the CPU ID module (the AP part).
228///
229/// Note that this method will use the BSP's CPU-local storage.
230/// This should be fine
231/// because `crate::cpu::init_on_bsp` must have been invoked before APs boot.
232///
233/// # Safety
234///
235/// The caller must ensure that:
236/// 1. We're in the boot context of an AP.
237/// 2. The CPU ID of the AP is correct.
238pub(super) unsafe fn init_on_ap(cpu_id: u32) {
239 // SAFETY:
240 // 1. We're in the boot context of the AP.
241 // 2. The CPU ID for the AP is correct.
242 unsafe { current::init_on_cpu(cpu_id) };
243}