xref: /DragonOS/kernel/src/arch/x86_64/driver/apic/ioapic.rs (revision 83ed0ebc293d5a10245089f627f52770fd5b9dd4)
1 use core::ptr::NonNull;
2 
3 use acpi::madt::Madt;
4 use bit_field::BitField;
5 use bitflags::bitflags;
6 
7 use crate::{
8     driver::acpi::acpi_manager,
9     kdebug, kinfo,
10     libs::{
11         once::Once,
12         spinlock::SpinLock,
13         volatile::{volwrite, Volatile},
14     },
15     mm::{
16         mmio_buddy::{mmio_pool, MMIOSpaceGuard},
17         PhysAddr,
18     },
19     syscall::SystemError,
20 };
21 
22 use super::{CurrentApic, LocalAPIC};
23 
24 static mut __IOAPIC: Option<SpinLock<IoApic>> = None;
25 
26 #[allow(non_snake_case)]
27 fn IOAPIC() -> &'static SpinLock<IoApic> {
28     unsafe { __IOAPIC.as_ref().unwrap() }
29 }
30 
31 #[allow(dead_code)]
32 pub struct IoApic {
33     reg: *mut u32,
34     data: *mut u32,
35     virt_eoi: *mut u32,
36     phys_base: PhysAddr,
37     mmio_guard: MMIOSpaceGuard,
38 }
39 
40 impl IoApic {
41     /// IO APIC的中断向量号从32开始
42     pub const VECTOR_BASE: u8 = 32;
43 
44     /// Create a new IOAPIC.
45     ///
46     /// # Safety
47     ///
48     /// You must provide a valid address.
49     pub unsafe fn new() -> Self {
50         static INIT_STATE: Once = Once::new();
51         assert!(!INIT_STATE.is_completed());
52 
53         let mut result: Option<IoApic> = None;
54         INIT_STATE.call_once(|| {
55             kinfo!("Initializing ioapic...");
56 
57             // get ioapic base from acpi
58 
59             let madt = acpi_manager()
60                 .tables()
61                 .unwrap()
62                 .find_table::<Madt>()
63                 .expect("IoApic::new(): failed to find MADT");
64 
65             let io_apic_paddr = madt
66                 .entries()
67                 .find(|x| {
68                     if let acpi::madt::MadtEntry::IoApic(_x) = x {
69                         return true;
70                     }
71                     return false;
72                 })
73                 .map(|x| {
74                     if let acpi::madt::MadtEntry::IoApic(x) = x {
75                         Some(x.io_apic_address)
76                     } else {
77                         None
78                     }
79                 })
80                 .flatten()
81                 .unwrap();
82 
83             let phys_base = PhysAddr::new(io_apic_paddr as usize);
84 
85             let mmio_guard = mmio_pool()
86                 .create_mmio(0x1000)
87                 .expect("IoApic::new(): failed to create mmio");
88             assert!(
89                 mmio_guard.map_phys(phys_base, 0x1000).is_ok(),
90                 "IoApic::new(): failed to map phys"
91             );
92             kdebug!("Ioapic map ok");
93             let reg = mmio_guard.vaddr();
94 
95             result = Some(IoApic {
96                 reg: reg.data() as *mut u32,
97                 data: (reg + 0x10).data() as *mut u32,
98                 virt_eoi: (reg + 0x40).data() as *mut u32,
99                 phys_base,
100                 mmio_guard,
101             });
102             kdebug!("IOAPIC: to mask all RTE");
103             // 屏蔽所有的RTE
104             let res_mut = result.as_mut().unwrap();
105             for i in 0..res_mut.supported_interrupts() {
106                 res_mut.write_rte(i, 0x20 + i, RedirectionEntry::DISABLED, 0);
107             }
108             kdebug!("Ioapic init done");
109         });
110 
111         assert!(
112             result.is_some(),
113             "Failed to init ioapic, maybe this is a double initialization bug?"
114         );
115         return result.unwrap();
116     }
117 
118     /// Disable all interrupts.
119     #[allow(dead_code)]
120     pub fn disable_all(&mut self) {
121         // Mark all interrupts edge-triggered, active high, disabled,
122         // and not routed to any CPUs.
123         for i in 0..self.supported_interrupts() {
124             self.disable(i);
125         }
126     }
127 
128     unsafe fn read(&mut self, reg: u8) -> u32 {
129         assert!(!(0x3..REG_TABLE).contains(&reg));
130         self.reg.write_volatile(reg as u32);
131         self.data.read_volatile()
132     }
133 
134     /// 直接写入REG_TABLE内的寄存器
135     ///
136     /// ## 参数
137     ///
138     /// * `reg` - 寄存器下标
139     /// * `data` - 寄存器数据
140     unsafe fn write(&mut self, reg: u8, data: u32) {
141         // 0x1 & 0x2 are read-only regs
142         assert!(!(0x1..REG_TABLE).contains(&reg));
143         self.reg.write_volatile(reg as u32);
144         self.data.write_volatile(data);
145     }
146 
147     fn write_rte(&mut self, rte_index: u8, vector: u8, flags: RedirectionEntry, dest: u8) {
148         unsafe {
149             self.write(REG_TABLE + 2 * rte_index, vector as u32 | flags.bits());
150             self.write(REG_TABLE + 2 * rte_index + 1, (dest as u32) << 24);
151         }
152     }
153 
154     /// 标记中断边沿触发、高电平有效、
155     /// 启用并路由到给定的 cpunum,即是是该 cpu 的 APIC ID(不是cpuid)
156     pub fn enable(&mut self, rte_index: u8) {
157         let mut val = unsafe { self.read(REG_TABLE + 2 * rte_index) };
158         val &= !RedirectionEntry::DISABLED.bits();
159         unsafe { self.write(REG_TABLE + 2 * rte_index, val) };
160     }
161 
162     pub fn disable(&mut self, rte_index: u8) {
163         let reg = REG_TABLE + 2 * rte_index;
164         let mut val = unsafe { self.read(reg) };
165         val |= RedirectionEntry::DISABLED.bits();
166         unsafe { self.write(reg, val) };
167     }
168 
169     /// 安装中断
170     ///
171     /// ## 参数
172     ///
173     /// * `rte_index` - RTE下标
174     /// * `vector` - 中断向量号
175     /// * `dest` - 目标CPU的APIC ID
176     /// * `level_triggered` - 是否为电平触发
177     /// * `active_high` - 是否为高电平有效
178     /// * `dest_logic` - 是否为逻辑模式
179     /// * `mask` - 是否屏蔽
180     pub fn install(
181         &mut self,
182         rte_index: u8,
183         vector: u8,
184         dest: u8,
185         level_triggered: bool,
186         active_high: bool,
187         dest_logic: bool,
188         mut mask: bool,
189     ) -> Result<(), SystemError> {
190         // 重定向表从 REG_TABLE 开始,使用两个寄存器来配置每个中断。
191         // 一对中的第一个(低位)寄存器包含配置位。32bit
192         // 第二个(高)寄存器包含一个位掩码,告诉哪些 CPU 可以服务该中断。
193         //  level_triggered:如果为真,表示中断触发方式为电平触发(level-triggered),则将RedirectionEntry::LEVEL标志位设置在flags中。
194         //  active_high:如果为假,表示中断的极性为低电平有效(active-low),则将RedirectionEntry::ACTIVELOW标志位设置在flags中。
195         //  dest_logic:如果为真,表示中断目标为逻辑模式(logical mode),则将RedirectionEntry::LOGICAL标志位设置在flags中。
196         //  !(0x20..=0xef).contains(&vector):判断中断向量号(vector)是否在范围0x20到0xef之外,如果是,则表示中断无效,将mask标志位设置为真。
197         //  mask:如果为真,表示中断被屏蔽(masked),将RedirectionEntry::DISABLED标志位设置在flags中。
198         let mut flags = RedirectionEntry::NONE;
199         if level_triggered {
200             flags |= RedirectionEntry::LEVEL;
201         }
202         if !active_high {
203             flags |= RedirectionEntry::ACTIVELOW;
204         }
205         if dest_logic {
206             flags |= RedirectionEntry::LOGICAL;
207         }
208         if !(0x20..=0xef).contains(&vector) {
209             mask = true;
210         }
211         if mask {
212             flags |= RedirectionEntry::DISABLED;
213         }
214         self.write_rte(rte_index, vector, flags, dest);
215         return Ok(());
216     }
217 
218     /// Get the vector number for the given IRQ.
219     #[allow(dead_code)]
220     pub fn irq_vector(&mut self, irq: u8) -> u8 {
221         unsafe { self.read(REG_TABLE + 2 * irq).get_bits(0..8) as u8 }
222     }
223 
224     /// Set the vector number for the given IRQ.
225     #[allow(dead_code)]
226     pub fn set_irq_vector(&mut self, irq: u8, vector: u8) {
227         let mut old = unsafe { self.read(REG_TABLE + 2 * irq) };
228         let old_vector = old.get_bits(0..8);
229         if !(0x20..=0xfe).contains(&old_vector) {
230             old |= RedirectionEntry::DISABLED.bits();
231         }
232         unsafe {
233             self.write(REG_TABLE + 2 * irq, *old.set_bits(0..8, vector as u32));
234         }
235     }
236 
237     #[allow(dead_code)]
238     pub fn id(&mut self) -> u8 {
239         unsafe { self.read(REG_ID).get_bits(24..28) as u8 }
240     }
241 
242     /// IO APIC Version
243     #[allow(dead_code)]
244     pub fn version(&mut self) -> u8 {
245         unsafe { self.read(REG_VER).get_bits(0..8) as u8 }
246     }
247 
248     /// Number of supported interrupts by this IO APIC.
249     ///
250     /// Max Redirection Entry = "how many IRQs can this I/O APIC handle - 1"
251     /// The -1 is silly so we add one back to it.
252     pub fn supported_interrupts(&mut self) -> u8 {
253         unsafe { (self.read(REG_VER).get_bits(16..24) + 1) as u8 }
254     }
255 
256     fn vector_rte_index(irq_num: u8) -> u8 {
257         assert!(irq_num >= Self::VECTOR_BASE);
258         irq_num - Self::VECTOR_BASE
259     }
260 
261     /// 电平响应
262     #[allow(dead_code)]
263     fn level_ack(&mut self, irq_num: u8) {
264         #[repr(C)]
265         struct LevelAck {
266             virt_eoi: Volatile<u32>,
267         }
268 
269         let p = NonNull::new(self.virt_eoi as *mut LevelAck).unwrap();
270 
271         unsafe {
272             volwrite!(p, virt_eoi, irq_num as u32);
273         }
274     }
275 
276     /// 边沿响应
277     #[allow(dead_code)]
278     fn edge_ack(&mut self, _irq_num: u8) {
279         CurrentApic.send_eoi();
280     }
281 }
282 
283 /// Register index: ID
284 const REG_ID: u8 = 0x00;
285 /// 获取IO APIC Version
286 const REG_VER: u8 = 0x01;
287 /// Redirection table base
288 const REG_TABLE: u8 = 0x10;
289 
290 bitflags! {
291     /// The redirection table starts at REG_TABLE and uses
292     /// two registers to configure each interrupt.
293     /// The first (low) register in a pair contains configuration bits.
294     /// The second (high) register contains a bitmask telling which
295     /// CPUs can serve that interrupt.
296     struct RedirectionEntry: u32 {
297         /// Interrupt disabled
298         const DISABLED  = 0x00010000;
299         /// Level-triggered (vs edge-)
300         const LEVEL     = 0x00008000;
301         /// Active low (vs high)
302         const ACTIVELOW = 0x00002000;
303         /// Destination is CPU id (vs APIC ID)
304         const LOGICAL   = 0x00000800;
305         /// None
306         const NONE		= 0x00000000;
307     }
308 }
309 
310 pub fn ioapic_init() {
311     kinfo!("Initializing ioapic...");
312     let ioapic = unsafe { IoApic::new() };
313     unsafe {
314         __IOAPIC = Some(SpinLock::new(ioapic));
315     }
316     kinfo!("IO Apic initialized.");
317 }
318 
319 /// 安装中断
320 ///
321 /// ## 参数
322 ///
323 /// * `vector` - 中断向量号
324 /// * `dest` - 目标CPU的APIC ID
325 /// * `level_triggered` - 是否为电平触发
326 /// * `active_high` - 是否为高电平有效
327 /// * `dest_logic` - 是否为逻辑模式
328 /// * `mask` - 是否屏蔽
329 pub(super) fn ioapic_install(
330     vector: u8,
331     dest: u8,
332     level_triggered: bool,
333     active_high: bool,
334     dest_logic: bool,
335 ) -> Result<(), SystemError> {
336     let rte_index = IoApic::vector_rte_index(vector);
337     return IOAPIC().lock_irqsave().install(
338         rte_index,
339         vector,
340         dest,
341         level_triggered,
342         active_high,
343         dest_logic,
344         true,
345     );
346 }
347 
348 /// 卸载中断
349 pub(super) fn ioapic_uninstall(vector: u8) {
350     let rte_index = IoApic::vector_rte_index(vector);
351     IOAPIC().lock_irqsave().disable(rte_index);
352 }
353 
354 /// 使能中断
355 pub(super) fn ioapic_enable(vector: u8) {
356     let rte_index = IoApic::vector_rte_index(vector);
357     IOAPIC().lock_irqsave().enable(rte_index);
358 }
359 
360 /// 禁用中断
361 pub(super) fn ioapic_disable(vector: u8) {
362     let rte_index = IoApic::vector_rte_index(vector);
363     IOAPIC().lock_irqsave().disable(rte_index);
364 }
365