xref: /DragonOS/kernel/src/arch/x86_64/driver/apic/mod.rs (revision 99dbf38d2e279ea70e9e186753fd37001dbb749f)
1 use core::sync::atomic::Ordering;
2 
3 use atomic_enum::atomic_enum;
4 use x86::{apic::Icr, msr::IA32_APIC_BASE};
5 
6 use crate::{
7     arch::{
8         driver::apic::{ioapic::ioapic_init, x2apic::X2Apic, xapic::XApic},
9         io::PortIOArch,
10         CurrentPortIOArch,
11     },
12     kdebug, kinfo,
13     mm::PhysAddr,
14     smp::core::smp_get_processor_id,
15     syscall::SystemError,
16 };
17 
18 use self::{
19     apic_timer::LocalApicTimerMode,
20     xapic::{current_xapic_instance, XApicOffset},
21 };
22 
23 pub mod apic_timer;
24 mod c_adapter;
25 pub mod ioapic;
26 pub mod x2apic;
27 pub mod xapic;
28 
29 /// 当前启用的APIC类型
30 #[atomic_enum]
31 #[derive(PartialEq, Eq)]
32 pub enum LocalApicEnableType {
33     XApic,
34     X2Apic,
35 }
36 
37 static LOCAL_APIC_ENABLE_TYPE: AtomicLocalApicEnableType =
38     AtomicLocalApicEnableType::new(LocalApicEnableType::XApic);
39 
40 pub trait LocalAPIC {
41     /// @brief 判断当前处理器是否支持这个类型的apic
42     ///
43     /// @return true 当前处理器支持这个类型的apic
44     /// @return false 当前处理器不支持这个类型的apic
45     fn support() -> bool;
46 
47     /// @brief 为当前处理器初始化local apic
48     ///
49     /// @return true 初始化成功
50     /// @return false 初始化失败
51     fn init_current_cpu(&mut self) -> bool;
52 
53     /// @brief 发送EOI信号(End of interrupt)
54     fn send_eoi(&self);
55 
56     /// @brief 获取APIC版本号
57     fn version(&self) -> u8;
58 
59     /// @brief 判断当前处理器是否支持EOI广播抑制
60     fn support_eoi_broadcast_suppression(&self) -> bool;
61 
62     /// 获取最多支持的LVT寄存器数量
63     fn max_lvt_entry(&self) -> u8;
64 
65     /// @brief 获取当前处理器的APIC ID
66     fn id(&self) -> u32;
67 
68     /// @brief 设置LVT寄存器
69     ///
70     /// @param register 寄存器
71     /// @param lvt 要被设置成的值
72     fn set_lvt(&mut self, lvt: LVT);
73 
74     /// 读取LVT寄存器
75     fn read_lvt(&self, reg: LVTRegister) -> LVT;
76 
77     fn mask_all_lvt(&mut self);
78 
79     /// 写入ICR寄存器
80     fn write_icr(&self, icr: Icr);
81 }
82 
83 /// @brief 所有LVT寄存器的枚举类型
84 #[allow(dead_code)]
85 #[repr(u32)]
86 #[derive(Debug, Clone, Copy)]
87 pub enum LVTRegister {
88     /// CMCI寄存器
89     ///
90     /// 如果支持CMCI功能,那么,当修正的机器错误超过阈值时,Local APIC通过CMCI寄存器的配置,
91     /// 向处理器核心投递中断消息
92     CMCI = 0x82f,
93     /// 定时器寄存器
94     ///
95     /// 当APIC定时器产生中断信号时,Local APIC通过定时器寄存器的设置,向处理器投递中断消息
96     Timer = 0x832,
97     /// 温度传感器寄存器
98     ///
99     /// 当处理器内部的温度传感器产生中断请求信号时,Local APIC会通过温度传感器寄存器的设置,
100     /// 向处理器投递中断消息。
101     Thermal = 0x833,
102     /// 性能监控计数器寄存器
103     ///
104     /// 当性能检测计数器寄存器溢出,产生中断请求时,Local APIC将会根据这个寄存器的配置,
105     /// 向处理器投递中断消息
106     PerformanceMonitor = 0x834,
107     /// 当处理器的LINT0引脚接收到中断请求信号时,Local APIC会根据这个寄存器的配置,
108     /// 向处理器投递中断消息
109     LINT0 = 0x835,
110     /// 当处理器的LINT0引脚接收到中断请求信号时,Local APIC会根据这个寄存器的配置,
111     /// 向处理器投递中断消息
112     LINT1 = 0x836,
113     /// 错误寄存器
114     ///
115     /// 当APIC检测到内部错误而产生中断请求信号时,它将会通过错误寄存器的设置,向处理器投递中断消息
116     ErrorReg = 0x837,
117 }
118 
119 impl Into<u32> for LVTRegister {
120     fn into(self) -> u32 {
121         self as u32
122     }
123 }
124 
125 #[derive(Debug)]
126 pub struct LVT {
127     register: LVTRegister,
128     data: u32,
129 }
130 
131 impl LVT {
132     /// 当第16位为1时,表示屏蔽中断
133     pub const MASKED: u32 = 1 << 16;
134 
135     pub fn new(register: LVTRegister, data: u32) -> Option<Self> {
136         // vector: u8, mode: DeliveryMode, status: DeliveryStatus
137         let mut result = Self { register, data: 0 };
138         result.set_vector((data & 0xFF) as u8);
139         match result.register {
140             LVTRegister::Timer | LVTRegister::ErrorReg => {}
141             _ => {
142                 result
143                     .set_delivery_mode(DeliveryMode::try_from(((data >> 8) & 0b111) as u8).ok()?)
144                     .ok()?;
145             }
146         }
147 
148         if let LVTRegister::LINT0 | LVTRegister::LINT1 = result.register {
149             result.set_interrupt_input_pin_polarity((data & (1 << 13)) == 0);
150 
151             if data & (1 << 15) != 0 {
152                 result.set_trigger_mode(TriggerMode::Level).ok()?;
153             } else {
154                 result.set_trigger_mode(TriggerMode::Edge).ok()?;
155             }
156         }
157         result.set_mask((data & (1 << 16)) != 0);
158 
159         if let LVTRegister::Timer = result.register {
160             result
161                 .set_timer_mode(LocalApicTimerMode::try_from(((data >> 17) & 0b11) as u8).ok()?)
162                 .ok()?;
163         }
164 
165         return Some(result);
166     }
167 
168     /// 获取LVT寄存器的原始值
169     #[allow(dead_code)]
170     pub fn data(&self) -> u32 {
171         return self.data;
172     }
173 
174     pub fn register(&self) -> LVTRegister {
175         return self.register;
176     }
177 
178     pub fn set_vector(&mut self, vector: u8) {
179         self.data &= !((1 << 8) - 1);
180         self.data |= vector as u32;
181     }
182 
183     /// 获取中断向量号
184     #[allow(dead_code)]
185     pub fn vector(&self) -> u8 {
186         return (self.data & 0xFF) as u8;
187     }
188 
189     /// 设置中断投递模式
190     ///
191     /// Timer、ErrorReg寄存器不支持这个功能
192     ///
193     /// ## 参数
194     ///
195     /// - `mode`:投递模式
196     pub fn set_delivery_mode(&mut self, mode: DeliveryMode) -> Result<(), SystemError> {
197         match self.register {
198             LVTRegister::Timer | LVTRegister::ErrorReg => {
199                 return Err(SystemError::EINVAL);
200             }
201             _ => {}
202         }
203 
204         self.data &= 0xFFFF_F8FF;
205         self.data |= ((mode as u32) & 0x7) << 8;
206         return Ok(());
207     }
208 
209     /// 获取中断投递模式
210     /// Timer、ErrorReg寄存器不支持这个功能
211     #[allow(dead_code)]
212     pub fn delivery_mode(&self) -> Option<DeliveryMode> {
213         if let LVTRegister::Timer | LVTRegister::ErrorReg = self.register {
214             return None;
215         }
216         return DeliveryMode::try_from(((self.data >> 8) & 0b111) as u8).ok();
217     }
218 
219     /// Get the delivery status of the interrupt
220     #[allow(dead_code)]
221     pub fn delivery_status(&self) -> DeliveryStatus {
222         return DeliveryStatus::from(self.data);
223     }
224 
225     /// 设置中断输入引脚的极性
226     ///
227     /// ## 参数
228     ///
229     /// - `high`:true表示高电平有效,false表示低电平有效
230     pub fn set_interrupt_input_pin_polarity(&mut self, high: bool) {
231         self.data &= 0xFFFF_DFFF;
232         // 0表示高电平有效,1表示低电平有效
233         if !high {
234             self.data |= 1 << 13;
235         }
236     }
237 
238     /// 获取中断输入引脚的极性
239     ///
240     /// true表示高电平有效,false表示低电平有效
241     #[allow(dead_code)]
242     pub fn interrupt_input_pin_polarity(&self) -> bool {
243         return (self.data & (1 << 13)) == 0;
244     }
245 
246     /// 设置中断输入引脚的触发模式
247     ///
248     /// 只有LINT0和LINT1寄存器支持这个功能
249     ///
250     /// ## 参数
251     ///
252     /// - `trigger_mode`:触发模式
253     pub fn set_trigger_mode(&mut self, trigger_mode: TriggerMode) -> Result<(), SystemError> {
254         match self.register {
255             LVTRegister::LINT0 | LVTRegister::LINT1 => {
256                 self.data &= 0xFFFF_7FFF;
257                 if trigger_mode == TriggerMode::Level {
258                     self.data |= 1 << 15;
259                 }
260                 return Ok(());
261             }
262             _ => {
263                 return Err(SystemError::EINVAL);
264             }
265         }
266     }
267 
268     /// 获取中断输入引脚的触发模式
269     ///
270     /// 只有LINT0和LINT1寄存器支持这个功能
271     #[allow(dead_code)]
272     pub fn trigger_mode(&self) -> Option<TriggerMode> {
273         match self.register {
274             LVTRegister::LINT0 | LVTRegister::LINT1 => {
275                 if self.data & (1 << 15) != 0 {
276                     return Some(TriggerMode::Level);
277                 } else {
278                     return Some(TriggerMode::Edge);
279                 }
280             }
281             _ => {
282                 return None;
283             }
284         }
285     }
286 
287     /// 设置是否屏蔽中断
288     ///
289     /// ## 参数
290     ///
291     /// - `mask`:true表示屏蔽中断,false表示不屏蔽中断
292     pub fn set_mask(&mut self, mask: bool) {
293         self.data &= 0xFFFE_FFFF;
294         if mask {
295             self.data |= 1 << 16;
296         }
297     }
298 
299     /// Check if the interrupt is masked
300     ///
301     /// true表示屏蔽中断,false表示不屏蔽中断
302     #[allow(dead_code)]
303     pub fn mask(&self) -> bool {
304         return (self.data & (1 << 16)) != 0;
305     }
306 
307     /// 设置定时器模式
308     pub fn set_timer_mode(&mut self, mode: LocalApicTimerMode) -> Result<(), SystemError> {
309         match self.register {
310             LVTRegister::Timer => {
311                 self.data &= 0xFFF9_FFFF;
312                 match mode {
313                     LocalApicTimerMode::Oneshot => {
314                         self.data |= 0b00 << 17;
315                     }
316                     LocalApicTimerMode::Periodic => {
317                         self.data |= 0b01 << 17;
318                     }
319                     LocalApicTimerMode::Deadline => {
320                         self.data |= 0b10 << 17;
321                     }
322                 }
323                 return Ok(());
324             }
325             _ => {
326                 return Err(SystemError::EINVAL);
327             }
328         }
329     }
330 
331     /// 获取定时器模式
332     #[allow(dead_code)]
333     pub fn timer_mode(&self) -> Option<LocalApicTimerMode> {
334         if let LVTRegister::Timer = self.register {
335             let mode = (self.data >> 17) & 0b11;
336             match mode {
337                 0b00 => {
338                     return Some(LocalApicTimerMode::Oneshot);
339                 }
340                 0b01 => {
341                     return Some(LocalApicTimerMode::Periodic);
342                 }
343                 0b10 => {
344                     return Some(LocalApicTimerMode::Deadline);
345                 }
346                 _ => {
347                     return None;
348                 }
349             }
350         }
351         return None;
352     }
353 }
354 
355 /// @brief
356 #[allow(dead_code)]
357 #[derive(Debug, PartialEq)]
358 pub enum DeliveryMode {
359     /// 由LVT寄存器的向量号区域指定中断向量号
360     Fixed = 0b000,
361     /// 通过处理器的SMI信号线,向处理器投递SMI中断请求。
362     /// 由于兼容性的原因,使用此投递模式时,LVT的中断向量号区域必须设置为0。
363     SMI = 0b010,
364     /// 向处理器投递不可屏蔽中断,并忽略向量号区域
365     NMI = 0b100,
366     /// 向处理器投递INIT中断请求,处理器会执行初始化的过程。
367     /// 由于兼容性的原因,使用此投递模式时,LVT的中断向量号区域必须设置为0。
368     /// CMCI、温度传感器、性能监控计数器等寄存器均不支持INIT投递模式
369     INIT = 0b101,
370 
371     /// 向目标处理器投递Start-Up IPI。
372     ///
373     /// 这个向量通常由多核引导模块调用(请参阅Intel开发手册Volume3 Section 8.4,
374     /// Multiple-Processor (MP) Initialization)。
375     /// 如果源APIC无法投递这个IPI,它不会自动重发。如果Start-Up IPI未成功投递,
376     /// 则交由软件决定是否在必要时重新投递SIPI
377     StartUp = 0b110,
378 
379     /// ExtINT模式可以将类8259A中断控制器产生的中断请求投递到处理器,并接收类
380     /// 8259A中断控制器提供的中断向量号。
381     /// CMCI、温度传感器、性能监控计数器等寄存器均不支持ExtINT投递模式
382     ExtINT = 0b111,
383 }
384 
385 impl TryFrom<u8> for DeliveryMode {
386     type Error = SystemError;
387 
388     fn try_from(value: u8) -> Result<Self, Self::Error> {
389         match value {
390             0b000 => {
391                 return Ok(DeliveryMode::Fixed);
392             }
393             0b010 => {
394                 return Ok(DeliveryMode::SMI);
395             }
396             0b100 => {
397                 return Ok(DeliveryMode::NMI);
398             }
399             0b101 => {
400                 return Ok(DeliveryMode::INIT);
401             }
402             0b110 => {
403                 return Ok(DeliveryMode::StartUp);
404             }
405             0b111 => {
406                 return Ok(DeliveryMode::ExtINT);
407             }
408             _ => {
409                 return Err(SystemError::EINVAL);
410             }
411         }
412     }
413 }
414 
415 /// @brief 投递状态
416 #[derive(Debug)]
417 #[allow(dead_code)]
418 pub enum DeliveryStatus {
419     /// 空闲态。
420     /// 此状态表明,当前中断源未产生中断,或者产生的中断已经投递到处理器,并被处理器处理。
421     Idle = 0,
422     /// 发送挂起状态。
423     /// 此状态表明,中断源产生的请求已经投递至处理器,但尚未被处理器处理。
424     SendPending = 1,
425 }
426 
427 impl DeliveryStatus {
428     pub fn from(data: u32) -> Self {
429         if data & (1 << 12) == 0 {
430             return DeliveryStatus::Idle;
431         } else {
432             return DeliveryStatus::SendPending;
433         }
434     }
435 }
436 
437 /// IPI Trigger Mode
438 #[derive(Debug, Eq, PartialEq)]
439 #[repr(u64)]
440 pub enum TriggerMode {
441     Edge = 0,
442     Level = 1,
443 }
444 
445 #[derive(Debug)]
446 pub struct CurrentApic;
447 
448 impl CurrentApic {
449     /// x2apic是否启用
450     pub fn x2apic_enabled(&self) -> bool {
451         return LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic;
452     }
453 
454     pub(self) unsafe fn write_xapic_register(&self, reg: XApicOffset, value: u32) {
455         current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
456             xapic.write(reg, value);
457         });
458     }
459 
460     /// 屏蔽类8259A芯片
461     unsafe fn mask8259a(&self) {
462         CurrentPortIOArch::out8(0x21, 0xff);
463         CurrentPortIOArch::out8(0xa1, 0xff);
464 
465         // 写入8259A pic的EOI位
466         CurrentPortIOArch::out8(0x20, 0x20);
467         CurrentPortIOArch::out8(0xa0, 0x20);
468 
469         kdebug!("8259A Masked.");
470 
471         // enable IMCR
472         CurrentPortIOArch::out8(0x22, 0x70);
473         CurrentPortIOArch::out8(0x23, 0x01);
474     }
475 }
476 
477 impl LocalAPIC for CurrentApic {
478     fn support() -> bool {
479         true
480     }
481 
482     fn init_current_cpu(&mut self) -> bool {
483         let cpu_id = smp_get_processor_id();
484         if cpu_id == 0 {
485             unsafe {
486                 self.mask8259a();
487             }
488         }
489         kinfo!("Initializing apic for cpu {}", cpu_id);
490         if X2Apic::support() && X2Apic.init_current_cpu() {
491             if cpu_id == 0 {
492                 LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::X2Apic, Ordering::SeqCst);
493             }
494             kinfo!("x2APIC initialized for cpu {}", cpu_id);
495         } else {
496             kinfo!("x2APIC not supported or failed to initialize, fallback to xAPIC.");
497             if cpu_id == 0 {
498                 LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::XApic, Ordering::SeqCst);
499             }
500             let apic_base =
501                 PhysAddr::new(unsafe { x86::msr::rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000 });
502             let xapic_instance = unsafe { XApic::new(apic_base) };
503 
504             let mut cur = current_xapic_instance().borrow_mut();
505             if cur.is_none() {
506                 *cur = Some(xapic_instance);
507             } else {
508                 panic!("xapic instance already initialized.");
509             }
510 
511             if let Some(xapic) = cur.as_mut() {
512                 xapic.init_current_cpu();
513             }
514 
515             kinfo!("xAPIC initialized for cpu {}", cpu_id);
516         }
517         if cpu_id == 0 {
518             ioapic_init();
519         }
520         kinfo!("Apic initialized.");
521         return true;
522     }
523 
524     fn send_eoi(&self) {
525         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
526             X2Apic.send_eoi();
527         } else {
528             current_xapic_instance().borrow().as_ref().map(|xapic| {
529                 xapic.send_eoi();
530             });
531         }
532     }
533 
534     fn version(&self) -> u8 {
535         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
536             return X2Apic.version();
537         } else {
538             return current_xapic_instance()
539                 .borrow()
540                 .as_ref()
541                 .map(|xapic| xapic.version())
542                 .unwrap_or(0);
543         }
544     }
545 
546     fn support_eoi_broadcast_suppression(&self) -> bool {
547         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
548             return X2Apic.support_eoi_broadcast_suppression();
549         } else {
550             return current_xapic_instance()
551                 .borrow()
552                 .as_ref()
553                 .map(|xapic| xapic.support_eoi_broadcast_suppression())
554                 .unwrap_or(false);
555         }
556     }
557 
558     fn max_lvt_entry(&self) -> u8 {
559         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
560             return X2Apic.max_lvt_entry();
561         } else {
562             return current_xapic_instance()
563                 .borrow()
564                 .as_ref()
565                 .map(|xapic| xapic.max_lvt_entry())
566                 .unwrap_or(0);
567         }
568     }
569 
570     fn id(&self) -> u32 {
571         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
572             return X2Apic.id();
573         } else {
574             return current_xapic_instance()
575                 .borrow()
576                 .as_ref()
577                 .map(|xapic| xapic.id())
578                 .unwrap_or(0);
579         }
580     }
581 
582     fn set_lvt(&mut self, lvt: LVT) {
583         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
584             X2Apic.set_lvt(lvt);
585         } else {
586             current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
587                 xapic.set_lvt(lvt);
588             });
589         }
590     }
591 
592     fn read_lvt(&self, reg: LVTRegister) -> LVT {
593         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
594             return X2Apic.read_lvt(reg);
595         } else {
596             return current_xapic_instance()
597                 .borrow()
598                 .as_ref()
599                 .map(|xapic| xapic.read_lvt(reg))
600                 .expect("xapic instance not initialized.");
601         }
602     }
603 
604     fn mask_all_lvt(&mut self) {
605         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
606             X2Apic.mask_all_lvt();
607         } else {
608             current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
609                 xapic.mask_all_lvt();
610             });
611         }
612     }
613 
614     fn write_icr(&self, icr: Icr) {
615         if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
616             X2Apic.write_icr(icr);
617         } else {
618             current_xapic_instance().borrow().as_ref().map(|xapic| {
619                 xapic.write_icr(icr);
620             });
621         }
622     }
623 }
624