@@ -3,18 +3,20 @@ use core::{fmt, str};
3
3
4
4
use aarch64:: regs:: * ;
5
5
use hermit_dtb:: Dtb ;
6
- use hermit_sync:: { Lazy , without_interrupts} ;
6
+ use hermit_sync:: { Lazy , OnceCell , without_interrupts} ;
7
7
8
8
use crate :: env;
9
9
10
- // System counter frequency in Hz
10
+ // System counter frequency in KHz
11
11
static CPU_FREQUENCY : Lazy < CpuFrequency > = Lazy :: new ( || {
12
12
let mut cpu_frequency = CpuFrequency :: new ( ) ;
13
13
unsafe {
14
14
cpu_frequency. detect ( ) ;
15
15
}
16
16
cpu_frequency
17
17
} ) ;
18
+ // Value of CNTPCT_EL0 at boot time
19
+ static BOOT_COUNTER : OnceCell < u64 > = OnceCell :: new ( ) ;
18
20
19
21
enum CpuFrequencySources {
20
22
Invalid ,
@@ -133,18 +135,21 @@ pub fn shutdown(error_code: i32) -> ! {
133
135
#[ inline]
134
136
pub fn get_timer_ticks ( ) -> u64 {
135
137
// We simulate a timer with a 1 microsecond resolution by taking the CPU timestamp
136
- // and dividing it by the CPU frequency in MHz.
137
- get_timestamp ( ) / u64:: from ( get_frequency ( ) )
138
+ // and dividing it by the CPU frequency (in KHz).
139
+
140
+ let freq: u64 = CPU_FREQUENCY . get ( ) . into ( ) ; // frequency in KHz
141
+ 1000 * get_timestamp ( ) / freq
138
142
}
139
143
144
+ /// Returns the timer frequency in MHz
140
145
#[ inline]
141
146
pub fn get_frequency ( ) -> u16 {
142
147
( CPU_FREQUENCY . get ( ) / 1_000 ) . try_into ( ) . unwrap ( )
143
148
}
144
149
145
150
#[ inline]
146
151
pub fn get_timestamp ( ) -> u64 {
147
- CNTPCT_EL0 . get ( )
152
+ CNTPCT_EL0 . get ( ) - BOOT_COUNTER . get ( ) . unwrap ( )
148
153
}
149
154
150
155
#[ inline]
@@ -200,14 +205,16 @@ pub fn configure() {
200
205
}
201
206
202
207
pub fn detect_frequency ( ) {
208
+ BOOT_COUNTER . set ( CNTPCT_EL0 . get ( ) ) . unwrap ( ) ;
203
209
Lazy :: force ( & CPU_FREQUENCY ) ;
204
210
}
205
211
206
212
#[ inline]
207
213
fn __set_oneshot_timer ( wakeup_time : Option < u64 > ) {
208
214
if let Some ( wt) = wakeup_time {
209
215
// wt is the absolute wakeup time in microseconds based on processor::get_timer_ticks.
210
- let deadline = ( wt * u64:: from ( get_frequency ( ) ) ) / 1000 ;
216
+ let freq: u64 = CPU_FREQUENCY . get ( ) . into ( ) ; // frequency in KHz
217
+ let deadline = ( wt / 1000 ) * freq;
211
218
212
219
CNTP_CVAL_EL0 . set ( deadline) ;
213
220
CNTP_CTL_EL0 . write ( CNTP_CTL_EL0 :: ENABLE :: SET ) ;
0 commit comments