Skip to main content

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} */