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