mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 22:36:48 +00:00
345 lines
12 KiB
Rust
345 lines
12 KiB
Rust
use core::{
|
||
cell::RefCell,
|
||
hint::spin_loop,
|
||
ptr::{read_volatile, write_volatile},
|
||
};
|
||
|
||
use log::{debug, error, info};
|
||
|
||
use crate::{
|
||
mm::{
|
||
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
|
||
percpu::PerCpu,
|
||
PhysAddr, VirtAddr,
|
||
},
|
||
smp::core::smp_get_processor_id,
|
||
};
|
||
|
||
use super::{hw_irq::ApicId, LVTRegister, LocalAPIC, LVT};
|
||
|
||
/// per-cpu的xAPIC的MMIO空间起始地址
|
||
static mut XAPIC_INSTANCES: [RefCell<Option<XApic>>; PerCpu::MAX_CPU_NUM as usize] =
|
||
[const { RefCell::new(None) }; PerCpu::MAX_CPU_NUM as usize];
|
||
|
||
#[inline(always)]
|
||
pub(super) fn current_xapic_instance() -> &'static RefCell<Option<XApic>> {
|
||
unsafe { &XAPIC_INSTANCES.as_ref()[smp_get_processor_id().data() as usize] }
|
||
}
|
||
|
||
/// TODO:统一变量
|
||
/// @brief local APIC 寄存器地址偏移量
|
||
#[derive(Debug)]
|
||
#[allow(dead_code)]
|
||
#[allow(non_camel_case_types)]
|
||
#[repr(u32)]
|
||
pub enum XApicOffset {
|
||
// 定义各个寄存器的地址偏移量
|
||
LOCAL_APIC_OFFSET_Local_APIC_ID = 0x20,
|
||
LOCAL_APIC_OFFSET_Local_APIC_Version = 0x30,
|
||
LOCAL_APIC_OFFSET_Local_APIC_TPR = 0x80,
|
||
LOCAL_APIC_OFFSET_Local_APIC_APR = 0x90,
|
||
LOCAL_APIC_OFFSET_Local_APIC_PPR = 0xa0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_EOI = 0xb0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_RRD = 0xc0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_LDR = 0xd0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_DFR = 0xe0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_SVR = 0xf0,
|
||
|
||
LOCAL_APIC_OFFSET_Local_APIC_ISR_31_0 = 0x100, // In-Service Register
|
||
LOCAL_APIC_OFFSET_Local_APIC_ISR_63_32 = 0x110,
|
||
LOCAL_APIC_OFFSET_Local_APIC_ISR_95_64 = 0x120,
|
||
LOCAL_APIC_OFFSET_Local_APIC_ISR_127_96 = 0x130,
|
||
LOCAL_APIC_OFFSET_Local_APIC_ISR_159_128 = 0x140,
|
||
LOCAL_APIC_OFFSET_Local_APIC_ISR_191_160 = 0x150,
|
||
LOCAL_APIC_OFFSET_Local_APIC_ISR_223_192 = 0x160,
|
||
LOCAL_APIC_OFFSET_Local_APIC_ISR_255_224 = 0x170,
|
||
|
||
LOCAL_APIC_OFFSET_Local_APIC_TMR_31_0 = 0x180, // Trigger Mode Register
|
||
LOCAL_APIC_OFFSET_Local_APIC_TMR_63_32 = 0x190,
|
||
LOCAL_APIC_OFFSET_Local_APIC_TMR_95_64 = 0x1a0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_TMR_127_96 = 0x1b0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_TMR_159_128 = 0x1c0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_TMR_191_160 = 0x1d0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_TMR_223_192 = 0x1e0,
|
||
LOCAL_APIC_OFFSET_Local_APIC_TMR_255_224 = 0x1f0,
|
||
|
||
LOCAL_APIC_OFFSET_Local_APIC_IRR_31_0 = 0x200, // Interrupt Request Register
|
||
LOCAL_APIC_OFFSET_Local_APIC_IRR_63_32 = 0x210,
|
||
LOCAL_APIC_OFFSET_Local_APIC_IRR_95_64 = 0x220,
|
||
LOCAL_APIC_OFFSET_Local_APIC_IRR_127_96 = 0x230,
|
||
LOCAL_APIC_OFFSET_Local_APIC_IRR_159_128 = 0x240,
|
||
LOCAL_APIC_OFFSET_Local_APIC_IRR_191_160 = 0x250,
|
||
LOCAL_APIC_OFFSET_Local_APIC_IRR_223_192 = 0x260,
|
||
LOCAL_APIC_OFFSET_Local_APIC_IRR_255_224 = 0x270,
|
||
|
||
LOCAL_APIC_OFFSET_Local_APIC_ESR = 0x280, // Error Status Register
|
||
|
||
LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI = 0x2f0, // Corrected Machine Check Interrupt Register
|
||
|
||
LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0 = 0x300, // Interrupt Command Register
|
||
LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32 = 0x310,
|
||
|
||
LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER = 0x320,
|
||
LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL = 0x330,
|
||
LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR = 0x340,
|
||
LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0 = 0x350,
|
||
LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1 = 0x360,
|
||
LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR = 0x370,
|
||
// 初始计数寄存器(定时器专用)
|
||
LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG = 0x380,
|
||
// 当前计数寄存器(定时器专用)
|
||
LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG = 0x390,
|
||
LOCAL_APIC_OFFSET_Local_APIC_CLKDIV = 0x3e0,
|
||
}
|
||
|
||
impl From<XApicOffset> for u32 {
|
||
fn from(val: XApicOffset) -> Self {
|
||
val as u32
|
||
}
|
||
}
|
||
|
||
impl From<LVTRegister> for XApicOffset {
|
||
fn from(lvt: LVTRegister) -> Self {
|
||
match lvt {
|
||
LVTRegister::Timer => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER,
|
||
LVTRegister::Thermal => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL,
|
||
LVTRegister::PerformanceMonitor => {
|
||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR
|
||
}
|
||
LVTRegister::LINT0 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0,
|
||
LVTRegister::LINT1 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1,
|
||
LVTRegister::ErrorReg => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR,
|
||
LVTRegister::CMCI => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
#[allow(dead_code)]
|
||
pub struct XApic {
|
||
/// 当前xAPIC的寄存器映射的虚拟地址。注意,每个CPU都有自己的xAPIC,所以这个地址是每个CPU都不一样的。
|
||
apic_vaddr: VirtAddr,
|
||
/// `apic_vaddr`与映射的空间起始位置之间的偏移量
|
||
offset: usize,
|
||
map_guard: MMIOSpaceGuard,
|
||
xapic_base: PhysAddr,
|
||
}
|
||
|
||
impl XApic {
|
||
/// 读取指定寄存器的值
|
||
#[allow(dead_code)]
|
||
pub unsafe fn read(&self, reg: XApicOffset) -> u32 {
|
||
read_volatile((self.apic_vaddr.data() + reg as usize) as *const u32)
|
||
}
|
||
|
||
/// 将指定的值写入寄存器
|
||
#[allow(dead_code)]
|
||
pub unsafe fn write(&self, reg: XApicOffset, value: u32) {
|
||
write_volatile(
|
||
(self.apic_vaddr.data() + (reg as u32) as usize) as *mut u32,
|
||
value,
|
||
);
|
||
self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID); // 等待写操作完成,通过读取进行同步
|
||
}
|
||
}
|
||
|
||
impl XApic {
|
||
/// 创建新的XAPIC实例
|
||
///
|
||
/// ## 参数
|
||
///
|
||
/// - `xapic_base` - 当前核心的xAPIC的寄存器的物理地址
|
||
pub unsafe fn new(xapic_base: PhysAddr) -> Self {
|
||
let offset = xapic_base.data() & 0xffff;
|
||
let paddr = PhysAddr::new(xapic_base.data() & !0xffff);
|
||
let g = mmio_pool()
|
||
.create_mmio(4096)
|
||
.expect("Fail to create MMIO for XAPIC");
|
||
g.map_phys(paddr, 4096).expect("Fail to map MMIO for XAPIC");
|
||
let addr = g.vaddr() + offset;
|
||
|
||
debug!(
|
||
"XAPIC: {:#x} -> {:#x}, offset={offset}",
|
||
xapic_base.data(),
|
||
addr.data()
|
||
);
|
||
|
||
let r = Self {
|
||
apic_vaddr: addr,
|
||
offset,
|
||
map_guard: g,
|
||
xapic_base,
|
||
};
|
||
|
||
return r;
|
||
}
|
||
}
|
||
|
||
#[allow(dead_code)]
|
||
const X1: u32 = 0x0000000B; // 将除数设置为1,即不除频率
|
||
#[allow(dead_code)]
|
||
const PERIODIC: u32 = 0x00020000; // 周期性模式
|
||
#[allow(dead_code)]
|
||
const ENABLE: u32 = 0x00000100; // 单元使能
|
||
#[allow(dead_code)]
|
||
const MASKED: u32 = 0x00010000; // 中断屏蔽
|
||
const LEVEL: u32 = 0x00008000; // 电平触发
|
||
const BCAST: u32 = 0x00080000; // 发送到所有APIC,包括自己
|
||
const DELIVS: u32 = 0x00001000; // 传递状态
|
||
const INIT: u32 = 0x00000500; // INIT/RESET
|
||
|
||
//中断请求
|
||
#[allow(dead_code)]
|
||
const T_IRQ0: u32 = 32; // IRQ 0 对应于 T_IRQ 中断
|
||
#[allow(dead_code)]
|
||
const IRQ_TIMER: u32 = 0;
|
||
#[allow(dead_code)]
|
||
const IRQ_KBD: u32 = 1;
|
||
#[allow(dead_code)]
|
||
const IRQ_COM1: u32 = 4;
|
||
#[allow(dead_code)]
|
||
const IRQ_IDE: u32 = 14;
|
||
#[allow(dead_code)]
|
||
const IRQ_ERROR: u32 = 19;
|
||
#[allow(dead_code)]
|
||
const IRQ_SPURIOUS: u32 = 31;
|
||
|
||
impl LocalAPIC for XApic {
|
||
/// @brief 判断处理器是否支持apic
|
||
fn support() -> bool {
|
||
return x86::cpuid::CpuId::new()
|
||
.get_feature_info()
|
||
.expect("Fail to get CPU feature.")
|
||
.has_apic();
|
||
}
|
||
|
||
/// @return true -> 函数运行成功
|
||
fn init_current_cpu(&mut self) -> bool {
|
||
unsafe {
|
||
// enable xapic
|
||
x86::msr::wrmsr(x86::msr::APIC_BASE, (self.xapic_base.data() | 0x800) as u64);
|
||
let val = x86::msr::rdmsr(x86::msr::APIC_BASE);
|
||
if val & 0x800 != 0x800 {
|
||
error!("xAPIC enable failed: APIC_BASE & 0x800 != 0x800");
|
||
return false;
|
||
}
|
||
// 设置 Spurious Interrupt Vector Register
|
||
let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR);
|
||
|
||
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR, val | ENABLE);
|
||
|
||
let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR);
|
||
if val & ENABLE == 0 {
|
||
error!("xAPIC software enable failed.");
|
||
|
||
return false;
|
||
} else {
|
||
info!("xAPIC software enabled.");
|
||
}
|
||
|
||
if val & 0x1000 != 0 {
|
||
info!("xAPIC EOI broadcast suppression enabled.");
|
||
}
|
||
|
||
self.mask_all_lvt();
|
||
|
||
// 清除错误状态寄存器(需要连续写入两次)
|
||
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR, 0);
|
||
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR, 0);
|
||
|
||
// 确认任何未完成的中断
|
||
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI, 0);
|
||
|
||
// 发送 Init Level De-Assert 信号以同步仲裁ID
|
||
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32, 0);
|
||
self.write(
|
||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0,
|
||
BCAST | INIT | LEVEL,
|
||
);
|
||
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) & DELIVS != 0 {
|
||
spin_loop();
|
||
}
|
||
}
|
||
|
||
true
|
||
}
|
||
|
||
/// 发送 EOI(End Of Interrupt)
|
||
fn send_eoi(&self) {
|
||
unsafe {
|
||
let s = self as *const Self as *mut Self;
|
||
(*s).write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI, 0);
|
||
}
|
||
}
|
||
|
||
/// 获取版本号
|
||
fn version(&self) -> u8 {
|
||
unsafe { (self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version) & 0xff) as u8 }
|
||
}
|
||
|
||
fn support_eoi_broadcast_suppression(&self) -> bool {
|
||
unsafe { ((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version) >> 24) & 1) == 1 }
|
||
}
|
||
|
||
fn max_lvt_entry(&self) -> u8 {
|
||
unsafe {
|
||
((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version) >> 16) & 0xff) as u8 + 1
|
||
}
|
||
}
|
||
|
||
/// 获取ID
|
||
fn id(&self) -> ApicId {
|
||
unsafe { ApicId::new(self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID) >> 24) }
|
||
}
|
||
|
||
/// 设置LVT寄存器的值
|
||
fn set_lvt(&mut self, lvt: LVT) {
|
||
unsafe {
|
||
self.write(lvt.register().into(), lvt.data);
|
||
}
|
||
}
|
||
|
||
fn read_lvt(&self, reg: LVTRegister) -> LVT {
|
||
unsafe {
|
||
LVT::new(
|
||
reg,
|
||
self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER),
|
||
)
|
||
.unwrap()
|
||
}
|
||
}
|
||
|
||
fn mask_all_lvt(&mut self) {
|
||
// self.set_lvt(LVT::new(LVTRegister::CMCI, LVT::MASKED).unwrap());
|
||
self.set_lvt(LVT::new(LVTRegister::Timer, LVT::MASKED).unwrap());
|
||
self.set_lvt(LVT::new(LVTRegister::Thermal, LVT::MASKED).unwrap());
|
||
self.set_lvt(LVT::new(LVTRegister::PerformanceMonitor, LVT::MASKED).unwrap());
|
||
self.set_lvt(LVT::new(LVTRegister::LINT0, LVT::MASKED).unwrap());
|
||
self.set_lvt(LVT::new(LVTRegister::LINT1, LVT::MASKED).unwrap());
|
||
self.set_lvt(LVT::new(LVTRegister::ErrorReg, LVT::MASKED).unwrap());
|
||
}
|
||
|
||
fn write_icr(&self, icr: x86::apic::Icr) {
|
||
unsafe {
|
||
// Wait for any previous send to finish
|
||
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) & DELIVS != 0 {
|
||
spin_loop();
|
||
}
|
||
|
||
self.write(
|
||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32,
|
||
icr.upper(),
|
||
);
|
||
self.write(
|
||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0,
|
||
icr.lower(),
|
||
);
|
||
|
||
// Wait for send to finish
|
||
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0) & DELIVS != 0 {
|
||
spin_loop();
|
||
}
|
||
}
|
||
}
|
||
}
|