xref: /DragonOS/kernel/src/arch/x86_64/driver/apic/x2apic.rs (revision a17651b14b86dd70655090381db4a2f710853aa1)
1 use core::sync::atomic::{fence, Ordering};
2 
3 use x86::msr::{
4     rdmsr, wrmsr, IA32_APIC_BASE, IA32_X2APIC_APICID, IA32_X2APIC_EOI, IA32_X2APIC_SIVR,
5     IA32_X2APIC_VERSION,
6 };
7 
8 use crate::{kdebug, kinfo};
9 
10 use super::{hw_irq::ApicId, LVTRegister, LocalAPIC, LVT};
11 
12 #[derive(Debug)]
13 pub struct X2Apic;
14 
15 impl LocalAPIC for X2Apic {
16     /// @brief 判断处理器是否支持x2APIC
17     fn support() -> bool {
18         return x86::cpuid::CpuId::new()
19             .get_feature_info()
20             .expect("Get cpu feature info failed.")
21             .has_x2apic();
22     }
23     /// @return true -> the function works
24     fn init_current_cpu(&mut self) -> bool {
25         unsafe {
26             // 设置 x2APIC 使能位
27             wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10);
28 
29             assert!(
30                 (rdmsr(IA32_APIC_BASE) & 0xc00) == 0xc00,
31                 "x2APIC enable failed."
32             );
33 
34             // 设置Spurious-Interrupt Vector Register
35             {
36                 let val = if self.support_eoi_broadcast_suppression() {
37                     (1 << 12) | (1 << 8)
38                 } else {
39                     1 << 8
40                 };
41 
42                 wrmsr(IA32_X2APIC_SIVR, val);
43 
44                 assert!(
45                     (rdmsr(IA32_X2APIC_SIVR) & 0x100) == 0x100,
46                     "x2APIC software enable failed."
47                 );
48                 kinfo!("x2APIC software enabled.");
49 
50                 if self.support_eoi_broadcast_suppression() {
51                     assert!(
52                         (rdmsr(IA32_X2APIC_SIVR) & 0x1000) == 0x1000,
53                         "x2APIC EOI broadcast suppression enable failed."
54                     );
55                     kinfo!("x2APIC EOI broadcast suppression enabled.");
56                 }
57             }
58             kdebug!("x2apic: to mask all lvt");
59             self.mask_all_lvt();
60             kdebug!("x2apic: all lvt masked");
61         }
62         true
63     }
64 
65     /// 发送 EOI (End Of Interrupt)
66     fn send_eoi(&self) {
67         fence(Ordering::SeqCst);
68         unsafe {
69             wrmsr(IA32_X2APIC_EOI, 0);
70         }
71 
72         fence(Ordering::SeqCst);
73     }
74 
75     /// 获取 x2APIC 版本
76     fn version(&self) -> u8 {
77         unsafe { (rdmsr(IA32_X2APIC_VERSION) & 0xff) as u8 }
78     }
79 
80     fn support_eoi_broadcast_suppression(&self) -> bool {
81         unsafe { ((rdmsr(IA32_X2APIC_VERSION) >> 24) & 1) == 1 }
82     }
83 
84     fn max_lvt_entry(&self) -> u8 {
85         unsafe { ((rdmsr(IA32_X2APIC_VERSION) >> 16) & 0xff) as u8 + 1 }
86     }
87 
88     /// 获取 x2APIC 的 APIC ID
89     fn id(&self) -> ApicId {
90         unsafe { ApicId::new(rdmsr(IA32_X2APIC_APICID) as u32) }
91     }
92 
93     /// 设置 Local Vector Table (LVT) 寄存器
94     fn set_lvt(&mut self, lvt: LVT) {
95         unsafe {
96             wrmsr(lvt.register().into(), lvt.data as u64);
97         }
98     }
99 
100     fn read_lvt(&self, reg: LVTRegister) -> LVT {
101         unsafe { LVT::new(reg, (rdmsr(reg.into()) & 0xffff_ffff) as u32).unwrap() }
102     }
103 
104     fn mask_all_lvt(&mut self) {
105         // self.set_lvt(LVT::new(LVTRegister::CMCI, LVT::MASKED).unwrap());
106         let cpuid = raw_cpuid::CpuId::new();
107         // cpuid.get_performance_monitoring_info();
108         self.set_lvt(LVT::new(LVTRegister::Timer, LVT::MASKED).unwrap());
109 
110         if cpuid.get_thermal_power_info().is_some() {
111             self.set_lvt(LVT::new(LVTRegister::Thermal, LVT::MASKED).unwrap());
112         }
113 
114         if cpuid.get_performance_monitoring_info().is_some() {
115             self.set_lvt(LVT::new(LVTRegister::PerformanceMonitor, LVT::MASKED).unwrap());
116         }
117 
118         self.set_lvt(LVT::new(LVTRegister::LINT0, LVT::MASKED).unwrap());
119         self.set_lvt(LVT::new(LVTRegister::LINT1, LVT::MASKED).unwrap());
120 
121         self.set_lvt(LVT::new(LVTRegister::ErrorReg, LVT::MASKED).unwrap());
122     }
123 
124     fn write_icr(&self, icr: x86::apic::Icr) {
125         unsafe { wrmsr(0x830, ((icr.upper() as u64) << 32) | icr.lower() as u64) };
126     }
127 }
128