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