use crate::binary::{sbi_call_0, sbi_call_1};
use sbi_spec::base::{
EID_BASE, GET_MARCHID, GET_MIMPID, GET_MVENDORID, GET_SBI_IMPL_ID, GET_SBI_IMPL_VERSION,
GET_SBI_SPEC_VERSION, PROBE_EXTENSION, Version,
};
#[inline]
#[doc(alias = "sbi_get_spec_version")]
pub fn get_spec_version() -> Version {
Version::from_raw(sbi_call_0(EID_BASE, GET_SBI_SPEC_VERSION).value)
}
#[inline]
#[doc(alias = "sbi_get_impl_id")]
pub fn get_sbi_impl_id() -> usize {
sbi_call_0(EID_BASE, GET_SBI_IMPL_ID).value
}
#[inline]
#[doc(alias = "sbi_get_impl_version")]
pub fn get_sbi_impl_version() -> usize {
sbi_call_0(EID_BASE, GET_SBI_IMPL_VERSION).value
}
#[inline]
#[doc(alias = "sbi_probe_extension")]
pub fn probe_extension<E>(extension: E) -> ExtensionInfo
where
E: Extension,
{
let ans = sbi_call_1(EID_BASE, PROBE_EXTENSION, extension.extension_id());
ExtensionInfo { raw: ans.value }
}
#[inline]
#[doc(alias = "sbi_get_mvendorid")]
pub fn get_mvendorid() -> usize {
sbi_call_0(EID_BASE, GET_MVENDORID).value
}
#[inline]
#[doc(alias = "sbi_get_marchid")]
pub fn get_marchid() -> usize {
sbi_call_0(EID_BASE, GET_MARCHID).value
}
#[inline]
#[doc(alias = "sbi_get_mimpid")]
pub fn get_mimpid() -> usize {
sbi_call_0(EID_BASE, GET_MIMPID).value
}
pub trait Extension {
fn extension_id(&self) -> usize;
}
macro_rules! define_extension {
($($struct:ident($value:expr) #[$doc:meta])*) => {
$(
#[derive(Clone, Copy, Debug)]
#[$doc]
pub struct $struct;
impl Extension for $struct {
#[inline]
fn extension_id(&self) -> usize {
$value
}
}
)*
};
}
define_extension! {
Base(sbi_spec::base::EID_BASE) Timer(sbi_spec::time::EID_TIME) Ipi(sbi_spec::spi::EID_SPI) Fence(sbi_spec::rfnc::EID_RFNC) Hsm(sbi_spec::hsm::EID_HSM) Reset(sbi_spec::srst::EID_SRST) Pmu(sbi_spec::pmu::EID_PMU) Console(sbi_spec::dbcn::EID_DBCN) Suspend(sbi_spec::susp::EID_SUSP) Cppc(sbi_spec::cppc::EID_CPPC) Nacl(sbi_spec::nacl::EID_NACL) Sta(sbi_spec::sta::EID_STA) Sse(sbi_spec::sse::EID_SSE) Fwft(sbi_spec::fwft::EID_FWFT) Dbtr(sbi_spec::dbtr::EID_DBTR) Mpxy(sbi_spec::mpxy::EID_MPXY) }
#[cfg(feature = "integer-impls")]
impl Extension for usize {
#[inline]
fn extension_id(&self) -> usize {
*self
}
}
#[cfg(feature = "integer-impls")]
impl Extension for isize {
#[inline]
fn extension_id(&self) -> usize {
usize::from_ne_bytes(isize::to_ne_bytes(*self))
}
}
#[derive(Clone, Copy, Debug)]
pub struct ExtensionInfo {
pub raw: usize,
}
impl ExtensionInfo {
#[inline]
pub const fn is_available(&self) -> bool {
self.raw != 0
}
#[inline]
pub const fn is_unavailable(&self) -> bool {
self.raw == 0
}
}
#[cfg(test)]
mod tests {
#[test]
fn extension_id_defined() {
use crate::Extension;
assert_eq!(crate::Base.extension_id(), 0x10);
assert_eq!(crate::Timer.extension_id(), 0x54494D45);
assert_eq!(crate::Ipi.extension_id(), 0x735049);
assert_eq!(crate::Fence.extension_id(), 0x52464E43);
assert_eq!(crate::Hsm.extension_id(), 0x48534D);
assert_eq!(crate::Reset.extension_id(), 0x53525354);
assert_eq!(crate::Pmu.extension_id(), 0x504D55);
assert_eq!(crate::Console.extension_id(), 0x4442434E);
assert_eq!(crate::Suspend.extension_id(), 0x53555350);
assert_eq!(crate::Cppc.extension_id(), 0x43505043);
assert_eq!(crate::Nacl.extension_id(), 0x4E41434C);
assert_eq!(crate::Sta.extension_id(), 0x535441);
assert_eq!(crate::Sse.extension_id(), 0x535345);
assert_eq!(crate::Fwft.extension_id(), 0x46574654);
assert_eq!(crate::Dbtr.extension_id(), 0x44425452);
assert_eq!(crate::Mpxy.extension_id(), 0x4D505859);
}
}