mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 08:53:29 +00:00
Prepare aster-time for platform-dependent implementations
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
acb4833aae
commit
97fab9edea
@ -1,19 +1,20 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
//! The system time of Asterinas.
|
//! The system time of Asterinas.
|
||||||
|
#![feature(let_chains)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use core::{sync::atomic::Ordering::Relaxed, time::Duration};
|
use core::time::Duration;
|
||||||
|
|
||||||
use clocksource::ClockSource;
|
use clocksource::ClockSource;
|
||||||
pub use clocksource::Instant;
|
pub use clocksource::Instant;
|
||||||
use component::{init_component, ComponentInitError};
|
use component::{init_component, ComponentInitError};
|
||||||
use ostd::sync::Mutex;
|
use ostd::sync::Mutex;
|
||||||
use rtc::{get_cmos, is_updating, CENTURY_REGISTER};
|
use rtc::Driver;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
mod clocksource;
|
mod clocksource;
|
||||||
@ -23,17 +24,18 @@ mod tsc;
|
|||||||
pub const NANOS_PER_SECOND: u32 = 1_000_000_000;
|
pub const NANOS_PER_SECOND: u32 = 1_000_000_000;
|
||||||
pub static VDSO_DATA_HIGH_RES_UPDATE_FN: Once<Arc<dyn Fn(Instant, u64) + Sync + Send>> =
|
pub static VDSO_DATA_HIGH_RES_UPDATE_FN: Once<Arc<dyn Fn(Instant, u64) + Sync + Send>> =
|
||||||
Once::new();
|
Once::new();
|
||||||
|
static RTC_DRIVER: Once<Arc<dyn Driver + Send + Sync>> = Once::new();
|
||||||
|
|
||||||
#[init_component]
|
#[init_component]
|
||||||
fn time_init() -> Result<(), ComponentInitError> {
|
fn time_init() -> Result<(), ComponentInitError> {
|
||||||
rtc::init();
|
let rtc = rtc::init_rtc_driver().ok_or(ComponentInitError::Unknown)?;
|
||||||
|
RTC_DRIVER.call_once(|| rtc);
|
||||||
tsc::init();
|
tsc::init();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct SystemTime {
|
pub struct SystemTime {
|
||||||
century: u8,
|
|
||||||
pub year: u16,
|
pub year: u16,
|
||||||
pub month: u8,
|
pub month: u8,
|
||||||
pub day: u8,
|
pub day: u8,
|
||||||
@ -46,7 +48,6 @@ pub struct SystemTime {
|
|||||||
impl SystemTime {
|
impl SystemTime {
|
||||||
pub(crate) const fn zero() -> Self {
|
pub(crate) const fn zero() -> Self {
|
||||||
Self {
|
Self {
|
||||||
century: 0,
|
|
||||||
year: 0,
|
year: 0,
|
||||||
month: 0,
|
month: 0,
|
||||||
day: 0,
|
day: 0,
|
||||||
@ -56,55 +57,6 @@ impl SystemTime {
|
|||||||
nanos: 0,
|
nanos: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update_from_rtc(&mut self) {
|
|
||||||
while is_updating() {}
|
|
||||||
self.second = get_cmos(0x00);
|
|
||||||
self.minute = get_cmos(0x02);
|
|
||||||
self.hour = get_cmos(0x04);
|
|
||||||
self.day = get_cmos(0x07);
|
|
||||||
self.month = get_cmos(0x08);
|
|
||||||
self.year = get_cmos(0x09) as u16;
|
|
||||||
|
|
||||||
let century_register = CENTURY_REGISTER.load(Relaxed);
|
|
||||||
if century_register != 0 {
|
|
||||||
self.century = get_cmos(century_register);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// convert BCD to binary values
|
|
||||||
/// ref:https://wiki.osdev.org/CMOS#Reading_All_RTC_Time_and_Date_Registers
|
|
||||||
pub(crate) fn convert_bcd_to_binary(&mut self, register_b: u8) {
|
|
||||||
if register_b & 0x04 == 0 {
|
|
||||||
self.second = (self.second & 0x0F) + ((self.second / 16) * 10);
|
|
||||||
self.minute = (self.minute & 0x0F) + ((self.minute / 16) * 10);
|
|
||||||
self.hour =
|
|
||||||
((self.hour & 0x0F) + (((self.hour & 0x70) / 16) * 10)) | (self.hour & 0x80);
|
|
||||||
self.day = (self.day & 0x0F) + ((self.day / 16) * 10);
|
|
||||||
self.month = (self.month & 0x0F) + ((self.month / 16) * 10);
|
|
||||||
self.year = (self.year & 0x0F) + ((self.year / 16) * 10);
|
|
||||||
if CENTURY_REGISTER.load(Relaxed) != 0 {
|
|
||||||
self.century = (self.century & 0x0F) + ((self.century / 16) * 10);
|
|
||||||
} else {
|
|
||||||
// 2000 ~ 2099
|
|
||||||
const DEFAULT_21_CENTURY: u8 = 20;
|
|
||||||
self.century = DEFAULT_21_CENTURY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// convert 12 hour clock to 24 hour clock
|
|
||||||
pub(crate) fn convert_12_hour_to_24_hour(&mut self, register_b: u8) {
|
|
||||||
// bit1 in register_b is not set if 12 hour format is enable
|
|
||||||
// if highest bit in hour is set, then it is pm
|
|
||||||
if ((register_b & 0x02) == 0) && ((self.hour & 0x80) != 0) {
|
|
||||||
self.hour = ((self.hour & 0x7F) + 12) % 24;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// convert raw year (10, 20 etc.) to real year (2010, 2020 etc.)
|
|
||||||
pub(crate) fn modify_year(&mut self) {
|
|
||||||
self.year += self.century as u16 * 100;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) static READ_TIME: Mutex<SystemTime> = Mutex::new(SystemTime::zero());
|
pub(crate) static READ_TIME: Mutex<SystemTime> = Mutex::new(SystemTime::zero());
|
||||||
@ -120,28 +72,9 @@ pub fn read() -> SystemTime {
|
|||||||
*READ_TIME.lock()
|
*READ_TIME.lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// read year,month,day and other data
|
|
||||||
/// ref: https://wiki.osdev.org/CMOS#Reading_All_RTC_Time_and_Date_Registers
|
|
||||||
fn update_time() {
|
fn update_time() {
|
||||||
let mut last_time: SystemTime;
|
|
||||||
|
|
||||||
let mut lock = READ_TIME.lock();
|
let mut lock = READ_TIME.lock();
|
||||||
|
*lock = RTC_DRIVER.get().unwrap().read_rtc();
|
||||||
lock.update_from_rtc();
|
|
||||||
|
|
||||||
last_time = *lock;
|
|
||||||
|
|
||||||
lock.update_from_rtc();
|
|
||||||
|
|
||||||
while *lock != last_time {
|
|
||||||
last_time = *lock;
|
|
||||||
lock.update_from_rtc();
|
|
||||||
}
|
|
||||||
let register_b: u8 = get_cmos(0x0B);
|
|
||||||
|
|
||||||
lock.convert_bcd_to_binary(register_b);
|
|
||||||
lock.convert_12_hour_to_24_hour(register_b);
|
|
||||||
lock.modify_year();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the `START_TIME`, which is the actual time when doing calibrate.
|
/// Return the `START_TIME`, which is the actual time when doing calibrate.
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
use core::sync::atomic::{AtomicU8, Ordering::Relaxed};
|
|
||||||
|
|
||||||
use ostd::arch::x86::device::cmos::{century_register, CMOS_ADDRESS, CMOS_DATA};
|
|
||||||
|
|
||||||
pub(crate) static CENTURY_REGISTER: AtomicU8 = AtomicU8::new(0);
|
|
||||||
|
|
||||||
pub fn init() {
|
|
||||||
let Some(century_register) = century_register() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
CENTURY_REGISTER.store(century_register, Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_cmos(reg: u8) -> u8 {
|
|
||||||
CMOS_ADDRESS.write(reg);
|
|
||||||
CMOS_DATA.read()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_updating() -> bool {
|
|
||||||
CMOS_ADDRESS.write(0x0A);
|
|
||||||
CMOS_DATA.read() & 0x80 != 0
|
|
||||||
}
|
|
140
kernel/comps/time/src/rtc/cmos.rs
Normal file
140
kernel/comps/time/src/rtc/cmos.rs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use core::sync::atomic::{AtomicU8, Ordering::Relaxed};
|
||||||
|
|
||||||
|
use ostd::arch::x86::device::cmos::{century_register, CMOS_ADDRESS, CMOS_DATA};
|
||||||
|
|
||||||
|
use crate::SystemTime;
|
||||||
|
use super::Driver;
|
||||||
|
|
||||||
|
static CENTURY_REGISTER: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
fn get_cmos(reg: u8) -> u8 {
|
||||||
|
CMOS_ADDRESS.write(reg);
|
||||||
|
CMOS_DATA.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_updating() -> bool {
|
||||||
|
CMOS_ADDRESS.write(0x0A);
|
||||||
|
CMOS_DATA.read() & 0x80 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct CmosData {
|
||||||
|
century: u8,
|
||||||
|
year: u16,
|
||||||
|
month: u8,
|
||||||
|
day: u8,
|
||||||
|
hour: u8,
|
||||||
|
minute: u8,
|
||||||
|
second: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmosData {
|
||||||
|
fn from_rtc_raw(century_register: u8) -> Self {
|
||||||
|
while is_updating() {}
|
||||||
|
|
||||||
|
let second = get_cmos(0x00);
|
||||||
|
let minute = get_cmos(0x02);
|
||||||
|
let hour = get_cmos(0x04);
|
||||||
|
let day = get_cmos(0x07);
|
||||||
|
let month = get_cmos(0x08);
|
||||||
|
let year = get_cmos(0x09) as u16;
|
||||||
|
|
||||||
|
let century = if century_register != 0 {
|
||||||
|
get_cmos(century_register)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
CmosData {
|
||||||
|
century,
|
||||||
|
year,
|
||||||
|
month,
|
||||||
|
day,
|
||||||
|
hour,
|
||||||
|
minute,
|
||||||
|
second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts BCD to binary values.
|
||||||
|
/// ref: https://wiki.osdev.org/CMOS#Reading_All_RTC_Time_and_Date_Registers
|
||||||
|
fn convert_bcd_to_binary(&mut self, register_b: u8) {
|
||||||
|
if register_b & 0x04 == 0 {
|
||||||
|
self.second = (self.second & 0x0F) + ((self.second / 16) * 10);
|
||||||
|
self.minute = (self.minute & 0x0F) + ((self.minute / 16) * 10);
|
||||||
|
self.hour =
|
||||||
|
((self.hour & 0x0F) + (((self.hour & 0x70) / 16) * 10)) | (self.hour & 0x80);
|
||||||
|
self.day = (self.day & 0x0F) + ((self.day / 16) * 10);
|
||||||
|
self.month = (self.month & 0x0F) + ((self.month / 16) * 10);
|
||||||
|
self.year = (self.year & 0x0F) + ((self.year / 16) * 10);
|
||||||
|
if CENTURY_REGISTER.load(Relaxed) != 0 {
|
||||||
|
self.century = (self.century & 0x0F) + ((self.century / 16) * 10);
|
||||||
|
} else {
|
||||||
|
// 2000 ~ 2099
|
||||||
|
const DEFAULT_21_CENTURY: u8 = 20;
|
||||||
|
self.century = DEFAULT_21_CENTURY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts 12 hour clock to 24 hour clock.
|
||||||
|
fn convert_12_hour_to_24_hour(&mut self, register_b: u8) {
|
||||||
|
// bit1 in register_b is not set if 12 hour format is enable
|
||||||
|
// if highest bit in hour is set, then it is pm
|
||||||
|
if ((register_b & 0x02) == 0) && ((self.hour & 0x80) != 0) {
|
||||||
|
self.hour = ((self.hour & 0x7F) + 12) % 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts raw year (10, 20 etc.) to real year (2010, 2020 etc.).
|
||||||
|
fn modify_year(&mut self) {
|
||||||
|
self.year += self.century as u16 * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_rtc(century_register: u8) -> Self {
|
||||||
|
let mut now = Self::from_rtc_raw(century_register);
|
||||||
|
while let new = Self::from_rtc_raw(century_register) && now != new {
|
||||||
|
now = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
let register_b: u8 = get_cmos(0x0B);
|
||||||
|
|
||||||
|
now.convert_bcd_to_binary(register_b);
|
||||||
|
now.convert_12_hour_to_24_hour(register_b);
|
||||||
|
now.modify_year();
|
||||||
|
|
||||||
|
now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CmosData> for SystemTime {
|
||||||
|
fn from(cmos: CmosData) -> SystemTime {
|
||||||
|
SystemTime {
|
||||||
|
year: cmos.year,
|
||||||
|
month: cmos.month,
|
||||||
|
day: cmos.day,
|
||||||
|
hour: cmos.hour,
|
||||||
|
minute: cmos.minute,
|
||||||
|
second: cmos.second,
|
||||||
|
nanos: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RtcCmos {
|
||||||
|
century_register: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Driver for RtcCmos {
|
||||||
|
fn try_new() -> Option<RtcCmos> {
|
||||||
|
Some(RtcCmos {
|
||||||
|
century_register: century_register().unwrap_or(0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_rtc(&self) -> SystemTime {
|
||||||
|
CmosData::read_rtc(self.century_register).into()
|
||||||
|
}
|
||||||
|
}
|
42
kernel/comps/time/src/rtc/mod.rs
Normal file
42
kernel/comps/time/src/rtc/mod.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
use crate::SystemTime;
|
||||||
|
|
||||||
|
/// Generic interface for RTC drivers
|
||||||
|
pub trait Driver {
|
||||||
|
/// Creates a RTC driver.
|
||||||
|
/// Returns [`Some<Self>`] on success, [`None`] otherwise (e.g. platform unsupported).
|
||||||
|
fn try_new() -> Option<Self>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
/// Reads RTC.
|
||||||
|
fn read_rtc(&self) -> SystemTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! declare_rtc_drivers {
|
||||||
|
( $( #[cfg $cfg:tt ] $module:ident :: $name:ident),* $(,)? ) => {
|
||||||
|
$(
|
||||||
|
#[cfg $cfg]
|
||||||
|
mod $module;
|
||||||
|
)*
|
||||||
|
|
||||||
|
pub fn init_rtc_driver() -> Option<Arc<dyn Driver + Send + Sync>> {
|
||||||
|
// iterate all possible drivers and pick one that can be initialized
|
||||||
|
$(
|
||||||
|
#[cfg $cfg]
|
||||||
|
if let Some(driver) = $module::$name::try_new() {
|
||||||
|
return Some(Arc::new(driver));
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_rtc_drivers! {
|
||||||
|
#[cfg(target_arch = "x86_64")] cmos::RtcCmos,
|
||||||
|
}
|
@ -9,7 +9,7 @@ use core::sync::atomic::{AtomicU64, Ordering};
|
|||||||
use ostd::arch::{
|
use ostd::arch::{
|
||||||
read_tsc,
|
read_tsc,
|
||||||
timer::{self, TIMER_FREQ},
|
timer::{self, TIMER_FREQ},
|
||||||
x86::tsc_freq,
|
tsc_freq,
|
||||||
};
|
};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user