/* * Copyright (c) 2023, Sönke Holz * * SPDX-License-Identifier: BSD-2-Clause */ #include #include namespace Kernel::SBI { static bool s_sbi_is_legacy = false; static SBIErrorOr 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(a1); return static_cast(a0); } static SBIErrorOr 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(a1); return static_cast(a0); } namespace Base { SBIErrorOr get_spec_version() { auto version = TRY(SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetSpecVersion))); return bit_cast(static_cast(version)); } SBIErrorOr get_impl_id() { return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetImplID)); } SBIErrorOr get_impl_version() { return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetImplVersion)); } SBIErrorOr probe_extension(EID extension_id) { return SBI::sbi_ecall1(EID::Base, to_underlying(FID::ProbeExtension), to_underlying(extension_id)); } SBIErrorOr get_mvendorid() { return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetMVENDORID)); } SBIErrorOr get_marchid() { return SBI::sbi_ecall0(EID::Base, to_underlying(FID::GetMARCHID)); } SBIErrorOr 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(a0); } LegacySBIErrorOr set_timer(u64 stime_value) { auto err = sbi_legacy_ecall1(LegacyEID::SetTimer, stime_value); if (err == 0) return {}; return err; } LegacySBIErrorOr console_putchar(int ch) { auto err = sbi_legacy_ecall1(LegacyEID::ConsolePutchar, ch); if (err == 0) return {}; return err; } } namespace Timer { SBIErrorOr set_timer(u64 stime_value) { TRY(SBI::sbi_ecall1(EID::Timer, to_underlying(FID::SetTimer), stime_value)); return {}; } } namespace DBCN { SBIErrorOr 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())); } } }