Kernel/riscv64: Add RISC-V Processor class

This commit is contained in:
Sönke Holz 2023-10-21 16:23:58 +02:00 committed by Andrew Kaster
parent 24e64cac7e
commit 194bf5a677
Notes: sideshowbarker 2024-07-17 11:29:41 +09:00
7 changed files with 406 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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();
}
}

View file

@ -513,6 +513,7 @@ elseif("${SERENITY_ARCH}" STREQUAL "riscv64")
kprintf.cpp
Arch/riscv64/boot.S
Arch/riscv64/Processor.cpp
Arch/riscv64/SBI.cpp
)

View file

@ -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())