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