Skip to main content

ostd/cpu/
mod.rs

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