Skip to main content

strat9_kernel/ostd/
cpu.rs

1//! CPU abstraction layer
2//!
3//! Provides safe abstractions for CPU-related operations including:
4//! - CPU identification and topology
5//! - Per-CPU data access
6//! - CPU control (halt, interrupt control)
7//!
8//! Inspired by Asterinas OSTD CPU module.
9
10#![allow(unsafe_code)]
11
12/// CPU identifier
13///
14/// Represents a logical CPU in the system. On x86_64, this corresponds
15/// to the APIC ID.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17#[repr(transparent)]
18pub struct CpuId {
19    id: usize,
20}
21
22impl CpuId {
23    /// Creates a new CpuId from a raw ID
24    pub const fn new(id: usize) -> Self {
25        Self { id }
26    }
27
28    /// Returns the raw CPU ID value
29    pub const fn id(&self) -> usize {
30        self.id
31    }
32
33    /// Returns the CpuId of the bootstrap processor (BSP)
34    pub const fn bsp() -> Self {
35        Self::new(0)
36    }
37
38    /// Returns the CpuId of the currently executing CPU
39    ///
40    /// # Safety
41    ///
42    /// This function reads the per-CPU GS base to determine the current CPU.
43    /// It requires that per-CPU data has been initialized for this CPU.
44    #[inline]
45    pub fn current_racy() -> Self {
46        // This is safe if per-CPU data has been set up via
47        // arch::x86_64::percpu::init_gs_base(). The "racy" suffix indicates
48        // that no additional synchronization is performed.
49        let cpu_index = crate::arch::x86_64::percpu::current_cpu_index();
50        Self::new(cpu_index)
51    }
52
53    /// Returns the number of CPUs in the system
54    pub fn num_cpus() -> usize {
55        crate::arch::x86_64::percpu::get_cpu_count()
56    }
57
58    /// Returns an iterator over all CPUs
59    pub fn iter() -> CpuIter {
60        CpuIter {
61            current: 0,
62            end: Self::num_cpus(),
63        }
64    }
65}
66
67impl From<usize> for CpuId {
68    /// Performs the from operation.
69    fn from(id: usize) -> Self {
70        Self::new(id)
71    }
72}
73
74impl From<CpuId> for usize {
75    /// Performs the from operation.
76    fn from(cpu_id: CpuId) -> Self {
77        cpu_id.id
78    }
79}
80
81impl core::fmt::Display for CpuId {
82    /// Performs the fmt operation.
83    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84        write!(f, "CPU #{}", self.id)
85    }
86}
87
88/// Iterator over all CPUs
89pub struct CpuIter {
90    current: usize,
91    end: usize,
92}
93
94impl Iterator for CpuIter {
95    type Item = CpuId;
96
97    /// Performs the next operation.
98    fn next(&mut self) -> Option<Self::Item> {
99        if self.current < self.end {
100            let cpu = CpuId::new(self.current);
101            self.current += 1;
102            Some(cpu)
103        } else {
104            None
105        }
106    }
107}
108
109/// CPU halt function
110///
111/// Halts the CPU until the next interrupt arrives.
112#[inline]
113pub fn halt_cpu() {
114    // hlt is a privileged instruction that halts the CPU until
115    // the next interrupt. This is safe to call in kernel mode.
116    crate::arch::x86_64::hlt();
117}
118
119/// Disable interrupts on the current CPU
120#[inline]
121pub fn disable_irqs() {
122    // cli is a privileged instruction that disables interrupts.
123    // This is safe to call in kernel mode and is commonly used to
124    // protect critical sections.
125    crate::arch::x86_64::cli();
126}
127
128/// Enable interrupts on the current CPU
129#[inline]
130pub fn enable_irqs() {
131    // sti is a privileged instruction that enables interrupts.
132    // This is safe to call in kernel mode.
133    crate::arch::x86_64::sti();
134}
135
136/// Check if interrupts are enabled on the current CPU
137#[inline]
138pub fn irqs_enabled() -> bool {
139    crate::arch::x86_64::interrupts_enabled()
140}
141
142/// Save interrupt flags and disable interrupts
143///
144/// Returns the previous interrupt state.
145#[inline]
146pub fn save_and_disable_irqs() -> bool {
147    let flags = crate::arch::x86_64::save_flags_and_cli();
148    (flags & 0x200) != 0
149}
150
151/// Restore interrupt flags
152///
153/// Restores the interrupt state to a previous value.
154#[inline]
155pub fn restore_irqs(enabled: bool) {
156    if enabled {
157        enable_irqs();
158    } else {
159        disable_irqs();
160    }
161}
162
163/// Execute a closure with interrupts disabled
164///
165/// Returns the result of the closure.
166pub fn without_interrupts<F, R>(f: F) -> R
167where
168    F: FnOnce() -> R,
169{
170    let irq_enabled = save_and_disable_irqs();
171    let result = f();
172    restore_irqs(irq_enabled);
173    result
174}