xref: /DragonOS/kernel/src/arch/x86_64/driver/apic/ioapic.rs (revision 01c18c64b14b4ebabd98fa92c587c26874275eb1)
1 use core::ptr::NonNull;
2 
3 use acpi::madt::Madt;
4 use alloc::sync::Arc;
5 use bit_field::BitField;
6 use bitflags::bitflags;
7 use log::{debug, info};
8 use system_error::SystemError;
9 
10 use crate::{
11     driver::acpi::acpi_manager,
12     exception::{
13         handle::{edge_irq_handler, fast_eoi_irq_handler},
14         irqchip::{IrqChip, IrqChipData, IrqChipFlags, IrqChipSetMaskResult, IrqChipState},
15         irqdata::{IrqData, IrqLineStatus},
16         irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler},
17         manage::irq_manager,
18         IrqNumber,
19     },
20     libs::{
21         cpumask::CpuMask,
22         once::Once,
23         spinlock::{SpinLock, SpinLockGuard},
24         volatile::{volwrite, Volatile},
25     },
26     mm::{
27         mmio_buddy::{mmio_pool, MMIOSpaceGuard},
28         PhysAddr,
29     },
30 };
31 
32 use super::{CurrentApic, LocalAPIC};
33 
34 static mut __IOAPIC: Option<SpinLock<IoApic>> = None;
35 static mut IOAPIC_IR_CHIP: Option<Arc<IoApicChip>> = None;
36 
37 #[allow(non_snake_case)]
38 fn IOAPIC() -> &'static SpinLock<IoApic> {
39     unsafe { __IOAPIC.as_ref().unwrap() }
40 }
41 
42 #[inline(always)]
43 pub(super) fn ioapic_ir_chip() -> Arc<dyn IrqChip> {
44     unsafe { IOAPIC_IR_CHIP.as_ref().unwrap().clone() }
45 }
46 
47 #[allow(dead_code)]
48 pub struct IoApic {
49     reg: *mut u32,
50     data: *mut u32,
51     virt_eoi: *mut u32,
52     phys_base: PhysAddr,
53     mmio_guard: MMIOSpaceGuard,
54 }
55 
56 impl IoApic {
57     /// IO APIC的中断向量号从32开始
58     pub const VECTOR_BASE: u8 = 32;
59 
60     /// Create a new IOAPIC.
61     ///
62     /// # Safety
63     ///
64     /// You must provide a valid address.
65     pub unsafe fn new() -> Self {
66         static INIT_STATE: Once = Once::new();
67         assert!(!INIT_STATE.is_completed());
68 
69         let mut result: Option<IoApic> = None;
70         INIT_STATE.call_once(|| {
71             info!("Initializing ioapic...");
72 
73             // get ioapic base from acpi
74 
75             let madt = acpi_manager()
76                 .tables()
77                 .unwrap()
78                 .find_table::<Madt>()
79                 .expect("IoApic::new(): failed to find MADT");
80 
81             let io_apic_paddr = madt
82                 .entries()
83                 .find(|x| {
84                     if let acpi::madt::MadtEntry::IoApic(_x) = x {
85                         return true;
86                     }
87                     return false;
88                 })
89                 .and_then(|x| {
90                     if let acpi::madt::MadtEntry::IoApic(x) = x {
91                         Some(x.io_apic_address)
92                     } else {
93                         None
94                     }
95                 })
96                 .unwrap();
97 
98             let phys_base = PhysAddr::new(io_apic_paddr as usize);
99 
100             let mmio_guard = mmio_pool()
101                 .create_mmio(0x1000)
102                 .expect("IoApic::new(): failed to create mmio");
103             assert!(
104                 mmio_guard.map_phys(phys_base, 0x1000).is_ok(),
105                 "IoApic::new(): failed to map phys"
106             );
107             debug!("Ioapic map ok");
108             let reg = mmio_guard.vaddr();
109 
110             result = Some(IoApic {
111                 reg: reg.data() as *mut u32,
112                 data: (reg + 0x10).data() as *mut u32,
113                 virt_eoi: (reg + 0x40).data() as *mut u32,
114                 phys_base,
115                 mmio_guard,
116             });
117             debug!("IOAPIC: to mask all RTE");
118             // 屏蔽所有的RTE
119             let res_mut = result.as_mut().unwrap();
120             for i in 0..res_mut.supported_interrupts() {
121                 res_mut.write_rte(i, 0x20 + i, RedirectionEntry::DISABLED, 0);
122             }
123             debug!("Ioapic init done");
124         });
125 
126         assert!(
127             result.is_some(),
128             "Failed to init ioapic, maybe this is a double initialization bug?"
129         );
130         return result.unwrap();
131     }
132 
133     /// Disable all interrupts.
134     #[allow(dead_code)]
135     pub fn disable_all(&mut self) {
136         // Mark all interrupts edge-triggered, active high, disabled,
137         // and not routed to any CPUs.
138         for i in 0..self.supported_interrupts() {
139             self.disable(i);
140         }
141     }
142 
143     unsafe fn read(&mut self, reg: u8) -> u32 {
144         assert!(!(0x3..REG_TABLE).contains(&reg));
145         self.reg.write_volatile(reg as u32);
146         self.data.read_volatile()
147     }
148 
149     /// 直接写入REG_TABLE内的寄存器
150     ///
151     /// ## 参数
152     ///
153     /// * `reg` - 寄存器下标
154     /// * `data` - 寄存器数据
155     unsafe fn write(&mut self, reg: u8, data: u32) {
156         // 0x1 & 0x2 are read-only regs
157         assert!(!(0x1..REG_TABLE).contains(&reg));
158         self.reg.write_volatile(reg as u32);
159         self.data.write_volatile(data);
160     }
161 
162     fn write_rte(&mut self, rte_index: u8, vector: u8, flags: RedirectionEntry, dest: u8) {
163         unsafe {
164             self.write(REG_TABLE + 2 * rte_index, vector as u32 | flags.bits());
165             self.write(REG_TABLE + 2 * rte_index + 1, (dest as u32) << 24);
166         }
167     }
168 
169     /// 标记中断边沿触发、高电平有效、
170     /// 启用并路由到给定的 cpunum,即是是该 cpu 的 APIC ID(不是cpuid)
171     pub fn enable(&mut self, rte_index: u8) {
172         let mut val = unsafe { self.read(REG_TABLE + 2 * rte_index) };
173         val &= !RedirectionEntry::DISABLED.bits();
174         unsafe { self.write(REG_TABLE + 2 * rte_index, val) };
175     }
176 
177     pub fn disable(&mut self, rte_index: u8) {
178         let reg = REG_TABLE + 2 * rte_index;
179         let mut val = unsafe { self.read(reg) };
180         val |= RedirectionEntry::DISABLED.bits();
181         unsafe { self.write(reg, val) };
182     }
183 
184     /// 安装中断
185     ///
186     /// ## 参数
187     ///
188     /// * `rte_index` - RTE下标
189     /// * `vector` - 中断向量号
190     /// * `dest` - 目标CPU的APIC ID
191     /// * `level_triggered` - 是否为电平触发
192     /// * `active_high` - 是否为高电平有效
193     /// * `dest_logic` - 是否为逻辑模式
194     /// * `mask` - 是否屏蔽
195     #[allow(clippy::too_many_arguments)]
196     pub fn install(
197         &mut self,
198         rte_index: u8,
199         vector: u8,
200         dest: u8,
201         level_triggered: bool,
202         active_high: bool,
203         dest_logic: bool,
204         mut mask: bool,
205     ) -> Result<(), SystemError> {
206         // 重定向表从 REG_TABLE 开始,使用两个寄存器来配置每个中断。
207         // 一对中的第一个(低位)寄存器包含配置位。32bit
208         // 第二个(高)寄存器包含一个位掩码,告诉哪些 CPU 可以服务该中断。
209         //  level_triggered:如果为真,表示中断触发方式为电平触发(level-triggered),则将RedirectionEntry::LEVEL标志位设置在flags中。
210         //  active_high:如果为假,表示中断的极性为低电平有效(active-low),则将RedirectionEntry::ACTIVELOW标志位设置在flags中。
211         //  dest_logic:如果为真,表示中断目标为逻辑模式(logical mode),则将RedirectionEntry::LOGICAL标志位设置在flags中。
212         //  !(0x20..=0xef).contains(&vector):判断中断向量号(vector)是否在范围0x20到0xef之外,如果是,则表示中断无效,将mask标志位设置为真。
213         //  mask:如果为真,表示中断被屏蔽(masked),将RedirectionEntry::DISABLED标志位设置在flags中。
214         let mut flags = RedirectionEntry::NONE;
215         if level_triggered {
216             flags |= RedirectionEntry::LEVEL;
217         }
218         if !active_high {
219             flags |= RedirectionEntry::ACTIVELOW;
220         }
221         if dest_logic {
222             flags |= RedirectionEntry::LOGICAL;
223         }
224         if !(0x20..=0xef).contains(&vector) {
225             mask = true;
226         }
227         if mask {
228             flags |= RedirectionEntry::DISABLED;
229         }
230         self.write_rte(rte_index, vector, flags, dest);
231         return Ok(());
232     }
233 
234     /// Get the vector number for the given IRQ.
235     #[allow(dead_code)]
236     pub fn irq_vector(&mut self, irq: u8) -> u8 {
237         unsafe { self.read(REG_TABLE + 2 * irq).get_bits(0..8) as u8 }
238     }
239 
240     /// Set the vector number for the given IRQ.
241     #[allow(dead_code)]
242     pub fn set_irq_vector(&mut self, irq: u8, vector: u8) {
243         let mut old = unsafe { self.read(REG_TABLE + 2 * irq) };
244         let old_vector = old.get_bits(0..8);
245         if !(0x20..=0xfe).contains(&old_vector) {
246             old |= RedirectionEntry::DISABLED.bits();
247         }
248         unsafe {
249             self.write(REG_TABLE + 2 * irq, *old.set_bits(0..8, vector as u32));
250         }
251     }
252 
253     #[allow(dead_code)]
254     pub fn id(&mut self) -> u8 {
255         unsafe { self.read(REG_ID).get_bits(24..28) as u8 }
256     }
257 
258     /// IO APIC Version
259     #[allow(dead_code)]
260     pub fn version(&mut self) -> u8 {
261         unsafe { self.read(REG_VER).get_bits(0..8) as u8 }
262     }
263 
264     /// Number of supported interrupts by this IO APIC.
265     ///
266     /// Max Redirection Entry = "how many IRQs can this I/O APIC handle - 1"
267     /// The -1 is silly so we add one back to it.
268     pub fn supported_interrupts(&mut self) -> u8 {
269         unsafe { (self.read(REG_VER).get_bits(16..24) + 1) as u8 }
270     }
271 
272     pub fn pending(&mut self, irq: u8) -> bool {
273         let rte_index = Self::vector_rte_index(irq);
274         let data = unsafe { self.read(REG_TABLE + 2 * rte_index) };
275         data & (1 << 12) != 0
276     }
277 
278     fn vector_rte_index(irq_num: u8) -> u8 {
279         assert!(irq_num >= Self::VECTOR_BASE);
280         irq_num - Self::VECTOR_BASE
281     }
282 
283     /// 电平响应
284     #[allow(dead_code)]
285     fn level_ack(&mut self, irq_num: u8) {
286         #[repr(C)]
287         struct LevelAck {
288             virt_eoi: Volatile<u32>,
289         }
290 
291         let p = NonNull::new(self.virt_eoi as *mut LevelAck).unwrap();
292 
293         unsafe {
294             volwrite!(p, virt_eoi, irq_num as u32);
295         }
296     }
297 }
298 
299 /// Register index: ID
300 const REG_ID: u8 = 0x00;
301 /// 获取IO APIC Version
302 const REG_VER: u8 = 0x01;
303 /// Redirection table base
304 const REG_TABLE: u8 = 0x10;
305 
306 bitflags! {
307     /// The redirection table starts at REG_TABLE and uses
308     /// two registers to configure each interrupt.
309     /// The first (low) register in a pair contains configuration bits.
310     /// The second (high) register contains a bitmask telling which
311     /// CPUs can serve that interrupt.
312     struct RedirectionEntry: u32 {
313         /// Interrupt disabled
314         const DISABLED  = 0x00010000;
315         /// Level-triggered (vs edge-)
316         const LEVEL     = 0x00008000;
317         /// Active low (vs high)
318         const ACTIVELOW = 0x00002000;
319         /// Destination is CPU id (vs APIC ID)
320         const LOGICAL   = 0x00000800;
321         /// None
322         const NONE		= 0x00000000;
323     }
324 }
325 
326 #[derive(Debug)]
327 struct IoApicChipData {
328     inner: SpinLock<InnerIoApicChipData>,
329 }
330 
331 impl IrqChipData for IoApicChipData {
332     fn as_any_ref(&self) -> &dyn core::any::Any {
333         self
334     }
335 }
336 
337 impl IoApicChipData {
338     const fn default() -> Self {
339         Self::new(0, 0, 0, false, false, false, true)
340     }
341 
342     const fn new(
343         rte_index: u8,
344         vector: u8,
345         dest: u8,
346         level_triggered: bool,
347         active_high: bool,
348         dest_logic: bool,
349         mask: bool,
350     ) -> Self {
351         IoApicChipData {
352             inner: SpinLock::new(InnerIoApicChipData {
353                 rte_index,
354                 vector,
355                 dest,
356                 level_triggered,
357                 active_high,
358                 dest_logic,
359                 mask,
360             }),
361         }
362     }
363 
364     fn inner(&self) -> SpinLockGuard<InnerIoApicChipData> {
365         self.inner.lock_irqsave()
366     }
367 }
368 
369 #[derive(Debug)]
370 struct InnerIoApicChipData {
371     rte_index: u8,
372     vector: u8,
373     dest: u8,
374     level_triggered: bool,
375     active_high: bool,
376     dest_logic: bool,
377     mask: bool,
378 }
379 
380 impl InnerIoApicChipData {
381     /// 把中断数据同步到芯片
382     fn sync_to_chip(&self) -> Result<(), SystemError> {
383         ioapic_install(
384             self.vector,
385             self.dest,
386             self.level_triggered,
387             self.active_high,
388             self.dest_logic,
389             self.mask,
390         )
391     }
392 }
393 
394 #[inline(never)]
395 pub fn ioapic_init(ignore: &'static [IrqNumber]) {
396     info!("Initializing ioapic...");
397     let ioapic = unsafe { IoApic::new() };
398     unsafe {
399         __IOAPIC = Some(SpinLock::new(ioapic));
400     }
401     unsafe {
402         IOAPIC_IR_CHIP = Some(Arc::new(IoApicChip));
403     }
404 
405     // 绑定irqchip
406     for i in IoApic::VECTOR_BASE as u32..256 {
407         let irq = IrqNumber::new(i);
408 
409         if ignore.contains(&irq) {
410             continue;
411         }
412 
413         let desc = irq_desc_manager().lookup(irq).unwrap();
414         let irq_data = desc.irq_data();
415         let mut chip_info_guard = irq_data.chip_info_write_irqsave();
416         chip_info_guard.set_chip(Some(ioapic_ir_chip()));
417         let chip_data = IoApicChipData::default();
418         chip_data.inner().rte_index = IoApic::vector_rte_index(i as u8);
419         chip_data.inner().vector = i as u8;
420         chip_info_guard.set_chip_data(Some(Arc::new(chip_data)));
421         drop(chip_info_guard);
422         let level = irq_data.is_level_type();
423 
424         register_handler(&desc, level);
425     }
426 
427     info!("IO Apic initialized.");
428 }
429 
430 fn register_handler(desc: &Arc<IrqDesc>, level_triggered: bool) {
431     let fasteoi: bool = if level_triggered {
432         desc.modify_status(IrqLineStatus::empty(), IrqLineStatus::IRQ_LEVEL);
433         true
434     } else {
435         desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
436         false
437     };
438 
439     let handler: &dyn IrqFlowHandler = if fasteoi {
440         fast_eoi_irq_handler()
441     } else {
442         edge_irq_handler()
443     };
444     desc.set_handler(handler);
445 }
446 
447 /// 安装中断
448 ///
449 /// ## 参数
450 ///
451 /// * `vector` - 中断向量号
452 /// * `dest` - 目标CPU的APIC ID
453 /// * `level_triggered` - 是否为电平触发
454 /// * `active_high` - 是否为高电平有效
455 /// * `dest_logic` - 是否为逻辑模式
456 /// * `mask` - 是否屏蔽
457 fn ioapic_install(
458     vector: u8,
459     dest: u8,
460     level_triggered: bool,
461     active_high: bool,
462     dest_logic: bool,
463     mask: bool,
464 ) -> Result<(), SystemError> {
465     let rte_index = IoApic::vector_rte_index(vector);
466     return IOAPIC().lock_irqsave().install(
467         rte_index,
468         vector,
469         dest,
470         level_triggered,
471         active_high,
472         dest_logic,
473         mask,
474     );
475 }
476 
477 /// IoApic中断芯片
478 ///
479 /// https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/io_apic.c#1994
480 #[derive(Debug)]
481 struct IoApicChip;
482 
483 impl IrqChip for IoApicChip {
484     fn name(&self) -> &'static str {
485         "IR-IO-APIC"
486     }
487 
488     fn irq_startup(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
489         self.irq_unmask(irq)
490     }
491 
492     fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
493         let binding = irq
494             .chip_info_read_irqsave()
495             .chip_data()
496             .ok_or(SystemError::EINVAL)?;
497         let chip_data = binding
498             .as_any_ref()
499             .downcast_ref::<IoApicChipData>()
500             .ok_or(SystemError::EINVAL)?;
501 
502         let mut chip_data_inner = chip_data.inner();
503         chip_data_inner.mask = true;
504         chip_data_inner.sync_to_chip().ok();
505 
506         drop(chip_data_inner);
507 
508         return Ok(());
509     }
510 
511     fn can_set_affinity(&self) -> bool {
512         true
513     }
514 
515     fn can_set_flow_type(&self) -> bool {
516         true
517     }
518 
519     fn irq_set_type(
520         &self,
521         irq: &Arc<IrqData>,
522         flow_type: IrqLineStatus,
523     ) -> Result<IrqChipSetMaskResult, SystemError> {
524         let binding = irq
525             .chip_info_read_irqsave()
526             .chip_data()
527             .ok_or(SystemError::EINVAL)?;
528         let chip_data = binding
529             .as_any_ref()
530             .downcast_ref::<IoApicChipData>()
531             .ok_or(SystemError::EINVAL)?;
532         let mut chip_data_inner = chip_data.inner();
533 
534         let level_triggered = flow_type.is_level_type();
535         let active_high = flow_type.is_level_high().unwrap_or(false);
536         chip_data_inner.active_high = active_high;
537         chip_data_inner.level_triggered = level_triggered;
538         chip_data_inner.sync_to_chip()?;
539 
540         return Ok(IrqChipSetMaskResult::Success);
541     }
542 
543     fn irq_set_affinity(
544         &self,
545         irq: &Arc<IrqData>,
546         cpu: &CpuMask,
547         _force: bool,
548     ) -> Result<IrqChipSetMaskResult, SystemError> {
549         // 使用mask的第1个可用CPU
550         let dest = (cpu.first().ok_or(SystemError::EINVAL)?.data() & 0xff) as u8;
551 
552         let binding = irq
553             .chip_info_read_irqsave()
554             .chip_data()
555             .ok_or(SystemError::EINVAL)?;
556         let chip_data = binding
557             .as_any_ref()
558             .downcast_ref::<IoApicChipData>()
559             .ok_or(SystemError::EINVAL)?;
560 
561         let mut chip_data_inner = chip_data.inner();
562         let origin_dest = chip_data_inner.dest;
563         if origin_dest == dest {
564             return Ok(IrqChipSetMaskResult::Success);
565         }
566 
567         chip_data_inner.dest = dest;
568 
569         chip_data_inner.sync_to_chip()?;
570 
571         return Ok(IrqChipSetMaskResult::Success);
572     }
573 
574     fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
575         IOAPIC()
576             .lock_irqsave()
577             .enable(IoApic::vector_rte_index(irq.irq().data() as u8));
578         Ok(())
579     }
580 
581     fn can_mask_ack(&self) -> bool {
582         true
583     }
584 
585     fn irq_mask_ack(&self, irq: &Arc<IrqData>) {
586         self.irq_mask(irq).ok();
587         self.irq_eoi(irq);
588     }
589 
590     fn irq_eoi(&self, irq: &Arc<IrqData>) {
591         if irq.is_level_type() {
592             IOAPIC().lock_irqsave().level_ack(irq.irq().data() as u8);
593         } else {
594             CurrentApic.send_eoi();
595         }
596     }
597 
598     fn retrigger(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
599         irq_manager().irq_chip_retrigger_hierarchy(irq_data)
600     }
601 
602     fn irqchip_state(&self, irq: &Arc<IrqData>, which: IrqChipState) -> Result<bool, SystemError> {
603         let binding = irq
604             .chip_info_read_irqsave()
605             .chip_data()
606             .ok_or(SystemError::EINVAL)?;
607         let chip_data = binding
608             .as_any_ref()
609             .downcast_ref::<IoApicChipData>()
610             .ok_or(SystemError::EINVAL)?;
611 
612         match which {
613             IrqChipState::Pending => {
614                 return Ok(IOAPIC().lock_irqsave().pending(irq.irq().data() as u8));
615             }
616             IrqChipState::Active => {
617                 let chip_data_inner = chip_data.inner();
618                 return Ok(!chip_data_inner.mask);
619             }
620             IrqChipState::Masked => {
621                 let chip_data_inner = chip_data.inner();
622                 return Ok(chip_data_inner.mask);
623             }
624             IrqChipState::LineLevel => {
625                 let chip_data_inner = chip_data.inner();
626                 return Ok(chip_data_inner.active_high);
627             }
628             #[allow(unreachable_patterns)]
629             _ => {
630                 return Err(SystemError::EINVAL);
631             }
632         }
633     }
634 
635     fn irq_disable(&self, irq: &Arc<IrqData>) {
636         let binding = irq
637             .chip_info_read_irqsave()
638             .chip_data()
639             .ok_or(SystemError::EINVAL)
640             .unwrap();
641         let chip_data = binding
642             .as_any_ref()
643             .downcast_ref::<IoApicChipData>()
644             .ok_or(SystemError::EINVAL)
645             .unwrap();
646         let mut chip_data_inner = chip_data.inner();
647         chip_data_inner.mask = true;
648         chip_data_inner.sync_to_chip().ok();
649     }
650 
651     fn irq_ack(&self, irq_data: &Arc<IrqData>) {
652         // irq_manager().irq_chip_ack_parent(irq_data);
653         self.irq_eoi(irq_data);
654     }
655 
656     fn flags(&self) -> IrqChipFlags {
657         IrqChipFlags::IRQCHIP_SKIP_SET_WAKE | IrqChipFlags::IRQCHIP_AFFINITY_PRE_STARTUP
658     }
659 }
660