Kernel/riscv64: Add basic SBI support
This commit is contained in:
parent
84777fbe62
commit
9bd3c542b4
Notes:
sideshowbarker
2024-07-16 23:03:06 +09:00
Author: https://github.com/spholz Commit: https://github.com/SerenityOS/serenity/commit/9bd3c542b4 Pull-request: https://github.com/SerenityOS/serenity/pull/20920 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/LucasChollet
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")
|
||||
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)
|
||||
|
|
Loading…
Add table
Reference in a new issue