实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型 (#674)

* 实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型。
This commit is contained in:
LoGin
2024-03-28 00:28:13 +08:00
committed by GitHub
parent 597ecc08c2
commit da15231979
28 changed files with 1441 additions and 156 deletions

View File

@ -16,6 +16,7 @@ pub mod timeconv;
pub mod timekeep;
pub mod timekeeping;
pub mod timer;
/* Time structures. (Partitially taken from smoltcp)
The `time` module contains structures used to represent both
@ -124,6 +125,61 @@ pub struct Instant {
impl Instant {
pub const ZERO: Instant = Instant::from_micros_const(0);
/// mktime64 - 将日期转换为秒。
///
/// ## 参数
///
/// - year0: 要转换的年份
/// - mon0: 要转换的月份
/// - day: 要转换的天
/// - hour: 要转换的小时
/// - min: 要转换的分钟
/// - sec: 要转换的秒
///
/// 将公历日期转换为1970-01-01 00:00:00以来的秒数。
/// 假设输入为正常的日期格式即1980-12-31 23:59:59 => 年份=1980, 月=12, 日=31, 时=23, 分=59, 秒=59。
///
/// [For the Julian calendar俄罗斯在1917年之前使用英国及其殖民地在大西洋1752年之前使用
/// 其他地方在1582年之前使用某些社区仍然在使用省略-year/100+year/400项
/// 并在结果上加10。]
///
/// 这个算法最初由高斯(我认为是)发表。
///
/// 要表示闰秒可以通过将sec设为60在ISO 8601允许来调用此函数。
/// 闰秒与随后的秒一样处理因为它们在UNIX时间中不存在。
///
/// 支持将午夜作为当日末尾的24:00:00编码 - 即明天的午夜在ISO 8601允许
///
/// ## 返回
///
/// 返回给定输入日期自1970-01-01 00:00:00以来的秒数
pub fn mktime64(year0: u32, mon0: u32, day: u32, hour: u32, min: u32, sec: u32) -> Self {
let mut mon: i64 = mon0.into();
let mut year: u64 = year0.into();
let day: u64 = day.into();
let hour: u64 = hour.into();
let min: u64 = min.into();
let sec: u64 = sec.into();
mon -= 2;
/* 1..12 -> 11,12,1..10 */
if mon <= 0 {
/* Puts Feb last since it has leap day */
mon += 12;
year -= 1;
}
let mon = mon as u64;
let secs = ((((year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) + year * 365
- 719499)
* 24 + hour) /* now have hours - midnight tomorrow handled here */
* 60 + min)/* now have minutes */
* 60
+ sec; /* finally seconds */
Self::from_secs(secs as i64)
}
/// Create a new `Instant` from a number of microseconds.
pub fn from_micros<T: Into<i64>>(micros: T) -> Instant {
Instant {

View File

@ -1,6 +1,10 @@
#![allow(dead_code)]
use crate::driver::timers::rtc::rtc::RtcTime;
use system_error::SystemError;
use crate::driver::rtc::interface::rtc_read_time_default;
use super::TimeSpec;
#[allow(non_camel_case_types)]
pub type ktime_t = i64;
@ -14,48 +18,16 @@ fn ktime_to_ns(kt: ktime_t) -> i64 {
/// @brief 从RTC获取当前时间然后计算时间戳。
/// 时间戳为从UTC+0 1970-01-01 00:00到当前UTC+0时间所经过的纳秒数。
/// 注意由于当前未引入时区因此本函数默认时区为UTC+8来计算
fn ktime_get_real() -> ktime_t {
let mut rtc_time: RtcTime = RtcTime::default();
{
let r = rtc_time.get();
// 返回错误码
if let Err(e) = r {
return e as ktime_t;
}
}
let mut day_count: i32 = 0;
for year in 1970..rtc_time.year {
let leap: bool = (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
if leap {
day_count += 366;
} else {
day_count += 365;
}
}
for month in 1..rtc_time.month {
match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => day_count += 31,
2 => day_count += 28,
4 | 6 | 9 | 11 => day_count += 30,
_ => day_count += 0,
}
}
day_count += rtc_time.day - 1;
//转换成纳秒
let timestamp: ktime_t = day_count as i64 * 86_400_000_000_000i64
+ (rtc_time.hour - 8) as i64 * 3_600_000_000_000i64
+ rtc_time.minute as i64 * 60_000_000_000i64
+ rtc_time.second as i64 * 1_000_000_000u64 as ktime_t;
return timestamp;
fn ktime_get_real() -> Result<ktime_t, SystemError> {
let rtc_time = rtc_read_time_default()?;
let time_spec: TimeSpec = rtc_time.into();
let r = time_spec.tv_sec * 1_000_000_000 + time_spec.tv_nsec;
return Ok(r);
}
/// @brief 暴露给外部使用的接口,返回一个时间戳
#[inline]
pub fn ktime_get_real_ns() -> i64 {
let kt: ktime_t = ktime_get_real();
let kt: ktime_t = ktime_get_real().unwrap_or(0);
return ktime_to_ns(kt);
}

View File

@ -1,5 +1,6 @@
use alloc::sync::Arc;
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, Ordering};
use system_error::SystemError;
use crate::{
arch::CurrentIrqArch,
@ -207,6 +208,13 @@ pub fn do_gettimeofday() -> PosixTimeval {
};
}
pub fn do_settimeofday64(time: TimeSpec) -> Result<(), SystemError> {
timekeeper().0.write_irqsave().xtime = time;
// todo: 模仿linux实现时间误差校准。
// https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/timekeeping.c?fi=do_settimeofday64#1312
return Ok(());
}
/// # 初始化timekeeping模块
#[inline(never)]
pub fn timekeeping_init() {