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