1 use core::cell::RefCell; 2 3 use crate::arch::driver::tsc::TSCManager; 4 use crate::arch::interrupt::TrapFrame; 5 use crate::driver::base::device::DeviceId; 6 use crate::exception::irqdata::{IrqHandlerData, IrqLineStatus}; 7 use crate::exception::irqdesc::{ 8 irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandleFlags, IrqHandler, IrqReturn, 9 }; 10 use crate::exception::manage::irq_manager; 11 use crate::exception::IrqNumber; 12 13 use crate::kdebug; 14 use crate::mm::percpu::PerCpu; 15 use crate::sched::core::sched_update_jiffies; 16 use crate::smp::core::smp_get_processor_id; 17 use crate::smp::cpu::ProcessorId; 18 use crate::time::clocksource::HZ; 19 use alloc::string::ToString; 20 use alloc::sync::Arc; 21 pub use drop; 22 use system_error::SystemError; 23 use x86::cpuid::cpuid; 24 use x86::msr::{wrmsr, IA32_X2APIC_DIV_CONF, IA32_X2APIC_INIT_COUNT}; 25 26 use super::lapic_vector::local_apic_chip; 27 use super::xapic::XApicOffset; 28 use super::{CurrentApic, LVTRegister, LocalAPIC, LVT}; 29 30 pub const APIC_TIMER_IRQ_NUM: IrqNumber = IrqNumber::new(151); 31 32 static mut LOCAL_APIC_TIMERS: [RefCell<LocalApicTimer>; PerCpu::MAX_CPU_NUM as usize] = 33 [const { RefCell::new(LocalApicTimer::new()) }; PerCpu::MAX_CPU_NUM as usize]; 34 35 #[allow(dead_code)] 36 #[inline(always)] 37 pub(super) fn local_apic_timer_instance( 38 cpu_id: ProcessorId, 39 ) -> core::cell::Ref<'static, LocalApicTimer> { 40 unsafe { LOCAL_APIC_TIMERS[cpu_id.data() as usize].borrow() } 41 } 42 43 #[inline(always)] 44 pub(super) fn local_apic_timer_instance_mut( 45 cpu_id: ProcessorId, 46 ) -> core::cell::RefMut<'static, LocalApicTimer> { 47 unsafe { LOCAL_APIC_TIMERS[cpu_id.data() as usize].borrow_mut() } 48 } 49 50 #[derive(Debug)] 51 struct LocalApicTimerHandler; 52 53 impl IrqHandler for LocalApicTimerHandler { 54 fn handle( 55 &self, 56 _irq: IrqNumber, 57 _static_data: Option<&dyn IrqHandlerData>, 58 _dynamic_data: Option<Arc<dyn IrqHandlerData>>, 59 ) -> Result<IrqReturn, SystemError> { 60 // empty (只是为了让编译通过,不会被调用到。真正的处理函数在LocalApicTimerIrqFlowHandler中) 61 Ok(IrqReturn::NotHandled) 62 } 63 } 64 65 #[derive(Debug)] 66 struct LocalApicTimerIrqFlowHandler; 67 68 impl IrqFlowHandler for LocalApicTimerIrqFlowHandler { 69 fn handle(&self, _irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) { 70 LocalApicTimer::handle_irq().ok(); 71 CurrentApic.send_eoi(); 72 } 73 } 74 75 pub fn apic_timer_init() { 76 irq_manager() 77 .request_irq( 78 APIC_TIMER_IRQ_NUM, 79 "LocalApic".to_string(), 80 &LocalApicTimerHandler, 81 IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_PERCPU, 82 Some(DeviceId::new(Some("lapic timer"), None).unwrap()), 83 ) 84 .expect("Apic timer init failed"); 85 86 LocalApicTimerIntrController.install(); 87 LocalApicTimerIntrController.enable(); 88 } 89 90 /// 初始化本地APIC定时器的中断描述符 91 #[inline(never)] 92 pub(super) fn local_apic_timer_irq_desc_init() { 93 let desc = irq_desc_manager().lookup(APIC_TIMER_IRQ_NUM).unwrap(); 94 let irq_data: Arc<crate::exception::irqdata::IrqData> = desc.irq_data(); 95 let mut chip_info_guard = irq_data.chip_info_write_irqsave(); 96 chip_info_guard.set_chip(Some(local_apic_chip().clone())); 97 98 desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty()); 99 drop(chip_info_guard); 100 desc.set_handler(&LocalApicTimerIrqFlowHandler); 101 } 102 103 /// 初始化BSP的APIC定时器 104 /// 105 fn init_bsp_apic_timer() { 106 kdebug!("init_bsp_apic_timer"); 107 assert!(smp_get_processor_id().data() == 0); 108 let mut local_apic_timer = local_apic_timer_instance_mut(ProcessorId::new(0)); 109 local_apic_timer.init( 110 LocalApicTimerMode::Periodic, 111 LocalApicTimer::periodic_default_initial_count(), 112 LocalApicTimer::DIVISOR as u32, 113 ); 114 kdebug!("init_bsp_apic_timer done"); 115 } 116 117 fn init_ap_apic_timer() { 118 kdebug!("init_ap_apic_timer"); 119 let cpu_id = smp_get_processor_id(); 120 assert!(cpu_id.data() != 0); 121 122 let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id); 123 local_apic_timer.init( 124 LocalApicTimerMode::Periodic, 125 LocalApicTimer::periodic_default_initial_count(), 126 LocalApicTimer::DIVISOR as u32, 127 ); 128 kdebug!("init_ap_apic_timer done"); 129 } 130 131 pub(super) struct LocalApicTimerIntrController; 132 133 impl LocalApicTimerIntrController { 134 pub(super) fn install(&self) { 135 kdebug!("LocalApicTimerIntrController::install"); 136 if smp_get_processor_id().data() == 0 { 137 init_bsp_apic_timer(); 138 } else { 139 init_ap_apic_timer(); 140 } 141 } 142 143 #[allow(dead_code)] 144 pub(super) fn uninstall(&self) { 145 let cpu_id = smp_get_processor_id(); 146 let local_apic_timer = local_apic_timer_instance(cpu_id); 147 local_apic_timer.stop_current(); 148 } 149 150 pub(super) fn enable(&self) { 151 kdebug!("LocalApicTimerIntrController::enable"); 152 let cpu_id = smp_get_processor_id(); 153 let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id); 154 local_apic_timer.start_current(); 155 } 156 157 pub(super) fn disable(&self) { 158 let cpu_id = smp_get_processor_id(); 159 let local_apic_timer = local_apic_timer_instance_mut(cpu_id); 160 local_apic_timer.stop_current(); 161 } 162 } 163 164 #[derive(Debug, Copy, Clone)] 165 pub struct LocalApicTimer { 166 mode: LocalApicTimerMode, 167 /// IntialCount 168 initial_count: u64, 169 divisor: u32, 170 /// 是否已经触发(oneshot模式) 171 triggered: bool, 172 } 173 174 #[derive(Debug, Copy, Clone)] 175 #[repr(u32)] 176 pub enum LocalApicTimerMode { 177 Oneshot = 0, 178 Periodic = 1, 179 Deadline = 2, 180 } 181 182 impl LocalApicTimer { 183 /// 定时器中断的间隔 184 pub const INTERVAL_MS: u64 = 1000 / HZ; 185 pub const DIVISOR: u64 = 4; 186 187 /// IoApicManager 初值为0或false 188 pub const fn new() -> Self { 189 LocalApicTimer { 190 mode: LocalApicTimerMode::Periodic, 191 initial_count: 0, 192 divisor: 0, 193 triggered: false, 194 } 195 } 196 197 /// 周期模式下的默认初始值 198 pub fn periodic_default_initial_count() -> u64 { 199 let cpu_khz = TSCManager::cpu_khz(); 200 201 // 疑惑:这里使用khz吗? 202 // 我觉得应该是hz,但是由于旧的代码是测量出initcnt的,而不是计算的 203 // 然后我发现使用hz会导致计算出来的initcnt太大,导致系统卡顿,而khz的却能跑 204 let count = cpu_khz * Self::INTERVAL_MS / (Self::DIVISOR); 205 return count; 206 } 207 208 /// Init this manager. 209 /// 210 /// At this time, it does nothing. 211 fn init(&mut self, mode: LocalApicTimerMode, initial_count: u64, divisor: u32) { 212 self.stop_current(); 213 self.triggered = false; 214 match mode { 215 LocalApicTimerMode::Periodic => self.install_periodic_mode(initial_count, divisor), 216 LocalApicTimerMode::Oneshot => todo!(), 217 LocalApicTimerMode::Deadline => todo!(), 218 } 219 } 220 221 fn install_periodic_mode(&mut self, initial_count: u64, divisor: u32) { 222 kdebug!( 223 "install_periodic_mode: initial_count = {}, divisor = {}", 224 initial_count, 225 divisor 226 ); 227 self.mode = LocalApicTimerMode::Periodic; 228 self.set_divisor(divisor); 229 self.set_initial_cnt(initial_count); 230 self.setup_lvt( 231 APIC_TIMER_IRQ_NUM.data() as u8, 232 true, 233 LocalApicTimerMode::Periodic, 234 ); 235 } 236 237 fn setup_lvt(&mut self, vector: u8, mask: bool, mode: LocalApicTimerMode) { 238 let mode: u32 = mode as u32; 239 let data = (mode << 17) | (vector as u32) | (if mask { 1 << 16 } else { 0 }); 240 let lvt = LVT::new(LVTRegister::Timer, data).unwrap(); 241 242 CurrentApic.set_lvt(lvt); 243 } 244 245 fn set_divisor(&mut self, divisor: u32) { 246 self.divisor = divisor; 247 CurrentApic.set_timer_divisor(divisor); 248 } 249 250 fn set_initial_cnt(&mut self, initial_count: u64) { 251 self.initial_count = initial_count; 252 CurrentApic.set_timer_initial_count(initial_count); 253 } 254 255 fn start_current(&mut self) { 256 let mut lvt = CurrentApic.read_lvt(LVTRegister::Timer); 257 lvt.set_mask(false); 258 CurrentApic.set_lvt(lvt); 259 } 260 261 fn stop_current(&self) { 262 let mut lvt = CurrentApic.read_lvt(LVTRegister::Timer); 263 lvt.set_mask(true); 264 CurrentApic.set_lvt(lvt); 265 } 266 267 /// 检查是否支持TSC-Deadline 268 /// 269 /// 此函数调用cpuid,请避免多次调用此函数。 270 /// 如果支持TSC-Deadline模式,则除非TSC为常数,否则不会启用该模式。 271 #[allow(dead_code)] 272 pub fn is_deadline_mode_supported(&self) -> bool { 273 let res = cpuid!(1); 274 return (res.ecx & (1 << 24)) != 0; 275 } 276 277 pub(super) fn handle_irq() -> Result<IrqReturn, SystemError> { 278 sched_update_jiffies(); 279 return Ok(IrqReturn::Handled); 280 } 281 } 282 283 impl TryFrom<u8> for LocalApicTimerMode { 284 type Error = SystemError; 285 286 fn try_from(value: u8) -> Result<Self, Self::Error> { 287 match value { 288 0b00 => { 289 return Ok(LocalApicTimerMode::Oneshot); 290 } 291 0b01 => { 292 return Ok(LocalApicTimerMode::Periodic); 293 } 294 0b10 => { 295 return Ok(LocalApicTimerMode::Deadline); 296 } 297 _ => { 298 return Err(SystemError::EINVAL); 299 } 300 } 301 } 302 } 303 304 impl CurrentApic { 305 fn set_timer_divisor(&self, divisor: u32) { 306 if self.x2apic_enabled() { 307 unsafe { wrmsr(IA32_X2APIC_DIV_CONF, divisor.into()) }; 308 } else { 309 unsafe { 310 self.write_xapic_register(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_CLKDIV, divisor) 311 }; 312 } 313 } 314 315 fn set_timer_initial_count(&self, initial_count: u64) { 316 if self.x2apic_enabled() { 317 unsafe { 318 wrmsr(IA32_X2APIC_INIT_COUNT, initial_count); 319 } 320 } else { 321 unsafe { 322 self.write_xapic_register( 323 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG, 324 initial_count as u32, 325 ) 326 }; 327 } 328 } 329 } 330