mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2026-05-24 08:55:20 -04:00
support for ARM PL031 RTC
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -29,6 +29,12 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arm_pl031"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13696b1c2b59992f4223e0ae5bb173c81c63039367ca90eee845346ad2a13421"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.89"
|
||||
@@ -539,6 +545,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"aarch64-cpu",
|
||||
"arm-pl011-uart",
|
||||
"arm_pl031",
|
||||
"async-trait",
|
||||
"bitflags 2.11.0",
|
||||
"blake2",
|
||||
|
||||
@@ -28,6 +28,7 @@ moss-macros = { path = "moss-macros" }
|
||||
|
||||
aarch64-cpu = "11.1.0"
|
||||
arm-pl011-uart = { version = "0.5.0", default-features = false }
|
||||
arm_pl031 = { version = "0.2.1", default-features = false }
|
||||
async-trait = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
blake2 = { version = "0.10.6", default-features = false }
|
||||
|
||||
@@ -38,6 +38,7 @@ default_args = {
|
||||
"-cpu": args.cpu,
|
||||
"-m": args.memory,
|
||||
"-smp": str(args.smp),
|
||||
"-rtc": "base=utc,clock=host",
|
||||
"-nographic": None,
|
||||
"-s": None,
|
||||
"-kernel": bin_executable_location,
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::{drivers::timer::uptime, memory::uaccess::copy_to_user};
|
||||
|
||||
pub async fn sys_clock_gettime(clockid: i32, time_spec: TUA<TimeSpec>) -> Result<usize> {
|
||||
let time = match ClockId::try_from(clockid).map_err(|_| KernelError::InvalidValue)? {
|
||||
ClockId::Monotonic => uptime(),
|
||||
ClockId::Realtime => date(),
|
||||
ClockId::Monotonic => uptime(),
|
||||
ClockId::ProcessCpuTimeId => {
|
||||
let task = current_task_shared();
|
||||
let total_time = task.process.stime.load(Ordering::Relaxed) as u64
|
||||
|
||||
@@ -5,8 +5,8 @@ pub mod timeofday;
|
||||
pub mod timespec;
|
||||
|
||||
pub enum ClockId {
|
||||
Monotonic = 0,
|
||||
Realtime = 1,
|
||||
Realtime = 0,
|
||||
Monotonic = 1,
|
||||
ProcessCpuTimeId = 2,
|
||||
ThreadCpuTimeId = 3,
|
||||
MonotonicRaw = 4,
|
||||
@@ -23,8 +23,8 @@ impl TryFrom<i32> for ClockId {
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(ClockId::Monotonic),
|
||||
1 => Ok(ClockId::Realtime),
|
||||
0 => Ok(ClockId::Realtime),
|
||||
1 => Ok(ClockId::Monotonic),
|
||||
2 => Ok(ClockId::ProcessCpuTimeId),
|
||||
3 => Ok(ClockId::ThreadCpuTimeId),
|
||||
4 => Ok(ClockId::MonotonicRaw),
|
||||
|
||||
@@ -25,7 +25,7 @@ pub fn set_date(duration: Duration) {
|
||||
}
|
||||
}
|
||||
|
||||
// Represents a known duration since the epoch at the assoicated instant.
|
||||
// Represents a known duration since the epoch at the associated instant.
|
||||
static EPOCH_DURATION: SpinLock<Option<(Duration, Instant)>> = SpinLock::new(None);
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -28,6 +28,7 @@ pub mod init;
|
||||
pub mod interrupts;
|
||||
pub mod probe;
|
||||
pub mod rng;
|
||||
pub mod rtc;
|
||||
pub mod timer;
|
||||
pub mod uart;
|
||||
mod virtio_hal;
|
||||
|
||||
29
src/drivers/rtc/mod.rs
Normal file
29
src/drivers/rtc/mod.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
//! Real-time clock (RTC) drivers.
|
||||
//!
|
||||
//! RTCs often differ in how they represent time, so the idea is to return a [`Duration`] since the Unix epoch,
|
||||
//! with each driver responsible for converting/handling hardware bugs.
|
||||
|
||||
pub mod pl031;
|
||||
|
||||
use crate::sync::OnceLock;
|
||||
use alloc::sync::Arc;
|
||||
use core::time::Duration;
|
||||
|
||||
pub trait Rtc: Send + Sync {
|
||||
/// Gets the current RTC time as a `Duration` since the Unix epoch.
|
||||
fn time(&self) -> Option<Duration>;
|
||||
|
||||
/// Sets the RTC time. The provided `Duration` should represent the time since the Unix epoch.
|
||||
#[expect(unused)]
|
||||
fn set_time(&mut self, time: Duration) -> libkernel::error::Result<()>;
|
||||
}
|
||||
|
||||
pub static RTC_DRIVER: OnceLock<Arc<dyn Rtc>> = OnceLock::new();
|
||||
|
||||
pub fn get_rtc() -> Option<&'static Arc<dyn Rtc>> {
|
||||
RTC_DRIVER.get()
|
||||
}
|
||||
|
||||
fn set_rtc_driver(driver: Arc<dyn Rtc>) -> bool {
|
||||
RTC_DRIVER.set(driver).is_ok()
|
||||
}
|
||||
81
src/drivers/rtc/pl031.rs
Normal file
81
src/drivers/rtc/pl031.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use crate::arch::ArchImpl;
|
||||
use crate::drivers::init::PlatformBus;
|
||||
use crate::drivers::probe::{DeviceDescriptor, DeviceMatchType};
|
||||
use crate::drivers::rtc::{Rtc, set_rtc_driver};
|
||||
use crate::drivers::{Driver, DriverManager};
|
||||
use crate::kernel_driver;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::sync::Arc;
|
||||
use core::time::Duration;
|
||||
use libkernel::error::{ProbeError, Result};
|
||||
use libkernel::memory::address::{PA, VA};
|
||||
use libkernel::memory::region::PhysMemoryRegion;
|
||||
use libkernel::{KernAddressSpace, VirtualMemory};
|
||||
|
||||
/// Driver for a PL031 real-time clock.
|
||||
pub struct PL031 {
|
||||
inner: arm_pl031::Rtc,
|
||||
}
|
||||
|
||||
impl PL031 {
|
||||
/// Constructs a new instance of the RTC driver for a PL031 device with the
|
||||
/// given base address.
|
||||
pub fn new(base_addr: VA) -> Self {
|
||||
let rtc = unsafe { arm_pl031::Rtc::new(base_addr.as_ptr_mut() as _) };
|
||||
Self { inner: rtc }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rtc for PL031 {
|
||||
fn time(&self) -> Option<Duration> {
|
||||
Some(Duration::new(self.inner.get_unix_timestamp() as u64, 0))
|
||||
}
|
||||
|
||||
fn set_time(&mut self, time: Duration) -> libkernel::error::Result<()> {
|
||||
self.inner.set_unix_timestamp(time.as_secs() as _);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Driver for PL031 {
|
||||
fn name(&self) -> &'static str {
|
||||
"ARM PrimeCell Real Time Clock"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pl031_probe(_dm: &mut DriverManager, d: DeviceDescriptor) -> Result<Arc<dyn Driver>> {
|
||||
match d {
|
||||
DeviceDescriptor::Fdt(fdt_node, _flags) => {
|
||||
let region = fdt_node
|
||||
.reg()
|
||||
.ok_or(ProbeError::NoReg)?
|
||||
.next()
|
||||
.ok_or(ProbeError::NoReg)?;
|
||||
|
||||
let size = region.size.ok_or(ProbeError::NoRegSize)?;
|
||||
|
||||
let mem =
|
||||
ArchImpl::kern_address_space()
|
||||
.lock_save_irq()
|
||||
.map_mmio(PhysMemoryRegion::new(
|
||||
PA::from_value(region.address as usize),
|
||||
size,
|
||||
))?;
|
||||
|
||||
let dev = Arc::new(PL031::new(mem));
|
||||
set_rtc_driver(dev.clone());
|
||||
Ok(dev)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pl031_init(bus: &mut PlatformBus, _dm: &mut DriverManager) -> Result<()> {
|
||||
bus.register_platform_driver(
|
||||
DeviceMatchType::FdtCompatible("arm,pl031"),
|
||||
Box::new(pl031_probe),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
kernel_driver!(pl031_init);
|
||||
@@ -109,6 +109,13 @@ async fn launch_init(mut opts: KOptions) {
|
||||
None
|
||||
};
|
||||
|
||||
// Set time to rtc time if possible
|
||||
if let Some(rtc) = drivers::rtc::get_rtc()
|
||||
&& let Some(time) = rtc.time()
|
||||
{
|
||||
clock::realtime::set_date(time);
|
||||
}
|
||||
|
||||
let root_fs = opts
|
||||
.root_fs
|
||||
.unwrap_or_else(|| panic!("No root FS driver specified in kernel command line"));
|
||||
|
||||
Reference in New Issue
Block a user