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