diff --git a/Cargo.lock b/Cargo.lock index deef7aae6..a8fbeebd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -387,6 +387,7 @@ dependencies = [ "crate_interface", "dtb", "dw_apb_uart", + "embedded-hal", "handler_table", "kernel_guard", "lazy_init", diff --git a/api/arceos_api/Cargo.toml b/api/arceos_api/Cargo.toml index 3699a6c46..4b759c654 100644 --- a/api/arceos_api/Cargo.toml +++ b/api/arceos_api/Cargo.toml @@ -13,6 +13,7 @@ documentation = "https://rcore-os.github.io/arceos/arceos_api/index.html" default = [] irq = ["axfeat/irq"] +rtc = ["axfeat/rtc"] alloc = ["dep:axalloc", "axfeat/alloc"] multitask = ["axtask/multitask", "axfeat/multitask"] fs = ["dep:axfs", "axfeat/fs"] diff --git a/api/arceos_posix_api/src/imp/time.rs b/api/arceos_posix_api/src/imp/time.rs index 6845cce47..221728f43 100644 --- a/api/arceos_posix_api/src/imp/time.rs +++ b/api/arceos_posix_api/src/imp/time.rs @@ -56,6 +56,23 @@ pub unsafe fn sys_clock_gettime(_clk: ctypes::clockid_t, ts: *mut ctypes::timesp }) } +/// Get clock time since booting +pub unsafe fn sys_clock_settime(_clk: ctypes::clockid_t, ts: *mut ctypes::timespec) -> c_int { + syscall_body!(sys_clock_setttime, { + if ts.is_null() { + return Err(LinuxError::EFAULT); + } + let new_tv = Duration::from(*ts); + debug!( + "sys_clock_setttime: {}.{:09}s", + new_tv.as_secs(), + new_tv.as_nanos() + ); + axhal::time::set_current_time(new_tv); + Ok(0) + }) +} + /// Sleep some nanoseconds /// /// TODO: should be woken by signals, and set errno diff --git a/api/arceos_posix_api/src/lib.rs b/api/arceos_posix_api/src/lib.rs index e87b54cb5..c78e95713 100644 --- a/api/arceos_posix_api/src/lib.rs +++ b/api/arceos_posix_api/src/lib.rs @@ -49,7 +49,7 @@ pub use imp::io::{sys_read, sys_write, sys_writev}; pub use imp::resources::{sys_getrlimit, sys_setrlimit}; pub use imp::sys::sys_sysinfo; pub use imp::task::{sys_exit, sys_getpid, sys_sched_yield}; -pub use imp::time::{sys_clock_gettime, sys_nanosleep}; +pub use imp::time::{sys_clock_gettime, sys_clock_settime, sys_nanosleep}; #[cfg(feature = "fd")] pub use imp::fd_ops::{sys_close, sys_dup, sys_dup2, sys_fcntl}; diff --git a/api/axfeat/Cargo.toml b/api/axfeat/Cargo.toml index 2947a7ea1..e05e521c0 100644 --- a/api/axfeat/Cargo.toml +++ b/api/axfeat/Cargo.toml @@ -21,6 +21,9 @@ fp_simd = ["axhal/fp_simd"] # Interrupts irq = ["axhal/irq", "axruntime/irq", "axtask?/irq"] +# Real time clock +rtc = ["axhal/rtc", "axruntime/rtc"] + # Memory alloc = ["axalloc", "axruntime/alloc"] alloc-tlsf = ["axalloc/tlsf"] diff --git a/apps/c/systime/features.txt b/apps/c/systime/features.txt new file mode 100644 index 000000000..8b9a44ab0 --- /dev/null +++ b/apps/c/systime/features.txt @@ -0,0 +1 @@ +rtc \ No newline at end of file diff --git a/apps/c/systime/main.c b/apps/c/systime/main.c new file mode 100644 index 000000000..60194917a --- /dev/null +++ b/apps/c/systime/main.c @@ -0,0 +1,39 @@ +#include +#include + +int main() +{ + struct timeval tv; + if (gettimeofday(&tv, NULL) != 0 ) { + perror("gettimeofday"); + return -1; + } + + printf("now time: %ld : %ld\n", tv.tv_sec,tv.tv_usec); + + usleep(3000000); + + if (gettimeofday(&tv, NULL) != 0 ) { + perror("gettimeofday"); + return -1; + } + + printf("now time: %ld : %ld\n", tv.tv_sec,tv.tv_usec); + + struct timeval new_time; + new_time.tv_sec = 1731110400; + new_time.tv_usec = 0; + + if (settimeofday(&new_time, NULL) != 0 ) { + perror("settimeofday"); + return -1; + } + if (gettimeofday(&tv, NULL) != 0 ) { + perror("gettimeofday"); + return -1; + } + + printf("now time: %ld : %ld\n", tv.tv_sec,tv.tv_usec); + return 0; + +} \ No newline at end of file diff --git a/modules/axhal/Cargo.toml b/modules/axhal/Cargo.toml index ec2a26c3f..2d4f2d932 100644 --- a/modules/axhal/Cargo.toml +++ b/modules/axhal/Cargo.toml @@ -15,6 +15,7 @@ alloc = [] fp_simd = [] paging = ["axalloc", "page_table"] irq = [] +rtc = [] tls = ["alloc"] default = [] @@ -23,6 +24,7 @@ log = "0.4" cfg-if = "1.0" bitflags = "2.2" static_assertions = "1.1.0" +embedded-hal = "0.2.7" axlog = { path = "../axlog" } axconfig = { path = "../axconfig" } axalloc = { path = "../axalloc", optional = true } diff --git a/modules/axhal/src/platform/aarch64_common/mod.rs b/modules/axhal/src/platform/aarch64_common/mod.rs index ece1d799f..46cd23906 100644 --- a/modules/axhal/src/platform/aarch64_common/mod.rs +++ b/modules/axhal/src/platform/aarch64_common/mod.rs @@ -18,3 +18,6 @@ pub mod gic; #[cfg(not(platform_family = "aarch64-bsta1000b"))] pub mod pl011; + +#[cfg(feature = "rtc")] +pub mod pl031; diff --git a/modules/axhal/src/platform/aarch64_common/pl031.rs b/modules/axhal/src/platform/aarch64_common/pl031.rs new file mode 100644 index 000000000..89e38ef25 --- /dev/null +++ b/modules/axhal/src/platform/aarch64_common/pl031.rs @@ -0,0 +1,74 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Rukos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +//! PL031 RTC. + +static RTC_DR: u32 = 0x000; //Data Register +static RTC_MR: u32 = 0x004; //Match Register +static RTC_LR: u32 = 0x008; //Load Register +static RTC_CR: u32 = 0x00c; //Control Register +static RTC_IMSC: u32 = 0x010; //Interrupt Mask Set or Clear register + +const PHYS_RTC: usize = axconfig::PHYS_VIRT_OFFSET + 0x09010000; + +static PL031_RTC: Pl031rtc = Pl031rtc { address: PHYS_RTC }; + +pub fn init() { + info!("Initialize pl031 rtc..."); + PL031_RTC.init(); + debug!("{}", rtc_read_time()); +} + +struct Pl031rtc { + address: usize, +} + +impl core::fmt::Display for Pl031rtc { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "RTC DR: {}\nRTC MR: {}\nRTC LR: {}\nRTC CR: {}\nRTC_IMSC: {}", + unsafe { self.read(RTC_DR) } as u64, + unsafe { self.read(RTC_MR) } as u64, + unsafe { self.read(RTC_LR) } as u64, + unsafe { self.read(RTC_CR) } as u64, + unsafe { self.read(RTC_IMSC) } as u64 + ) + } +} + +impl Pl031rtc { + fn init(&self) { + unsafe { + if self.read(RTC_CR) != 1 { + self.write(RTC_CR, 1); + } + } + } + + pub unsafe fn read(&self, reg: u32) -> u32 { + core::ptr::read_volatile((PHYS_RTC + reg as usize) as *const u32) + } + + pub unsafe fn write(&self, reg: u32, value: u32) { + core::ptr::write_volatile((PHYS_RTC + reg as usize) as *mut u32, value); + } + + pub fn time(&self) -> u64 { + unsafe { self.read(RTC_DR) as u64 } + } +} + +pub fn rtc_read_time() -> u64 { + PL031_RTC.time() +} + +pub fn rtc_write_time(seconds: u32) { + unsafe { PL031_RTC.write(RTC_LR, seconds) }; +} diff --git a/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs b/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs index d20b007b0..cba38247d 100644 --- a/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs +++ b/modules/axhal/src/platform/aarch64_qemu_virt/mod.rs @@ -23,6 +23,8 @@ pub mod console { pub mod time { pub use crate::platform::aarch64_common::generic_timer::*; + #[cfg(feature = "rtc")] + pub use crate::platform::aarch64_common::pl031::*; } pub mod misc { @@ -64,6 +66,8 @@ pub fn platform_init() { #[cfg(feature = "irq")] super::aarch64_common::gic::init_primary(); super::aarch64_common::generic_timer::init_percpu(); + #[cfg(feature = "rtc")] + super::aarch64_common::pl031::init(); super::aarch64_common::pl011::init(); } diff --git a/modules/axhal/src/platform/aarch64_raspi/mod.rs b/modules/axhal/src/platform/aarch64_raspi/mod.rs index 0517f3529..bed5e3045 100644 --- a/modules/axhal/src/platform/aarch64_raspi/mod.rs +++ b/modules/axhal/src/platform/aarch64_raspi/mod.rs @@ -23,6 +23,8 @@ pub mod console { pub mod time { pub use crate::platform::aarch64_common::generic_timer::*; + #[cfg(feature = "rtc")] + pub use crate::platform::aarch64_common::pl031::*; } pub mod misc { @@ -66,6 +68,8 @@ pub fn platform_init() { #[cfg(feature = "irq")] super::aarch64_common::gic::init_primary(); super::aarch64_common::generic_timer::init_percpu(); + #[cfg(feature = "rtc")] + super::aarch64_common::pl031::init(); super::aarch64_common::pl011::init(); } diff --git a/modules/axhal/src/platform/x86_pc/mod.rs b/modules/axhal/src/platform/x86_pc/mod.rs index 96af56cc4..92d0ae12d 100644 --- a/modules/axhal/src/platform/x86_pc/mod.rs +++ b/modules/axhal/src/platform/x86_pc/mod.rs @@ -14,6 +14,8 @@ mod uart16550; pub mod mem; pub mod misc; +#[cfg(feature = "rtc")] +pub mod rtc; pub mod time; #[cfg(feature = "smp")] diff --git a/modules/axhal/src/platform/x86_pc/rtc.rs b/modules/axhal/src/platform/x86_pc/rtc.rs new file mode 100644 index 000000000..715cc8f80 --- /dev/null +++ b/modules/axhal/src/platform/x86_pc/rtc.rs @@ -0,0 +1,360 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Rukos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +use core::arch::asm; +use core::cmp::PartialEq; +use core::marker::PhantomData; +use core::ops::{BitAnd, BitOr, Not}; +use lazy_init::LazyInit; + +pub trait Io { + type Value: Copy + + PartialEq + + BitAnd + + BitOr + + Not; + + fn read(&self) -> Self::Value; + fn write(&mut self, value: Self::Value); + + #[inline(always)] + fn readf(&self, flags: Self::Value) -> bool { + (self.read() & flags) as Self::Value == flags + } + + #[inline(always)] + fn writef(&mut self, flags: Self::Value, value: bool) { + let tmp: Self::Value = match value { + true => self.read() | flags, + false => self.read() & !flags, + }; + self.write(tmp); + } +} + +/// Generic PIO +#[derive(Copy, Clone)] +pub struct Pio { + port: u16, + value: PhantomData, +} + +impl Pio { + /// Create a PIO from a given port + pub const fn new(port: u16) -> Self { + Pio:: { + port, + value: PhantomData, + } + } +} + +/// Read/Write for byte PIO +impl Io for Pio { + type Value = u8; + + /// Read + #[inline(always)] + fn read(&self) -> u8 { + let value: u8; + unsafe { + asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u8) { + unsafe { + asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags)); + } + } +} + +/// Read/Write for word PIO +impl Io for Pio { + type Value = u16; + + /// Read + #[inline(always)] + fn read(&self) -> u16 { + let value: u16; + unsafe { + asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u16) { + unsafe { + asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags)); + } + } +} + +/// Read/Write for doubleword PIO +impl Io for Pio { + type Value = u32; + + /// Read + #[inline(always)] + fn read(&self) -> u32 { + let value: u32; + unsafe { + asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u32) { + unsafe { + asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags)); + } + } +} + +static mut X86_RTC: LazyInit = LazyInit::new(); + +fn cvt_bcd(value: usize) -> usize { + (value & 0xF) + ((value / 16) * 10) +} + +fn cvt_dec(value: usize) -> usize { + ((value / 10) << 4) | (value % 10) +} + +/// RTC +pub struct Rtc { + addr: Pio, + data: Pio, + nmi: bool, +} + +impl Rtc { + /// Create new empty RTC + pub fn new() -> Self { + Rtc { + addr: Pio::::new(0x70), + data: Pio::::new(0x71), + nmi: false, + } + } + + /// Read + unsafe fn read(&mut self, reg: u8) -> u8 { + if self.nmi { + self.addr.write(reg & 0x7F); + } else { + self.addr.write(reg | 0x80); + } + self.data.read() + } + + /// Write + #[allow(dead_code)] + unsafe fn write(&mut self, reg: u8, value: u8) { + if self.nmi { + self.addr.write(reg & 0x7F); + } else { + self.addr.write(reg | 0x80); + } + self.data.write(value); + } + + /// Wait for an update, can take one second if full is specified! + unsafe fn wait(&mut self, full: bool) { + if full { + while self.read(0xA) & 0x80 != 0x80 {} + } + while self.read(0xA) & 0x80 == 0x80 {} + } + + /// Get time without waiting + unsafe fn time_no_wait(&mut self) -> u64 { + let mut second = self.read(0) as usize; + let mut minute = self.read(2) as usize; + let mut hour = self.read(4) as usize; + let mut day = self.read(7) as usize; + let mut month = self.read(8) as usize; + let mut year = self.read(9) as usize; + let century = 20; + let register_b = self.read(0xB); + + if register_b & 4 != 4 { + second = cvt_bcd(second); + minute = cvt_bcd(minute); + hour = cvt_bcd(hour & 0x7F) | (hour & 0x80); + day = cvt_bcd(day); + month = cvt_bcd(month); + year = cvt_bcd(year); + } + + if register_b & 2 != 2 || hour & 0x80 == 0x80 { + hour = ((hour & 0x7F) + 12) % 24; + } + + year += century * 100; + + // Unix time from clock + let mut secs: u64 = (year as u64 - 1970) * 31_536_000; + + let mut leap_days = (year as u64 - 1972) / 4 + 1; + if year % 4 == 0 && month <= 2 { + leap_days -= 1; + } + secs += leap_days * 86_400; + + match month { + 2 => secs += 2_678_400, + 3 => secs += 5_097_600, + 4 => secs += 7_776_000, + 5 => secs += 10_368_000, + 6 => secs += 13_046_400, + 7 => secs += 15_638_400, + 8 => secs += 18_316_800, + 9 => secs += 20_995_200, + 10 => secs += 23_587_200, + 11 => secs += 26_265_600, + 12 => secs += 28_857_600, + _ => (), + } + + secs += (day as u64 - 1) * 86_400; + secs += hour as u64 * 3600; + secs += minute as u64 * 60; + secs += second as u64; + + secs + } + + /// Get time + fn time(&mut self) -> u64 { + loop { + unsafe { + self.wait(false); + let time = self.time_no_wait(); + self.wait(false); + let next_time = self.time_no_wait(); + if time == next_time { + return time; + } + } + } + } + + unsafe fn write_time_no_wait(&mut self, unix_time: u32) { + let register_b = self.read(0xB); + + let secs = unix_time; + + // Calculate date and time + let t = secs; + let mut tdiv = t / 86400; + let mut tt = t % 86400; + let mut hour = tt / 3600; + tt %= 3600; + let mut min = tt / 60; + tt %= 60; + let mut sec = tt; + let mut year = 1970; + let mut mon = 1; + + while tdiv >= 365 { + let days = if is_leap_year(year) { 366 } else { 365 }; + if tdiv >= days { + tdiv -= days; + year += 1; + } else { + break; + } + } + + while tdiv > 0 { + let days = days_in_month(mon, year); + if u64::from(tdiv) >= days { + tdiv -= days as u32; + mon += 1; + } else { + break; + } + } + + let mut mday = tdiv + 1; + + year -= 2000; + + if register_b & 4 != 4 { + sec = cvt_dec(sec as usize) as u32; + min = cvt_dec(min as usize) as u32; + mday = cvt_dec(mday as usize) as u32; + mon = cvt_dec(mon as usize) as u64; + year = cvt_dec(year as usize) as u64; + } + let mut bcd_value = hour % 10; + let tens = hour / 10; + if hour >= 12 { + bcd_value |= 0x80; + } + bcd_value |= tens << 4; + hour = bcd_value; + + self.write(0, sec as u8); + self.write(2, min as u8); + self.write(4, hour as u8); + self.write(7, mday as u8); + self.write(8, mon as u8); + self.write(9, year as u8); + } +} + +fn is_leap_year(year: u64) -> bool { + (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) +} + +fn days_in_month(month: u64, year: u64) -> u64 { + match month { + 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, + 4 | 6 | 9 | 11 => 30, + 2 => { + if is_leap_year(year) { + 29 + } else { + 28 + } + } + _ => 0, + } +} + +/// return rtc time value +pub fn rtc_read_time() -> u64 { + unsafe { + if !X86_RTC.is_init() { + X86_RTC.init_by(Rtc::new()); + } + let rtc: &mut Rtc = X86_RTC.get_mut_unchecked(); + rtc.time() + } +} + +/// change rtc time value +pub fn rtc_write_time(seconds: u32) { + unsafe { + if !X86_RTC.is_init() { + X86_RTC.init_by(Rtc::new()); + } + let rtc: &mut Rtc = X86_RTC.get_mut_unchecked(); + rtc.write_time_no_wait(seconds); + } +} diff --git a/modules/axhal/src/platform/x86_pc/time.rs b/modules/axhal/src/platform/x86_pc/time.rs index 205316a2d..0b351a485 100644 --- a/modules/axhal/src/platform/x86_pc/time.rs +++ b/modules/axhal/src/platform/x86_pc/time.rs @@ -15,6 +15,9 @@ const LAPIC_TICKS_PER_SEC: u64 = 1_000_000_000; // TODO: need to calibrate #[cfg(feature = "irq")] static mut NANOS_TO_LAPIC_TICKS_RATIO: ratio::Ratio = ratio::Ratio::zero(); +#[cfg(feature = "rtc")] +pub use crate::platform::x86_pc::rtc::*; + static mut INIT_TICK: u64 = 0; static mut CPU_FREQ_MHZ: u64 = axconfig::TIMER_FREQUENCY as u64 / 1_000_000; diff --git a/modules/axhal/src/time.rs b/modules/axhal/src/time.rs index fc6aca332..99cebaf7b 100644 --- a/modules/axhal/src/time.rs +++ b/modules/axhal/src/time.rs @@ -22,6 +22,9 @@ pub use crate::platform::irq::TIMER_IRQ_NUM; #[cfg(feature = "irq")] pub use crate::platform::time::set_oneshot_timer; pub use crate::platform::time::{current_ticks, nanos_to_ticks, ticks_to_nanos}; +#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] +#[cfg(feature = "rtc")] +pub use crate::platform::time::{rtc_read_time, rtc_write_time}; /// Number of milliseconds in a second. pub const MILLIS_PER_SEC: u64 = 1_000; @@ -40,10 +43,25 @@ pub fn current_time_nanos() -> u64 { } /// Returns the current clock time in [`TimeValue`]. +#[allow(unreachable_code)] pub fn current_time() -> TimeValue { + #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] + #[cfg(feature = "rtc")] + { + let nanos = current_time_nanos(); + let rtc_time = rtc_read_time(); + return Duration::new(rtc_time, (nanos % (NANOS_PER_SEC)) as u32); + } TimeValue::from_nanos(current_time_nanos()) } +/// set time value +pub fn set_current_time(_new_tv: TimeValue) { + #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] + #[cfg(feature = "rtc")] + rtc_write_time(_new_tv.as_secs() as u32); +} + /// Busy waiting for the given duration. pub fn busy_wait(dur: Duration) { busy_wait_until(current_time() + dur); diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index 38615f588..1fe3b3254 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -17,6 +17,7 @@ irq = ["axhal/irq", "axtask?/irq", "percpu", "kernel_guard"] tls = ["axhal/tls", "axtask?/tls"] alloc = ["axalloc", "dtb"] paging = ["axhal/paging", "lazy_init"] +rtc = ["axhal/rtc"] multitask = ["axtask/multitask"] fs = ["axdriver", "axfs"] diff --git a/platforms/aarch64-qemu-virt.toml b/platforms/aarch64-qemu-virt.toml index 723bba7eb..9349d0fd6 100644 --- a/platforms/aarch64-qemu-virt.toml +++ b/platforms/aarch64-qemu-virt.toml @@ -23,6 +23,7 @@ mmio-regions = [ ["0x0a00_0000", "0x4000"], # VirtIO ["0x1000_0000", "0x2eff_0000"], # PCI memory ranges (ranges 1: 32-bit MMIO space) ["0x40_1000_0000", "0x1000_0000"], # PCI config space + ["0x0901_0000", "0x1000"], # RTC space ] # VirtIO MMIO regions with format (`base_paddr`, `size`). virtio-mmio-regions = [ diff --git a/ulib/axlibc/c/time.c b/ulib/axlibc/c/time.c index 40ae7f4e2..519bd90bf 100644 --- a/ulib/axlibc/c/time.c +++ b/ulib/axlibc/c/time.c @@ -3,8 +3,9 @@ * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A + * PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. */ #include @@ -169,6 +170,16 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) return 0; } +int settimeofday(const struct timeval *tv, const struct timezone *_tz) +{ + if (!tv) + return 0; + if (tv->tv_usec >= 1000000ULL) + return -EINVAL; + return clock_settime(CLOCK_REALTIME, + &((struct timespec){.tv_sec = tv->tv_sec, .tv_nsec = tv->tv_usec * 1000})); +} + // TODO: int utimes(const char *filename, const struct timeval times[2]) { diff --git a/ulib/axlibc/include/sys/time.h b/ulib/axlibc/include/sys/time.h index 5acb5588a..a49cea430 100644 --- a/ulib/axlibc/include/sys/time.h +++ b/ulib/axlibc/include/sys/time.h @@ -3,8 +3,9 @@ * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A + * PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. */ #ifndef __SYS_TIME_H__ @@ -42,6 +43,7 @@ struct itimerval { }; int gettimeofday(struct timeval *tv, struct timezone *tz); +int settimeofday(const struct timeval *, const struct timezone *); int getitimer(int, struct itimerval *); int setitimer(int, const struct itimerval *__restrict, struct itimerval *__restrict); diff --git a/ulib/axlibc/include/time.h b/ulib/axlibc/include/time.h index 041b0fca7..3103f3893 100644 --- a/ulib/axlibc/include/time.h +++ b/ulib/axlibc/include/time.h @@ -3,8 +3,9 @@ * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A + * PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. */ #ifndef __TIME_H__ @@ -48,5 +49,6 @@ void tzset(void); int nanosleep(const struct timespec *requested_time, struct timespec *remaining); int clock_gettime(clockid_t _clk, struct timespec *ts); +int clock_settime(clockid_t, const struct timespec *); #endif // __TIME_H__ diff --git a/ulib/axlibc/src/time.rs b/ulib/axlibc/src/time.rs index 684fa6e62..fc5b19ccd 100644 --- a/ulib/axlibc/src/time.rs +++ b/ulib/axlibc/src/time.rs @@ -7,7 +7,7 @@ * See the Mulan PSL v2 for more details. */ -use arceos_posix_api::{sys_clock_gettime, sys_nanosleep}; +use arceos_posix_api::{sys_clock_gettime, sys_clock_settime, sys_nanosleep}; use core::ffi::c_int; use crate::{ctypes, utils::e}; @@ -18,6 +18,12 @@ pub unsafe extern "C" fn clock_gettime(clk: ctypes::clockid_t, ts: *mut ctypes:: e(sys_clock_gettime(clk, ts)) } +/// Set clock time since booting +#[no_mangle] +pub unsafe extern "C" fn clock_settime(clk: ctypes::clockid_t, ts: *mut ctypes::timespec) -> c_int { + e(sys_clock_settime(clk, ts)) +} + /// Sleep some nanoseconds /// /// TODO: should be woken by signals, and set errno diff --git a/ulib/axstd/Cargo.toml b/ulib/axstd/Cargo.toml index 83239c3ed..fc3eff0f1 100644 --- a/ulib/axstd/Cargo.toml +++ b/ulib/axstd/Cargo.toml @@ -28,6 +28,9 @@ fp_simd = ["axfeat/fp_simd"] # Interrupts irq = ["arceos_api/irq", "axfeat/irq"] +# real time clock +rtc = ["arceos_api/rtc", "axfeat/rtc"] + # Memory alloc = ["arceos_api/alloc", "axfeat/alloc", "axio/alloc"] alloc-tlsf = ["axfeat/alloc-tlsf"]