Browse Source

Kernel/riscv64: Add RISC-V Processor class

Sönke Holz 1 year ago
parent
commit
194bf5a677

+ 2 - 0
Kernel/Arch/CPUID.h

@@ -12,6 +12,8 @@
 #    include <Kernel/Arch/x86_64/CPUID.h>
 #elif ARCH(AARCH64)
 #    include <Kernel/Arch/aarch64/CPUID.h>
+#elif ARCH(RISCV64)
+#    include <Kernel/Arch/riscv64/CPUID.h>
 #else
 #    error "Unknown architecture"
 #endif

+ 2 - 0
Kernel/Arch/Processor.h

@@ -210,6 +210,8 @@ template class ProcessorBase<Processor>;
 #    include <Kernel/Arch/x86_64/Processor.h>
 #elif ARCH(AARCH64)
 #    include <Kernel/Arch/aarch64/Processor.h>
+#elif ARCH(RISCV64)
+#    include <Kernel/Arch/riscv64/Processor.h>
 #else
 #    error "Unknown architecture"
 #endif

+ 17 - 0
Kernel/Arch/riscv64/CPUID.h

@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2023, Sönke Holz <sholz8530@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/ArbitrarySizedEnum.h>
+#include <AK/Types.h>
+#include <AK/UFixedBigInt.h>
+
+#include <AK/Platform.h>
+VALIDATE_IS_RISCV64()
+
+AK_MAKE_ARBITRARY_SIZED_ENUM(CPUFeature, u256,
+    __End = CPUFeature(1u) << 255u) // SENTINEL VALUE

+ 168 - 0
Kernel/Arch/riscv64/Processor.cpp

@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2023, Sönke Holz <sholz8530@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/Arch/Interrupts.h>
+#include <Kernel/Arch/Processor.h>
+#include <Kernel/Arch/TrapFrame.h>
+#include <Kernel/Interrupts/InterruptDisabler.h>
+#include <Kernel/Sections.h>
+#include <Kernel/Security/Random.h>
+#include <Kernel/Tasks/Process.h>
+#include <Kernel/Tasks/Scheduler.h>
+
+namespace Kernel {
+
+Processor* g_current_processor;
+
+template<typename T>
+void ProcessorBase<T>::early_initialize(u32 cpu)
+{
+    VERIFY(g_current_processor == nullptr);
+    m_cpu = cpu;
+
+    g_current_processor = static_cast<Processor*>(this);
+}
+
+template<typename T>
+void ProcessorBase<T>::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<typename T>
+[[noreturn]] void ProcessorBase<T>::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<typename T>
+void ProcessorBase<T>::flush_tlb_local(VirtualAddress, size_t)
+{
+    // FIXME: Don't flush all pages
+    flush_entire_tlb_local();
+}
+
+template<typename T>
+void ProcessorBase<T>::flush_entire_tlb_local()
+{
+    asm volatile("sfence.vma");
+}
+
+template<typename T>
+void ProcessorBase<T>::flush_tlb(Memory::PageDirectory const*, VirtualAddress vaddr, size_t page_count)
+{
+    flush_tlb_local(vaddr, page_count);
+}
+
+template<typename T>
+u32 ProcessorBase<T>::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<typename T>
+u32 ProcessorBase<T>::smp_wake_n_idle_processors(u32)
+{
+    // FIXME: Actually wake up other cores when SMP is supported for riscv64.
+    return 0;
+}
+
+template<typename T>
+void ProcessorBase<T>::initialize_context_switching(Thread&)
+{
+    TODO_RISCV64();
+}
+
+template<typename T>
+void ProcessorBase<T>::switch_context(Thread*&, Thread*&)
+{
+    TODO_RISCV64();
+}
+
+extern "C" FlatPtr do_init_context(Thread*, u32)
+{
+    TODO_RISCV64();
+}
+
+template<typename T>
+void ProcessorBase<T>::assume_context(Thread&, InterruptsState)
+{
+    TODO_RISCV64();
+}
+
+template<typename T>
+FlatPtr ProcessorBase<T>::init_context(Thread&, bool)
+{
+    TODO_RISCV64();
+}
+
+template<typename T>
+void ProcessorBase<T>::exit_trap(TrapFrame&)
+{
+    TODO_RISCV64();
+}
+
+template<typename T>
+ErrorOr<Vector<FlatPtr, 32>> ProcessorBase<T>::capture_stack_trace(Thread&, size_t)
+{
+    dbgln("FIXME: Implement Processor::capture_stack_trace() for riscv64");
+    return Vector<FlatPtr, 32> {};
+}
+
+NAKED void thread_context_first_enter(void)
+{
+    asm("unimp");
+}
+
+NAKED void do_assume_context(Thread*, u32)
+{
+    asm("unimp");
+}
+
+template<typename T>
+StringView ProcessorBase<T>::platform_string()
+{
+    return "riscv64"sv;
+}
+
+template<typename T>
+void ProcessorBase<T>::set_thread_specific_data(VirtualAddress)
+{
+    TODO_RISCV64();
+}
+
+template<typename T>
+void ProcessorBase<T>::wait_for_interrupt() const
+{
+    asm("wfi");
+}
+
+template<typename T>
+Processor& ProcessorBase<T>::by_id(u32)
+{
+    TODO_RISCV64();
+}
+
+}
+
+#include <Kernel/Arch/ProcessorFunctions.include>

+ 215 - 0
Kernel/Arch/riscv64/Processor.h

@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2023, Sönke Holz <sholz8530@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Function.h>
+#include <AK/Types.h>
+#include <AK/Vector.h>
+
+#include <Kernel/API/POSIX/errno.h>
+#include <Kernel/Arch/DeferredCallPool.h>
+#include <Kernel/Arch/ProcessorSpecificDataID.h>
+#include <Kernel/Arch/riscv64/CSR.h>
+#include <Kernel/Memory/VirtualAddress.h>
+
+#include <AK/Platform.h>
+VALIDATE_IS_RISCV64()
+
+namespace Kernel {
+
+namespace Memory {
+class PageDirectory;
+};
+
+class Thread;
+class Processor;
+struct TrapFrame;
+enum class InterruptsState;
+
+template<typename ProcessorT>
+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<Processor> {
+public:
+    template<IteratorFunction<Processor&> 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<VoidFunction<Processor&> 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<typename T>
+ALWAYS_INLINE bool ProcessorBase<T>::is_initialized()
+{
+    return g_current_processor != nullptr;
+}
+
+template<typename T>
+ALWAYS_INLINE Thread* ProcessorBase<T>::idle_thread()
+{
+    return current().m_idle_thread;
+}
+
+template<typename T>
+ALWAYS_INLINE void ProcessorBase<T>::set_current_thread(Thread& current_thread)
+{
+    current().m_current_thread = &current_thread;
+}
+
+// FIXME: When riscv64 supports multiple cores, return the correct core id here.
+template<typename T>
+ALWAYS_INLINE u32 ProcessorBase<T>::current_id()
+{
+    return 0;
+}
+
+template<typename T>
+ALWAYS_INLINE u32 ProcessorBase<T>::in_critical()
+{
+    return current().m_in_critical;
+}
+
+template<typename T>
+ALWAYS_INLINE void ProcessorBase<T>::enter_critical()
+{
+    auto& current_processor = current();
+    current_processor.m_in_critical += 1;
+}
+
+template<typename T>
+ALWAYS_INLINE void ProcessorBase<T>::restore_critical(u32 prev_critical)
+{
+    current().m_in_critical = prev_critical;
+}
+
+template<typename T>
+ALWAYS_INLINE T& ProcessorBase<T>::current()
+{
+    return *g_current_processor;
+}
+
+template<typename T>
+void ProcessorBase<T>::idle_begin() const
+{
+    // FIXME: Implement this when SMP for riscv64 is supported.
+}
+
+template<typename T>
+void ProcessorBase<T>::idle_end() const
+{
+    // FIXME: Implement this when SMP for riscv64 is supported.
+}
+
+template<typename T>
+void ProcessorBase<T>::smp_enable()
+{
+    // FIXME: Implement this when SMP for riscv64 is supported.
+}
+
+template<typename T>
+bool ProcessorBase<T>::is_smp_enabled()
+{
+    return false;
+}
+
+template<typename T>
+ALWAYS_INLINE bool ProcessorBase<T>::are_interrupts_enabled()
+{
+    return RISCV64::CSR::SSTATUS::read().SIE == 1;
+}
+
+template<typename T>
+ALWAYS_INLINE void ProcessorBase<T>::enable_interrupts()
+{
+    RISCV64::CSR::set_bits(RISCV64::CSR::Address::SSTATUS, 1 << to_underlying(RISCV64::CSR::SSTATUS::Offset::SIE));
+}
+
+template<typename T>
+ALWAYS_INLINE void ProcessorBase<T>::disable_interrupts()
+{
+    RISCV64::CSR::clear_bits(RISCV64::CSR::Address::SSTATUS, 1 << to_underlying(RISCV64::CSR::SSTATUS::Offset::SIE));
+}
+
+template<typename T>
+ALWAYS_INLINE bool ProcessorBase<T>::is_kernel_mode()
+{
+    // FIXME: Implement this correctly.
+    return true;
+}
+
+template<typename T>
+ALWAYS_INLINE bool ProcessorBase<T>::current_in_scheduler()
+{
+    return current().m_in_scheduler;
+}
+
+template<typename T>
+ALWAYS_INLINE void ProcessorBase<T>::set_current_in_scheduler(bool value)
+{
+    current().m_in_scheduler = value;
+}
+
+template<typename T>
+ALWAYS_INLINE bool ProcessorBase<T>::has_nx() const
+{
+    return true;
+}
+
+template<typename T>
+ALWAYS_INLINE bool ProcessorBase<T>::has_pat() const
+{
+    return false;
+}
+
+template<typename T>
+ALWAYS_INLINE FlatPtr ProcessorBase<T>::current_in_irq()
+{
+    return current().m_in_irq;
+}
+
+template<typename T>
+ALWAYS_INLINE Thread* ProcessorBase<T>::current_thread()
+{
+    return current().m_current_thread;
+}
+
+template<typename T>
+ALWAYS_INLINE void ProcessorBase<T>::pause()
+{
+    TODO_RISCV64();
+}
+
+template<typename T>
+ALWAYS_INLINE void ProcessorBase<T>::wait_check()
+{
+    Processor::pause();
+    // FIXME: Process SMP messages once we support SMP on riscv64; cf. x86_64
+}
+
+template<typename T>
+ALWAYS_INLINE u64 ProcessorBase<T>::read_cpu_counter()
+{
+    TODO_RISCV64();
+}
+
+}

+ 1 - 0
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
     )
 

+ 1 - 0
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())