Kernel/riscv64: Add basic SBI support

This commit is contained in:
Sönke Holz 2023-09-02 22:52:30 +02:00 committed by Andrew Kaster
parent 84777fbe62
commit 9bd3c542b4
Notes: sideshowbarker 2024-07-16 23:03:06 +09:00
3 changed files with 339 additions and 1 deletions

156
Kernel/Arch/riscv64/SBI.cpp Normal file
View file

@ -0,0 +1,156 @@
/*
* 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);
}
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_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;
}
}
namespace Timer {
SBIErrorOr<void> set_timer(u64 stime_value)
{
TRY(SBI::sbi_ecall1(EID::Timer, to_underlying(FID::SetTimer), stime_value));
return {};
}
}
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()));
}
}
}

180
Kernel/Arch/riscv64/SBI.h Normal file
View file

@ -0,0 +1,180 @@
/*
* Copyright (c) 2023, Sönke Holz <sholz8530@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Error.h>
#include <AK/Format.h>
// Documentation about the SBI:
// RISC-V Supervisor Binary Interface Specification (https://github.com/riscv-non-isa/riscv-sbi-doc)
namespace Kernel::SBI {
// Chapter 3. Binary Encoding
enum class SBIError : long {
// SBI_SUCCESS: Completed successfully
Success = 0,
// SBI_ERR_FAILED: Failed
Failed = -1,
// SBI_ERR_NOT_SUPPORTED: Not supported
NotSupported = -2,
// SBI_ERR_INVALID_PARAM: Invalid parameter(s)
InvalidParam = -3,
// SBI_ERR_DENIED: Denied or not allowed
Denied = -4,
// SBI_ERR_INVALID_ADDRESS: Invalid address(s)
InvalidAddress = -5,
// SBI_ERR_ALREADY_AVAILABLE: Already available
AlreadyAvailable = -6,
// SBI_ERR_ALREADY_STARTED: Already started
AlreadyStarted = -7,
// SBI_ERR_ALREADY_STOPPED: Already stopped
AlreadyStopped = -8,
// SBI_ERR_NO_SHMEM: Shared memory not available
NoSHMEM = -9,
};
template<typename T>
using SBIErrorOr = ErrorOr<T, SBIError>;
enum class EID : i32 {
// Base Extension
Base = 0x10,
// Debug Console Extension ("DBCN")
DebugConsole = 0x4442434E,
// Timer Extension ("TIME")
Timer = 0x54494D45,
};
// Chapter 4. Base Extension (EID #0x10)
// Required extension since SBI v0.2
namespace Base {
enum class FID : i32 {
GetSpecVersion = 0,
GetImplID = 1,
GetImplVersion = 2,
ProbeExtension = 3,
GetMVENDORID = 4,
GetMARCHID = 5,
GetMIMPID = 6,
};
struct SpecificationVersion {
u32 minor : 24;
u32 major : 7;
u32 reserved : 1;
};
static_assert(AssertSize<SpecificationVersion, 4>());
// Get SBI specification version (FID #0)
// Returns the current SBI specification version. This function must always succeed.
// The minor number of the SBI specification is encoded in the low 24 bits,
// with the major number encoded in the next 7 bits. Bit 31 must be 0 and is reserved for future expansion.
SBIErrorOr<SpecificationVersion> get_spec_version();
// Get SBI implementation ID (FID #1)
// Returns the current SBI implementation ID, which is different for every SBI implementation. It is
// intended that this implementation ID allows software to probe for SBI implementation quirks.
SBIErrorOr<long> get_impl_id();
// Get SBI implementation version (FID #2)
// Returns the current SBI implementation version. The encoding of this version number is specific to
// the SBI implementation.
SBIErrorOr<long> get_impl_version();
// Probe SBI extension (FID #3)
// Returns 0 if the given SBI extension ID (EID) is not available, or 1 if it is available unless defined as
// any other non-zero value by the implementation.
SBIErrorOr<long> probe_extension(EID extension_id);
// Get machine vendor ID (FID #4)
// Return a value that is legal for the mvendorid CSR and 0 is always a legal value for this CSR.
SBIErrorOr<long> get_mvendorid();
// Get machine architecture ID (FID #5)
// Return a value that is legal for the marchid CSR and 0 is always a legal value for this CSR.
SBIErrorOr<long> get_marchid();
// Get machine implementation ID (FID #6)
// Return a value that is legal for the mimpid CSR and 0 is always a legal value for this CSR.
SBIErrorOr<long> get_mimpid();
}
// Chapter 5. Legacy Extensions (EIDs #0x00 - #0x0F)
namespace Legacy {
enum class LegacyEID : i32 {
SetTimer = 0,
ConsolePutchar = 1,
ConsoleGetchar = 2,
ClearIPI = 3,
SendIPI = 4,
RemoteFENCEI = 5,
RemoteSFENCEVMA = 6,
RemoteSFENCEVMAWithASID = 7,
SystemShutdown = 8,
};
template<typename T>
using LegacySBIErrorOr = ErrorOr<T, long>;
// Set Timer (EID #0x00)
// Programs the clock for next event after stime_value time. This function also clears the pending
// timer interrupt bit.
LegacySBIErrorOr<void> set_timer(u64 stime_value);
// Console Putchar (EID #0x01)
// Write data present in ch to debug console.
LegacySBIErrorOr<void> console_putchar(int ch);
}
// Chapter 6. Timer Extension (EID #0x54494D45 "TIME")
// Since SBI v0.2
namespace Timer {
enum class FID : i32 {
SetTimer = 0,
};
// Set Timer (FID #0)
// Programs the clock for next event after stime_value time. stime_value is in absolute time. This
// function must clear the pending timer interrupt bit as well.
SBIErrorOr<void> set_timer(u64 stime_value);
}
// Chapter 12. Debug Console Extension (EID #0x4442434E "DBCN")
// Since SBI v2.0
namespace DBCN {
enum class FID : i32 {
DebugConsoleWrite = 0,
DebugConsoleRead = 1,
DebugConsoleWriteByte = 2,
};
// Console Write Byte (FID #2)
// Write a single byte to the debug console.
SBIErrorOr<void> debug_console_write_byte(u8 byte);
}
void initialize();
}
template<>
struct AK::Formatter<Kernel::SBI::Base::SpecificationVersion> : Formatter<FormatString> {
ErrorOr<void> format(FormatBuilder& builder, Kernel::SBI::Base::SpecificationVersion const& version)
{
VERIFY(version.reserved == 0);
return Formatter<FormatString>::format(builder, "{}.{}"sv, version.major, version.minor);
}
};

View file

@ -499,9 +499,11 @@ elseif("${SERENITY_ARCH}" STREQUAL "aarch64")
elseif("${SERENITY_ARCH}" STREQUAL "riscv64")
set(KERNEL_SOURCES
${KERNEL_SOURCES}
Arch/riscv64/boot.S
Arch/Processor.cpp
kprintf.cpp
Arch/riscv64/boot.S
Arch/riscv64/SBI.cpp
)
add_compile_options(-fno-stack-protector -fno-sanitize=all)