1 use alloc::sync::Arc; 2 use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, Ordering}; 3 4 use crate::{ 5 arch::CurrentIrqArch, 6 exception::InterruptArch, 7 kdebug, kinfo, 8 libs::rwlock::RwLock, 9 time::{jiffies::clocksource_default_clock, timekeep::ktime_get_real_ns, TimeSpec}, 10 }; 11 12 use super::{ 13 clocksource::{clocksource_cyc2ns, Clocksource, CycleNum, HZ}, 14 syscall::PosixTimeval, 15 NSEC_PER_SEC, USEC_PER_SEC, 16 }; 17 /// NTP周期频率 18 pub const NTP_INTERVAL_FREQ: u64 = HZ; 19 /// NTP周期长度 20 pub const NTP_INTERVAL_LENGTH: u64 = NSEC_PER_SEC as u64 / NTP_INTERVAL_FREQ; 21 /// NTP转换比例 22 pub const NTP_SCALE_SHIFT: u32 = 32; 23 24 /// timekeeping休眠标志,false为未休眠 25 pub static TIMEKEEPING_SUSPENDED: AtomicBool = AtomicBool::new(false); 26 /// 已经递增的微秒数 27 static __ADDED_USEC: AtomicI64 = AtomicI64::new(0); 28 /// 已经递增的秒数 29 static __ADDED_SEC: AtomicI64 = AtomicI64::new(0); 30 /// timekeeper全局变量,用于管理timekeeper模块 31 static mut __TIMEKEEPER: Option<Timekeeper> = None; 32 33 #[derive(Debug)] 34 pub struct Timekeeper(RwLock<TimekeeperData>); 35 36 #[allow(dead_code)] 37 #[derive(Debug)] 38 pub struct TimekeeperData { 39 /// 用于计时的当前时钟源。 40 clock: Option<Arc<dyn Clocksource>>, 41 /// 当前时钟源的移位值。 42 shift: i32, 43 /// 一个NTP间隔中的时钟周期数。 44 cycle_interval: CycleNum, 45 /// 一个NTP间隔中时钟移位的纳秒数。 46 xtime_interval: u64, 47 /// 48 xtime_remainder: i64, 49 /// 每个NTP间隔累积的原始纳米秒 50 raw_interval: i64, 51 /// 时钟移位纳米秒余数 52 xtime_nsec: u64, 53 /// 积累时间和ntp时间在ntp位移纳秒量上的差距 54 ntp_error: i64, 55 /// 用于转换时钟偏移纳秒和ntp偏移纳秒的偏移量 56 ntp_error_shift: i32, 57 /// NTP调整时钟乘法器 58 mult: u32, 59 raw_time: TimeSpec, 60 wall_to_monotonic: TimeSpec, 61 total_sleep_time: TimeSpec, 62 xtime: TimeSpec, 63 } 64 impl TimekeeperData { 65 pub fn new() -> Self { 66 Self { 67 clock: None, 68 shift: Default::default(), 69 cycle_interval: CycleNum(0), 70 xtime_interval: Default::default(), 71 xtime_remainder: Default::default(), 72 raw_interval: Default::default(), 73 xtime_nsec: Default::default(), 74 ntp_error: Default::default(), 75 ntp_error_shift: Default::default(), 76 mult: Default::default(), 77 xtime: TimeSpec { 78 tv_nsec: 0, 79 tv_sec: 0, 80 }, 81 wall_to_monotonic: TimeSpec { 82 tv_nsec: 0, 83 tv_sec: 0, 84 }, 85 total_sleep_time: TimeSpec { 86 tv_nsec: 0, 87 tv_sec: 0, 88 }, 89 raw_time: TimeSpec { 90 tv_nsec: 0, 91 tv_sec: 0, 92 }, 93 } 94 } 95 } 96 impl Timekeeper { 97 /// # 设置timekeeper的参数 98 /// 99 /// ## 参数 100 /// 101 /// * 'clock' - 指定的时钟实际类型。初始为ClocksourceJiffies 102 pub fn timekeeper_setup_internals(&self, clock: Arc<dyn Clocksource>) { 103 let mut timekeeper = self.0.write(); 104 // 更新clock 105 let mut clock_data = clock.clocksource_data(); 106 clock_data.watchdog_last = clock.read(); 107 if clock.update_clocksource_data(clock_data).is_err() { 108 kdebug!("timekeeper_setup_internals:update_clocksource_data run failed"); 109 } 110 timekeeper.clock.replace(clock.clone()); 111 112 let clock_data = clock.clocksource_data(); 113 let mut temp = NTP_INTERVAL_LENGTH << clock_data.shift; 114 let ntpinterval = temp; 115 temp += (clock_data.mult / 2) as u64; 116 // do div 117 118 timekeeper.cycle_interval = CycleNum(temp); 119 timekeeper.xtime_interval = temp * clock_data.mult as u64; 120 // 这里可能存在下界溢出问题,debug模式下会报错panic 121 timekeeper.xtime_remainder = (ntpinterval - timekeeper.xtime_interval) as i64; 122 timekeeper.raw_interval = (timekeeper.xtime_interval >> clock_data.shift) as i64; 123 timekeeper.xtime_nsec = 0; 124 timekeeper.shift = clock_data.shift as i32; 125 126 timekeeper.ntp_error = 0; 127 timekeeper.ntp_error_shift = (NTP_SCALE_SHIFT - clock_data.shift) as i32; 128 129 timekeeper.mult = clock_data.mult; 130 } 131 132 /// # 获取当前时钟源距离上次检测走过的纳秒数 133 #[allow(dead_code)] 134 pub fn tk_get_ns(&self) -> u64 { 135 let timekeeper = self.0.read(); 136 let clock = timekeeper.clock.clone().unwrap(); 137 let clock_now = clock.read(); 138 let clcok_data = clock.clocksource_data(); 139 let clock_delta = clock_now.div(clcok_data.watchdog_last).data() & clcok_data.mask.bits(); 140 return clocksource_cyc2ns(CycleNum(clock_delta), clcok_data.mult, clcok_data.shift); 141 } 142 } 143 pub fn timekeeper() -> &'static Timekeeper { 144 let r = unsafe { __TIMEKEEPER.as_ref().unwrap() }; 145 146 return r; 147 } 148 149 pub fn timekeeper_init() { 150 unsafe { __TIMEKEEPER = Some(Timekeeper(RwLock::new(TimekeeperData::new()))) }; 151 } 152 153 /// # 获取1970.1.1至今的UTC时间戳(最小单位:nsec) 154 /// 155 /// ## 返回值 156 /// 157 /// * 'TimeSpec' - 时间戳 158 pub fn getnstimeofday() -> TimeSpec { 159 // kdebug!("enter getnstimeofday"); 160 161 // let mut nsecs: u64 = 0;0 162 let mut _xtime = TimeSpec { 163 tv_nsec: 0, 164 tv_sec: 0, 165 }; 166 loop { 167 match timekeeper().0.try_read() { 168 None => continue, 169 Some(tk) => { 170 _xtime = tk.xtime; 171 drop(tk); 172 // nsecs = timekeeper().tk_get_ns(); 173 // TODO 不同架构可能需要加上不同的偏移量 174 break; 175 } 176 } 177 } 178 // xtime.tv_nsec += nsecs as i64; 179 let sec = __ADDED_SEC.load(Ordering::SeqCst); 180 _xtime.tv_sec += sec; 181 while _xtime.tv_nsec >= NSEC_PER_SEC.into() { 182 _xtime.tv_nsec -= NSEC_PER_SEC as i64; 183 _xtime.tv_sec += 1; 184 } 185 186 // TODO 将xtime和当前时间源的时间相加 187 188 return _xtime; 189 } 190 191 /// # 获取1970.1.1至今的UTC时间戳(最小单位:usec) 192 /// 193 /// ## 返回值 194 /// 195 /// * 'PosixTimeval' - 时间戳 196 pub fn do_gettimeofday() -> PosixTimeval { 197 let tp = getnstimeofday(); 198 return PosixTimeval { 199 tv_sec: tp.tv_sec, 200 tv_usec: (tp.tv_nsec / 1000) as i32, 201 }; 202 } 203 204 /// # 初始化timekeeping模块 205 pub fn timekeeping_init() { 206 kinfo!("Initializing timekeeping module..."); 207 let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; 208 timekeeper_init(); 209 210 // TODO 有ntp模块后 在此初始化ntp模块 211 212 let clock = clocksource_default_clock(); 213 clock 214 .enable() 215 .expect("clocksource_default_clock enable failed"); 216 timekeeper().timekeeper_setup_internals(clock); 217 // 暂时不支持其他架构平台对时间的设置 所以使用x86平台对应值初始化 218 let mut timekeeper = timekeeper().0.write(); 219 timekeeper.xtime.tv_nsec = ktime_get_real_ns(); 220 221 // 初始化wall time到monotonic的时间 222 let mut nsec = -timekeeper.xtime.tv_nsec; 223 let mut sec = -timekeeper.xtime.tv_sec; 224 // FIXME: 这里有个奇怪的奇怪的bug 225 let num = nsec % NSEC_PER_SEC as i64; 226 nsec += num * NSEC_PER_SEC as i64; 227 sec -= num; 228 timekeeper.wall_to_monotonic.tv_nsec = nsec; 229 timekeeper.wall_to_monotonic.tv_sec = sec; 230 231 __ADDED_USEC.store(0, Ordering::SeqCst); 232 __ADDED_SEC.store(0, Ordering::SeqCst); 233 234 drop(irq_guard); 235 kinfo!("timekeeping_init successfully"); 236 } 237 238 /// # 使用当前时钟源增加wall time 239 pub fn update_wall_time() { 240 // kdebug!("enter update_wall_time, stack_use = {:}",stack_use); 241 compiler_fence(Ordering::SeqCst); 242 let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; 243 // 如果在休眠那就不更新 244 if TIMEKEEPING_SUSPENDED.load(Ordering::SeqCst) { 245 return; 246 } 247 248 // ===== 请不要删除这些注释 ===== 249 // let clock = timekeeper.clock.clone().unwrap(); 250 // let clock_data = clock.clocksource_data(); 251 // let offset = (clock.read().div(clock_data.watchdog_last).data()) & clock_data.mask.bits(); 252 253 // timekeeper.xtime_nsec = (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift; 254 // // TODO 当有ntp模块之后 需要将timekeep与ntp进行同步并检查 255 // timekeeper.xtime.tv_nsec = ((timekeeper.xtime_nsec as i64) >> timekeeper.shift) + 1; 256 // timekeeper.xtime_nsec -= (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift; 257 258 // timekeeper.xtime.tv_nsec += offset as i64; 259 // while unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC.into()) { 260 // timekeeper.xtime.tv_nsec -= NSEC_PER_SEC as i64; 261 // timekeeper.xtime.tv_sec += 1; 262 // // TODO 需要处理闰秒 263 // } 264 // ================ 265 compiler_fence(Ordering::SeqCst); 266 267 // !!! todo: 这里是硬编码了HPET的500us中断,需要修改 268 __ADDED_USEC.fetch_add(500, Ordering::SeqCst); 269 compiler_fence(Ordering::SeqCst); 270 let mut retry = 10; 271 272 let usec = __ADDED_USEC.load(Ordering::SeqCst); 273 if usec % USEC_PER_SEC as i64 == 0 { 274 compiler_fence(Ordering::SeqCst); 275 276 __ADDED_SEC.fetch_add(1, Ordering::SeqCst); 277 compiler_fence(Ordering::SeqCst); 278 } 279 // 一分钟同步一次 280 loop { 281 if (usec & !((1 << 26) - 1)) != 0 { 282 if __ADDED_USEC 283 .compare_exchange(usec, 0, Ordering::SeqCst, Ordering::SeqCst) 284 .is_ok() 285 || retry == 0 286 { 287 // 同步时间 288 // 我感觉这里会出问题:多个读者不退出的话,写者就无法写入 289 // 然后这里会超时,导致在中断返回之后,会不断的进入这个中断,最终爆栈。 290 let mut timekeeper = timekeeper().0.write_irqsave(); 291 timekeeper.xtime.tv_nsec = ktime_get_real_ns(); 292 timekeeper.xtime.tv_sec = 0; 293 __ADDED_SEC.store(0, Ordering::SeqCst); 294 drop(timekeeper); 295 break; 296 } 297 retry -= 1; 298 } else { 299 break; 300 } 301 } 302 // TODO 需要检查是否更新时间源 303 compiler_fence(Ordering::SeqCst); 304 drop(irq_guard); 305 compiler_fence(Ordering::SeqCst); 306 } 307 // TODO timekeeping_adjust 308 // TODO wall_to_monotic 309 310 // ========= 以下为对C的接口 ========= 311 #[no_mangle] 312 pub extern "C" fn rs_timekeeping_init() { 313 timekeeping_init(); 314 } 315