diff --git a/Cargo.lock b/Cargo.lock index 132f30d794..d49167ab10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.9.8", ] [[package]] @@ -705,7 +705,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.9.8", ] [[package]] @@ -809,9 +809,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "maybe-uninit" @@ -873,9 +873,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "orbclient" @@ -1226,6 +1226,14 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "rtcd" +version = "0.1.0" +dependencies = [ + "anyhow", + "common", +] + [[package]] name = "rtl8139d" version = "0.1.0" @@ -1285,7 +1293,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.9.8", ] [[package]] @@ -1420,6 +1428,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.2.5" @@ -1688,7 +1705,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.10.0", "static_assertions", "thiserror", "virtio-core", @@ -1728,7 +1745,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.9.8", "static_assertions", "virtio-core", ] diff --git a/Cargo.toml b/Cargo.toml index d27f9e6e46..4fb623614e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "hwd", "pcid", "pcid-spawner", + "rtcd", "vboxd", "xhcid", "usbctl", diff --git a/rtcd/Cargo.toml b/rtcd/Cargo.toml new file mode 100644 index 0000000000..a6b9587872 --- /dev/null +++ b/rtcd/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rtcd" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" +license = "MIT" + + +[dependencies] +anyhow = "1" + +common = { path = "../common" } diff --git a/rtcd/src/main.rs b/rtcd/src/main.rs new file mode 100644 index 0000000000..3e913780ab --- /dev/null +++ b/rtcd/src/main.rs @@ -0,0 +1,26 @@ +use anyhow::{Context, Result}; + +// TODO: Do not use target architecture to distinguish these. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod x86; + +/// The rtc driver runs only once, being perhaps the first of all processes that init starts (since +/// early logging benefits from knowing the time, even though this can be adjusted later once the +/// time is known). The sole job of `rtcd` is to read from the hardware real-time clock, and then +/// write the offset to the kernel. + +fn main() -> Result<()> { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + common::acquire_port_io_rights().context("failed to set iopl")?; + + let time_s = self::x86::get_time(); + let time_ns = u128::from(time_s) * 1_000_000_000; + + std::fs::write("/scheme/sys/update_time_offset", &time_ns.to_ne_bytes()) + .context("failed to write to time offset")?; + } + // TODO: aarch64 is currently handled in the kernel + + Ok(()) +} diff --git a/rtcd/src/x86.rs b/rtcd/src/x86.rs new file mode 100644 index 0000000000..ea2aebcbbf --- /dev/null +++ b/rtcd/src/x86.rs @@ -0,0 +1,147 @@ +// TODO: Get RTC information from acpid. +use common::io::{Io, Pio}; + +pub fn get_time() -> u64 { + Rtc::new().time() +} + +fn cvt_bcd(value: usize) -> usize { + (value & 0xF) + ((value / 16) * 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 + pub unsafe fn time_no_wait(&mut self) -> u64 { + /*let century_register = if let Some(ref fadt) = acpi::ACPI_TABLE.lock().fadt { + Some(fadt.century) + } else { + None + };*/ + + 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 mut century = /* TODO: Fix invalid value from VirtualBox + if let Some(century_reg) = century_register { + self.read(century_reg) as usize + } else */ { + 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); + century = /* TODO: Fix invalid value from VirtualBox + if century_register.is_some() { + cvt_bcd(century) + } else */ { + century + }; + } + + 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 + pub 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; + } + } + } + } +}