xref: /DragonOS/kernel/src/arch/x86_64/smp/mod.rs (revision 81294aa2e6b257f0de5e3c28c3f3c89798330836)
1 use core::{
2     arch::asm,
3     hint::spin_loop,
4     sync::atomic::{compiler_fence, AtomicBool, Ordering},
5 };
6 
7 use kdepends::memoffset::offset_of;
8 use system_error::SystemError;
9 
10 use crate::{
11     arch::process::table::TSSManager, exception::InterruptArch,
12     include::bindings::bindings::cpu_core_info, kdebug, libs::rwlock::RwLock, mm::percpu::PerCpu,
13     process::ProcessManager, smp::core::smp_get_processor_id,
14 };
15 
16 use super::CurrentIrqArch;
17 
18 extern "C" {
19     fn smp_ap_start_stage2();
20 }
21 
22 pub(super) static X86_64_SMP_MANAGER: X86_64SmpManager = X86_64SmpManager::new();
23 
24 #[repr(C)]
25 struct ApStartStackInfo {
26     vaddr: usize,
27 }
28 
29 /// AP处理器启动时执行
30 #[no_mangle]
31 unsafe extern "C" fn smp_ap_start() -> ! {
32     CurrentIrqArch::interrupt_disable();
33     let vaddr = cpu_core_info[smp_get_processor_id() as usize].stack_start as usize;
34     compiler_fence(core::sync::atomic::Ordering::SeqCst);
35     let v = ApStartStackInfo { vaddr };
36     smp_init_switch_stack(&v);
37 }
38 
39 #[naked]
40 unsafe extern "sysv64" fn smp_init_switch_stack(st: &ApStartStackInfo) -> ! {
41     asm!(concat!("
42         mov rsp, [rdi + {off_rsp}]
43         mov rbp, [rdi + {off_rsp}]
44         jmp {stage1}
45     "),
46         off_rsp = const(offset_of!(ApStartStackInfo, vaddr)),
47         stage1 = sym smp_ap_start_stage1,
48     options(noreturn));
49 }
50 
51 unsafe extern "C" fn smp_ap_start_stage1() -> ! {
52     let id = smp_get_processor_id();
53     kdebug!("smp_ap_start_stage1: id: {}\n", id);
54     let current_idle = ProcessManager::idle_pcb()[smp_get_processor_id() as usize].clone();
55 
56     let tss = TSSManager::current_tss();
57 
58     tss.set_rsp(
59         x86::Ring::Ring0,
60         current_idle.kernel_stack().stack_max_address().data() as u64,
61     );
62     TSSManager::load_tr();
63 
64     smp_ap_start_stage2();
65     loop {
66         spin_loop();
67     }
68 }
69 
70 /// 多核的数据
71 #[derive(Debug)]
72 pub struct SmpBootData {
73     initialized: AtomicBool,
74     cpu_count: usize,
75     /// CPU的物理ID(指的是Local APIC ID)
76     ///
77     /// 这里必须保证第0项的是bsp的物理ID
78     phys_id: [usize; PerCpu::MAX_CPU_NUM],
79 }
80 
81 #[allow(dead_code)]
82 impl SmpBootData {
83     pub fn cpu_count(&self) -> usize {
84         self.cpu_count
85     }
86 
87     /// 获取CPU的物理ID
88     pub fn phys_id(&self, cpu_id: usize) -> usize {
89         self.phys_id[cpu_id]
90     }
91 
92     /// 获取BSP的物理ID
93     pub fn bsp_phys_id(&self) -> usize {
94         self.phys_id[0]
95     }
96 
97     pub unsafe fn set_cpu_count(&self, cpu_count: usize) {
98         if self.initialized.load(Ordering::SeqCst) == false {
99             let p = self as *const SmpBootData as *mut SmpBootData;
100             (*p).cpu_count = cpu_count;
101         }
102     }
103 
104     pub unsafe fn set_phys_id(&self, cpu_id: usize, phys_id: usize) {
105         if self.initialized.load(Ordering::SeqCst) == false {
106             let p = self as *const SmpBootData as *mut SmpBootData;
107             (*p).phys_id[cpu_id] = phys_id;
108         }
109     }
110 
111     /// 标记boot data结构体已经初始化完成
112     pub fn mark_initialized(&self) {
113         self.initialized.store(true, Ordering::SeqCst);
114     }
115 }
116 
117 pub(super) static SMP_BOOT_DATA: SmpBootData = SmpBootData {
118     initialized: AtomicBool::new(false),
119     cpu_count: 0,
120     phys_id: [0; PerCpu::MAX_CPU_NUM],
121 };
122 
123 #[allow(dead_code)]
124 #[derive(Debug)]
125 pub struct X86_64SmpManager {
126     ia64_cpu_to_sapicid: RwLock<[Option<usize>; PerCpu::MAX_CPU_NUM]>,
127 }
128 
129 impl X86_64SmpManager {
130     pub const fn new() -> Self {
131         return Self {
132             ia64_cpu_to_sapicid: RwLock::new([None; PerCpu::MAX_CPU_NUM]),
133         };
134     }
135     /// initialize the logical cpu number to APIC ID mapping
136     pub fn build_cpu_map(&self) -> Result<(), SystemError> {
137         // 参考:https://opengrok.ringotek.cn/xref/linux-6.1.9/arch/ia64/kernel/smpboot.c?fi=smp_build_cpu_map#496
138         // todo!("build_cpu_map")
139         return Ok(());
140     }
141 }
142