1#![allow(dead_code)]
3use alloc::string::String;
4use core::sync::atomic::{AtomicUsize, Ordering};
5
6static SYSTEM_TICKS: AtomicUsize = AtomicUsize::new(0);
27static mut TIMER_PERIOD_TICKS: u64 = 0;
28
29struct WallClock {
42 base_unix: u64,
43 base_ms: u64,
44 set: bool,
45}
46static WALL_CLOCK: spin::Mutex<WallClock> = spin::Mutex::new(WallClock {
47 base_unix: 0,
48 base_ms: 0,
49 set: false,
50});
51
52const JST_OFFSET_SECS: u64 = 9 * 3600;
54pub const NTP_UNIX_OFFSET: u64 = 2_208_988_800;
56
57pub fn init() {
59 unsafe {
60 let freq: u64;
61 core::arch::asm!("mrs {}, cntfrq_el0", out(reg) freq);
62 TIMER_PERIOD_TICKS = freq / 100;
63 core::arch::asm!("msr cntp_tval_el0, {}", in(reg) TIMER_PERIOD_TICKS);
64 let ctrl: u64 = 1;
65 core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) ctrl);
66 }
67 SYSTEM_TICKS.store(0, Ordering::Relaxed);
68 crate::debug!("[TIMER] ARM Generic Timer enabled at 10ms intervals");
69}
70
71pub fn init_secondary() {
72 unsafe {
73 core::arch::asm!("msr cntp_tval_el0, {}", in(reg) TIMER_PERIOD_TICKS);
74 let ctrl: u64 = 1;
75 core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) ctrl);
76 }
77}
78
79pub fn handle_timer_irq() {
81 unsafe {
82 core::arch::asm!("msr cntp_tval_el0, {}", in(reg) TIMER_PERIOD_TICKS);
84 }
85
86 if crate::kernel::scheduler::core_id() == 0 {
91 SYSTEM_TICKS.fetch_add(1, Ordering::Relaxed);
92 }
93
94 crate::kernel::watchdog::check_from_irq();
97}
98
99pub fn get_ticks() -> usize {
101 SYSTEM_TICKS.load(Ordering::Relaxed)
102}
103
104pub fn get_system_time_us() -> u64 {
106 let count: u64;
107 let freq: u64;
108 unsafe {
109 core::arch::asm!("mrs {}, cntpct_el0", out(reg) count);
110 core::arch::asm!("mrs {}, cntfrq_el0", out(reg) freq);
111 }
112 ((count as u128 * 1_000_000) / freq as u128) as u64
113}
114
115pub fn get_system_time_ms() -> u64 {
117 get_system_time_us() / 1000
118}
119
120pub fn set_wall_clock(unix_secs: u64) {
126 let now_ms = get_system_time_ms();
127 let mut w = WALL_CLOCK.lock();
128 w.base_unix = unix_secs;
129 w.base_ms = now_ms;
130 w.set = true;
131}
132
133pub fn is_wall_clock_set() -> bool {
135 WALL_CLOCK.lock().set
136}
137
138pub fn get_unix_time() -> Option<u64> {
140 let w = WALL_CLOCK.lock();
141 if !w.set {
142 return None;
143 }
144 let elapsed_ms = get_system_time_ms().wrapping_sub(w.base_ms);
145 Some(w.base_unix + elapsed_ms / 1000)
146}
147
148fn civil_from_days(z: i64) -> (i64, u32, u32) {
151 let z = z + 719468;
152 let era = (if z >= 0 { z } else { z - 146096 }) / 146097;
153 let doe = z - era * 146097; let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; let y = yoe + era * 400;
156 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); let mp = (5 * doy + 2) / 153; let d = (doy - (153 * mp + 2) / 5 + 1) as u32; let m = (if mp < 10 { mp + 3 } else { mp - 9 }) as u32; (if m <= 2 { y + 1 } else { y }, m, d)
161}
162
163pub fn get_datetime_jst() -> Option<(i64, u32, u32, u32, u32, u32)> {
165 let unix = get_unix_time()?;
166 let local = unix + JST_OFFSET_SECS;
167 let days = (local / 86400) as i64;
168 let secs_of_day = local % 86400;
169 let (y, mo, d) = civil_from_days(days);
170 let hh = (secs_of_day / 3600) as u32;
171 let mm = ((secs_of_day % 3600) / 60) as u32;
172 let ss = (secs_of_day % 60) as u32;
173 Some((y, mo, d, hh, mm, ss))
174}
175
176pub fn format_datetime_jst() -> Option<String> {
178 let (y, mo, d, hh, mm, _ss) = get_datetime_jst()?;
179 Some(alloc::format!(
180 "{:04}-{:02}-{:02} {:02}:{:02}",
181 y,
182 mo,
183 d,
184 hh,
185 mm
186 ))
187}
188
189pub fn format_time_hms_jst() -> Option<String> {
191 let (_y, _mo, _d, hh, mm, ss) = get_datetime_jst()?;
192 Some(alloc::format!("{:02}:{:02}:{:02}", hh, mm, ss))
193}