mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
Kernel/riscv64: Add RISC-V Processor class
This commit is contained in:
parent
24e64cac7e
commit
194bf5a677
Notes:
sideshowbarker
2024-07-17 11:29:41 +09:00
Author: https://github.com/spholz Commit: https://github.com/SerenityOS/serenity/commit/194bf5a677 Pull-request: https://github.com/SerenityOS/serenity/pull/21504 Reviewed-by: https://github.com/ADKaster
7 changed files with 406 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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
Kernel/Arch/riscv64/CPUID.h
Normal file
17
Kernel/Arch/riscv64/CPUID.h
Normal 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
|
168
Kernel/Arch/riscv64/Processor.cpp
Normal file
168
Kernel/Arch/riscv64/Processor.cpp
Normal 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>
|
215
Kernel/Arch/riscv64/Processor.h
Normal file
215
Kernel/Arch/riscv64/Processor.h
Normal 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 = ¤t_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();
|
||||
}
|
||||
|
||||
}
|
|
@ -513,6 +513,7 @@ elseif("${SERENITY_ARCH}" STREQUAL "riscv64")
|
|||
kprintf.cpp
|
||||
|
||||
Arch/riscv64/boot.S
|
||||
Arch/riscv64/Processor.cpp
|
||||
Arch/riscv64/SBI.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
Loading…
Reference in a new issue