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