xref: /DragonOS/kernel/src/arch/x86_64/driver/apic/apic_timer.rs (revision c566df451ce6dbf2af684333e68b39fdfff86498)
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::time::clocksource::HZ;
11 pub use drop;
12 use system_error::SystemError;
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 = 4;
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 / (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