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