diff --git a/Cargo.toml b/Cargo.toml index 945bd9c2c76440d46f48bb27f5b096255cba59dc..9872574c59847442a0c81cbf28762068cc46deba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ num = { version = "0.4", default-features = false } num-traits = { version = "0.2", default-features = false } num-derive = "0.3" zerocopy = "0.6" +time = { version = "0.3", default-features = false } [dependencies.smoltcp] version = "0.9" @@ -111,7 +112,6 @@ features = [ [target.'cfg(target_arch = "x86_64")'.dependencies] multiboot = "0.8" -time = { version = "0.3", default-features = false } uart_16550 = "0.2" x86 = { version = "0.52", default-features = false } x86_64 = "0.14" diff --git a/src/arch/aarch64/kernel/mod.rs b/src/arch/aarch64/kernel/mod.rs index 870342bcae2616dc91ff0401ff762114946c2335..48134b0b240071097d12095d09a39a91d7906093 100644 --- a/src/arch/aarch64/kernel/mod.rs +++ b/src/arch/aarch64/kernel/mod.rs @@ -185,10 +185,7 @@ pub fn boot_processor_init() { interrupts::enable(); processor::detect_frequency(); processor::print_information(); - - /* systemtime::init(); - */ finish_processor_init(); } diff --git a/src/arch/aarch64/kernel/systemtime.rs b/src/arch/aarch64/kernel/systemtime.rs index 616d0b6f1429c33e987a60c376b7482d5d895fb8..41b6d0bdc789dbc1654ea3a96e703fc0081c3a91 100644 --- a/src/arch/aarch64/kernel/systemtime.rs +++ b/src/arch/aarch64/kernel/systemtime.rs @@ -1,9 +1,99 @@ -use crate::env; +use alloc::vec::Vec; +use core::arch::asm; +use core::str; -extern "C" { - static mut boot_gtod: u64; +use hermit_dtb::Dtb; +use hermit_sync::OnceCell; +use time::OffsetDateTime; + +use crate::arch::aarch64::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags}; +use crate::arch::aarch64::mm::{virtualmem, PhysAddr, VirtAddr}; +use crate::kernel::boot_info; + +static PL031_ADDRESS: OnceCell<VirtAddr> = OnceCell::new(); +static BOOT_TIME: OnceCell<u64> = OnceCell::new(); + +const RTC_DR: usize = 0x00; +const RTC_MR: usize = 0x04; +const RTC_LR: usize = 0x08; +const RTC_CR: usize = 0x0c; +/// Interrupt mask and set register +const RTC_IRQ_MASK: usize = 0x10; +/// Raw interrupt status +const RTC_RAW_IRQ_STATUS: usize = 0x14; +/// Masked interrupt status +const RTC_MASK_IRQ_STATUS: usize = 0x18; +/// Interrupt clear register +const RTC_IRQ_CLEAR: usize = 0x1c; + +#[inline] +fn rtc_read(off: usize) -> u32 { + let value: u32; + + // we have to use inline assembly to guarantee 32bit memory access + unsafe { + asm!("ldar {value:w}, [{addr}]", + value = out(reg) value, + addr = in(reg) (PL031_ADDRESS.get().unwrap().as_usize() + off), + options(nostack, readonly), + ); + } + + value } pub fn get_boot_time() -> u64 { - unsafe { boot_gtod } + *BOOT_TIME.get().unwrap() +} + +pub fn init() { + let dtb = unsafe { + Dtb::from_raw(boot_info().hardware_info.device_tree.unwrap().get() as *const u8) + .expect(".dtb file has invalid header") + }; + + for node in dtb.enum_subnodes("/") { + let parts: Vec<_> = node.split('@').collect(); + + if let Some(compatible) = dtb.get_property(parts.first().unwrap(), "compatible") { + if str::from_utf8(compatible).unwrap().find("pl031").is_some() { + let reg = dtb.get_property(parts.first().unwrap(), "reg").unwrap(); + let (slice, residual_slice) = reg.split_at(core::mem::size_of::<u64>()); + let addr = PhysAddr(u64::from_be_bytes(slice.try_into().unwrap())); + let (slice, residual_slice) = residual_slice.split_at(core::mem::size_of::<u64>()); + let size = u64::from_be_bytes(slice.try_into().unwrap()); + + debug!("Found RTC at {:#X} (size {:#X})", addr, size); + + let pl031_address = virtualmem::allocate_aligned( + size.try_into().unwrap(), + BasePageSize::SIZE.try_into().unwrap(), + ) + .unwrap(); + PL031_ADDRESS.set(pl031_address).unwrap(); + debug!("Mapping RTC to virtual address {pl031_address:p}",); + + let mut flags = PageTableEntryFlags::empty(); + flags.device().writable().execute_disable(); + paging::map::<BasePageSize>( + pl031_address, + addr, + (size / BasePageSize::SIZE).try_into().unwrap(), + flags, + ); + + let boot_time = + OffsetDateTime::from_unix_timestamp(rtc_read(RTC_DR) as i64).unwrap(); + info!("HermitCore-rs booted on {boot_time}"); + + let micros = u64::try_from(boot_time.unix_timestamp_nanos() / 1000).unwrap(); + BOOT_TIME.set(micros).unwrap(); + + return; + } + } + } + + PL031_ADDRESS.set(VirtAddr::zero()).unwrap(); + BOOT_TIME.set(0).unwrap(); }