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(®)); 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(®)); 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