소스 검색

Kernel/riscv64: Add basic SBI support

Sönke Holz 1 년 전
부모
커밋
9bd3c542b4
3개의 변경된 파일339개의 추가작업 그리고 1개의 파일을 삭제
  1. 156 0
      Kernel/Arch/riscv64/SBI.cpp
  2. 180 0
      Kernel/Arch/riscv64/SBI.h
  3. 3 1
      Kernel/CMakeLists.txt

+ 156 - 0
Kernel/Arch/riscv64/SBI.cpp

@@ -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 - 0
Kernel/Arch/riscv64/SBI.h

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

+ 3 - 1
Kernel/CMakeLists.txt

@@ -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)