diff --git a/Kernel/Arch/CPUID.h b/Kernel/Arch/CPUID.h index 1d1a2797aa..d8d6fad5d6 100644 --- a/Kernel/Arch/CPUID.h +++ b/Kernel/Arch/CPUID.h @@ -12,6 +12,8 @@ # include #elif ARCH(AARCH64) # include +#elif ARCH(RISCV64) +# include #else # error "Unknown architecture" #endif diff --git a/Kernel/Arch/Processor.h b/Kernel/Arch/Processor.h index 5faa96271a..6e6b962eb9 100644 --- a/Kernel/Arch/Processor.h +++ b/Kernel/Arch/Processor.h @@ -210,6 +210,8 @@ template class ProcessorBase; # include #elif ARCH(AARCH64) # include +#elif ARCH(RISCV64) +# include #else # error "Unknown architecture" #endif diff --git a/Kernel/Arch/riscv64/CPUID.h b/Kernel/Arch/riscv64/CPUID.h new file mode 100644 index 0000000000..a3eb3c5db6 --- /dev/null +++ b/Kernel/Arch/riscv64/CPUID.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +#include +VALIDATE_IS_RISCV64() + +AK_MAKE_ARBITRARY_SIZED_ENUM(CPUFeature, u256, + __End = CPUFeature(1u) << 255u) // SENTINEL VALUE diff --git a/Kernel/Arch/riscv64/Processor.cpp b/Kernel/Arch/riscv64/Processor.cpp new file mode 100644 index 0000000000..0bea1a8afe --- /dev/null +++ b/Kernel/Arch/riscv64/Processor.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +Processor* g_current_processor; + +template +void ProcessorBase::early_initialize(u32 cpu) +{ + VERIFY(g_current_processor == nullptr); + m_cpu = cpu; + + g_current_processor = static_cast(this); +} + +template +void ProcessorBase::initialize(u32) +{ + m_deferred_call_pool.init(); + + // Enable the FPU + auto sstatus = RISCV64::CSR::SSTATUS::read(); + sstatus.FS = RISCV64::CSR::SSTATUS::FloatingPointStatus::Initial; + RISCV64::CSR::SSTATUS::write(sstatus); + + initialize_interrupts(); +} + +template +[[noreturn]] void ProcessorBase::halt() +{ + // WFI ignores the value of sstatus.SIE, so we can't use disable_interrupts(). + // Instead, disable all interrupts sources by setting sie to zero. + RISCV64::CSR::write(RISCV64::CSR::Address::SIE, 0); + for (;;) + asm volatile("wfi"); +} + +template +void ProcessorBase::flush_tlb_local(VirtualAddress, size_t) +{ + // FIXME: Don't flush all pages + flush_entire_tlb_local(); +} + +template +void ProcessorBase::flush_entire_tlb_local() +{ + asm volatile("sfence.vma"); +} + +template +void ProcessorBase::flush_tlb(Memory::PageDirectory const*, VirtualAddress vaddr, size_t page_count) +{ + flush_tlb_local(vaddr, page_count); +} + +template +u32 ProcessorBase::clear_critical() +{ + InterruptDisabler disabler; + auto prev_critical = in_critical(); + auto& proc = current(); + proc.m_in_critical = 0; + if (proc.m_in_irq == 0) + proc.check_invoke_scheduler(); + return prev_critical; +} + +template +u32 ProcessorBase::smp_wake_n_idle_processors(u32) +{ + // FIXME: Actually wake up other cores when SMP is supported for riscv64. + return 0; +} + +template +void ProcessorBase::initialize_context_switching(Thread&) +{ + TODO_RISCV64(); +} + +template +void ProcessorBase::switch_context(Thread*&, Thread*&) +{ + TODO_RISCV64(); +} + +extern "C" FlatPtr do_init_context(Thread*, u32) +{ + TODO_RISCV64(); +} + +template +void ProcessorBase::assume_context(Thread&, InterruptsState) +{ + TODO_RISCV64(); +} + +template +FlatPtr ProcessorBase::init_context(Thread&, bool) +{ + TODO_RISCV64(); +} + +template +void ProcessorBase::exit_trap(TrapFrame&) +{ + TODO_RISCV64(); +} + +template +ErrorOr> ProcessorBase::capture_stack_trace(Thread&, size_t) +{ + dbgln("FIXME: Implement Processor::capture_stack_trace() for riscv64"); + return Vector {}; +} + +NAKED void thread_context_first_enter(void) +{ + asm("unimp"); +} + +NAKED void do_assume_context(Thread*, u32) +{ + asm("unimp"); +} + +template +StringView ProcessorBase::platform_string() +{ + return "riscv64"sv; +} + +template +void ProcessorBase::set_thread_specific_data(VirtualAddress) +{ + TODO_RISCV64(); +} + +template +void ProcessorBase::wait_for_interrupt() const +{ + asm("wfi"); +} + +template +Processor& ProcessorBase::by_id(u32) +{ + TODO_RISCV64(); +} + +} + +#include diff --git a/Kernel/Arch/riscv64/Processor.h b/Kernel/Arch/riscv64/Processor.h new file mode 100644 index 0000000000..6bce31b782 --- /dev/null +++ b/Kernel/Arch/riscv64/Processor.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2023, Sönke Holz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +VALIDATE_IS_RISCV64() + +namespace Kernel { + +namespace Memory { +class PageDirectory; +}; + +class Thread; +class Processor; +struct TrapFrame; +enum class InterruptsState; + +template +class ProcessorBase; + +// FIXME: Remove this once we support SMP in riscv64 +extern Processor* g_current_processor; + +constexpr size_t MAX_CPU_COUNT = 1; + +class Processor final : public ProcessorBase { +public: + template Callback> + static inline IterationDecision for_each(Callback callback) + { + // FIXME: Once we support SMP for riscv64, make sure to call the callback for every processor. + if (callback(*g_current_processor) == IterationDecision::Break) + return IterationDecision::Break; + return IterationDecision::Continue; + } + + template Callback> + static inline IterationDecision for_each(Callback callback) + { + // FIXME: Once we support SMP for riscv64, make sure to call the callback for every processor. + callback(*g_current_processor); + return IterationDecision::Continue; + } +}; + +template +ALWAYS_INLINE bool ProcessorBase::is_initialized() +{ + return g_current_processor != nullptr; +} + +template +ALWAYS_INLINE Thread* ProcessorBase::idle_thread() +{ + return current().m_idle_thread; +} + +template +ALWAYS_INLINE void ProcessorBase::set_current_thread(Thread& current_thread) +{ + current().m_current_thread = ¤t_thread; +} + +// FIXME: When riscv64 supports multiple cores, return the correct core id here. +template +ALWAYS_INLINE u32 ProcessorBase::current_id() +{ + return 0; +} + +template +ALWAYS_INLINE u32 ProcessorBase::in_critical() +{ + return current().m_in_critical; +} + +template +ALWAYS_INLINE void ProcessorBase::enter_critical() +{ + auto& current_processor = current(); + current_processor.m_in_critical += 1; +} + +template +ALWAYS_INLINE void ProcessorBase::restore_critical(u32 prev_critical) +{ + current().m_in_critical = prev_critical; +} + +template +ALWAYS_INLINE T& ProcessorBase::current() +{ + return *g_current_processor; +} + +template +void ProcessorBase::idle_begin() const +{ + // FIXME: Implement this when SMP for riscv64 is supported. +} + +template +void ProcessorBase::idle_end() const +{ + // FIXME: Implement this when SMP for riscv64 is supported. +} + +template +void ProcessorBase::smp_enable() +{ + // FIXME: Implement this when SMP for riscv64 is supported. +} + +template +bool ProcessorBase::is_smp_enabled() +{ + return false; +} + +template +ALWAYS_INLINE bool ProcessorBase::are_interrupts_enabled() +{ + return RISCV64::CSR::SSTATUS::read().SIE == 1; +} + +template +ALWAYS_INLINE void ProcessorBase::enable_interrupts() +{ + RISCV64::CSR::set_bits(RISCV64::CSR::Address::SSTATUS, 1 << to_underlying(RISCV64::CSR::SSTATUS::Offset::SIE)); +} + +template +ALWAYS_INLINE void ProcessorBase::disable_interrupts() +{ + RISCV64::CSR::clear_bits(RISCV64::CSR::Address::SSTATUS, 1 << to_underlying(RISCV64::CSR::SSTATUS::Offset::SIE)); +} + +template +ALWAYS_INLINE bool ProcessorBase::is_kernel_mode() +{ + // FIXME: Implement this correctly. + return true; +} + +template +ALWAYS_INLINE bool ProcessorBase::current_in_scheduler() +{ + return current().m_in_scheduler; +} + +template +ALWAYS_INLINE void ProcessorBase::set_current_in_scheduler(bool value) +{ + current().m_in_scheduler = value; +} + +template +ALWAYS_INLINE bool ProcessorBase::has_nx() const +{ + return true; +} + +template +ALWAYS_INLINE bool ProcessorBase::has_pat() const +{ + return false; +} + +template +ALWAYS_INLINE FlatPtr ProcessorBase::current_in_irq() +{ + return current().m_in_irq; +} + +template +ALWAYS_INLINE Thread* ProcessorBase::current_thread() +{ + return current().m_current_thread; +} + +template +ALWAYS_INLINE void ProcessorBase::pause() +{ + TODO_RISCV64(); +} + +template +ALWAYS_INLINE void ProcessorBase::wait_check() +{ + Processor::pause(); + // FIXME: Process SMP messages once we support SMP on riscv64; cf. x86_64 +} + +template +ALWAYS_INLINE u64 ProcessorBase::read_cpu_counter() +{ + TODO_RISCV64(); +} + +} diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 56734f25ed..635a90d43f 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -513,6 +513,7 @@ elseif("${SERENITY_ARCH}" STREQUAL "riscv64") kprintf.cpp Arch/riscv64/boot.S + Arch/riscv64/Processor.cpp Arch/riscv64/SBI.cpp ) diff --git a/Kernel/Library/Assertions.h b/Kernel/Library/Assertions.h index aa0094f5e2..a989ba3d2e 100644 --- a/Kernel/Library/Assertions.h +++ b/Kernel/Library/Assertions.h @@ -27,6 +27,7 @@ extern "C" { #define TODO() __assertion_failed("TODO", __FILE__, __LINE__, __PRETTY_FUNCTION__) #define TODO_AARCH64() __assertion_failed("TODO_AARCH64", __FILE__, __LINE__, __PRETTY_FUNCTION__) +#define TODO_RISCV64() __assertion_failed("TODO_RISCV64", __FILE__, __LINE__, __PRETTY_FUNCTION__) #define VERIFY_INTERRUPTS_DISABLED() VERIFY(!(Processor::are_interrupts_enabled())) #define VERIFY_INTERRUPTS_ENABLED() VERIFY(Processor::are_interrupts_enabled())