xref: /DragonOS/kernel/src/smp/cpu/mod.rs (revision 9621ab16ef27bc94f223e6254fafb9bb07d46d57)
1 use core::sync::atomic::AtomicU32;
2 
3 use alloc::{sync::Arc, vec::Vec};
4 use system_error::SystemError;
5 
6 use crate::{
7     arch::CurrentSMPArch,
8     libs::cpumask::CpuMask,
9     mm::percpu::{PerCpu, PerCpuVar},
10     process::{ProcessControlBlock, ProcessManager},
11     sched::completion::Completion,
12 };
13 
14 use super::{core::smp_get_processor_id, SMPArch};
15 
16 int_like!(ProcessorId, AtomicProcessorId, u32, AtomicU32);
17 
18 impl ProcessorId {
19     pub const INVALID: ProcessorId = ProcessorId::new(u32::MAX);
20 }
21 
22 static mut SMP_CPU_MANAGER: Option<SmpCpuManager> = None;
23 
24 #[inline]
25 pub fn smp_cpu_manager() -> &'static SmpCpuManager {
26     unsafe { SMP_CPU_MANAGER.as_ref().unwrap() }
27 }
28 
29 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
30 pub enum CpuHpState {
31     /// 启动阈值
32     ThresholdBringUp = 0,
33 
34     /// 该CPU是离线的
35     Offline,
36 
37     /// 该CPU是在线的
38     Online,
39 }
40 
41 /// Per-Cpu Cpu的热插拔状态
42 pub struct CpuHpCpuState {
43     /// 当前状态
44     state: CpuHpState,
45     /// 目标状态
46     target_state: CpuHpState,
47     /// 指向热插拔的线程的PCB
48     thread: Option<Arc<ProcessControlBlock>>,
49 
50     /// 当前是否为启动流程
51     bringup: bool,
52     /// 启动完成的信号
53     comp_done_up: Completion,
54 }
55 
56 impl CpuHpCpuState {
57     const fn new() -> Self {
58         Self {
59             state: CpuHpState::Offline,
60             target_state: CpuHpState::Offline,
61             thread: None,
62             bringup: false,
63             comp_done_up: Completion::new(),
64         }
65     }
66 
67     pub const fn thread(&self) -> &Option<Arc<ProcessControlBlock>> {
68         &self.thread
69     }
70 }
71 
72 pub struct SmpCpuManager {
73     /// 可用的CPU
74     possible_cpus: CpuMask,
75     /// 出现的CPU
76     present_cpus: CpuMask,
77     /// 出现在系统中的CPU的数量
78     present_cnt: AtomicU32,
79     /// 可用的CPU的数量
80     possible_cnt: AtomicU32,
81     /// CPU的状态
82     cpuhp_state: PerCpuVar<CpuHpCpuState>,
83 }
84 
85 impl SmpCpuManager {
86     fn new() -> Self {
87         let possible_cpus = CpuMask::new();
88         let present_cpus = CpuMask::new();
89         let mut data = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
90         for i in 0..PerCpu::MAX_CPU_NUM {
91             let mut hpstate = CpuHpCpuState::new();
92             hpstate.thread = Some(ProcessManager::idle_pcb()[i as usize].clone());
93             data.push(hpstate);
94         }
95         let cpuhp_state = PerCpuVar::new(data).unwrap();
96 
97         Self {
98             possible_cpus,
99             present_cpus,
100             cpuhp_state,
101             present_cnt: AtomicU32::new(0),
102             possible_cnt: AtomicU32::new(0),
103         }
104     }
105 
106     /// 设置可用的CPU
107     ///
108     /// # Safety
109     ///
110     /// - 该函数不会检查CPU的有效性,调用者需要保证CPU的有效性。
111     /// - 由于possible_cpus是一个全局变量,且为了性能考虑,并不会加锁
112     ///     访问,因此该函数只能在初始化阶段调用。
113     pub unsafe fn set_possible_cpu(&self, cpu: ProcessorId, value: bool) {
114         // 强制获取mut引用,因为该函数只能在初始化阶段调用
115         let p = (self as *const Self as *mut Self).as_mut().unwrap();
116 
117         if let Some(prev) = p.possible_cpus.set(cpu, value) {
118             if prev != value {
119                 if value {
120                     p.possible_cnt
121                         .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
122                 } else {
123                     p.possible_cnt
124                         .fetch_sub(1, core::sync::atomic::Ordering::SeqCst);
125                 }
126             }
127         }
128     }
129 
130     /// 获取可用的CPU
131     pub fn possible_cpus(&self) -> &CpuMask {
132         &self.possible_cpus
133     }
134 
135     #[allow(dead_code)]
136     pub fn possible_cpus_count(&self) -> u32 {
137         self.possible_cnt.load(core::sync::atomic::Ordering::SeqCst)
138     }
139 
140     pub fn present_cpus_count(&self) -> u32 {
141         self.present_cnt.load(core::sync::atomic::Ordering::SeqCst)
142     }
143 
144     pub unsafe fn set_present_cpu(&self, cpu: ProcessorId, value: bool) {
145         // 强制获取mut引用,因为该函数只能在初始化阶段调用
146         let p = (self as *const Self as *mut Self).as_mut().unwrap();
147 
148         if let Some(prev) = p.present_cpus.set(cpu, value) {
149             if prev != value {
150                 if value {
151                     p.present_cnt
152                         .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
153                 } else {
154                     p.present_cnt
155                         .fetch_sub(1, core::sync::atomic::Ordering::SeqCst);
156                 }
157             }
158         }
159     }
160 
161     /// 获取CPU的状态
162     pub fn cpuhp_state(&self, cpu_id: ProcessorId) -> &CpuHpCpuState {
163         unsafe { self.cpuhp_state.force_get(cpu_id) }
164     }
165 
166     #[allow(clippy::mut_from_ref)]
167     fn cpuhp_state_mut(&self, cpu_id: ProcessorId) -> &mut CpuHpCpuState {
168         unsafe { self.cpuhp_state.force_get_mut(cpu_id) }
169     }
170 
171     /// 设置CPU的状态, 返回旧的状态
172     pub unsafe fn set_cpuhp_state(
173         &self,
174         cpu_id: ProcessorId,
175         target_state: CpuHpState,
176     ) -> CpuHpState {
177         let p = self.cpuhp_state.force_get_mut(cpu_id);
178         let old_state = p.state;
179 
180         let bringup = target_state > p.state;
181         p.target_state = target_state;
182         p.bringup = bringup;
183 
184         return old_state;
185     }
186 
187     pub fn set_online_cpu(&self, cpu_id: ProcessorId) {
188         unsafe { self.set_cpuhp_state(cpu_id, CpuHpState::Online) };
189     }
190 
191     /// 获取出现在系统中的CPU
192     #[allow(dead_code)]
193     pub fn present_cpus(&self) -> &CpuMask {
194         &self.present_cpus
195     }
196 
197     /// 启动bsp以外的CPU
198     pub(super) fn bringup_nonboot_cpus(&self) {
199         for cpu_id in self.present_cpus().iter_cpu() {
200             if cpu_id == smp_get_processor_id() {
201                 continue;
202             }
203 
204             kdebug!("Bring up CPU {}", cpu_id.data());
205 
206             if let Err(e) = self.cpu_up(cpu_id, CpuHpState::Online) {
207                 kerror!("Failed to bring up CPU {}: {:?}", cpu_id.data(), e);
208             }
209         }
210 
211         kinfo!("All non-boot CPUs have been brought up");
212     }
213 
214     fn cpu_up(&self, cpu_id: ProcessorId, target_state: CpuHpState) -> Result<(), SystemError> {
215         if !self.possible_cpus().get(cpu_id).unwrap_or(false) {
216             return Err(SystemError::EINVAL);
217         }
218 
219         let cpu_state = self.cpuhp_state(cpu_id).state;
220         kdebug!(
221             "cpu_up: cpu_id: {}, cpu_state: {:?}, target_state: {:?}",
222             cpu_id.data(),
223             cpu_state,
224             target_state
225         );
226         // 如果CPU的状态已经达到或者超过目标状态,则直接返回
227         if cpu_state >= target_state {
228             return Ok(());
229         }
230 
231         unsafe { self.set_cpuhp_state(cpu_id, target_state) };
232         let cpu_state = self.cpuhp_state(cpu_id).state;
233         if cpu_state > CpuHpState::ThresholdBringUp {
234             self.cpuhp_kick_ap(cpu_id, target_state)?;
235         }
236 
237         return Ok(());
238     }
239 
240     fn cpuhp_kick_ap(
241         &self,
242         cpu_id: ProcessorId,
243         target_state: CpuHpState,
244     ) -> Result<(), SystemError> {
245         let prev_state = unsafe { self.set_cpuhp_state(cpu_id, target_state) };
246         let hpstate = self.cpuhp_state_mut(cpu_id);
247         if let Err(e) = self.do_cpuhp_kick_ap(hpstate) {
248             self.cpuhp_reset_state(hpstate, prev_state);
249             self.do_cpuhp_kick_ap(hpstate).ok();
250 
251             return Err(e);
252         }
253 
254         return Ok(());
255     }
256 
257     fn do_cpuhp_kick_ap(&self, cpu_state: &mut CpuHpCpuState) -> Result<(), SystemError> {
258         let pcb = cpu_state.thread.as_ref().ok_or(SystemError::EINVAL)?;
259         let cpu_id = pcb.sched_info().on_cpu().ok_or(SystemError::EINVAL)?;
260 
261         // todo: 等待CPU启动完成
262 
263         ProcessManager::wakeup(cpu_state.thread.as_ref().unwrap())?;
264 
265         CurrentSMPArch::start_cpu(cpu_id, cpu_state)?;
266         assert_eq!(ProcessManager::current_pcb().preempt_count(), 0);
267         self.wait_for_ap_thread(cpu_state, cpu_state.bringup);
268 
269         return Ok(());
270     }
271 
272     fn wait_for_ap_thread(&self, cpu_state: &mut CpuHpCpuState, bringup: bool) {
273         if bringup {
274             cpu_state
275                 .comp_done_up
276                 .wait_for_completion()
277                 .expect("failed to wait ap thread");
278         } else {
279             todo!("wait_for_ap_thread")
280         }
281     }
282 
283     /// 完成AP的启动
284     pub fn complete_ap_thread(&self, bringup: bool) {
285         let cpu_id = smp_get_processor_id();
286         let cpu_state = self.cpuhp_state_mut(cpu_id);
287         if bringup {
288             cpu_state.comp_done_up.complete();
289         } else {
290             todo!("complete_ap_thread")
291         }
292     }
293 
294     fn cpuhp_reset_state(&self, st: &mut CpuHpCpuState, prev_state: CpuHpState) {
295         let bringup = !st.bringup;
296         st.target_state = prev_state;
297 
298         st.bringup = bringup;
299     }
300 }
301 
302 pub fn smp_cpu_manager_init(boot_cpu: ProcessorId) {
303     unsafe {
304         SMP_CPU_MANAGER = Some(SmpCpuManager::new());
305     }
306 
307     unsafe { smp_cpu_manager().set_possible_cpu(boot_cpu, true) };
308 
309     SmpCpuManager::arch_init(boot_cpu);
310 }
311