xref: /DragonOS/kernel/src/arch/x86_64/smp/mod.rs (revision c719ddc6312acd7976e0f6fd449a94ff9abad5a6)
1 use core::{
2     arch::asm,
3     hint::spin_loop,
4     sync::atomic::{compiler_fence, fence, AtomicBool, Ordering},
5 };
6 
7 use kdepends::memoffset::offset_of;
8 use system_error::SystemError;
9 
10 use crate::{
11     arch::{mm::LowAddressRemapping, process::table::TSSManager, MMArch},
12     exception::InterruptArch,
13     kdebug,
14     libs::{cpumask::CpuMask, rwlock::RwLock},
15     mm::{percpu::PerCpu, MemoryManagementArch, PhysAddr, VirtAddr, IDLE_PROCESS_ADDRESS_SPACE},
16     process::ProcessManager,
17     smp::{
18         core::smp_get_processor_id,
19         cpu::{smp_cpu_manager, CpuHpCpuState, ProcessorId, SmpCpuManager},
20         init::smp_ap_start_stage2,
21         SMPArch,
22     },
23 };
24 
25 use super::{
26     acpi::early_acpi_boot_init,
27     interrupt::ipi::{ipi_send_smp_init, ipi_send_smp_startup},
28     CurrentIrqArch,
29 };
30 
31 extern "C" {
32     /// AP处理器启动时,会将CR3设置为这个值
33     pub static mut __APU_START_CR3: u64;
34     fn _apu_boot_start();
35     fn _apu_boot_end();
36 }
37 
38 pub(super) static X86_64_SMP_MANAGER: X86_64SmpManager = X86_64SmpManager::new();
39 
40 #[repr(C)]
41 struct ApStartStackInfo {
42     vaddr: usize,
43 }
44 
45 /// AP处理器启动时执行
46 #[no_mangle]
47 unsafe extern "C" fn smp_ap_start() -> ! {
48     CurrentIrqArch::interrupt_disable();
49 
50     let vaddr = if let Some(t) = smp_cpu_manager()
51         .cpuhp_state(smp_get_processor_id())
52         .thread()
53     {
54         t.kernel_stack_force_ref().stack_max_address().data() - 16
55     } else {
56         // 没有设置ap核心的栈,那么就进入死循环。
57         loop {
58             spin_loop();
59         }
60     };
61     compiler_fence(core::sync::atomic::Ordering::SeqCst);
62     let v = ApStartStackInfo { vaddr };
63     smp_init_switch_stack(&v);
64 }
65 
66 #[naked]
67 unsafe extern "sysv64" fn smp_init_switch_stack(st: &ApStartStackInfo) -> ! {
68     asm!(concat!("
69         mov rsp, [rdi + {off_rsp}]
70         mov rbp, [rdi + {off_rsp}]
71         jmp {stage1}
72     "),
73         off_rsp = const(offset_of!(ApStartStackInfo, vaddr)),
74         stage1 = sym smp_ap_start_stage1,
75     options(noreturn));
76 }
77 
78 unsafe extern "C" fn smp_ap_start_stage1() -> ! {
79     let id = smp_get_processor_id();
80     kdebug!("smp_ap_start_stage1: id: {}\n", id.data());
81     let current_idle = ProcessManager::idle_pcb()[smp_get_processor_id().data() as usize].clone();
82 
83     let tss = TSSManager::current_tss();
84 
85     tss.set_rsp(
86         x86::Ring::Ring0,
87         current_idle.kernel_stack().stack_max_address().data() as u64,
88     );
89     TSSManager::load_tr();
90 
91     CurrentIrqArch::arch_ap_early_irq_init().expect("arch_ap_early_irq_init failed");
92 
93     smp_ap_start_stage2();
94 }
95 
96 /// 多核的数据
97 #[derive(Debug)]
98 pub struct SmpBootData {
99     initialized: AtomicBool,
100     cpu_count: usize,
101     /// CPU的物理ID(指的是Local APIC ID)
102     ///
103     /// 这里必须保证第0项的是bsp的物理ID
104     phys_id: [usize; PerCpu::MAX_CPU_NUM as usize],
105 }
106 
107 #[allow(dead_code)]
108 impl SmpBootData {
109     pub fn cpu_count(&self) -> usize {
110         self.cpu_count
111     }
112 
113     /// 获取CPU的物理ID
114     pub fn phys_id(&self, cpu_id: usize) -> usize {
115         self.phys_id[cpu_id]
116     }
117 
118     /// 获取BSP的物理ID
119     pub fn bsp_phys_id(&self) -> usize {
120         self.phys_id[0]
121     }
122 
123     pub unsafe fn set_cpu_count(&self, cpu_count: u32) {
124         if !self.initialized.load(Ordering::SeqCst) {
125             let p = self as *const SmpBootData as *mut SmpBootData;
126             (*p).cpu_count = cpu_count.try_into().unwrap();
127         }
128     }
129 
130     pub unsafe fn set_phys_id(&self, cpu_id: ProcessorId, phys_id: usize) {
131         if !self.initialized.load(Ordering::SeqCst) {
132             let p = self as *const SmpBootData as *mut SmpBootData;
133             (*p).phys_id[cpu_id.data() as usize] = phys_id;
134         }
135     }
136 
137     /// 标记boot data结构体已经初始化完成
138     pub fn mark_initialized(&self) {
139         self.initialized.store(true, Ordering::SeqCst);
140     }
141 }
142 
143 pub(super) static SMP_BOOT_DATA: SmpBootData = SmpBootData {
144     initialized: AtomicBool::new(false),
145     cpu_count: 0,
146     phys_id: [0; PerCpu::MAX_CPU_NUM as usize],
147 };
148 
149 #[allow(dead_code)]
150 #[derive(Debug)]
151 pub struct X86_64SmpManager {
152     ia64_cpu_to_sapicid: RwLock<[Option<usize>; PerCpu::MAX_CPU_NUM as usize]>,
153 }
154 
155 impl X86_64SmpManager {
156     pub const fn new() -> Self {
157         return Self {
158             ia64_cpu_to_sapicid: RwLock::new([None; PerCpu::MAX_CPU_NUM as usize]),
159         };
160     }
161     /// initialize the logical cpu number to APIC ID mapping
162     pub fn build_cpu_map(&self) -> Result<(), SystemError> {
163         // 参考:https://code.dragonos.org.cn/xref/linux-6.1.9/arch/ia64/kernel/smpboot.c?fi=smp_build_cpu_map#496
164         // todo!("build_cpu_map")
165         unsafe {
166             smp_cpu_manager().set_possible_cpu(ProcessorId::new(0), true);
167             smp_cpu_manager().set_present_cpu(ProcessorId::new(0), true);
168             smp_cpu_manager().set_online_cpu(ProcessorId::new(0));
169         }
170 
171         for cpu in 1..SMP_BOOT_DATA.cpu_count() {
172             unsafe {
173                 smp_cpu_manager().set_possible_cpu(ProcessorId::new(cpu as u32), true);
174                 smp_cpu_manager().set_present_cpu(ProcessorId::new(cpu as u32), true);
175             }
176         }
177 
178         print_cpus("possible", smp_cpu_manager().possible_cpus());
179         print_cpus("present", smp_cpu_manager().present_cpus());
180         return Ok(());
181     }
182 }
183 
184 fn print_cpus(s: &str, mask: &CpuMask) {
185     let mut v = vec![];
186     for cpu in mask.iter_cpu() {
187         v.push(cpu.data());
188     }
189 
190     kdebug!("{s}: cpus: {v:?}\n");
191 }
192 
193 pub struct X86_64SMPArch;
194 
195 impl SMPArch for X86_64SMPArch {
196     #[inline(never)]
197     fn prepare_cpus() -> Result<(), SystemError> {
198         early_acpi_boot_init()?;
199         X86_64_SMP_MANAGER.build_cpu_map()?;
200         return Ok(());
201     }
202 
203     fn post_init() -> Result<(), SystemError> {
204         // AP核心启动完毕,取消低地址映射
205         unsafe {
206             LowAddressRemapping::unmap_at_low_address(
207                 &mut IDLE_PROCESS_ADDRESS_SPACE()
208                     .write_irqsave()
209                     .user_mapper
210                     .utable,
211                 true,
212             )
213         }
214         return Ok(());
215     }
216 
217     fn start_cpu(cpu_id: ProcessorId, _cpu_hpstate: &CpuHpCpuState) -> Result<(), SystemError> {
218         Self::copy_smp_start_code();
219 
220         fence(Ordering::SeqCst);
221         ipi_send_smp_init();
222         fence(Ordering::SeqCst);
223         ipi_send_smp_startup(cpu_id)?;
224 
225         fence(Ordering::SeqCst);
226         ipi_send_smp_startup(cpu_id)?;
227 
228         fence(Ordering::SeqCst);
229 
230         return Ok(());
231     }
232 }
233 
234 impl X86_64SMPArch {
235     const SMP_CODE_START: usize = 0x20000;
236     /// 复制SMP启动代码到0x20000处
237     fn copy_smp_start_code() -> (VirtAddr, usize) {
238         let apu_boot_size = Self::start_code_size();
239 
240         fence(Ordering::SeqCst);
241         unsafe {
242             core::ptr::copy(
243                 _apu_boot_start as *const u8,
244                 Self::SMP_CODE_START as *mut u8,
245                 apu_boot_size,
246             )
247         };
248         fence(Ordering::SeqCst);
249 
250         return (VirtAddr::new(Self::SMP_CODE_START), apu_boot_size);
251     }
252 
253     fn start_code_size() -> usize {
254         let apu_boot_start = _apu_boot_start as usize;
255         let apu_boot_end = _apu_boot_end as usize;
256         let apu_boot_size = apu_boot_end - apu_boot_start;
257         return apu_boot_size;
258     }
259 }
260 
261 impl SmpCpuManager {
262     pub fn arch_init(_boot_cpu: ProcessorId) {
263         assert!(smp_get_processor_id().data() == 0);
264         // 写入APU_START_CR3,这个值会在AP处理器启动时设置到CR3寄存器
265         let addr = IDLE_PROCESS_ADDRESS_SPACE()
266             .read_irqsave()
267             .user_mapper
268             .utable
269             .table()
270             .phys();
271         let vaddr = unsafe {
272             MMArch::phys_2_virt(PhysAddr::new(&mut __APU_START_CR3 as *mut u64 as usize)).unwrap()
273         };
274         let ptr = vaddr.data() as *mut u64;
275         unsafe { *ptr = addr.data() as u64 };
276 
277         // 添加低地址映射
278         unsafe {
279             LowAddressRemapping::remap_at_low_address(
280                 &mut IDLE_PROCESS_ADDRESS_SPACE()
281                     .write_irqsave()
282                     .user_mapper
283                     .utable,
284             )
285         };
286     }
287 }
288