diff --git a/src/drivers/net/mod.rs b/src/drivers/net/mod.rs index 686279013c..d56e73e5b6 100644 --- a/src/drivers/net/mod.rs +++ b/src/drivers/net/mod.rs @@ -80,3 +80,16 @@ pub(crate) extern "x86-interrupt" fn network_irqhandler(_stack_frame: ExceptionS core_scheduler().reschedule(); } + +#[cfg(target_arch = "riscv64")] +pub fn network_irqhandler() { + use crate::scheduler::PerCoreSchedulerExt; + + debug!("Receive network interrupt"); + + // PLIC end of interrupt + crate::arch::kernel::interrupts::external_eoi(); + let _ = _irqhandler(); + + core_scheduler().reschedule(); +} diff --git a/src/drivers/net/virtio_net.rs b/src/drivers/net/virtio_net.rs index 864206536e..e3bbb17c7b 100644 --- a/src/drivers/net/virtio_net.rs +++ b/src/drivers/net/virtio_net.rs @@ -18,6 +18,7 @@ use zerocopy::AsBytes; use self::constants::{FeatureSet, Features, NetHdrFlag, NetHdrGSO, Status, MAX_NUM_VQ}; use self::error::VirtioNetError; +#[cfg(not(target_arch = "riscv64"))] use crate::arch::kernel::core_local::increment_irq_counter; use crate::config::VIRTIO_MAX_QUEUE_SIZE; #[cfg(not(feature = "pci"))] @@ -462,6 +463,7 @@ pub(crate) struct VirtioNetDriver { pub(super) send_vqs: TxQueues, pub(super) num_vqs: u16, + #[cfg_attr(target_arch = "riscv64", allow(dead_code))] pub(super) irq: InterruptLine, pub(super) mtu: u16, pub(super) checksums: ChecksumCapabilities, @@ -648,6 +650,7 @@ impl NetworkDriver for VirtioNetDriver { } fn handle_interrupt(&mut self) -> bool { + #[cfg(not(target_arch = "riscv64"))] increment_irq_counter(32 + self.irq); let result = if self.isr_stat.is_interrupt() { diff --git a/src/drivers/virtio/transport/mmio.rs b/src/drivers/virtio/transport/mmio.rs index 3c899cc980..cb3465d98f 100644 --- a/src/drivers/virtio/transport/mmio.rs +++ b/src/drivers/virtio/transport/mmio.rs @@ -394,6 +394,7 @@ pub(crate) fn init_device( info!("Virtio network driver initialized."); // Install interrupt handler irq_install_handler(irq_no, network_irqhandler); + #[cfg(not(target_arch = "riscv64"))] add_irq_name(irq_no, "virtio_net"); Ok(VirtioDriver::Network(virt_net_drv)) diff --git a/src/env.rs b/src/env.rs index 7d1b8e601e..d85c5f152d 100644 --- a/src/env.rs +++ b/src/env.rs @@ -23,6 +23,7 @@ pub fn init() { struct Cli { #[allow(dead_code)] image_path: Option, + #[cfg(not(target_arch = "riscv64"))] freq: Option, env_vars: HashMap, args: Vec, @@ -36,6 +37,7 @@ pub fn is_uhyve() -> bool { impl Default for Cli { fn default() -> Self { let mut image_path = None; + #[cfg(not(target_arch = "riscv64"))] let mut freq = None; let mut env_vars = HashMap::::with_hasher( RandomState::with_seeds(0, 0, 0, 0), @@ -53,6 +55,7 @@ impl Default for Cli { }; while let Some(word) = words.next() { match word.as_str() { + #[cfg(not(target_arch = "riscv64"))] "-freq" => { let s = expect_arg(words.next(), word.as_str()); freq = Some(s.parse().unwrap()); @@ -81,6 +84,7 @@ impl Default for Cli { Self { image_path, + #[cfg(not(target_arch = "riscv64"))] freq, env_vars, args, @@ -89,6 +93,7 @@ impl Default for Cli { } /// CPU Frequency in MHz if given through the -freq command-line parameter. +#[cfg(not(target_arch = "riscv64"))] pub fn freq() -> Option { CLI.get().unwrap().freq } diff --git a/src/executor/network.rs b/src/executor/network.rs index 21ca5ede19..be49df67dd 100644 --- a/src/executor/network.rs +++ b/src/executor/network.rs @@ -83,6 +83,13 @@ fn start_endpoint() -> u16 { (value % (u16::MAX as u64)).try_into().unwrap() } +#[cfg(target_arch = "riscv64")] +fn start_endpoint() -> u16 { + (riscv::register::time::read64() % (u16::MAX as u64)) + .try_into() + .unwrap() +} + #[inline] pub(crate) fn now() -> Instant { let microseconds = arch::processor::get_timer_ticks() + arch::get_boot_time(); diff --git a/src/fd/mod.rs b/src/fd/mod.rs index 4c329a980d..d357d14c18 100644 --- a/src/fd/mod.rs +++ b/src/fd/mod.rs @@ -1,5 +1,6 @@ use alloc::sync::Arc; use core::ffi::{c_void, CStr}; +#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] use core::ptr; use core::sync::atomic::{AtomicI32, Ordering}; @@ -164,6 +165,13 @@ fn uhyve_send(port: u16, data: &mut T) { } } +/// forward a request to the hypervisor uhyve +#[inline] +#[cfg(target_arch = "riscv64")] +fn uhyve_send(_port: u16, _data: &mut T) { + todo!() +} + fn open_flags_to_perm(flags: i32, mode: u32) -> FilePerms { let mut perms = FilePerms { raw: flags as u32, diff --git a/src/lib.rs b/src/lib.rs index e3ef209452..dae21bb324 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,12 @@ #![warn(clippy::uninlined_format_args)] #![warn(clippy::transmute_ptr_to_ptr)] #![allow(clippy::missing_safety_doc)] -#![cfg_attr(target_arch = "aarch64", allow(incomplete_features))] +#![cfg_attr( + any(target_arch = "aarch64", target_arch = "riscv64"), + allow(incomplete_features) +)] #![cfg_attr(target_arch = "x86_64", feature(abi_x86_interrupt))] +#![cfg_attr(target_arch = "riscv64", feature(offset_of))] #![feature(allocator_api)] #![feature(asm_const)] #![feature(core_intrinsics)] @@ -19,7 +23,10 @@ #![feature(pointer_is_aligned)] #![feature(ptr_from_ref)] #![feature(slice_from_ptr_range)] -#![cfg_attr(target_arch = "aarch64", feature(specialization))] +#![cfg_attr( + any(target_arch = "aarch64", target_arch = "riscv64"), + feature(specialization) +)] #![feature(strict_provenance)] #![cfg_attr(target_os = "none", no_std)] #![cfg_attr(target_os = "none", feature(custom_test_frameworks))] @@ -268,6 +275,10 @@ extern "C" fn initd(_arg: usize) { arch::init_drivers(); crate::executor::init(); + // Initialize MMIO Drivers if on riscv64 + #[cfg(target_arch = "riscv64")] + riscv64::kernel::init_drivers(); + syscalls::init(); fd::init(); #[cfg(feature = "fs")] @@ -320,6 +331,8 @@ fn boot_processor_main() -> ! { }); info!("tls_info = {:#x?}", kernel::boot_info().load_info.tls_info); arch::boot_processor_init(); + + #[cfg(not(target_arch = "riscv64"))] scheduler::add_current_core(); if !env::is_uhyve() { @@ -354,6 +367,7 @@ fn boot_processor_main() -> ! { #[cfg(all(target_os = "none", feature = "smp"))] fn application_processor_main() -> ! { arch::application_processor_init(); + #[cfg(not(target_arch = "riscv64"))] scheduler::add_current_core(); info!("Entering idle loop for application processor"); diff --git a/src/logging.rs b/src/logging.rs index 10e3ef453d..905268a9ba 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -53,6 +53,7 @@ macro_rules! infoheader { }}; } +#[cfg_attr(target_arch = "riscv64", allow(unused))] macro_rules! infoentry { ($str:expr, $rhs:expr) => (infoentry!($str, "{}", $rhs)); ($str:expr, $($arg:tt)+) => (::log::info!("{:25}{}", concat!($str, ":"), format_args!($($arg)+))); diff --git a/src/macros.rs b/src/macros.rs index 7b559fd2d0..8110521912 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -72,7 +72,10 @@ macro_rules! dbg { /// let ret = f(arg); /// ``` #[allow(unused_macro_rules)] -#[cfg(not(feature = "newlib"))] +#[cfg(not(any( + target_arch = "riscv64", + all(target_arch = "x86_64", feature = "newlib") +)))] macro_rules! kernel_function { ($f:ident()) => { $crate::arch::switch::kernel_function0($f) @@ -105,7 +108,11 @@ macro_rules! kernel_function { // TODO: Properly switch kernel stack with newlib // https://github.com/hermit-os/kernel/issues/471 -#[cfg(all(target_arch = "x86_64", feature = "newlib"))] +// TODO: Switch kernel stack on RISC-V +#[cfg(any( + target_arch = "riscv64", + all(target_arch = "x86_64", feature = "newlib") +))] macro_rules! kernel_function { ($f:ident($($x:tt)*)) => {{ $f($($x)*) diff --git a/src/mm/mod.rs b/src/mm/mod.rs index 26ce32c82e..bfacc26c21 100644 --- a/src/mm/mod.rs +++ b/src/mm/mod.rs @@ -9,7 +9,7 @@ use hermit_sync::Lazy; #[cfg(feature = "newlib")] use hermit_sync::OnceCell; -#[cfg(target_arch = "x86_64")] +#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] use crate::arch::mm::paging::HugePageSize; #[cfg(target_arch = "x86_64")] use crate::arch::mm::paging::PageTableEntryFlagsExt; @@ -82,7 +82,7 @@ pub(crate) fn init() { let reserved_space = (npage_3tables + npage_2tables + npage_1tables) * BasePageSize::SIZE as usize + LargePageSize::SIZE as usize; - #[cfg(target_arch = "x86_64")] + #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] let has_1gib_pages = arch::processor::supports_1gib_pages(); let has_2mib_pages = arch::processor::supports_2mib_pages(); @@ -152,7 +152,7 @@ pub(crate) fn init() { virt_addr ); - #[cfg(target_arch = "x86_64")] + #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] if has_1gib_pages && virt_size > HugePageSize::SIZE as usize { // Mount large pages to the next huge page boundary let npages = (virt_addr.align_up_to_huge_page().as_usize() - virt_addr.as_usize()) @@ -169,14 +169,14 @@ pub(crate) fn init() { map_size = virt_size; } - #[cfg(not(target_arch = "x86_64"))] + #[cfg(not(any(target_arch = "x86_64", target_arch = "riscv64")))] { map_addr = virt_addr; map_size = virt_size; } } - #[cfg(target_arch = "x86_64")] + #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] if has_1gib_pages && map_size > HugePageSize::SIZE as usize && map_addr.is_aligned(HugePageSize::SIZE) diff --git a/src/scheduler/mod.rs b/src/scheduler/mod.rs index 65432edf03..6637c31e20 100644 --- a/src/scheduler/mod.rs +++ b/src/scheduler/mod.rs @@ -9,10 +9,14 @@ use core::sync::atomic::{AtomicU32, Ordering}; use crossbeam_utils::Backoff; use hermit_sync::{without_interrupts, *}; +#[cfg(target_arch = "riscv64")] +use riscv::register::sstatus; use crate::arch; use crate::arch::core_local::*; use crate::arch::interrupts; +#[cfg(target_arch = "riscv64")] +use crate::arch::switch::switch_to_task; #[cfg(target_arch = "x86_64")] use crate::arch::switch::{switch_to_fpu_owner, switch_to_task}; use crate::kernel::scheduler::TaskStacks; @@ -142,6 +146,11 @@ impl PerCoreSchedulerExt for &mut PerCoreScheduler { interrupts::enable(); } + #[cfg(target_arch = "riscv64")] + fn reschedule(self) { + without_interrupts(|| self.scheduler()); + } + #[cfg(any(feature = "tcp", feature = "udp"))] fn add_network_timer(self, wakeup_time: Option) { without_interrupts(|| { @@ -357,7 +366,7 @@ impl PerCoreScheduler { /// Returns `true` if a reschedule is required #[inline] - #[cfg(all(target_arch = "x86_64", feature = "smp"))] + #[cfg(all(any(target_arch = "x86_64", target_arch = "riscv64"), feature = "smp"))] pub fn is_scheduling(&self) -> bool { self.current_task.borrow().prio < self.ready_queue.get_highest_priority() } @@ -492,6 +501,17 @@ impl PerCoreScheduler { }) } + #[cfg(target_arch = "riscv64")] + pub fn set_current_kernel_stack(&self) { + let current_task_borrowed = self.current_task.borrow(); + + let stack = (current_task_borrowed.stacks.get_kernel_stack() + + current_task_borrowed.stacks.get_kernel_stack_size() + - TaskStacks::MARKER_SIZE) + .as_u64(); + CoreLocal::get().kernel_stack.set(stack); + } + /// Save the FPU context for the current FPU owner and restore it for the current task, /// which wants to use the FPU now. #[cfg(target_arch = "x86_64")] @@ -517,7 +537,7 @@ impl PerCoreScheduler { } } - #[cfg(all(target_arch = "x86_64", feature = "smp"))] + #[cfg(all(any(target_arch = "x86_64", target_arch = "riscv64"), feature = "smp"))] pub fn check_input(&mut self) { let mut input_locked = CoreLocal::get().scheduler_input.lock(); @@ -648,10 +668,26 @@ impl PerCoreScheduler { unsafe { *last_stack_pointer }, new_stack_pointer ); - self.current_task = task; + #[cfg(not(target_arch = "riscv64"))] + { + self.current_task = task; + } // Finally return the context of the new task. + #[cfg(not(target_arch = "riscv64"))] return Some(last_stack_pointer); + + #[cfg(target_arch = "riscv64")] + { + if sstatus::read().fs() == sstatus::FS::Dirty { + self.current_task.borrow_mut().last_fpu_state.save(); + } + task.borrow().last_fpu_state.restore(); + self.current_task = task; + unsafe { + switch_to_task(last_stack_pointer, new_stack_pointer.as_usize()); + } + } } } diff --git a/src/scheduler/task.rs b/src/scheduler/task.rs index 7078e9a3f0..19e1a8e82f 100644 --- a/src/scheduler/task.rs +++ b/src/scheduler/task.rs @@ -324,7 +324,7 @@ impl PriorityTaskQueue { } /// Returns the highest priority of all available task - #[cfg(all(target_arch = "x86_64", feature = "smp"))] + #[cfg(all(any(target_arch = "x86_64", target_arch = "riscv64"), feature = "smp"))] pub fn get_highest_priority(&self) -> Priority { if let Some(i) = msb(self.prio_bitmap) { Priority::from(i.try_into().unwrap()) diff --git a/src/syscalls/entropy.rs b/src/syscalls/entropy.rs index 65322f706d..32db7fc73e 100644 --- a/src/syscalls/entropy.rs +++ b/src/syscalls/entropy.rs @@ -50,6 +50,7 @@ unsafe extern "C" fn __sys_read_entropy(buf: *mut u8, len: usize, flags: u32) -> /// * `-EINVAL` if `flags` contains unknown flags. /// * `-ENOSYS` if the system does not support random data generation. #[no_mangle] +#[cfg_attr(target_arch = "riscv64", allow(unsafe_op_in_unsafe_fn))] // FIXME pub unsafe extern "C" fn sys_read_entropy(buf: *mut u8, len: usize, flags: u32) -> isize { kernel_function!(__sys_read_entropy(buf, len, flags)) } diff --git a/src/syscalls/interfaces/uhyve.rs b/src/syscalls/interfaces/uhyve.rs index a19c2e3873..637c3f9a83 100644 --- a/src/syscalls/interfaces/uhyve.rs +++ b/src/syscalls/interfaces/uhyve.rs @@ -56,6 +56,13 @@ pub(crate) fn uhyve_send(port: u16, data: &mut T) { } } +/// forward a request to the hypervisor uhyve +#[inline] +#[cfg(target_arch = "riscv64")] +fn uhyve_send(_port: u16, _data: &mut T) { + todo!() +} + const MAX_ARGC_ENVC: usize = 128; #[repr(C, packed)]