1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-26 00:25:08 +00:00
serenity/Kernel/Arch/riscv64/SBI.cpp
Sönke Holz 27087318bc Kernel/riscv64: Add support for SRST "System Reset" SBI extension
This extension will be used for rebooting and shutting down.
2024-01-12 16:25:46 -07:00

204 lines
5.3 KiB
C++

/*
* Copyright (c) 2023, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <Kernel/Arch/riscv64/SBI.h>
namespace Kernel::SBI {
static bool s_sbi_is_legacy = false;
static SBIErrorOr<long> sbi_ecall0(EID extension_id, u32 function_id)
{
register unsigned long a0 asm("a0");
register unsigned long a1 asm("a1");
register unsigned long a6 asm("a6") = function_id;
register unsigned long a7 asm("a7") = to_underlying(extension_id);
asm volatile("ecall"
: "=r"(a0), "=r"(a1)
: "r"(a6), "r"(a7)
: "memory");
if (a0 == to_underlying(SBIError::Success))
return static_cast<long>(a1);
return static_cast<SBIError>(a0);
}
static SBIErrorOr<long> sbi_ecall1(EID extension_id, u32 function_id, unsigned long arg0)
{
register unsigned long a0 asm("a0") = arg0;
register unsigned long a1 asm("a1");
register unsigned long a6 asm("a6") = function_id;
register unsigned long a7 asm("a7") = to_underlying(extension_id);
asm volatile("ecall"
: "+r"(a0), "=r"(a1)
: "r"(a0), "r"(a6), "r"(a7)
: "memory");
if (a0 == to_underlying(SBIError::Success))
return static_cast<long>(a1);
return static_cast<SBIError>(a0);
}
static SBIErrorOr<long> sbi_ecall2(EID extension_id, u32 function_id, unsigned long arg0, unsigned long arg1)
{
register unsigned long a0 asm("a0") = arg0;
register unsigned long a1 asm("a1") = arg1;
register unsigned long a6 asm("a6") = function_id;
register unsigned long a7 asm("a7") = to_underlying(extension_id);
asm volatile("ecall"
: "+r"(a0), "+r"(a1)
: "r"(a0), "r"(a1), "r"(a6), "r"(a7)
: "memory");
if (a0 == to_underlying(SBIError::Success))
return static_cast<long>(a1);
return static_cast<SBIError>(a0);
}
namespace Base {
SBIErrorOr<SpecificationVersion> get_spec_version()
{
auto version = TRY(SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetSpecVersion)));
return bit_cast<SpecificationVersion>(static_cast<u32>(version));
}
SBIErrorOr<long> get_impl_id()
{
return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetImplID));
}
SBIErrorOr<long> get_impl_version()
{
return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetImplVersion));
}
SBIErrorOr<long> probe_extension(EID extension_id)
{
return SBI::sbi_ecall1(EID::Base, to_underlying(FID::ProbeExtension), to_underlying(extension_id));
}
SBIErrorOr<long> get_mvendorid()
{
return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetMVENDORID));
}
SBIErrorOr<long> get_marchid()
{
return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetMARCHID));
}
SBIErrorOr<long> get_mimpid()
{
return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetMIMPID));
}
}
namespace Legacy {
static long sbi_legacy_ecall0(LegacyEID extension_id)
{
register unsigned long a0 asm("a0");
register unsigned long a7 asm("a7") = to_underlying(extension_id);
asm volatile("ecall"
: "=r"(a0)
: "r"(a7)
: "memory");
return static_cast<long>(a0);
}
static long sbi_legacy_ecall1(LegacyEID extension_id, unsigned long arg0)
{
register unsigned long a0 asm("a0") = arg0;
register unsigned long a7 asm("a7") = to_underlying(extension_id);
asm volatile("ecall"
: "+r"(a0)
: "r"(a0), "r"(a7)
: "memory");
return static_cast<long>(a0);
}
LegacySBIErrorOr<void> set_timer(u64 stime_value)
{
auto err = sbi_legacy_ecall1(LegacyEID::SetTimer, stime_value);
if (err == 0)
return {};
return err;
}
LegacySBIErrorOr<void> console_putchar(int ch)
{
auto err = sbi_legacy_ecall1(LegacyEID::ConsolePutchar, ch);
if (err == 0)
return {};
return err;
}
void shutdown()
{
sbi_legacy_ecall0(LegacyEID::SystemShutdown);
VERIFY_NOT_REACHED();
}
}
namespace Timer {
SBIErrorOr<void> set_timer(u64 stime_value)
{
TRY(SBI::sbi_ecall1(EID::Timer, to_underlying(FID::SetTimer), stime_value));
return {};
}
}
namespace SystemReset {
SBIError system_reset(ResetType reset_type, ResetReason reset_reason)
{
auto const res = SBI::sbi_ecall2(EID::SystemReset, to_underlying(FID::SystemReset), to_underlying(reset_type), to_underlying(reset_reason));
// This SBI call shold only return if it didn't succeed
VERIFY(res.is_error());
return res.error();
}
}
namespace DBCN {
SBIErrorOr<void> debug_console_write_byte(u8 byte)
{
TRY(SBI::sbi_ecall1(EID::DebugConsole, to_underlying(FID::DebugConsoleWriteByte), byte));
return {};
}
}
void initialize()
{
auto spec_version = Base::get_spec_version();
if (spec_version.is_error()) {
s_sbi_is_legacy = true;
dbgln("SBI: Specification version: 0.1");
} else {
dbgln("SBI: Specification version: {}", spec_version.value());
dbgln("SBI: Implementation ID: {}", MUST(Base::get_impl_id()));
dbgln("SBI: Implementation version: {:#x}", MUST(Base::get_impl_version()));
dbgln("SBI: mvendorid: {:#x}", MUST(Base::get_mvendorid()));
dbgln("SBI: marchid: {:#x}", MUST(Base::get_marchid()));
dbgln("SBI: mimpid: {:#x}", MUST(Base::get_mimpid()));
}
}
}