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