123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- use core::sync::atomic::Ordering;
- use atomic_enum::atomic_enum;
- use log::{debug, info};
- use system_error::SystemError;
- use x86::{apic::Icr, msr::IA32_APIC_BASE};
- use crate::{
- arch::{
- driver::apic::{hw_irq::ApicId, x2apic::X2Apic, xapic::XApic},
- io::PortIOArch,
- CurrentPortIOArch,
- },
- mm::PhysAddr,
- smp::core::smp_get_processor_id,
- };
- use self::{
- apic_timer::LocalApicTimerMode,
- xapic::{current_xapic_instance, XApicOffset},
- };
- pub mod apic_timer;
- pub mod hw_irq;
- pub mod ioapic;
- pub mod lapic_vector;
- pub mod x2apic;
- pub mod xapic;
- /// 当前启用的APIC类型
- #[atomic_enum]
- #[derive(PartialEq, Eq)]
- pub enum LocalApicEnableType {
- XApic,
- X2Apic,
- }
- static LOCAL_APIC_ENABLE_TYPE: AtomicLocalApicEnableType =
- AtomicLocalApicEnableType::new(LocalApicEnableType::XApic);
- pub trait LocalAPIC {
- /// @brief 判断当前处理器是否支持这个类型的apic
- ///
- /// @return true 当前处理器支持这个类型的apic
- /// @return false 当前处理器不支持这个类型的apic
- fn support() -> bool;
- /// @brief 为当前处理器初始化local apic
- ///
- /// @return true 初始化成功
- /// @return false 初始化失败
- fn init_current_cpu(&mut self) -> bool;
- /// @brief 发送EOI信号(End of interrupt)
- fn send_eoi(&self);
- /// @brief 获取APIC版本号
- #[allow(dead_code)]
- fn version(&self) -> u8;
- /// @brief 判断当前处理器是否支持EOI广播抑制
- fn support_eoi_broadcast_suppression(&self) -> bool;
- /// 获取最多支持的LVT寄存器数量
- #[allow(dead_code)]
- fn max_lvt_entry(&self) -> u8;
- /// @brief 获取当前处理器的APIC ID
- #[allow(dead_code)]
- fn id(&self) -> ApicId;
- /// @brief 设置LVT寄存器
- ///
- /// @param register 寄存器
- /// @param lvt 要被设置成的值
- fn set_lvt(&mut self, lvt: LVT);
- /// 读取LVT寄存器
- fn read_lvt(&self, reg: LVTRegister) -> LVT;
- fn mask_all_lvt(&mut self);
- /// 写入ICR寄存器
- fn write_icr(&self, icr: Icr);
- }
- /// @brief 所有LVT寄存器的枚举类型
- #[allow(dead_code)]
- #[repr(u32)]
- #[derive(Debug, Clone, Copy)]
- pub enum LVTRegister {
- /// CMCI寄存器
- ///
- /// 如果支持CMCI功能,那么,当修正的机器错误超过阈值时,Local APIC通过CMCI寄存器的配置,
- /// 向处理器核心投递中断消息
- CMCI = 0x82f,
- /// 定时器寄存器
- ///
- /// 当APIC定时器产生中断信号时,Local APIC通过定时器寄存器的设置,向处理器投递中断消息
- Timer = 0x832,
- /// 温度传感器寄存器
- ///
- /// 当处理器内部的温度传感器产生中断请求信号时,Local APIC会通过温度传感器寄存器的设置,
- /// 向处理器投递中断消息。
- Thermal = 0x833,
- /// 性能监控计数器寄存器
- ///
- /// 当性能检测计数器寄存器溢出,产生中断请求时,Local APIC将会根据这个寄存器的配置,
- /// 向处理器投递中断消息
- PerformanceMonitor = 0x834,
- /// 当处理器的LINT0引脚接收到中断请求信号时,Local APIC会根据这个寄存器的配置,
- /// 向处理器投递中断消息
- LINT0 = 0x835,
- /// 当处理器的LINT0引脚接收到中断请求信号时,Local APIC会根据这个寄存器的配置,
- /// 向处理器投递中断消息
- LINT1 = 0x836,
- /// 错误寄存器
- ///
- /// 当APIC检测到内部错误而产生中断请求信号时,它将会通过错误寄存器的设置,向处理器投递中断消息
- ErrorReg = 0x837,
- }
- impl From<LVTRegister> for u32 {
- fn from(val: LVTRegister) -> Self {
- val as u32
- }
- }
- #[derive(Debug)]
- pub struct LVT {
- register: LVTRegister,
- data: u32,
- }
- impl LVT {
- /// 当第16位为1时,表示屏蔽中断
- pub const MASKED: u32 = 1 << 16;
- pub fn new(register: LVTRegister, data: u32) -> Option<Self> {
- // vector: u8, mode: DeliveryMode, status: DeliveryStatus
- let mut result = Self { register, data: 0 };
- result.set_vector((data & 0xFF) as u8);
- match result.register {
- LVTRegister::Timer | LVTRegister::ErrorReg => {}
- _ => {
- result
- .set_delivery_mode(DeliveryMode::try_from(((data >> 8) & 0b111) as u8).ok()?)
- .ok()?;
- }
- }
- if let LVTRegister::LINT0 | LVTRegister::LINT1 = result.register {
- result.set_interrupt_input_pin_polarity((data & (1 << 13)) == 0);
- if data & (1 << 15) != 0 {
- result.set_trigger_mode(TriggerMode::Level).ok()?;
- } else {
- result.set_trigger_mode(TriggerMode::Edge).ok()?;
- }
- }
- result.set_mask((data & (1 << 16)) != 0);
- if let LVTRegister::Timer = result.register {
- result
- .set_timer_mode(LocalApicTimerMode::try_from(((data >> 17) & 0b11) as u8).ok()?)
- .ok()?;
- }
- return Some(result);
- }
- /// 获取LVT寄存器的原始值
- #[allow(dead_code)]
- pub fn data(&self) -> u32 {
- return self.data;
- }
- pub fn register(&self) -> LVTRegister {
- return self.register;
- }
- pub fn set_vector(&mut self, vector: u8) {
- self.data &= !((1 << 8) - 1);
- self.data |= vector as u32;
- }
- /// 获取中断向量号
- #[allow(dead_code)]
- pub fn vector(&self) -> u8 {
- return (self.data & 0xFF) as u8;
- }
- /// 设置中断投递模式
- ///
- /// Timer、ErrorReg寄存器不支持这个功能
- ///
- /// ## 参数
- ///
- /// - `mode`:投递模式
- pub fn set_delivery_mode(&mut self, mode: DeliveryMode) -> Result<(), SystemError> {
- match self.register {
- LVTRegister::Timer | LVTRegister::ErrorReg => {
- return Err(SystemError::EINVAL);
- }
- _ => {}
- }
- self.data &= 0xFFFF_F8FF;
- self.data |= ((mode as u32) & 0x7) << 8;
- return Ok(());
- }
- /// 获取中断投递模式
- /// Timer、ErrorReg寄存器不支持这个功能
- #[allow(dead_code)]
- pub fn delivery_mode(&self) -> Option<DeliveryMode> {
- if let LVTRegister::Timer | LVTRegister::ErrorReg = self.register {
- return None;
- }
- return DeliveryMode::try_from(((self.data >> 8) & 0b111) as u8).ok();
- }
- /// Get the delivery status of the interrupt
- #[allow(dead_code)]
- pub fn delivery_status(&self) -> DeliveryStatus {
- return DeliveryStatus::from(self.data);
- }
- /// 设置中断输入引脚的极性
- ///
- /// ## 参数
- ///
- /// - `high`:true表示高电平有效,false表示低电平有效
- pub fn set_interrupt_input_pin_polarity(&mut self, high: bool) {
- self.data &= 0xFFFF_DFFF;
- // 0表示高电平有效,1表示低电平有效
- if !high {
- self.data |= 1 << 13;
- }
- }
- /// 获取中断输入引脚的极性
- ///
- /// true表示高电平有效,false表示低电平有效
- #[allow(dead_code)]
- pub fn interrupt_input_pin_polarity(&self) -> bool {
- return (self.data & (1 << 13)) == 0;
- }
- /// 设置中断输入引脚的触发模式
- ///
- /// 只有LINT0和LINT1寄存器支持这个功能
- ///
- /// ## 参数
- ///
- /// - `trigger_mode`:触发模式
- pub fn set_trigger_mode(&mut self, trigger_mode: TriggerMode) -> Result<(), SystemError> {
- match self.register {
- LVTRegister::LINT0 | LVTRegister::LINT1 => {
- self.data &= 0xFFFF_7FFF;
- if trigger_mode == TriggerMode::Level {
- self.data |= 1 << 15;
- }
- return Ok(());
- }
- _ => {
- return Err(SystemError::EINVAL);
- }
- }
- }
- /// 获取中断输入引脚的触发模式
- ///
- /// 只有LINT0和LINT1寄存器支持这个功能
- #[allow(dead_code)]
- pub fn trigger_mode(&self) -> Option<TriggerMode> {
- match self.register {
- LVTRegister::LINT0 | LVTRegister::LINT1 => {
- if self.data & (1 << 15) != 0 {
- return Some(TriggerMode::Level);
- } else {
- return Some(TriggerMode::Edge);
- }
- }
- _ => {
- return None;
- }
- }
- }
- /// 设置是否屏蔽中断
- ///
- /// ## 参数
- ///
- /// - `mask`:true表示屏蔽中断,false表示不屏蔽中断
- pub fn set_mask(&mut self, mask: bool) {
- self.data &= 0xFFFE_FFFF;
- if mask {
- self.data |= 1 << 16;
- }
- }
- /// Check if the interrupt is masked
- ///
- /// true表示屏蔽中断,false表示不屏蔽中断
- #[allow(dead_code)]
- pub fn mask(&self) -> bool {
- return (self.data & (1 << 16)) != 0;
- }
- /// 设置定时器模式
- pub fn set_timer_mode(&mut self, mode: LocalApicTimerMode) -> Result<(), SystemError> {
- match self.register {
- LVTRegister::Timer => {
- self.data &= 0xFFF9_FFFF;
- match mode {
- LocalApicTimerMode::Oneshot => {
- self.data |= 0b00 << 17;
- }
- LocalApicTimerMode::Periodic => {
- self.data |= 0b01 << 17;
- }
- LocalApicTimerMode::Deadline => {
- self.data |= 0b10 << 17;
- }
- }
- return Ok(());
- }
- _ => {
- return Err(SystemError::EINVAL);
- }
- }
- }
- /// 获取定时器模式
- #[allow(dead_code)]
- pub fn timer_mode(&self) -> Option<LocalApicTimerMode> {
- if let LVTRegister::Timer = self.register {
- let mode = (self.data >> 17) & 0b11;
- match mode {
- 0b00 => {
- return Some(LocalApicTimerMode::Oneshot);
- }
- 0b01 => {
- return Some(LocalApicTimerMode::Periodic);
- }
- 0b10 => {
- return Some(LocalApicTimerMode::Deadline);
- }
- _ => {
- return None;
- }
- }
- }
- return None;
- }
- }
- /// @brief
- #[allow(dead_code)]
- #[derive(Debug, PartialEq)]
- pub enum DeliveryMode {
- /// 由LVT寄存器的向量号区域指定中断向量号
- Fixed = 0b000,
- /// 通过处理器的SMI信号线,向处理器投递SMI中断请求。
- /// 由于兼容性的原因,使用此投递模式时,LVT的中断向量号区域必须设置为0。
- SMI = 0b010,
- /// 向处理器投递不可屏蔽中断,并忽略向量号区域
- NMI = 0b100,
- /// 向处理器投递INIT中断请求,处理器会执行初始化的过程。
- /// 由于兼容性的原因,使用此投递模式时,LVT的中断向量号区域必须设置为0。
- /// CMCI、温度传感器、性能监控计数器等寄存器均不支持INIT投递模式
- INIT = 0b101,
- /// 向目标处理器投递Start-Up IPI。
- ///
- /// 这个向量通常由多核引导模块调用(请参阅Intel开发手册Volume3 Section 8.4,
- /// Multiple-Processor (MP) Initialization)。
- /// 如果源APIC无法投递这个IPI,它不会自动重发。如果Start-Up IPI未成功投递,
- /// 则交由软件决定是否在必要时重新投递SIPI
- StartUp = 0b110,
- /// ExtINT模式可以将类8259A中断控制器产生的中断请求投递到处理器,并接收类
- /// 8259A中断控制器提供的中断向量号。
- /// CMCI、温度传感器、性能监控计数器等寄存器均不支持ExtINT投递模式
- ExtINT = 0b111,
- }
- impl TryFrom<u8> for DeliveryMode {
- type Error = SystemError;
- fn try_from(value: u8) -> Result<Self, Self::Error> {
- match value {
- 0b000 => {
- return Ok(DeliveryMode::Fixed);
- }
- 0b010 => {
- return Ok(DeliveryMode::SMI);
- }
- 0b100 => {
- return Ok(DeliveryMode::NMI);
- }
- 0b101 => {
- return Ok(DeliveryMode::INIT);
- }
- 0b110 => {
- return Ok(DeliveryMode::StartUp);
- }
- 0b111 => {
- return Ok(DeliveryMode::ExtINT);
- }
- _ => {
- return Err(SystemError::EINVAL);
- }
- }
- }
- }
- /// @brief 投递状态
- #[derive(Debug)]
- #[allow(dead_code)]
- pub enum DeliveryStatus {
- /// 空闲态。
- /// 此状态表明,当前中断源未产生中断,或者产生的中断已经投递到处理器,并被处理器处理。
- Idle = 0,
- /// 发送挂起状态。
- /// 此状态表明,中断源产生的请求已经投递至处理器,但尚未被处理器处理。
- SendPending = 1,
- }
- impl DeliveryStatus {
- pub fn from(data: u32) -> Self {
- if data & (1 << 12) == 0 {
- return DeliveryStatus::Idle;
- } else {
- return DeliveryStatus::SendPending;
- }
- }
- }
- /// IPI Trigger Mode
- #[derive(Debug, Eq, PartialEq)]
- #[repr(u64)]
- pub enum TriggerMode {
- Edge = 0,
- Level = 1,
- }
- #[derive(Debug)]
- pub struct CurrentApic;
- impl CurrentApic {
- /// x2apic是否启用
- pub fn x2apic_enabled(&self) -> bool {
- return LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic;
- }
- pub(self) unsafe fn write_xapic_register(&self, reg: XApicOffset, value: u32) {
- if let Some(xapic) = current_xapic_instance().borrow_mut().as_mut() {
- xapic.write(reg, value);
- }
- }
- /// 屏蔽类8259A芯片
- unsafe fn mask8259a(&self) {
- CurrentPortIOArch::out8(0x21, 0xff);
- CurrentPortIOArch::out8(0xa1, 0xff);
- // 写入8259A pic的EOI位
- CurrentPortIOArch::out8(0x20, 0x20);
- CurrentPortIOArch::out8(0xa0, 0x20);
- debug!("8259A Masked.");
- // enable IMCR
- CurrentPortIOArch::out8(0x22, 0x70);
- CurrentPortIOArch::out8(0x23, 0x01);
- }
- }
- impl LocalAPIC for CurrentApic {
- fn support() -> bool {
- true
- }
- fn init_current_cpu(&mut self) -> bool {
- let cpu_id = smp_get_processor_id();
- if cpu_id.data() == 0 {
- unsafe {
- self.mask8259a();
- }
- }
- info!("Initializing apic for cpu {:?}", cpu_id);
- if X2Apic::support() && X2Apic.init_current_cpu() {
- if cpu_id.data() == 0 {
- LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::X2Apic, Ordering::SeqCst);
- }
- info!("x2APIC initialized for cpu {:?}", cpu_id);
- } else {
- info!("x2APIC not supported or failed to initialize, fallback to xAPIC.");
- if cpu_id.data() == 0 {
- LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::XApic, Ordering::SeqCst);
- }
- let apic_base =
- PhysAddr::new(unsafe { x86::msr::rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000 });
- let xapic_instance = unsafe { XApic::new(apic_base) };
- let mut cur = current_xapic_instance().borrow_mut();
- if cur.is_none() {
- *cur = Some(xapic_instance);
- } else {
- panic!("xapic instance already initialized.");
- }
- if let Some(xapic) = cur.as_mut() {
- xapic.init_current_cpu();
- }
- info!("xAPIC initialized for cpu {:?}", cpu_id);
- }
- info!("Apic initialized.");
- return true;
- }
- fn send_eoi(&self) {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- X2Apic.send_eoi();
- } else if let Some(xapic) = current_xapic_instance().borrow().as_ref() {
- xapic.send_eoi();
- }
- }
- fn version(&self) -> u8 {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- return X2Apic.version();
- } else {
- return current_xapic_instance()
- .borrow()
- .as_ref()
- .map(|xapic| xapic.version())
- .unwrap_or(0);
- }
- }
- fn support_eoi_broadcast_suppression(&self) -> bool {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- return X2Apic.support_eoi_broadcast_suppression();
- } else {
- return current_xapic_instance()
- .borrow()
- .as_ref()
- .map(|xapic| xapic.support_eoi_broadcast_suppression())
- .unwrap_or(false);
- }
- }
- fn max_lvt_entry(&self) -> u8 {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- return X2Apic.max_lvt_entry();
- } else {
- return current_xapic_instance()
- .borrow()
- .as_ref()
- .map(|xapic| xapic.max_lvt_entry())
- .unwrap_or(0);
- }
- }
- fn id(&self) -> ApicId {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- return X2Apic.id();
- } else {
- return current_xapic_instance()
- .borrow()
- .as_ref()
- .map(|xapic| xapic.id())
- .unwrap_or(ApicId::new(0));
- }
- }
- fn set_lvt(&mut self, lvt: LVT) {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- X2Apic.set_lvt(lvt);
- } else if let Some(xapic) = current_xapic_instance().borrow_mut().as_mut() {
- xapic.set_lvt(lvt);
- }
- }
- fn read_lvt(&self, reg: LVTRegister) -> LVT {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- return X2Apic.read_lvt(reg);
- } else {
- return current_xapic_instance()
- .borrow()
- .as_ref()
- .map(|xapic| xapic.read_lvt(reg))
- .expect("xapic instance not initialized.");
- }
- }
- fn mask_all_lvt(&mut self) {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- X2Apic.mask_all_lvt();
- } else if let Some(xapic) = current_xapic_instance().borrow_mut().as_mut() {
- xapic.mask_all_lvt();
- }
- }
- fn write_icr(&self, icr: Icr) {
- if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
- X2Apic.write_icr(icr);
- } else if let Some(xapic) = current_xapic_instance().borrow().as_ref() {
- xapic.write_icr(icr);
- }
- }
- }
|