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