diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1624fcd8d9..cb34ee36d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -300,20 +300,20 @@ jobs: if: matrix.arch == 'x86_64' || matrix.arch == 'riscv64' - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package httpd --features ci,hermit/dhcpv4,hermit/rtl8139 qemu ${{ matrix.qemu_flags }} --devices rtl8139 if: matrix.arch != 'riscv64' - - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package httpd --no-default-features --features ci,hermit/dhcpv4,hermit/tcp,hermit/gem-net qemu ${{ matrix.qemu_flags }} --devices cadence-gem + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package httpd --no-default-features --features ci,hermit/dhcpv4,hermit/tcp,hermit/gem-net,hermit/riscv-legacy-timer qemu ${{ matrix.qemu_flags }} --devices cadence-gem if: matrix.arch == 'riscv64' - run: cargo clean working-directory: . - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package testudp --features hermit/udp,hermit/dhcpv4,hermit/virtio-net qemu ${{ matrix.qemu_flags }} --devices virtio-net-pci - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package testudp --features hermit/udp,hermit/dhcpv4,hermit/rtl8139 qemu ${{ matrix.qemu_flags }} --devices rtl8139 if: matrix.arch != 'riscv64' - - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package testudp --no-default-features --features hermit/udp,hermit/dhcpv4,hermit/gem-net qemu ${{ matrix.qemu_flags }} --devices cadence-gem + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package testudp --no-default-features --features hermit/udp,hermit/dhcpv4,hermit/gem-net,hermit/riscv-legacy-timer qemu ${{ matrix.qemu_flags }} --devices cadence-gem if: matrix.arch == 'riscv64' - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package miotcp --features hermit/dhcpv4,hermit/virtio-net qemu ${{ matrix.qemu_flags }} --devices virtio-net-pci if: matrix.arch != 'riscv64' - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package miotcp --features hermit/dhcpv4,hermit/rtl8139 qemu ${{ matrix.qemu_flags }} --devices rtl8139 if: matrix.arch != 'riscv64' - - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package miotcp --no-default-features --features hermit/dhcpv4,hermit/tcp,hermit/gem-net qemu ${{ matrix.qemu_flags }} --devices cadence-gem + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package miotcp --no-default-features --features hermit/dhcpv4,hermit/tcp,hermit/gem-net,hermit/riscv-legacy-timer qemu ${{ matrix.qemu_flags }} --devices cadence-gem if: matrix.arch == 'riscv64' - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package poll --features hermit/dhcpv4,hermit/virtio-net qemu ${{ matrix.qemu_flags }} --devices virtio-net-pci - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package poll --features hermit/dhcpv4,hermit/rtl8139 qemu ${{ matrix.qemu_flags }} --devices rtl8139 diff --git a/Cargo.lock b/Cargo.lock index d8218099d9..7a6b6c3ff8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1559,8 +1559,7 @@ dependencies = [ [[package]] name = "riscv" version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42cdafa0aa3f0f956b7993cace26de5dafff7bb4f2c5b1dcb2c3723f4267a4f" +source = "git+https://github.com/rust-embedded/riscv?branch=master#ac863e802243fed2ff2ee754a92bf1aef2889bcf" dependencies = [ "critical-section", "embedded-hal", @@ -1572,8 +1571,7 @@ dependencies = [ [[package]] name = "riscv-macros" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad9f6dda08d90d091bc0743967cab369b8fe39ea74b26783ba2ca5c0ce39e86" +source = "git+https://github.com/rust-embedded/riscv?branch=master#ac863e802243fed2ff2ee754a92bf1aef2889bcf" dependencies = [ "proc-macro2", "quote", @@ -1583,8 +1581,7 @@ dependencies = [ [[package]] name = "riscv-types" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3f2ad9f15a07f4a0e1677124f9120ce7e83ab7e1ca7186af0ca9da529b62e80" +source = "git+https://github.com/rust-embedded/riscv?branch=master#ac863e802243fed2ff2ee754a92bf1aef2889bcf" [[package]] name = "rustix" diff --git a/Cargo.toml b/Cargo.toml index ae60e66285..3c9f9d7690 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -163,6 +163,15 @@ semihosting = ["dep:semihosting"] ## _application processor_s (AP) from the _boot-strap processor_ (BSP). smp = ["acpi"] +## Enables timer management via SBI. +## +## This allows hardware without Sstc support to manage timers. +## E.g. SiFive Freedom U740 +## If this flag is not set, timers will be managed using the Sstc extension. +## +## This flag is only evaluated for riscv64. +riscv-legacy-timer = [] + #! ### Network Features ## Enables TCP support. @@ -418,7 +427,8 @@ semihosting = { version = "0.1", optional = true } [target.'cfg(target_arch = "riscv64")'.dependencies] fdt = { version = "0.1", features = ["pretty-printing"] } memory_addresses = { version = "0.4", default-features = false, features = ["riscv64"] } -riscv = "0.16" +#TODO: use upstream version once changes merged and published +riscv = { version = "0.16", git = "https://github.com/rust-embedded/riscv", branch = "master" } sbi-rt = "0.0.4" semihosting = { version = "0.1", optional = true } tock-registers = { version = "0.10", optional = true } diff --git a/src/arch/riscv64/kernel/devicetree.rs b/src/arch/riscv64/kernel/devicetree.rs index 145bb9c77a..9a6d0f4469 100644 --- a/src/arch/riscv64/kernel/devicetree.rs +++ b/src/arch/riscv64/kernel/devicetree.rs @@ -57,6 +57,19 @@ enum Model { Unknown, } +pub fn detect_timebase_frequency() -> u64 { + let fdt = env::start_info().fdt().unwrap(); + + let cpus_node = fdt + .find_node("/cpus") + .expect("cpus node missing or invalid"); + cpus_node + .property("timebase-frequency") + .expect("timebase-frequency node not found in /cpus") + .as_usize() + .unwrap() as u64 +} + /// Inits variables based on the device tree /// This function should only be called once pub fn init() { diff --git a/src/arch/riscv64/kernel/mod.rs b/src/arch/riscv64/kernel/mod.rs index 492772be1b..ed959814fd 100644 --- a/src/arch/riscv64/kernel/mod.rs +++ b/src/arch/riscv64/kernel/mod.rs @@ -19,10 +19,10 @@ use riscv::register::sstatus; pub(crate) use self::processor::{set_oneshot_timer, wakeup_core}; use crate::arch::kernel::core_local::core_id; -pub use crate::arch::kernel::devicetree::init_drivers; +pub use crate::arch::kernel::devicetree::{detect_timebase_frequency, init_drivers}; use crate::arch::kernel::processor::lsb; use crate::config::KERNEL_STACK_SIZE; -use crate::env::{self, FdtStartInfo}; +use crate::env; use crate::init_cell::InitCell; use crate::mm::{FrameAlloc, PageRangeAllocator}; @@ -59,20 +59,6 @@ pub fn get_hart_mask() -> u64 { HART_MASK.load(Ordering::Relaxed) } -pub fn get_timebase_freq() -> u64 { - let fdt = env::start_info().fdt().unwrap(); - - // Get timebase-freq - let cpus_node = fdt - .find_node("/cpus") - .expect("cpus node missing or invalid"); - cpus_node - .property("timebase-frequency") - .expect("timebase-frequency node not found in /cpus") - .as_usize() - .unwrap() as u64 -} - pub fn get_current_boot_id() -> u32 { CURRENT_BOOT_ID.load(Ordering::Relaxed) } diff --git a/src/arch/riscv64/kernel/processor.rs b/src/arch/riscv64/kernel/processor.rs index a0aaaf7c32..a20313d2ff 100644 --- a/src/arch/riscv64/kernel/processor.rs +++ b/src/arch/riscv64/kernel/processor.rs @@ -1,11 +1,16 @@ use core::arch::asm; use core::num::NonZeroU64; +use hermit_sync::{Lazy, without_interrupts}; +#[cfg(not(feature = "riscv-legacy-timer"))] +use riscv::register::stimecmp; use riscv::register::{sie, sstatus, time}; -use crate::arch::kernel::{HARTS_AVAILABLE, get_timebase_freq}; +use crate::arch::kernel::{HARTS_AVAILABLE, detect_timebase_frequency}; use crate::scheduler::CoreId; +static TIMEBASE_FREQUENCY: Lazy = Lazy::new(detect_timebase_frequency); + /// Current FPU state. Saved at context switch when changed #[repr(C, packed)] #[derive(Clone, Copy, Debug)] @@ -254,7 +259,7 @@ pub fn get_timer_ticks() -> u64 { /// Returns the timer frequency in MHz pub fn get_frequency() -> u16 { - (get_timebase_freq() / 1_000_000).try_into().unwrap() + (*TIMEBASE_FREQUENCY / 1_000_000).try_into().unwrap() } #[inline] @@ -270,23 +275,36 @@ pub fn supports_2mib_pages() -> bool { true } -pub fn set_oneshot_timer(wakeup_time: Option) { +#[inline] +pub fn __set_oneshot_timer(wakeup_time: Option) { let Some(wt) = wakeup_time else { // Disable the Timer (and clear a pending interrupt) - debug!("Stopping Timer"); + #[cfg(not(feature = "riscv-legacy-timer"))] + unsafe { + stimecmp::write(usize::MAX); + } + #[cfg(feature = "riscv-legacy-timer")] sbi_rt::set_timer(u64::MAX); return; }; - debug!("Starting Timer: {:x}", get_timestamp()); unsafe { sie::set_stimer(); } let next_time = wt * u64::from(get_frequency()); + #[cfg(not(feature = "riscv-legacy-timer"))] + unsafe { + stimecmp::write(next_time.try_into().unwrap()); + } + #[cfg(feature = "riscv-legacy-timer")] sbi_rt::set_timer(next_time); } +pub fn set_oneshot_timer(wakeup_time: Option) { + without_interrupts(|| __set_oneshot_timer(wakeup_time)); +} + pub fn wakeup_core(core_to_wakeup: CoreId) { let hart_id = HARTS_AVAILABLE.finalize()[core_to_wakeup as usize]; debug!("Wakeup core: {core_to_wakeup} , hart_id: {hart_id}");