Newer
Older
minerva / Kernel / Arch / riscv64 / SBI.h
@minerva minerva on 13 Jul 7 KB Initial commit
/*
 * 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>
#include <AK/StdLibExtras.h>

// Documentation about the SBI:
// RISC-V Supervisor Binary Interface Specification (https://github.com/riscv-non-isa/riscv-sbi-doc)

namespace Kernel::SBI {

// Returns true if the SBI version is 0.1.
bool is_legacy();

// 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,
    // System Reset Extension ("SRST")
    SystemReset = 0x53525354,
    // 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);

// System Shutdown (EID #0x08)
// Puts all the harts to shutdown state from supervisor point of view.
// This SBI call doesn’t return irrespective whether it succeeds or fails.
[[noreturn]] void shutdown();

}

// 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 10. System Reset Extension (EID #0x53525354 "SRST")
// Since SBI v0.2
namespace SystemReset {

enum class FID : i32 {
    SystemReset = 0,
};

enum class ResetType : u32 {
    Shutdown = 0x0,
    ColdReboot = 0x1,
    WarmReboot = 0x2,
};

enum class ResetReason : u32 {
    NoReason = 0x0,
    SystemFailure = 0x1,
};

// System reset (FID #0)
// Reset the system based on provided reset_type and reset_reason. This is a synchronous call and
// does not return if it succeeds.
SBIError system_reset(ResetType reset_type, ResetReason reset_reason);

}

// 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::SBIError> : Formatter<StringView> {
    ErrorOr<void> format(FormatBuilder& builder, Kernel::SBI::SBIError error)
    {
        auto string = "Unknown error"sv;

        using enum Kernel::SBI::SBIError;
        switch (error) {
        case Success:
            string = "Completed successfully"sv;
            break;
        case Failed:
            string = "Failed"sv;
            break;
        case NotSupported:
            string = "Not supported"sv;
            break;
        case InvalidParam:
            string = "Invalid parameter(s)"sv;
            break;
        case Denied:
            string = "Denied or not allowed"sv;
            break;
        case InvalidAddress:
            string = "Invalid address(s)"sv;
            break;
        case AlreadyAvailable:
            string = "Already available"sv;
            break;
        case AlreadyStarted:
            string = "Already started"sv;
            break;
        case AlreadyStopped:
            string = "Already stopped"sv;
            break;
        case NoSHMEM:
            string = "Shared memory not available"sv;
            break;
        }

        return builder.put_string(string);
    }
};

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);
    }
};