1 use alloc::vec::Vec;
2 use hashbrown::HashSet;
3 
4 use crate::{driver::acpi::acpi_manager, kdebug};
5 
6 /// 这是一个临时的函数,用于在acpi、cpu模块被正式实现之前,让原本的C写的smp模块能正常运行
7 ///
8 /// 请注意!这样写会使得smp模块与x86强耦合。正确的做法是:
9 /// - 在sysfs中新增acpi firmware
10 /// - 在acpi初始化的时候,初始化处理器拓扑信息
11 /// - 初始化cpu模块(加入到sysfs,放置在/sys/devices/system下面)
12 /// - smp模块从cpu模块处,获取到与架构无关的处理器拓扑信息
13 /// - smp根据上述信息,初始化指定的处理器(这部分在arch下面实现)
14 ///
15 /// 但是由于acpi、cpu模块还没有被正式实现,所以暂时使用这个函数来代替,接下来会按照上述步骤进行编写代码
16 #[no_mangle]
rs_smp_get_cpus(res: *mut X86CpuInfo) -> usize17 unsafe extern "C" fn rs_smp_get_cpus(res: *mut X86CpuInfo) -> usize {
18     let acpi_table = acpi_manager().tables().unwrap();
19     let platform_info = acpi_table
20         .platform_info()
21         .expect("smp_get_cpu_topology(): failed to get platform info");
22     let processor_info = platform_info
23         .processor_info
24         .expect("smp_get_cpu_topology(): failed to get processor info");
25 
26     let mut id_set = HashSet::new();
27     let mut cpu_info = processor_info
28         .application_processors
29         .iter()
30         .filter_map(|ap| {
31             if id_set.contains(&ap.local_apic_id) {
32                 return None;
33             }
34             let can_boot = ap.state == acpi::platform::ProcessorState::WaitingForSipi;
35             if !can_boot {
36                 return None;
37             }
38 
39             id_set.insert(ap.local_apic_id);
40             Some(X86CpuInfo::new(
41                 ap.local_apic_id,
42                 ap.processor_uid,
43                 can_boot,
44             ))
45         })
46         .collect::<Vec<_>>();
47 
48     let bsp_info = X86CpuInfo::new(
49         processor_info.boot_processor.local_apic_id,
50         processor_info.boot_processor.processor_uid,
51         processor_info.boot_processor.state == acpi::platform::ProcessorState::WaitingForSipi,
52     );
53     cpu_info.push(bsp_info);
54 
55     cpu_info.sort_by(|a, b| a.apic_id.cmp(&b.apic_id));
56     kdebug!("cpu_info: {:?}", cpu_info);
57 
58     res.copy_from_nonoverlapping(cpu_info.as_ptr(), cpu_info.len());
59     return cpu_info.len();
60 }
61 
62 /// 这个是临时用于传数据给c版本代码的结构体,请勿用作其他用途
63 #[repr(C)]
64 #[derive(Debug)]
65 struct X86CpuInfo {
66     apic_id: u32,
67     core_id: u32,
68     can_boot: core::ffi::c_char,
69 }
70 
71 impl X86CpuInfo {
new(apic_id: u32, core_id: u32, can_boot: bool) -> Self72     fn new(apic_id: u32, core_id: u32, can_boot: bool) -> Self {
73         Self {
74             apic_id,
75             core_id,
76             can_boot: can_boot as core::ffi::c_char,
77         }
78     }
79 }
80