mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 04:37:34 +00:00
Kernel/riscv64: Add basic SBI support
This commit is contained in:
parent
84777fbe62
commit
9bd3c542b4
3 changed files with 339 additions and 1 deletions
156
Kernel/Arch/riscv64/SBI.cpp
Normal file
156
Kernel/Arch/riscv64/SBI.cpp
Normal 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
180
Kernel/Arch/riscv64/SBI.h
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
|
@ -499,9 +499,11 @@ elseif("${SERENITY_ARCH}" STREQUAL "aarch64")
|
||||||
elseif("${SERENITY_ARCH}" STREQUAL "riscv64")
|
elseif("${SERENITY_ARCH}" STREQUAL "riscv64")
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
Arch/riscv64/boot.S
|
|
||||||
Arch/Processor.cpp
|
Arch/Processor.cpp
|
||||||
kprintf.cpp
|
kprintf.cpp
|
||||||
|
|
||||||
|
Arch/riscv64/boot.S
|
||||||
|
Arch/riscv64/SBI.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_compile_options(-fno-stack-protector -fno-sanitize=all)
|
add_compile_options(-fno-stack-protector -fno-sanitize=all)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue