diff --git a/doc/lisp.md b/doc/lisp.md index 98370150..509bf092 100644 --- a/doc/lisp.md +++ b/doc/lisp.md @@ -79,7 +79,7 @@ MOROS Lisp is a Lisp-1 dialect inspired by Scheme, Clojure, and Ruby! - `read`, `write`, `append` - `read-binary`, `write-binary`, `append-binary` - `read-line`, `read-char` -- `uptime`, `realtime` +- `clock/boot`, `clock/epoch` - `p`, `print`, `eprint`, `error` ### Math Library @@ -176,6 +176,7 @@ Would produce the following output: ### Unreleased - Add `dirname`, `filename`, `eprint`, and `error` functions +- Rename `uptime` to `clk/boot` and `realtime` to `clk/epoch` ### 0.7.1 (2024-06-20) - Add `floor`, `ceil`, and `round` functions diff --git a/doc/manual.md b/doc/manual.md index 182c071d..6ad1caf1 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -85,9 +85,9 @@ commands to test the system or `install` to setup the Created '/dev/ata/1/0' Created '/dev/ata/1/1' Created '/dev/clk' - Created '/dev/clk/uptime' - Created '/dev/clk/realtime' - Created '/dev/rtc' + Created '/dev/clk/boot' + Created '/dev/clk/epoch' + Created '/dev/clk/rtc' Created '/dev/null' Created '/dev/random' Created '/dev/console' @@ -270,7 +270,7 @@ You can print the date with `date`: You can update the real time clock by writing the correct time to its device file: - > print "2023-03-21 10:00:00" => /dev/rtc + > print "2023-03-21 10:00:00" => /dev/clk/rtc > date 2023-03-21 10:00:00 +0000 @@ -297,12 +297,12 @@ Add `env TZ 7200` to `/ini/boot.sh` before `shell` to save the timezone: There's a device file to get the number of seconds elapsed since Unix Epoch: - > read /dev/clk/realtime + > read /dev/clk/epoch 1682105344.624905 And another one since boot: - > read /dev/clk/uptime + > read /dev/clk/boot 1169.384929 ## Aliases @@ -312,7 +312,7 @@ You can add custom commands to the shell with the `alias` command. For example you can define an `uptime` command that will read the device file described above: - > alias uptime "read /dev/clk/uptime" + > alias uptime "read /dev/clk/boot" > uptime 1406.304852 @@ -377,5 +377,5 @@ There is also a `ntp` script to synchronize the clock over the network: > ntp 2023-03-21 10:00:00 - > ntp => /dev/rtc + > ntp => /dev/clk/rtc [12.111156] RTC 2023-03-21 10:00:00 +0000 diff --git a/doc/network.md b/doc/network.md index 221b0bba..c4906ab0 100644 --- a/doc/network.md +++ b/doc/network.md @@ -163,5 +163,5 @@ passed as an argument or defined in `/ini/ntp`: It can be used to synchronize the real-time clock (RTC): - > ntp => /dev/rtc + > ntp => /dev/clk/rtc [42.123456] RTC 2023-03-21 10:00:00 +0000 diff --git a/dsk/lib/lisp/file.lsp b/dsk/lib/lisp/file.lsp index 0fa6f1ee..bac39f98 100644 --- a/dsk/lib/lisp/file.lsp +++ b/dsk/lib/lisp/file.lsp @@ -75,13 +75,13 @@ # Clocks -(def (uptime) - "Returns the current value of the uptime clock" - (binary->number (read-binary "/dev/clk/uptime") "float")) +(def (clock/boot) + "Returns the number of seconds since boot" + (binary->number (read-binary "/dev/clk/boot") "float")) -(def (realtime) - "Returns the current value of the realtime clock" - (binary->number (read-binary "/dev/clk/realtime") "float")) +(def (clock/epoch) + "Returns the number of seconds since epoch" + (binary->number (read-binary "/dev/clk/epoch") "float")) # Path diff --git a/dsk/tmp/lisp/geotime.lsp b/dsk/tmp/lisp/geotime.lsp index 72e89467..a4cd4863 100644 --- a/dsk/tmp/lisp/geotime.lsp +++ b/dsk/tmp/lisp/geotime.lsp @@ -32,7 +32,7 @@ (print (if (= (len args) 1) - (geotime (str->num (first args)) (realtime)) + (geotime (str->num (first args)) (clk/epoch)) (if (= (len args) 2) (geotime (str->num (first args)) (str->num (second args))) "Usage: geotime []"))) diff --git a/src/api/clock.rs b/src/api/clock.rs index f84bac50..6d7ba833 100644 --- a/src/api/clock.rs +++ b/src/api/clock.rs @@ -18,10 +18,10 @@ fn read_float(path: &str) -> f64 { 0.0 } -pub fn uptime() -> f64 { - read_float("/dev/clk/uptime") +pub fn boot_time() -> f64 { + read_float("/dev/clk/boot") } -pub fn realtime() -> f64 { - read_float("/dev/clk/realtime") +pub fn epoch_time() -> f64 { + read_float("/dev/clk/epoch") } diff --git a/src/api/fs.rs b/src/api/fs.rs index 0841f900..3cf255a8 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -161,9 +161,9 @@ fn device_type(name: &str) -> Result { "file" => Ok(DeviceType::File), "console" => Ok(DeviceType::Console), "random" => Ok(DeviceType::Random), - "uptime" => Ok(DeviceType::Uptime), - "realtime" => Ok(DeviceType::Realtime), - "rtc" => Ok(DeviceType::RTC), + "clk-boot" => Ok(DeviceType::BootTime), + "clk-epoch" => Ok(DeviceType::EpochTime), + "clk-rtc" => Ok(DeviceType::RTC), "tcp" => Ok(DeviceType::TcpSocket), "udp" => Ok(DeviceType::UdpSocket), "vga-buffer" => Ok(DeviceType::VgaBuffer), diff --git a/src/api/time.rs b/src/api/time.rs index 9f9b133c..63a01926 100644 --- a/src/api/time.rs +++ b/src/api/time.rs @@ -8,7 +8,7 @@ pub fn now() -> OffsetDateTime { } pub fn now_utc() -> OffsetDateTime { - let s = clock::realtime(); // Since Unix Epoch + let s = clock::epoch_time(); // Since Unix Epoch let ns = Duration::nanoseconds( libm::floor(1e9 * (s - libm::floor(s))) as i64 ); diff --git a/src/bin/geocal.rs b/src/bin/geocal.rs index 775075d6..6c2aec5b 100644 --- a/src/bin/geocal.rs +++ b/src/bin/geocal.rs @@ -37,7 +37,7 @@ fn main(args: &[&str]) { let timestamp = if args.len() == 4 { args[3].parse().unwrap() } else { - clock::realtime() as i64 + clock::epoch_time() as i64 }; let week; diff --git a/src/bin/geodate.rs b/src/bin/geodate.rs index 10aa70e8..ae74b509 100644 --- a/src/bin/geodate.rs +++ b/src/bin/geodate.rs @@ -21,7 +21,7 @@ fn main(args: &[&str]) { let timestamp = if args.len() == 3 { args[2].parse().expect("Could not parse timestamp") } else { - clock::realtime() + clock::epoch_time() }; let t = geodate::get_formatted_date(format, timestamp as i64, longitude); diff --git a/src/lib.rs b/src/lib.rs index 984e521f..b76c3a64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ pub fn init(boot_info: &'static BootInfo) { sys::pic::init(); // Enable interrupts sys::serial::init(); sys::keyboard::init(); - sys::time::init(); + sys::clk::init(); let v = option_env!("MOROS_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")); log!("SYS MOROS v{}", v); @@ -42,7 +42,8 @@ pub fn init(boot_info: &'static BootInfo) { sys::net::init(); // Require PCI sys::ata::init(); sys::fs::init(); // Require ATA - sys::clock::init(); // Require MEM + + log!("RTC {}", sys::clk::date()); } #[allow(dead_code)] diff --git a/src/sys/ata.rs b/src/sys/ata.rs index 5e6e7bd2..b38010f4 100644 --- a/src/sys/ata.rs +++ b/src/sys/ata.rs @@ -100,7 +100,7 @@ impl Bus { } fn wait(&mut self, ns: u64) { - sys::time::nanowait(ns); + sys::clk::wait(ns); } fn clear_interrupt(&mut self) -> u8 { @@ -132,9 +132,9 @@ impl Bus { } fn poll(&mut self, bit: Status, val: bool) -> Result<(), ()> { - let start = sys::clock::uptime(); + let start = sys::clk::boot_time(); while self.status().get_bit(bit as usize) != val { - if sys::clock::uptime() - start > 1.0 { + if sys::clk::boot_time() - start > 1.0 { debug!( "ATA hanged while polling {:?} bit in status register", bit @@ -164,7 +164,7 @@ impl Bus { // Bit 7 => 1 self.drive_register.write(0xA0 | (drive << 4)) } - sys::time::nanowait(400); // Wait at least 400 ns + sys::clk::wait(400); // Wait at least 400 ns self.poll(Status::BSY, false)?; self.poll(Status::DRQ, false)?; Ok(()) @@ -392,7 +392,7 @@ impl FileIO for Drive { } fn write(&mut self, _buf: &[u8]) -> Result { - unimplemented!(); + Err(()) } fn close(&mut self) { diff --git a/src/sys/clk/boot.rs b/src/sys/clk/boot.rs new file mode 100644 index 00000000..bb9e1d64 --- /dev/null +++ b/src/sys/clk/boot.rs @@ -0,0 +1,54 @@ +use super::timer; + +use crate::api::fs::{FileIO, IO}; + +#[derive(Debug, Clone)] +pub struct BootTime; + +impl BootTime { + pub fn new() -> Self { + Self {} + } + + pub fn size() -> usize { + core::mem::size_of::() + } +} + +impl FileIO for BootTime { + fn read(&mut self, buf: &mut [u8]) -> Result { + let time = boot_time().to_be_bytes(); + let n = time.len(); + if buf.len() >= n { + buf[0..n].clone_from_slice(&time); + Ok(n) + } else { + Err(()) + } + } + + fn write(&mut self, _buf: &[u8]) -> Result { + Err(()) + } + + fn close(&mut self) {} + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => false, + } + } +} + +/// Returns the number of seconds since boot. +/// +/// This clock is monotonic. +pub fn boot_time() -> f64 { + timer::time_between_ticks() * timer::ticks() as f64 +} + +#[test_case] +fn test_boot_time() { + assert!(boot_time() > 0.0); +} diff --git a/src/sys/cmos.rs b/src/sys/clk/cmos.rs similarity index 70% rename from src/sys/cmos.rs rename to src/sys/clk/cmos.rs index 99fe704b..624bb0c6 100644 --- a/src/sys/cmos.rs +++ b/src/sys/clk/cmos.rs @@ -1,105 +1,10 @@ -use crate::sys; -use crate::api::clock::{DATE_TIME, DATE_TIME_LEN}; -use crate::api::fs::{FileIO, IO}; +use super::rtc::{Interrupt, RTC, Register, RTC_CENTURY}; -use alloc::string::String; use bit_field::BitField; use core::hint::spin_loop; -use time::{Date, PrimitiveDateTime}; use x86_64::instructions::interrupts; use x86_64::instructions::port::Port; -const RTC_CENTURY: u16 = 2000; // NOTE: Change this at the end of 2099 - -#[repr(u8)] -enum Register { - Second = 0x00, - Minute = 0x02, - Hour = 0x04, - Day = 0x07, - Month = 0x08, - Year = 0x09, - A = 0x0A, - B = 0x0B, - C = 0x0C, -} - -#[repr(u8)] -enum Interrupt { - Periodic = 1 << 6, - Alarm = 1 << 5, - Update = 1 << 4, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RTC { - pub year: u16, - pub month: u8, - pub day: u8, - pub hour: u8, - pub minute: u8, - pub second: u8, -} - -impl RTC { - pub fn new() -> Self { - CMOS::new().rtc() - } - - pub fn size() -> usize { - DATE_TIME_LEN - } - - pub fn sync(&mut self) { - *self = RTC::new(); - } -} - -impl FileIO for RTC { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.sync(); - let date = Date::try_from_ymd( - self.year.into(), self.month, self.day - ).map_err(|_| ())?; - let date_time = date.try_with_hms( - self.hour, self.minute, self.second - ).map_err(|_| ())?; - let out = date_time.format(DATE_TIME); - buf.copy_from_slice(out.as_bytes()); - Ok(out.len()) - } - - fn write(&mut self, buf: &[u8]) -> Result { - let s = String::from_utf8_lossy(buf); - let s = s.trim_end(); - if s.len() != RTC::size() { - return Err(()); - } - let date_time = PrimitiveDateTime::parse(s, DATE_TIME).map_err(|_| ())?; - self.year = date_time.year() as u16; - self.month = date_time.month(); - self.day = date_time.day(); - self.hour = date_time.hour(); - self.minute = date_time.minute(); - self.second = date_time.second(); - if self.year < RTC_CENTURY || self.year > RTC_CENTURY + 99 { - return Err(()); - } - CMOS::new().update_rtc(self); - sys::clock::init(); - Ok(buf.len()) - } - - fn close(&mut self) {} - - fn poll(&mut self, event: IO) -> bool { - match event { - IO::Read => true, - IO::Write => true, - } - } -} - pub struct CMOS { addr: Port, data: Port, @@ -202,10 +107,12 @@ impl CMOS { self.write_register(Register::Year, year as u8); } + #[allow(dead_code)] pub fn enable_periodic_interrupt(&mut self) { self.enable_interrupt(Interrupt::Periodic); } + #[allow(dead_code)] pub fn enable_alarm_interrupt(&mut self) { self.enable_interrupt(Interrupt::Alarm); } @@ -214,8 +121,9 @@ impl CMOS { self.enable_interrupt(Interrupt::Update); } - /// Rate must be between 3 and 15 - /// Resulting in the following frequency: 32768 >> (rate - 1) + // Rate must be between 3 and 15 + // Resulting in the following frequency: 32768 >> (rate - 1) + #[allow(dead_code)] pub fn set_periodic_interrupt_rate(&mut self, rate: u8) { interrupts::without_interrupts(|| { self.disable_nmi(); diff --git a/src/sys/clk/epoch.rs b/src/sys/clk/epoch.rs new file mode 100644 index 00000000..5ce264c0 --- /dev/null +++ b/src/sys/clk/epoch.rs @@ -0,0 +1,94 @@ +use super::cmos::CMOS; +use super::timer; + +use crate::api::fs::{FileIO, IO}; + +const DAYS_BEFORE_MONTH: [u64; 13] = [ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 +]; + +#[derive(Debug, Clone)] +pub struct EpochTime; + +impl EpochTime { + pub fn new() -> Self { + Self {} + } + + pub fn size() -> usize { + core::mem::size_of::() + } +} + +impl FileIO for EpochTime { + fn read(&mut self, buf: &mut [u8]) -> Result { + let time = epoch_time().to_be_bytes(); + let n = time.len(); + if buf.len() >= n { + buf[0..n].clone_from_slice(&time); + Ok(n) + } else { + Err(()) + } + } + + fn write(&mut self, _buf: &[u8]) -> Result { + Err(()) + } + + fn close(&mut self) {} + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => false, + } + } +} + +/// Returns the number of seconds since Unix epoch (1970-01-01 00:00:00 UTC). +/// +/// This clock is not monotonic. +pub fn epoch_time() -> f64 { + let rtc = CMOS::new().rtc(); // Assuming GMT + + let ts = 86400 * days_before_year(rtc.year as u64) + + 86400 * days_before_month(rtc.year as u64, rtc.month as u64) + + 86400 * (rtc.day - 1) as u64 + + 3600 * rtc.hour as u64 + + 60 * rtc.minute as u64 + + rtc.second as u64; + + let fract = timer::time_between_ticks() + * (timer::ticks() - timer::last_rtc_update()) as f64; + + (ts as f64) + fract +} + +fn days_before_year(year: u64) -> u64 { + (1970..year).fold(0, |days, y| + days + if is_leap_year(y) { 366 } else { 365 } + ) +} + +fn days_before_month(year: u64, month: u64) -> u64 { + let leap_day = is_leap_year(year) && month > 2; + DAYS_BEFORE_MONTH[(month as usize) - 1] + (leap_day as u64) +} + +fn is_leap_year(year: u64) -> bool { + if year % 4 != 0 { + false + } else if year % 100 != 0 { + true + } else if year % 400 != 0 { + false + } else { + true + } +} + +#[test_case] +fn test_epoch_time() { + assert!(epoch_time() > 1234567890.0); +} diff --git a/src/sys/clk/mod.rs b/src/sys/clk/mod.rs new file mode 100644 index 00000000..47c5f320 --- /dev/null +++ b/src/sys/clk/mod.rs @@ -0,0 +1,31 @@ +mod cmos; +mod boot; +mod epoch; +mod rtc; +mod sync; +mod timer; + +pub use boot::{boot_time, BootTime}; +pub use epoch::{epoch_time, EpochTime}; +pub use rtc::RTC; +pub use sync::{halt, sleep, wait}; +pub use timer::{ticks, pit_frequency, set_pit_frequency}; + +use crate::api; + +use alloc::string::String; +use time::{Duration, OffsetDateTime}; + +pub fn init() { + timer::init(); +} + +/// Returns the current date and time. +pub fn date() -> String { + let s = epoch::epoch_time(); + let ns = Duration::nanoseconds( + libm::floor(1e9 * (s - libm::floor(s))) as i64 + ); + let dt = OffsetDateTime::from_unix_timestamp(s as i64) + ns; + dt.format(api::clock::DATE_TIME_ZONE) +} diff --git a/src/sys/clk/rtc.rs b/src/sys/clk/rtc.rs new file mode 100644 index 00000000..511ccefc --- /dev/null +++ b/src/sys/clk/rtc.rs @@ -0,0 +1,98 @@ +use super::cmos::CMOS; + +use crate::api::clock::{DATE_TIME, DATE_TIME_LEN}; +use crate::api::fs::{FileIO, IO}; + +use alloc::string::String; +use time::{Date, PrimitiveDateTime}; + +pub const RTC_CENTURY: u16 = 2000; // NOTE: Change this at the end of 2099 + +#[repr(u8)] +pub enum Register { + Second = 0x00, + Minute = 0x02, + Hour = 0x04, + Day = 0x07, + Month = 0x08, + Year = 0x09, + A = 0x0A, + B = 0x0B, + C = 0x0C, +} + +#[repr(u8)] +pub enum Interrupt { + Periodic = 1 << 6, + Alarm = 1 << 5, + Update = 1 << 4, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RTC { + pub year: u16, + pub month: u8, + pub day: u8, + pub hour: u8, + pub minute: u8, + pub second: u8, +} + +impl RTC { + pub fn new() -> Self { + CMOS::new().rtc() + } + + pub fn size() -> usize { + DATE_TIME_LEN + } + + pub fn sync(&mut self) { + *self = RTC::new(); + } +} + +impl FileIO for RTC { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.sync(); + let date = Date::try_from_ymd( + self.year.into(), self.month, self.day + ).map_err(|_| ())?; + let date_time = date.try_with_hms( + self.hour, self.minute, self.second + ).map_err(|_| ())?; + let out = date_time.format(DATE_TIME); + buf.copy_from_slice(out.as_bytes()); + Ok(out.len()) + } + + fn write(&mut self, buf: &[u8]) -> Result { + let s = String::from_utf8_lossy(buf); + let s = s.trim_end(); + if s.len() != RTC::size() { + return Err(()); + } + let date_time = PrimitiveDateTime::parse(s, DATE_TIME).map_err(|_| ())?; + self.year = date_time.year() as u16; + self.month = date_time.month(); + self.day = date_time.day(); + self.hour = date_time.hour(); + self.minute = date_time.minute(); + self.second = date_time.second(); + if self.year < RTC_CENTURY || self.year > RTC_CENTURY + 99 { + return Err(()); + } + CMOS::new().update_rtc(self); + log!("RTC {}", super::date()); + Ok(buf.len()) + } + + fn close(&mut self) {} + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => true, + } + } +} diff --git a/src/sys/clk/sync.rs b/src/sys/clk/sync.rs new file mode 100644 index 00000000..ed006f2b --- /dev/null +++ b/src/sys/clk/sync.rs @@ -0,0 +1,38 @@ +use super::boot; +use super::timer; + +use x86_64::instructions::interrupts; + +/// Halts the CPU until the next interrupt. +/// +/// This function preserves interrupt state. +pub fn halt() { + let disabled = !interrupts::are_enabled(); + interrupts::enable_and_hlt(); + if disabled { + interrupts::disable(); + } +} + +/// Sleeps for the specified number of seconds. +/// +/// This function works by repeatedly halting the CPU until the time is +/// elapsed. +pub fn sleep(seconds: f64) { + let start = boot::boot_time(); + while boot::boot_time() - start < seconds { + halt(); + } +} + +/// Waits for the specified number of nanoseconds. +/// +/// This function use a busy-wait loop with the `RDTSC` and `PAUSE` +/// instructions. +pub fn wait(nanoseconds: u64) { + let delta = nanoseconds * timer::tsc_frequency(); + let start = timer::tsc(); + while timer::tsc() - start < delta { + core::hint::spin_loop(); + } +} diff --git a/src/sys/time.rs b/src/sys/clk/timer.rs similarity index 65% rename from src/sys/time.rs rename to src/sys/clk/timer.rs index e5899fbb..5381cb3a 100644 --- a/src/sys/time.rs +++ b/src/sys/clk/timer.rs @@ -1,6 +1,8 @@ +use super::sync; +use super::cmos::CMOS; + use crate::sys; -use crate::sys::cmos::CMOS; -use core::hint::spin_loop; + use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; use x86_64::instructions::interrupts; use x86_64::instructions::port::Port; @@ -9,13 +11,13 @@ use x86_64::instructions::port::Port; // which will result in about 54.926 ms between ticks. // During init we will change the divider to 1193 to have about 1.000 ms // between ticks to improve time measurements accuracy. -pub const PIT_FREQUENCY: f64 = 3_579_545.0 / 3.0; // 1_193_181.666 Hz +const PIT_FREQUENCY: f64 = 3_579_545.0 / 3.0; // 1_193_181.666 Hz const PIT_DIVIDER: usize = 1193; const PIT_INTERVAL: f64 = (PIT_DIVIDER as f64) / PIT_FREQUENCY; static PIT_TICKS: AtomicUsize = AtomicUsize::new(0); static LAST_RTC_UPDATE: AtomicUsize = AtomicUsize::new(0); -static CLOCKS_PER_NANOSECOND: AtomicU64 = AtomicU64::new(0); +static TSC_FREQUENCY: AtomicU64 = AtomicU64::new(0); pub fn ticks() -> usize { PIT_TICKS.load(Ordering::Relaxed) @@ -29,38 +31,12 @@ pub fn last_rtc_update() -> usize { LAST_RTC_UPDATE.load(Ordering::Relaxed) } -pub fn halt() { - let disabled = !interrupts::are_enabled(); - interrupts::enable_and_hlt(); - if disabled { - interrupts::disable(); - } -} - -fn rdtsc() -> u64 { - unsafe { - core::arch::x86_64::_mm_lfence(); - core::arch::x86_64::_rdtsc() - } -} - -pub fn sleep(seconds: f64) { - let start = sys::clock::uptime(); - while sys::clock::uptime() - start < seconds { - halt(); - } +pub fn pit_frequency() -> f64 { + PIT_FREQUENCY } -pub fn nanowait(nanoseconds: u64) { - let start = rdtsc(); - let delta = nanoseconds * CLOCKS_PER_NANOSECOND.load(Ordering::Relaxed); - while rdtsc() - start < delta { - spin_loop(); - } -} - -/// The frequency divider must be between 0 and 65535, with 0 acting as 65536 -pub fn set_pit_frequency_divider(divider: u16, channel: u8) { +// The frequency divider must be between 0 and 65535, with 0 acting as 65536 +pub fn set_pit_frequency(divider: u16, channel: u8) { interrupts::without_interrupts(|| { let bytes = divider.to_le_bytes(); let mut cmd: Port = Port::new(0x43); @@ -75,6 +51,18 @@ pub fn set_pit_frequency_divider(divider: u16, channel: u8) { }); } +// Time Stamp Counter +pub fn tsc() -> u64 { + unsafe { + core::arch::x86_64::_mm_lfence(); + core::arch::x86_64::_rdtsc() + } +} + +pub fn tsc_frequency() -> u64 { + TSC_FREQUENCY.load(Ordering::Relaxed) +} + pub fn pit_interrupt_handler() { PIT_TICKS.fetch_add(1, Ordering::Relaxed); } @@ -88,7 +76,7 @@ pub fn init() { // PIT timmer let divider = if PIT_DIVIDER < 65536 { PIT_DIVIDER } else { 0 }; let channel = 0; - set_pit_frequency_divider(divider as u16, channel); + set_pit_frequency(divider as u16, channel); sys::idt::set_irq_handler(0, pit_interrupt_handler); // RTC timmer @@ -97,8 +85,8 @@ pub fn init() { // TSC timmer let calibration_time = 250_000; // 0.25 seconds - let a = rdtsc(); - sleep(calibration_time as f64 / 1e6); - let b = rdtsc(); - CLOCKS_PER_NANOSECOND.store((b - a) / calibration_time, Ordering::Relaxed); + let a = tsc(); + sync::sleep(calibration_time as f64 / 1e6); + let b = tsc(); + TSC_FREQUENCY.store((b - a) / calibration_time, Ordering::Relaxed); } diff --git a/src/sys/clock.rs b/src/sys/clock.rs deleted file mode 100644 index 1e400779..00000000 --- a/src/sys/clock.rs +++ /dev/null @@ -1,153 +0,0 @@ -use crate::api::clock::DATE_TIME_ZONE; -use crate::api::fs::{FileIO, IO}; -use crate::sys; -use crate::sys::cmos::CMOS; - -use time::{Duration, OffsetDateTime}; - -const DAYS_BEFORE_MONTH: [u64; 13] = [ - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 -]; - -#[derive(Debug, Clone)] -pub struct Uptime; - -impl Uptime { - pub fn new() -> Self { - Self {} - } - - pub fn size() -> usize { - core::mem::size_of::() - } -} - -impl FileIO for Uptime { - fn read(&mut self, buf: &mut [u8]) -> Result { - let time = uptime().to_be_bytes(); - let n = time.len(); - if buf.len() >= n { - buf[0..n].clone_from_slice(&time); - Ok(n) - } else { - Err(()) - } - } - - fn write(&mut self, _buf: &[u8]) -> Result { - unimplemented!(); - } - - fn close(&mut self) {} - - fn poll(&mut self, event: IO) -> bool { - match event { - IO::Read => true, - IO::Write => false, - } - } -} - -// NOTE: This clock is monotonic -pub fn uptime() -> f64 { - sys::time::time_between_ticks() * sys::time::ticks() as f64 -} - -#[derive(Debug, Clone)] -pub struct Realtime; - -impl Realtime { - pub fn new() -> Self { - Self {} - } - - pub fn size() -> usize { - core::mem::size_of::() - } -} - -impl FileIO for Realtime { - fn read(&mut self, buf: &mut [u8]) -> Result { - let time = realtime().to_be_bytes(); - let n = time.len(); - if buf.len() >= n { - buf[0..n].clone_from_slice(&time); - Ok(n) - } else { - Err(()) - } - } - - fn write(&mut self, _buf: &[u8]) -> Result { - unimplemented!(); - } - - fn close(&mut self) {} - - fn poll(&mut self, event: IO) -> bool { - match event { - IO::Read => true, - IO::Write => false, - } - } -} - -// NOTE: This clock is not monotonic -pub fn realtime() -> f64 { - let rtc = CMOS::new().rtc(); // Assuming GMT - - let ts = 86400 * days_before_year(rtc.year as u64) - + 86400 * days_before_month(rtc.year as u64, rtc.month as u64) - + 86400 * (rtc.day - 1) as u64 - + 3600 * rtc.hour as u64 - + 60 * rtc.minute as u64 - + rtc.second as u64; - - let fract = sys::time::time_between_ticks() - * (sys::time::ticks() - sys::time::last_rtc_update()) as f64; - - (ts as f64) + fract -} - -fn days_before_year(year: u64) -> u64 { - (1970..year).fold(0, |days, y| - days + if is_leap_year(y) { 366 } else { 365 } - ) -} - -fn days_before_month(year: u64, month: u64) -> u64 { - let leap_day = is_leap_year(year) && month > 2; - DAYS_BEFORE_MONTH[(month as usize) - 1] + (leap_day as u64) -} - -fn is_leap_year(year: u64) -> bool { - if year % 4 != 0 { - false - } else if year % 100 != 0 { - true - } else if year % 400 != 0 { - false - } else { - true - } -} - -pub fn init() { - let s = realtime(); - let ns = Duration::nanoseconds( - libm::floor(1e9 * (s - libm::floor(s))) as i64 - ); - let dt = OffsetDateTime::from_unix_timestamp(s as i64) + ns; - let rtc = dt.format(DATE_TIME_ZONE); - log!("RTC {}", rtc); -} - -#[test_case] -fn test_uptime() { - assert!(uptime() > 0.0); -} - -#[test_case] -fn test_realtime() { - assert!(realtime() > 1234567890.0); -} diff --git a/src/sys/console.rs b/src/sys/console.rs index a98b5bdb..7502a253 100644 --- a/src/sys/console.rs +++ b/src/sys/console.rs @@ -141,7 +141,7 @@ pub fn read_char() -> char { sys::console::disable_echo(); sys::console::enable_raw(); loop { - sys::time::halt(); + sys::clk::halt(); let res = interrupts::without_interrupts(|| { let mut stdin = STDIN.lock(); if !stdin.is_empty() { @@ -160,7 +160,7 @@ pub fn read_char() -> char { pub fn read_line() -> String { loop { - sys::time::halt(); + sys::clk::halt(); let res = interrupts::without_interrupts(|| { let mut stdin = STDIN.lock(); match stdin.chars().next_back() { diff --git a/src/sys/fs/device.rs b/src/sys/fs/device.rs index ee4197bf..888a7607 100644 --- a/src/sys/fs/device.rs +++ b/src/sys/fs/device.rs @@ -4,8 +4,7 @@ use super::file::File; use super::{dirname, filename, realpath, FileIO, IO}; use crate::sys::ata::Drive; -use crate::sys::clock::{Realtime, Uptime}; -use crate::sys::cmos::RTC; +use crate::sys::clk::{RTC, EpochTime, BootTime}; use crate::sys::console::Console; use crate::sys::net::socket::tcp::TcpSocket; use crate::sys::net::socket::udp::UdpSocket; @@ -24,8 +23,8 @@ pub enum DeviceType { File = 1, Console = 2, Random = 3, - Uptime = 4, - Realtime = 5, + BootTime = 4, + EpochTime = 5, RTC = 6, TcpSocket = 7, UdpSocket = 8, @@ -45,8 +44,8 @@ impl TryFrom<&[u8]> for DeviceType { 1 => Ok(DeviceType::File), 2 => Ok(DeviceType::Console), 3 => Ok(DeviceType::Random), - 4 => Ok(DeviceType::Uptime), - 5 => Ok(DeviceType::Realtime), + 4 => Ok(DeviceType::BootTime), + 5 => Ok(DeviceType::EpochTime), 6 => Ok(DeviceType::RTC), 7 => Ok(DeviceType::TcpSocket), 8 => Ok(DeviceType::UdpSocket), @@ -67,8 +66,8 @@ impl DeviceType { pub fn buf(self) -> Vec { let len = match self { DeviceType::RTC => RTC::size(), - DeviceType::Uptime => Uptime::size(), - DeviceType::Realtime => Realtime::size(), + DeviceType::BootTime => BootTime::size(), + DeviceType::EpochTime => EpochTime::size(), DeviceType::Console => Console::size(), DeviceType::TcpSocket => TcpSocket::size(), DeviceType::UdpSocket => UdpSocket::size(), @@ -90,8 +89,8 @@ pub enum Device { File(File), Console(Console), Random(Random), - Uptime(Uptime), - Realtime(Realtime), + BootTime(BootTime), + EpochTime(EpochTime), RTC(RTC), TcpSocket(TcpSocket), UdpSocket(UdpSocket), @@ -111,8 +110,8 @@ impl TryFrom<&[u8]> for Device { DeviceType::File => Ok(Device::File(File::new())), DeviceType::Console => Ok(Device::Console(Console::new())), DeviceType::Random => Ok(Device::Random(Random::new())), - DeviceType::Uptime => Ok(Device::Uptime(Uptime::new())), - DeviceType::Realtime => Ok(Device::Realtime(Realtime::new())), + DeviceType::BootTime => Ok(Device::BootTime(BootTime::new())), + DeviceType::EpochTime => Ok(Device::EpochTime(EpochTime::new())), DeviceType::RTC => Ok(Device::RTC(RTC::new())), DeviceType::TcpSocket => Ok(Device::TcpSocket(TcpSocket::new())), DeviceType::UdpSocket => Ok(Device::UdpSocket(UdpSocket::new())), @@ -173,8 +172,8 @@ impl FileIO for Device { Device::File(io) => io.read(buf), Device::Console(io) => io.read(buf), Device::Random(io) => io.read(buf), - Device::Uptime(io) => io.read(buf), - Device::Realtime(io) => io.read(buf), + Device::BootTime(io) => io.read(buf), + Device::EpochTime(io) => io.read(buf), Device::RTC(io) => io.read(buf), Device::TcpSocket(io) => io.read(buf), Device::UdpSocket(io) => io.read(buf), @@ -192,8 +191,8 @@ impl FileIO for Device { Device::File(io) => io.write(buf), Device::Console(io) => io.write(buf), Device::Random(io) => io.write(buf), - Device::Uptime(io) => io.write(buf), - Device::Realtime(io) => io.write(buf), + Device::BootTime(io) => io.write(buf), + Device::EpochTime(io) => io.write(buf), Device::RTC(io) => io.write(buf), Device::TcpSocket(io) => io.write(buf), Device::UdpSocket(io) => io.write(buf), @@ -211,8 +210,8 @@ impl FileIO for Device { Device::File(io) => io.close(), Device::Console(io) => io.close(), Device::Random(io) => io.close(), - Device::Uptime(io) => io.close(), - Device::Realtime(io) => io.close(), + Device::BootTime(io) => io.close(), + Device::EpochTime(io) => io.close(), Device::RTC(io) => io.close(), Device::TcpSocket(io) => io.close(), Device::UdpSocket(io) => io.close(), @@ -230,8 +229,8 @@ impl FileIO for Device { Device::File(io) => io.poll(event), Device::Console(io) => io.poll(event), Device::Random(io) => io.poll(event), - Device::Uptime(io) => io.poll(event), - Device::Realtime(io) => io.poll(event), + Device::BootTime(io) => io.poll(event), + Device::EpochTime(io) => io.poll(event), Device::RTC(io) => io.poll(event), Device::TcpSocket(io) => io.poll(event), Device::UdpSocket(io) => io.poll(event), diff --git a/src/sys/fs/dir.rs b/src/sys/fs/dir.rs index c5e0fe92..a90a997b 100644 --- a/src/sys/fs/dir.rs +++ b/src/sys/fs/dir.rs @@ -135,7 +135,7 @@ impl Dir { let entry_kind = kind as u8; let entry_addr = entry_block.addr(); let entry_size = 0u32; - let entry_time = sys::clock::realtime() as u64; + let entry_time = sys::clk::epoch_time() as u64; let entry_name = truncate(name, u8::MAX as usize); let n = entry_name.len(); let i = entries.block_offset(); @@ -193,7 +193,7 @@ impl Dir { } pub fn update_entry(&self, name: &str, size: u32) { - let time = sys::clock::realtime() as u64; + let time = sys::clk::epoch_time() as u64; let mut entries = self.entries(); for entry in &mut entries { if entry.name() == name { diff --git a/src/sys/mod.rs b/src/sys/mod.rs index aef35894..233c9638 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -20,18 +20,18 @@ macro_rules! debug { macro_rules! log { ($($arg:tt)*) => ({ if !cfg!(test) { - let uptime = $crate::sys::clock::uptime(); + let time = $crate::sys::clk::boot_time(); let csi_color = $crate::api::console::Style::color("lime"); let csi_reset = $crate::api::console::Style::reset(); $crate::sys::console::print_fmt(format_args!( "{}[{:.6}]{} {}\n", - csi_color, uptime, csi_reset, format_args!($($arg)*) + csi_color, time, csi_reset, format_args!($($arg)*) )); - let realtime = $crate::sys::clock::realtime(); + let time = $crate::sys::clk::epoch_time(); $crate::sys::log::write_fmt(format_args!( "[{:.6}] {}\n", - realtime, format_args!($($arg)*) + time, format_args!($($arg)*) )); } }); @@ -39,8 +39,7 @@ macro_rules! log { pub mod acpi; pub mod ata; -pub mod clock; -pub mod cmos; +pub mod clk; pub mod console; pub mod cpu; pub mod fs; @@ -56,5 +55,4 @@ pub mod process; pub mod rng; pub mod serial; pub mod syscall; -pub mod time; pub mod vga; diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs index 481c7151..e4a26e75 100644 --- a/src/sys/net/mod.rs +++ b/src/sys/net/mod.rs @@ -28,7 +28,7 @@ pub enum SocketStatus { } fn time() -> Instant { - Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64) + Instant::from_micros((sys::clk::epoch_time() * 1000000.0) as i64) } #[derive(Clone)] diff --git a/src/sys/net/nic/e1000.rs b/src/sys/net/nic/e1000.rs index 27ebb022..83a27e31 100644 --- a/src/sys/net/nic/e1000.rs +++ b/src/sys/net/nic/e1000.rs @@ -168,7 +168,7 @@ impl Device { // Reset device let ctrl = self.read(REG_CTRL); self.write(REG_CTRL, ctrl | CTRL_RST); // Reset - sys::time::nanowait(500); // TODO: How long should we wait? + sys::clk::wait(500); // TODO: How long should we wait? // Disable interrupts again self.write(REG_IMC, 0xFFFF); diff --git a/src/sys/net/nic/pcnet.rs b/src/sys/net/nic/pcnet.rs index e971d75f..dc11c200 100644 --- a/src/sys/net/nic/pcnet.rs +++ b/src/sys/net/nic/pcnet.rs @@ -229,7 +229,7 @@ impl Device { // Wait until init is done while !self.ports.read_csr_32(0).get_bit(CSR0_IDON) { - sys::time::halt(); + sys::clk::halt(); } // IDON + INTR + INIT diff --git a/src/sys/net/socket/mod.rs b/src/sys/net/socket/mod.rs index ee90bb19..a63fb34a 100644 --- a/src/sys/net/socket/mod.rs +++ b/src/sys/net/socket/mod.rs @@ -20,5 +20,5 @@ fn random_port() -> u16 { } fn wait(duration: Duration) { - sys::time::sleep((duration.total_micros() as f64) / 1000000.0); + sys::clk::sleep((duration.total_micros() as f64) / 1000000.0); } diff --git a/src/sys/net/socket/tcp.rs b/src/sys/net/socket/tcp.rs index 33fa0065..55118577 100644 --- a/src/sys/net/socket/tcp.rs +++ b/src/sys/net/socket/tcp.rs @@ -56,10 +56,10 @@ impl TcpSocket { pub fn connect(&mut self, addr: IpAddress, port: u16) -> Result<(), ()> { let mut connecting = false; let timeout = 5.0; - let started = sys::clock::realtime(); + let started = sys::clk::epoch_time(); if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { loop { - if sys::clock::realtime() - started > timeout { + if sys::clk::epoch_time() - started > timeout { return Err(()); } let mut sockets = SOCKETS.lock(); @@ -91,7 +91,7 @@ impl TcpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } } Ok(()) @@ -110,7 +110,7 @@ impl TcpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); Ok(()) } else { Err(()) @@ -119,10 +119,10 @@ impl TcpSocket { pub fn accept(&mut self) -> Result { let timeout = 5.0; - let started = sys::clock::realtime(); + let started = sys::clk::epoch_time(); if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { loop { - if sys::clock::realtime() - started > timeout { + if sys::clk::epoch_time() - started > timeout { return Err(()); } let mut sockets = SOCKETS.lock(); @@ -136,7 +136,7 @@ impl TcpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } } else { Err(()) @@ -147,12 +147,12 @@ impl TcpSocket { impl FileIO for TcpSocket { fn read(&mut self, buf: &mut [u8]) -> Result { let timeout = 5.0; - let started = sys::clock::realtime(); + let started = sys::clk::epoch_time(); let mut bytes = 0; if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { let mut sockets = SOCKETS.lock(); loop { - if sys::clock::realtime() - started > timeout { + if sys::clk::epoch_time() - started > timeout { return Err(()); } iface.poll(sys::net::time(), device, &mut sockets); @@ -174,7 +174,7 @@ impl FileIO for TcpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } Ok(bytes) } else { @@ -184,12 +184,12 @@ impl FileIO for TcpSocket { fn write(&mut self, buf: &[u8]) -> Result { let timeout = 5.0; - let started = sys::clock::realtime(); + let started = sys::clk::epoch_time(); let mut sent = false; if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { let mut sockets = SOCKETS.lock(); loop { - if sys::clock::realtime() - started > timeout { + if sys::clk::epoch_time() - started > timeout { return Err(()); } iface.poll(sys::net::time(), device, &mut sockets); @@ -208,7 +208,7 @@ impl FileIO for TcpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } Ok(buf.len()) } else { @@ -233,7 +233,7 @@ impl FileIO for TcpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } } } diff --git a/src/sys/net/socket/udp.rs b/src/sys/net/socket/udp.rs index ff9a24f0..0573c65c 100644 --- a/src/sys/net/socket/udp.rs +++ b/src/sys/net/socket/udp.rs @@ -60,10 +60,10 @@ impl UdpSocket { pub fn connect(&mut self, addr: IpAddress, port: u16) -> Result<(), ()> { let timeout = 5.0; - let started = sys::clock::realtime(); + let started = sys::clk::epoch_time(); if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { loop { - if sys::clock::realtime() - started > timeout { + if sys::clk::epoch_time() - started > timeout { return Err(()); } let mut sockets = SOCKETS.lock(); @@ -79,7 +79,7 @@ impl UdpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } } self.remote_endpoint = Some(IpEndpoint::new(addr, port)); @@ -98,12 +98,12 @@ impl UdpSocket { impl FileIO for UdpSocket { fn read(&mut self, buf: &mut [u8]) -> Result { let timeout = 5.0; - let started = sys::clock::realtime(); + let started = sys::clk::epoch_time(); if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { let bytes; let mut sockets = SOCKETS.lock(); loop { - if sys::clock::realtime() - started > timeout { + if sys::clk::epoch_time() - started > timeout { return Err(()); } iface.poll(sys::net::time(), device, &mut sockets); @@ -122,7 +122,7 @@ impl FileIO for UdpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } Ok(bytes) } else { @@ -132,12 +132,12 @@ impl FileIO for UdpSocket { fn write(&mut self, buf: &[u8]) -> Result { let timeout = 5.0; - let started = sys::clock::realtime(); + let started = sys::clk::epoch_time(); let mut sent = false; if let Some((ref mut iface, ref mut device)) = *sys::net::NET.lock() { let mut sockets = SOCKETS.lock(); loop { - if sys::clock::realtime() - started > timeout { + if sys::clk::epoch_time() - started > timeout { return Err(()); } iface.poll(sys::net::time(), device, &mut sockets); @@ -160,7 +160,7 @@ impl FileIO for UdpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } Ok(buf.len()) } else { @@ -185,7 +185,7 @@ impl FileIO for UdpSocket { if let Some(d) = iface.poll_delay(sys::net::time(), &sockets) { wait(d); } - sys::time::halt(); + sys::clk::halt(); } } } diff --git a/src/sys/rng.rs b/src/sys/rng.rs index 93e73af8..d9e56f89 100644 --- a/src/sys/rng.rs +++ b/src/sys/rng.rs @@ -33,7 +33,7 @@ impl FileIO for Random { } fn write(&mut self, _buf: &[u8]) -> Result { - unimplemented!(); + Err(()) } fn close(&mut self) {} @@ -81,9 +81,9 @@ pub fn init() { } else { log!("RNG RDRAND unavailable"); let mut hasher = Sha256::new(); - hasher.update(sys::time::ticks().to_be_bytes()); - hasher.update(sys::clock::realtime().to_be_bytes()); - hasher.update(sys::clock::uptime().to_be_bytes()); + hasher.update(sys::clk::ticks().to_be_bytes()); + hasher.update(sys::clk::epoch_time().to_be_bytes()); + hasher.update(sys::clk::boot_time().to_be_bytes()); seed = hasher.finalize().into(); } diff --git a/src/sys/serial.rs b/src/sys/serial.rs index 184b5b3b..8ea0a443 100644 --- a/src/sys/serial.rs +++ b/src/sys/serial.rs @@ -48,7 +48,7 @@ impl fmt::Write for Serial { } } -/// See https://vt100.net/emu/dec_ansi_parser +// Source: https://vt100.net/emu/dec_ansi_parser impl Perform for Serial { fn csi_dispatch(&mut self, params: &Params, _: &[u8], _: bool, c: char) { match c { diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index b834eadf..1bc6dd7a 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -17,7 +17,7 @@ pub fn exit(code: ExitCode) -> ExitCode { } pub fn sleep(seconds: f64) { - sys::time::sleep(seconds); + sys::clk::sleep(seconds); } pub fn delete(path: &str) -> isize { diff --git a/src/usr/beep.rs b/src/usr/beep.rs index 25261769..fd049d87 100644 --- a/src/usr/beep.rs +++ b/src/usr/beep.rs @@ -9,9 +9,9 @@ use x86_64::instructions::port::Port; const SPEAKER_PORT: u16 = 0x61; fn start_sound(freq: f64) { - let divider = (sys::time::PIT_FREQUENCY / freq) as u16; + let divider = (sys::clk::pit_frequency() / freq) as u16; let channel = 2; - sys::time::set_pit_frequency_divider(divider, channel); + sys::clk::set_pit_frequency(divider, channel); let mut speaker: Port = Port::new(SPEAKER_PORT); let tmp = unsafe { speaker.read() }; diff --git a/src/usr/chess.rs b/src/usr/chess.rs index f8082055..2782e85b 100644 --- a/src/usr/chess.rs +++ b/src/usr/chess.rs @@ -53,7 +53,7 @@ fn update_autocomplete(prompt: &mut Prompt, game: &mut Game) { } fn system_time() -> u128 { - (api::clock::realtime() * 1000.0) as u128 + (api::clock::epoch_time() * 1000.0) as u128 } struct Chess { diff --git a/src/usr/dhcp.rs b/src/usr/dhcp.rs index 0be39fe3..3c90a4f8 100644 --- a/src/usr/dhcp.rs +++ b/src/usr/dhcp.rs @@ -34,9 +34,9 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { debug!("DHCP Discover transmitted"); } let timeout = 30.0; - let started = clock::realtime(); + let started = clock::epoch_time(); loop { - if clock::realtime() - started > timeout { + if clock::epoch_time() - started > timeout { error!("Timeout reached"); return Err(ExitCode::Failure); } @@ -45,7 +45,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { return Err(ExitCode::Failure); } - let ms = (clock::realtime() * 1000000.0) as i64; + let ms = (clock::epoch_time() * 1000000.0) as i64; let time = Instant::from_micros(ms); iface.poll(time, device, &mut sockets); let event = sockets.get_mut::(dhcp_handle).poll(); diff --git a/src/usr/geodate.rs b/src/usr/geodate.rs index 3ba8d38c..e5445f59 100644 --- a/src/usr/geodate.rs +++ b/src/usr/geodate.rs @@ -15,7 +15,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { let timestamp = if args.len() == 3 { args[2].parse().expect("Could not parse timestamp") } else { - clock::realtime() + clock::epoch_time() }; let t = geodate::get_formatted_date(format, timestamp as i64, longitude); diff --git a/src/usr/httpd.rs b/src/usr/httpd.rs index 7270d01c..a0406375 100644 --- a/src/usr/httpd.rs +++ b/src/usr/httpd.rs @@ -368,7 +368,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { return Ok(()); } - let ms = (clock::realtime() * 1000000.0) as i64; + let ms = (clock::epoch_time() * 1000000.0) as i64; let time = Instant::from_micros(ms); iface.poll(time, device, &mut sockets); diff --git a/src/usr/install.rs b/src/usr/install.rs index 43d58bac..d199f05e 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -54,9 +54,9 @@ pub fn copy_files(verbose: bool) { create_dev("/dev/ata/0/1", "ata-0-1", verbose); create_dev("/dev/ata/1/0", "ata-1-0", verbose); create_dev("/dev/ata/1/1", "ata-1-1", verbose); - create_dev("/dev/clk/uptime", "uptime", verbose); - create_dev("/dev/clk/realtime", "realtime", verbose); - create_dev("/dev/rtc", "rtc", verbose); + create_dev("/dev/clk/boot", "clk-boot", verbose); + create_dev("/dev/clk/epoch", "clk-epoch", verbose); + create_dev("/dev/clk/rtc", "clk-rtc", verbose); create_dev("/dev/null", "null", verbose); create_dev("/dev/random", "random", verbose); create_dev("/dev/console", "console", verbose); diff --git a/src/usr/life.rs b/src/usr/life.rs index ff5e6f50..98c23ca7 100644 --- a/src/usr/life.rs +++ b/src/usr/life.rs @@ -61,7 +61,7 @@ impl Game { return; } print!("{}", self); - sys::time::sleep(1.0 / self.speed); + sys::clk::sleep(1.0 / self.speed); if self.is_game_over() { continue; // Display the screen until ^C is received } diff --git a/src/usr/net.rs b/src/usr/net.rs index cfab61dd..2a91542d 100644 --- a/src/usr/net.rs +++ b/src/usr/net.rs @@ -275,7 +275,7 @@ fn monitor() { } syscall::sleep(0.1); - let ms = (clock::realtime() * 1000000.0) as i64; + let ms = (clock::epoch_time() * 1000000.0) as i64; let time = Instant::from_micros(ms); iface.poll(time, device, &mut sockets); let socket = sockets.get_mut::(tcp_handle); diff --git a/src/usr/time.rs b/src/usr/time.rs index 5d0b9b8f..616d1151 100644 --- a/src/usr/time.rs +++ b/src/usr/time.rs @@ -7,9 +7,9 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { let csi_color = Style::color("blue"); let csi_reset = Style::reset(); let cmd = args[1..].join(" "); - let start = clock::realtime(); + let start = clock::epoch_time(); let res = usr::shell::exec(&cmd); - let duration = clock::realtime() - start; + let duration = clock::epoch_time() - start; eprintln!( "{}Executed '{}' in {:.6}s{}", csi_color, cmd, duration, csi_reset diff --git a/www/lisp.html b/www/lisp.html index 08e21e65..89e1f3d6 100644 --- a/www/lisp.html +++ b/www/lisp.html @@ -104,7 +104,7 @@

File Library

  • read, write, append
  • read-binary, write-binary, append-binary
  • read-line, read-char
  • -
  • uptime, realtime
  • +
  • clock/boot, clock/epoch
  • p, print, eprint, error
  • @@ -205,6 +205,7 @@

    Unreleased

    • Add dirname, filename, eprint, and error functions
    • +
    • Rename uptime to clk/boot and realtime to clk/epoch

    0.7.1 (2024-06-20)

    diff --git a/www/manual.html b/www/manual.html index 68d440c4..babe01f2 100644 --- a/www/manual.html +++ b/www/manual.html @@ -94,9 +94,9 @@

    Installation

    Created '/dev/ata/1/0' Created '/dev/ata/1/1' Created '/dev/clk' -Created '/dev/clk/uptime' -Created '/dev/clk/realtime' -Created '/dev/rtc' +Created '/dev/clk/boot' +Created '/dev/clk/epoch' +Created '/dev/clk/rtc' Created '/dev/null' Created '/dev/random' Created '/dev/console' @@ -290,7 +290,7 @@

    Time

    You can update the real time clock by writing the correct time to its device file:

    -
    > print "2023-03-21 10:00:00" => /dev/rtc
    +    
    > print "2023-03-21 10:00:00" => /dev/clk/rtc
     
     > date
     2023-03-21 10:00:00 +0000
    @@ -320,13 +320,13 @@ 

    Time

    There's a device file to get the number of seconds elapsed since Unix Epoch:

    -
    > read /dev/clk/realtime
    +    
    > read /dev/clk/epoch
     1682105344.624905
     

    And another one since boot:

    -
    > read /dev/clk/uptime
    +    
    > read /dev/clk/boot
     1169.384929
     
    @@ -337,7 +337,7 @@

    Aliases

    For example you can define an uptime command that will read the device file described above:

    -
    > alias uptime "read /dev/clk/uptime"
    +    
    > alias uptime "read /dev/clk/boot"
     
     > uptime
     1406.304852
    @@ -407,7 +407,7 @@ 

    Network

    > ntp
     2023-03-21 10:00:00
     
    -> ntp => /dev/rtc
    +> ntp => /dev/clk/rtc
     [12.111156] RTC 2023-03-21 10:00:00 +0000
     
    diff --git a/www/network.html b/www/network.html index 73e0c199..3cd7a81e 100644 --- a/www/network.html +++ b/www/network.html @@ -188,7 +188,7 @@

    NTP

    It can be used to synchronize the real-time clock (RTC):

    -
    > ntp => /dev/rtc
    +    
    > ntp => /dev/clk/rtc
     [42.123456] RTC 2023-03-21 10:00:00 +0000