xref: /DragonOS/kernel/src/arch/x86_64/driver/hpet.rs (revision 911132c4b8ea0e9c49a4e84b9fa1db114102acbb)
1 use core::{
2     intrinsics::unlikely,
3     mem::size_of,
4     ptr::NonNull,
5     sync::atomic::{AtomicBool, Ordering},
6 };
7 
8 use acpi::HpetInfo;
9 use alloc::{string::ToString, sync::Arc};
10 use system_error::SystemError;
11 
12 use crate::{
13     arch::CurrentIrqArch,
14     driver::{
15         acpi::acpi_manager,
16         timers::hpet::{HpetRegisters, HpetTimerRegisters},
17     },
18     exception::{
19         irqdata::IrqHandlerData,
20         irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn},
21         manage::irq_manager,
22         softirq::{softirq_vectors, SoftirqNumber},
23         InterruptArch, IrqNumber,
24     },
25     kdebug, kerror, kinfo,
26     libs::{
27         rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
28         volatile::volwrite,
29     },
30     mm::{
31         mmio_buddy::{mmio_pool, MMIOSpaceGuard},
32         PhysAddr,
33     },
34     time::timer::{clock, timer_get_first_expire, update_timer_jiffies},
35 };
36 
37 static mut HPET_INSTANCE: Option<Hpet> = None;
38 
39 #[inline(always)]
40 pub fn hpet_instance() -> &'static Hpet {
41     unsafe { HPET_INSTANCE.as_ref().unwrap() }
42 }
43 
44 pub struct Hpet {
45     info: HpetInfo,
46     _mmio_guard: MMIOSpaceGuard,
47     inner: RwLock<InnerHpet>,
48     enabled: AtomicBool,
49 }
50 
51 struct InnerHpet {
52     registers_ptr: NonNull<HpetRegisters>,
53     timer_registers_ptr: NonNull<HpetTimerRegisters>,
54 }
55 
56 impl Hpet {
57     /// HPET0 中断间隔为 10ms
58     pub const HPET0_INTERVAL_USEC: u64 = 10000;
59 
60     const HPET0_IRQ: IrqNumber = IrqNumber::new(34);
61 
62     fn new(mut hpet_info: HpetInfo) -> Result<Self, SystemError> {
63         let paddr = PhysAddr::new(hpet_info.base_address);
64         let map_size = size_of::<HpetRegisters>();
65         let mmio = mmio_pool().create_mmio(map_size)?;
66         unsafe { mmio.map_phys(paddr, map_size)? };
67         let hpet = unsafe {
68             (mmio.vaddr().data() as *const HpetRegisters)
69                 .as_ref()
70                 .unwrap()
71         };
72         let tm_num = hpet.timers_num();
73         kinfo!("HPET has {} timers", tm_num);
74         hpet_info.hpet_number = tm_num as u8;
75 
76         drop(mmio);
77         if tm_num == 0 {
78             return Err(SystemError::ENODEV);
79         }
80 
81         let bytes_to_map = size_of::<HpetRegisters>()
82             + hpet_info.hpet_number as usize * size_of::<HpetTimerRegisters>();
83         let mmio = mmio_pool().create_mmio(bytes_to_map)?;
84 
85         unsafe { mmio.map_phys(paddr, bytes_to_map)? };
86         let ptr = NonNull::new(mmio.vaddr().data() as *mut HpetRegisters).unwrap();
87         let timer_ptr = NonNull::new(
88             (mmio.vaddr().data() + size_of::<HpetRegisters>()) as *mut HpetTimerRegisters,
89         )
90         .unwrap();
91 
92         let hpet = Hpet {
93             info: hpet_info,
94             _mmio_guard: mmio,
95             inner: RwLock::new(InnerHpet {
96                 registers_ptr: ptr,
97                 timer_registers_ptr: timer_ptr,
98             }),
99             enabled: AtomicBool::new(false),
100         };
101 
102         return Ok(hpet);
103     }
104 
105     pub fn enabled(&self) -> bool {
106         self.enabled.load(Ordering::SeqCst)
107     }
108 
109     /// 使能HPET
110     pub fn hpet_enable(&self) -> Result<(), SystemError> {
111         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
112 
113         // !!!这里是临时糊代码的,需要在apic重构的时候修改!!!
114         let (inner_guard, regs) = unsafe { self.hpet_regs_mut() };
115         let freq = regs.frequency();
116         kdebug!("HPET frequency: {} Hz", freq);
117         let ticks = Self::HPET0_INTERVAL_USEC * freq / 1000000;
118         if ticks == 0 || ticks > freq * 8 {
119             kerror!("HPET enable: ticks '{ticks}' is invalid");
120             return Err(SystemError::EINVAL);
121         }
122         if unlikely(regs.timers_num() == 0) {
123             return Err(SystemError::ENODEV);
124         }
125 
126         unsafe { regs.write_main_counter_value(0) };
127 
128         drop(inner_guard);
129 
130         let (inner_guard, timer_reg) = unsafe { self.timer_mut(0).ok_or(SystemError::ENODEV) }?;
131 
132         let timer_reg = NonNull::new(timer_reg as *mut HpetTimerRegisters).unwrap();
133 
134         unsafe {
135             // 设置定时器0为周期定时,边沿触发,默认投递到IO APIC的2号引脚(看conf寄存器的高32bit,哪一位被置1,则可以投递到哪一个I/O apic引脚)
136             volwrite!(timer_reg, config, 0x004c);
137             volwrite!(timer_reg, comparator_value, ticks);
138         }
139         drop(inner_guard);
140 
141         irq_manager().request_irq(
142             Self::HPET0_IRQ,
143             "HPET0".to_string(),
144             &HpetIrqHandler,
145             IrqHandleFlags::IRQF_TRIGGER_RISING,
146             None,
147         )?;
148 
149         self.enabled.store(true, Ordering::SeqCst);
150 
151         let (inner_guard, regs) = unsafe { self.hpet_regs_mut() };
152 
153         // 置位旧设备中断路由兼容标志位、定时器组使能标志位
154         unsafe { regs.write_general_config(3) };
155 
156         drop(inner_guard);
157 
158         kinfo!("HPET enabled");
159 
160         drop(irq_guard);
161         return Ok(());
162     }
163 
164     fn inner(&self) -> RwLockReadGuard<InnerHpet> {
165         self.inner.read()
166     }
167 
168     fn inner_mut(&self) -> RwLockWriteGuard<InnerHpet> {
169         self.inner.write()
170     }
171 
172     #[allow(dead_code)]
173     fn timer(&self, index: u8) -> Option<(RwLockReadGuard<InnerHpet>, &HpetTimerRegisters)> {
174         let inner = self.inner();
175         if index >= self.info.hpet_number {
176             return None;
177         }
178         let timer_regs = unsafe {
179             inner
180                 .timer_registers_ptr
181                 .as_ptr()
182                 .add(index as usize)
183                 .as_ref()
184                 .unwrap()
185         };
186         return Some((inner, timer_regs));
187     }
188 
189     unsafe fn timer_mut(
190         &self,
191         index: u8,
192     ) -> Option<(RwLockWriteGuard<InnerHpet>, &mut HpetTimerRegisters)> {
193         let inner = self.inner_mut();
194         if index >= self.info.hpet_number {
195             return None;
196         }
197         let timer_regs = unsafe {
198             inner
199                 .timer_registers_ptr
200                 .as_ptr()
201                 .add(index as usize)
202                 .as_mut()
203                 .unwrap()
204         };
205         return Some((inner, timer_regs));
206     }
207 
208     unsafe fn hpet_regs(&self) -> (RwLockReadGuard<InnerHpet>, &HpetRegisters) {
209         let inner = self.inner();
210         let regs = unsafe { inner.registers_ptr.as_ref() };
211         return (inner, regs);
212     }
213 
214     unsafe fn hpet_regs_mut(&self) -> (RwLockWriteGuard<InnerHpet>, &mut HpetRegisters) {
215         let mut inner = self.inner_mut();
216         let regs = unsafe { inner.registers_ptr.as_mut() };
217         return (inner, regs);
218     }
219 
220     pub fn main_counter_value(&self) -> u64 {
221         let (inner_guard, regs) = unsafe { self.hpet_regs() };
222         let value = regs.main_counter_value();
223 
224         drop(inner_guard);
225         return value;
226     }
227 
228     pub fn period(&self) -> u64 {
229         let (inner_guard, regs) = unsafe { self.hpet_regs() };
230         let period = regs.counter_clock_period();
231         kdebug!("HPET period: {}", period);
232 
233         drop(inner_guard);
234         return period;
235     }
236 
237     /// 处理HPET的中断
238     pub(super) fn handle_irq(&self, timer_num: u32) {
239         if timer_num == 0 {
240             assert!(!CurrentIrqArch::is_irq_enabled());
241             update_timer_jiffies(Self::HPET0_INTERVAL_USEC, Self::HPET0_INTERVAL_USEC as i64);
242 
243             if let Ok(first_expire) = timer_get_first_expire() {
244                 if first_expire <= clock() {
245                     softirq_vectors().raise_softirq(SoftirqNumber::TIMER);
246                 }
247             }
248         }
249     }
250 }
251 
252 pub fn hpet_init() -> Result<(), SystemError> {
253     let hpet_info = HpetInfo::new(acpi_manager().tables().unwrap()).map_err(|e| {
254         kerror!("Failed to get HPET info: {:?}", e);
255         SystemError::ENODEV
256     })?;
257 
258     let hpet_instance = Hpet::new(hpet_info)?;
259     unsafe {
260         HPET_INSTANCE = Some(hpet_instance);
261     }
262 
263     return Ok(());
264 }
265 
266 #[derive(Debug)]
267 struct HpetIrqHandler;
268 
269 impl IrqHandler for HpetIrqHandler {
270     fn handle(
271         &self,
272         _irq: IrqNumber,
273         _static_data: Option<&dyn IrqHandlerData>,
274         _dynamic_data: Option<Arc<dyn IrqHandlerData>>,
275     ) -> Result<IrqReturn, SystemError> {
276         hpet_instance().handle_irq(0);
277         return Ok(IrqReturn::Handled);
278     }
279 }
280