1 use core::cell::RefCell; 2 3 use crate::arch::driver::tsc::TSCManager; 4 use crate::include::bindings::bindings::APIC_TIMER_IRQ_NUM; 5 6 use crate::kdebug; 7 use crate::mm::percpu::PerCpu; 8 use crate::sched::core::sched_update_jiffies; 9 use crate::smp::core::smp_get_processor_id; 10 use crate::syscall::SystemError; 11 pub use drop; 12 use x86::cpuid::cpuid; 13 use x86::msr::{wrmsr, IA32_X2APIC_DIV_CONF, IA32_X2APIC_INIT_COUNT}; 14 15 use super::xapic::XApicOffset; 16 use super::{CurrentApic, LVTRegister, LocalAPIC, LVT}; 17 18 static mut LOCAL_APIC_TIMERS: [RefCell<LocalApicTimer>; PerCpu::MAX_CPU_NUM] = 19 [const { RefCell::new(LocalApicTimer::new()) }; PerCpu::MAX_CPU_NUM]; 20 21 #[inline(always)] 22 pub(super) fn local_apic_timer_instance(cpu_id: u32) -> core::cell::Ref<'static, LocalApicTimer> { 23 unsafe { LOCAL_APIC_TIMERS[cpu_id as usize].borrow() } 24 } 25 26 #[inline(always)] 27 pub(super) fn local_apic_timer_instance_mut( 28 cpu_id: u32, 29 ) -> core::cell::RefMut<'static, LocalApicTimer> { 30 unsafe { LOCAL_APIC_TIMERS[cpu_id as usize].borrow_mut() } 31 } 32 33 /// 初始化BSP的APIC定时器 34 /// 35 fn init_bsp_apic_timer() { 36 kdebug!("init_bsp_apic_timer"); 37 assert!(smp_get_processor_id() == 0); 38 let mut local_apic_timer = local_apic_timer_instance_mut(0); 39 local_apic_timer.init( 40 LocalApicTimerMode::Periodic, 41 LocalApicTimer::periodic_default_initial_count(), 42 LocalApicTimer::DIVISOR as u32, 43 ); 44 kdebug!("init_bsp_apic_timer done"); 45 } 46 47 fn init_ap_apic_timer() { 48 kdebug!("init_ap_apic_timer"); 49 let cpu_id = smp_get_processor_id(); 50 assert!(cpu_id != 0); 51 52 let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id); 53 local_apic_timer.init( 54 LocalApicTimerMode::Periodic, 55 LocalApicTimer::periodic_default_initial_count(), 56 LocalApicTimer::DIVISOR as u32, 57 ); 58 kdebug!("init_ap_apic_timer done"); 59 } 60 61 pub(super) struct LocalApicTimerIntrController; 62 63 impl LocalApicTimerIntrController { 64 pub(super) fn install(&self, _irq_num: u8) { 65 kdebug!("LocalApicTimerIntrController::install"); 66 if smp_get_processor_id() == 0 { 67 init_bsp_apic_timer(); 68 } else { 69 init_ap_apic_timer(); 70 } 71 } 72 73 pub(super) fn uninstall(&self) { 74 let cpu_id = smp_get_processor_id(); 75 let local_apic_timer = local_apic_timer_instance(cpu_id); 76 local_apic_timer.stop_current(); 77 } 78 79 pub(super) fn enable(&self) { 80 kdebug!("LocalApicTimerIntrController::enable"); 81 let cpu_id = smp_get_processor_id(); 82 let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id); 83 local_apic_timer.start_current(); 84 } 85 86 pub(super) fn disable(&self) { 87 let cpu_id = smp_get_processor_id(); 88 let local_apic_timer = local_apic_timer_instance_mut(cpu_id); 89 local_apic_timer.stop_current(); 90 } 91 } 92 93 #[derive(Debug, Copy, Clone)] 94 pub struct LocalApicTimer { 95 mode: LocalApicTimerMode, 96 /// IntialCount 97 initial_count: u64, 98 divisor: u32, 99 /// 是否已经触发(oneshot模式) 100 triggered: bool, 101 } 102 103 #[derive(Debug, Copy, Clone)] 104 #[repr(u32)] 105 pub enum LocalApicTimerMode { 106 Oneshot = 0, 107 Periodic = 1, 108 Deadline = 2, 109 } 110 111 impl LocalApicTimer { 112 /// 定时器中断的间隔 113 pub const INTERVAL_MS: u64 = 5; 114 pub const DIVISOR: u64 = 3; 115 116 /// IoApicManager 初值为0或false 117 pub const fn new() -> Self { 118 LocalApicTimer { 119 mode: LocalApicTimerMode::Periodic, 120 initial_count: 0, 121 divisor: 0, 122 triggered: false, 123 } 124 } 125 126 /// 周期模式下的默认初始值 127 pub fn periodic_default_initial_count() -> u64 { 128 let cpu_khz = TSCManager::cpu_khz(); 129 130 // 疑惑:这里使用khz吗? 131 // 我觉得应该是hz,但是由于旧的代码是测量出initcnt的,而不是计算的 132 // 然后我发现使用hz会导致计算出来的initcnt太大,导致系统卡顿,而khz的却能跑 133 let count = cpu_khz * Self::INTERVAL_MS / (1000 * Self::DIVISOR); 134 return count; 135 } 136 137 /// Init this manager. 138 /// 139 /// At this time, it does nothing. 140 fn init(&mut self, mode: LocalApicTimerMode, initial_count: u64, divisor: u32) { 141 self.stop_current(); 142 self.triggered = false; 143 match mode { 144 LocalApicTimerMode::Periodic => self.install_periodic_mode(initial_count, divisor), 145 LocalApicTimerMode::Oneshot => todo!(), 146 LocalApicTimerMode::Deadline => todo!(), 147 } 148 } 149 150 fn install_periodic_mode(&mut self, initial_count: u64, divisor: u32) { 151 kdebug!( 152 "install_periodic_mode: initial_count = {}, divisor = {}", 153 initial_count, 154 divisor 155 ); 156 self.mode = LocalApicTimerMode::Periodic; 157 self.set_divisor(divisor); 158 self.set_initial_cnt(initial_count); 159 self.setup_lvt(APIC_TIMER_IRQ_NUM as u8, true, LocalApicTimerMode::Periodic); 160 } 161 162 fn setup_lvt(&mut self, vector: u8, mask: bool, mode: LocalApicTimerMode) { 163 let mode: u32 = mode as u32; 164 let data = (mode << 17) | (vector as u32) | (if mask { 1 << 16 } else { 0 }); 165 let lvt = LVT::new(LVTRegister::Timer, data).unwrap(); 166 167 CurrentApic.set_lvt(lvt); 168 } 169 170 fn set_divisor(&mut self, divisor: u32) { 171 self.divisor = divisor; 172 CurrentApic.set_timer_divisor(divisor as u32); 173 } 174 175 fn set_initial_cnt(&mut self, initial_count: u64) { 176 self.initial_count = initial_count; 177 CurrentApic.set_timer_initial_count(initial_count); 178 } 179 180 fn start_current(&mut self) { 181 let mut lvt = CurrentApic.read_lvt(LVTRegister::Timer); 182 lvt.set_mask(false); 183 CurrentApic.set_lvt(lvt); 184 } 185 186 fn stop_current(&self) { 187 let mut lvt = CurrentApic.read_lvt(LVTRegister::Timer); 188 lvt.set_mask(true); 189 CurrentApic.set_lvt(lvt); 190 } 191 192 /// 检查是否支持TSC-Deadline 193 /// 194 /// 此函数调用cpuid,请避免多次调用此函数。 195 /// 如果支持TSC-Deadline模式,则除非TSC为常数,否则不会启用该模式。 196 #[allow(dead_code)] 197 pub fn is_deadline_mode_supported(&self) -> bool { 198 let res = cpuid!(1); 199 return (res.ecx & (1 << 24)) != 0; 200 } 201 202 pub(super) fn handle_irq() -> Result<(), SystemError> { 203 sched_update_jiffies(); 204 return Ok(()); 205 } 206 } 207 208 impl TryFrom<u8> for LocalApicTimerMode { 209 type Error = SystemError; 210 211 fn try_from(value: u8) -> Result<Self, Self::Error> { 212 match value { 213 0b00 => { 214 return Ok(LocalApicTimerMode::Oneshot); 215 } 216 0b01 => { 217 return Ok(LocalApicTimerMode::Periodic); 218 } 219 0b10 => { 220 return Ok(LocalApicTimerMode::Deadline); 221 } 222 _ => { 223 return Err(SystemError::EINVAL); 224 } 225 } 226 } 227 } 228 229 impl CurrentApic { 230 fn set_timer_divisor(&self, divisor: u32) { 231 if self.x2apic_enabled() { 232 unsafe { wrmsr(IA32_X2APIC_DIV_CONF, divisor.into()) }; 233 } else { 234 unsafe { 235 self.write_xapic_register( 236 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_CLKDIV, 237 divisor.into(), 238 ) 239 }; 240 } 241 } 242 243 fn set_timer_initial_count(&self, initial_count: u64) { 244 if self.x2apic_enabled() { 245 unsafe { 246 wrmsr(IA32_X2APIC_INIT_COUNT.into(), initial_count); 247 } 248 } else { 249 unsafe { 250 self.write_xapic_register( 251 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG, 252 initial_count as u32, 253 ) 254 }; 255 } 256 } 257 } 258