ostd/cpu/mod.rs
1// SPDX-License-Identifier: MPL-2.0
2//! CPU-related definitions.
3use vstd::{prelude::*, std_specs::convert::TryFromSpecImpl};
4
5// pub mod local;
6pub mod set;
7
8pub use set::{AtomicCpuSet, CpuSet};
9
10// pub use crate::arch::cpu::*;
11// use crate::{cpu_local_cell, task::atomic_mode::InAtomicMode};
12
13/// The ID of a CPU in the system.
14///
15/// If converting from/to an integer, the integer must start from 0 and be less
16/// than the number of CPUs.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[verifier::allow(autoderive_clone_without_spec)]
19#[verus_verify]
20pub struct CpuId(u32);
21
22impl CpuId {
23 /// Returns the CPU ID of the bootstrap processor (BSP).
24 pub const fn bsp() -> Self {
25 CpuId(0)
26 }
27
28 /// Converts the CPU ID to an `usize`.
29 #[verus_verify(dual_spec, closed)]
30 #[verus_spec(r => ensures r == self@, returns self.as_usize())]
31 pub const fn as_usize(self) -> usize {
32 self.0 as usize
33 }
34
35 /* /// Returns the ID of the current CPU.
36 ///
37 /// This function is safe to call, but is vulnerable to races. The returned CPU
38 /// ID may be outdated if the task migrates to another CPU.
39 ///
40 /// To ensure that the CPU ID is up-to-date, do it under any guards that
41 /// implement the [`PinCurrentCpu`] trait.
42 pub fn current_racy() -> Self {
43 #[cfg(debug_assertions)]
44 assert!(IS_CURRENT_CPU_INITED.load());
45
46 Self(CURRENT_CPU.load())
47 } */
48}
49
50/// The error type returned when converting an out-of-range integer to [`CpuId`].
51#[derive(Debug, Clone, Copy)]
52#[verus_verify]
53pub struct CpuIdFromIntError;
54
55#[verus_verify]
56impl TryFrom<usize> for CpuId {
57 type Error = CpuIdFromIntError;
58
59 #[verus_spec(ret =>
60 ensures
61 ret matches Ok(id) ==> id@ == value && cpu_count() > value,
62 cpu_count() > value ==> ret is Ok,
63 )]
64 fn try_from(value: usize) -> Result<Self, Self::Error> {
65 proof! {
66 broadcast use { axiom_cpu_count_bounds };
67 }
68 if value < num_cpus() {
69 Ok(CpuId(value as u32))
70 } else {
71 Err(CpuIdFromIntError)
72 }
73 }
74}
75
76/// The number of CPUs.
77static mut NUM_CPUS: u32 = 1;
78
79/// Initializes the number of CPUs.
80///
81/// # Safety
82///
83/// The caller must ensure that
84/// 1. We're in the boot context of the BSP and APs have not yet booted.
85/// 2. The argument is the correct value of the number of CPUs (which
86/// is a constant, since we don't support CPU hot-plugging anyway).
87unsafe fn init_num_cpus(num_cpus: u32) {
88 assert!(num_cpus >= 1);
89
90 // SAFETY: It is safe to mutate this global variable because we
91 // are in the boot context.
92 unsafe { NUM_CPUS = num_cpus };
93
94 // Note that decreasing the number of CPUs may break existing
95 // `CpuId`s (which have a type invariant to say that the ID is
96 // less than the number of CPUs).
97 //
98 // However, this never happens: due to the safety conditions
99 // it's only legal to call this function to increase the number
100 // of CPUs from one (the initial value) to the actual number of
101 // CPUs.
102}
103
104/// Returns the number of CPUs.
105#[verus_verify(external_body)]
106#[verus_spec(
107 returns cpu_count() as usize,
108)]
109pub fn num_cpus() -> usize {
110 // SAFETY: As far as the safe APIs are concerned, `NUM_CPUS` is
111 // read-only, so it is always valid to read.
112 (unsafe { NUM_CPUS }) as usize
113}
114
115/// Returns an iterator over all CPUs.
116pub fn all_cpus() -> impl Iterator<Item = CpuId> {
117 (0..num_cpus()).map(|id| CpuId(id as u32))
118}
119
120verus! {
121
122/// The underlying numeric CPU id.
123impl View for CpuId {
124 type V = int;
125
126 closed spec fn view(&self) -> int {
127 self.0 as int
128 }
129}
130
131/// The trusted value of the system CPU count. The exec reads `NUM_CPUS`, a `u32`
132/// initialized to 1 and set once at boot (never decreased, no hot-plug), so it is a
133/// stable constant; Verus cannot mention an `exec static` in a spec, so this uninterp
134/// is the explicit specification boundary (mirrors io_port's num_cpus-style pattern).
135pub uninterp spec fn cpu_count() -> int;
136
137/// The count is a positive value that fits a `u32` (the exec reads `static NUM_CPUS: u32`),
138/// hence also a `usize`; the `u32` bound is what lets a `CpuSet` bitset fit in its backing
139/// `SmallVec` without overflowing `isize::MAX`.
140pub broadcast axiom fn axiom_cpu_count_bounds()
141 ensures
142 #![trigger cpu_count()]
143 1 <= cpu_count() <= u32::MAX,
144;
145
146impl CpuId {
147 /// A CPU id is always in the range of CPUs present in the system.
148 #[verifier::type_invariant]
149 pub closed spec fn type_inv(self) -> bool {
150 0 <= self@ < cpu_count()
151 }
152}
153
154/// The `CpuId` at numeric index `i`.
155pub closed spec fn cpu_id_from_index(i: int) -> CpuId {
156 CpuId(i as u32)
157}
158
159/// Re-exposes the range fact of a `CpuId` beyond the closed `type_inv`.
160pub broadcast proof fn lemma_type_inv_range(cpu_id: CpuId)
161 requires
162 CpuId::type_inv(cpu_id),
163 ensures
164 #![trigger cpu_id@]
165 0 <= cpu_id@ < cpu_count(),
166{
167}
168
169/// `as_usize` and its `u32` re-encoding equal the numeric view of a `CpuId`.
170pub broadcast proof fn lemma_cpu_id_model(cpu_id: CpuId)
171 ensures
172 #![trigger cpu_id.as_usize()]
173 cpu_id.as_usize() == cpu_id@,
174 (cpu_id.as_usize() as u32) == cpu_id@,
175{
176}
177
178impl TryFromSpecImpl<usize> for CpuId {
179 open spec fn obeys_try_from_spec() -> bool {
180 true
181 }
182
183 open spec fn try_from_spec(v: usize) -> Result<Self, Self::Error> {
184 if cpu_count() > v {
185 Ok(cpu_id_from_index(v as int))
186 } else {
187 Err(arbitrary())
188 }
189 }
190}
191
192} // verus!
193/* cpu_local_cell! {
194 /// The current CPU ID.
195 static CURRENT_CPU: u32 = 0;
196 /// The initialization state of the current CPU ID.
197 #[cfg(debug_assertions)]
198 static IS_CURRENT_CPU_INITED: bool = false;
199}
200
201/// Initializes the current CPU ID.
202///
203/// # Safety
204///
205/// This method must be called on each processor during the early
206/// boot phase of the processor.
207///
208/// The caller must ensure that this function is called with
209/// the correct value of the CPU ID.
210unsafe fn set_this_cpu_id(id: u32) {
211 // FIXME: If there are safe APIs that rely on the correctness of
212 // the CPU ID for soundness, we'd better make the CPU ID a global
213 // invariant and initialize it before entering `ap_early_entry`.
214 CURRENT_CPU.store(id);
215
216 #[cfg(debug_assertions)]
217 IS_CURRENT_CPU_INITED.store(true);
218}
219
220/// A marker trait for guard types that can "pin" the current task to the
221/// current CPU.
222///
223/// Such guard types include [`DisabledLocalIrqGuard`] and
224/// [`DisabledPreemptGuard`]. When such guards exist, the CPU executing the
225/// current task is pinned. So getting the current CPU ID or CPU-local
226/// variables are safe.
227///
228/// # Safety
229///
230/// The implementor must ensure that the current task is pinned to the current
231/// CPU while any one of the instances of the implemented structure exists.
232///
233/// [`DisabledLocalIrqGuard`]: crate::trap::irq::DisabledLocalIrqGuard
234/// [`DisabledPreemptGuard`]: crate::task::DisabledPreemptGuard
235pub unsafe trait PinCurrentCpu {
236 /// Returns the ID of the current CPU.
237 fn current_cpu(&self) -> CpuId {
238 CpuId::current_racy()
239 }
240}
241
242// SAFETY: A guard that enforces the atomic mode requires disabling any
243// context switching. So naturally, the current task is pinned on the CPU.
244unsafe impl<T: InAtomicMode> PinCurrentCpu for T {}
245unsafe impl PinCurrentCpu for dyn InAtomicMode + '_ {}
246
247/// # Safety
248///
249/// The caller must ensure that
250/// 1. We're in the boot context of the BSP and APs have not yet booted.
251/// 2. The number of available processors is available.
252/// 3. No CPU-local objects have been accessed.
253pub(crate) unsafe fn init_on_bsp() {
254 let num_cpus = crate::arch::boot::smp::count_processors().unwrap_or(1);
255
256 // SAFETY: The safety is upheld by the caller and
257 // the correctness of the `get_num_processors` method.
258 unsafe {
259 local::copy_bsp_for_ap(num_cpus as usize);
260
261 set_this_cpu_id(0);
262
263 // Note that `init_num_cpus` should be called after `copy_bsp_for_ap`.
264 // This helps to build the safety reasoning in `CpuLocal::get_on_cpu`.
265 // See its implementation for details.
266 init_num_cpus(num_cpus);
267 }
268}
269
270/// # Safety
271///
272/// The caller must ensure that:
273/// 1. We're in the boot context of an AP.
274/// 2. The CPU ID of the AP is `cpu_id`.
275pub(crate) unsafe fn init_on_ap(cpu_id: u32) {
276 // SAFETY: The safety is upheld by the caller.
277 unsafe { set_this_cpu_id(cpu_id) };
278} */