xref: /DragonOS/kernel/src/arch/x86_64/driver/apic/apic_timer.rs (revision b5b571e02693d91eb6918d3b7561e088c3e7ee81)
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