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