rustsbi 0.4.0

Minimal RISC-V's SBI implementation library in Rust
Documentation
use spec::{
    binary::{SbiRet, SharedPtr},
    nacl::shmem_size::NATIVE,
};

/// Nested Acceleration extension.
///
/// Nested virtualization is the ability of a hypervisor to run another hypervisor
/// as a guest. RISC-V nested virtualization requires an L0 hypervisor (running
/// in hypervisor-mode) to trap-and-emulate the RISC-V H-extension functionality
/// (such as CSR accesses, HFENCE instructions, HLV/HSV instructions,
/// etc.) for the L1 hypervisor (running in virtualized supervisor-mode).
///
/// The SBI nested acceleration extension defines a shared memory based interface
/// between the SBI implementation (or L0 hypervisor) and the supervisor software
/// (or L1 hypervisor), which allows both to collaboratively reduce traps taken
/// by the L0 hypervisor for emulating RISC-V H-extension functionality. The
/// nested acceleration shared memory allows the L1 hypervisor to batch multiple
/// RISC-V H-extension CSR accesses and HFENCE requests which are then emulated
/// by the L0 hypervisor upon an explicit synchronization SBI call.
///
/// *NOTE:* The M-mode firmware should not implement the SBI nested acceleration
/// extension if the underlying platform has the RISC-V H-extension implemented
/// in hardware.
pub trait Nacl {
    /// Probe nested acceleration feature.
    ///
    /// Probe a nested acceleration feature. This is a mandatory function of the
    /// SBI nested acceleration extension.
    ///
    /// # Parameters
    ///
    /// The `feature_id` parameter specifies the nested acceleration feature to probe.
    ///
    /// # Return Value
    ///
    /// This function always returns SBI_SUCCESS in `SbiRet.error`. It returns `0`
    /// in `SbiRet.value` if the given `feature_id` is not available, or `1` in
    /// `SbiRet.value` if it is available.
    fn probe_feature(&self, feature_id: u32) -> SbiRet;
    /// Set nested acceleration shared memory.
    ///
    /// Set and enable the shared memory for nested acceleration on the calling
    /// hart.
    ///
    /// # Parameters
    ///
    /// If the physical address of `shmem` is not all-ones bitwise, then the `shmem` pointer
    /// specifies the shared memory physical base address. The physical address of `shmem`
    /// MUST be 4096-byte aligned. The size of the shared memory must be 4096 + (XLEN * 128) bytes.
    /// The SBI implementation MUST zero the shared memory before returning from the SBI
    /// call.
    ///
    /// If the physical address of `shmem` is all-ones bitwise, then the nested acceleration features
    /// are disabled.
    ///
    /// The `flags` parameter is reserved for future use and must be zero.
    ///
    /// # Return Value
    ///
    /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
    ///
    /// | Return code                 | Description
    /// |:----------------------------|:----------------------------------------------
    /// | `SbiRet::success()`         | The steal-time shared memory physical base address was set or cleared successfully.
    /// | `SbiRet::invalid_param()`   | The `flags` parameter is not zero or the `shmem` is not 4096-byte aligned.
    /// | `SbiRet::invalid_address()` | The shared memory pointed to by the `shmem` parameter is not writable or does not satisfy other requirements of shared memory physical address range.
    fn set_shmem(&self, shmem: SharedPtr<[u8; NATIVE]>, flags: usize) -> SbiRet;
    /// Synchronize shared memory CSRs.
    ///
    /// Synchronize CSRs in the nested acceleration shared memory. This is an
    /// optional function that is only available if the SBI_NACL_FEAT_SYNC_CSR
    /// feature is available.
    ///
    /// # Parameters
    ///
    /// The parameter `csr_num` specifies the set of RISC-V H-extension CSRs to be synchronized.
    ///
    /// If `csr_num` is all-ones bitwise, then all RISC-V H-extension CSRs implemented by the SBI
    /// implementation (or L0 hypervisor) are synchronized.
    ///
    /// If `(csr_num & 0x300) == 0x200` and `csr_num < 0x1000` then only a single RISC-V H-extension
    /// CSR specified by the `csr_num` parameter is synchronized.
    ///
    /// # Return Value
    ///
    /// The possible error codes returned in `SbiRet.error` are shown in the table below:
    ///
    /// | Return code               | Description
    /// |:--------------------------|:----------------------------------------------
    /// | `SbiRet::success()`       | CSRs synchronized successfully.
    /// | `SbiRet::not_supported()` | SBI_NACL_FEAT_SYNC_CSR feature is not available.
    /// | `SbiRet::invalid_param()` | `csr_num` is not all-ones bitwise and either: `(csr_num & 0x300) != 0x200` or `csr_num >= 0x1000` or `csr_num` is not implemented by the SBI implementation
    /// | `SbiRet::no_shmem()`      | Nested acceleration shared memory not available.
    fn sync_csr(&self, csr_num: usize) -> SbiRet;
    /// Synchronize shared memory HFENCEs.
    ///
    /// Synchronize HFENCEs in the nested acceleration shared memory. This is an
    /// optional function that is only available if the SBI_NACL_FEAT_SYNC_HFENCE
    /// feature is available.
    ///
    /// # Parameters
    ///
    /// The parameter `entry_index` specifies the set of nested HFENCE entries to be synchronized.
    ///
    /// If `entry_index` is all-ones bitwise, then all nested HFENCE entries are
    /// synchronized.
    ///
    /// If `entry_index < (3840 / XLEN)` then only a single nested HFENCE entry
    /// specified by the `entry_index` parameter is synchronized.
    ///
    /// # Return Value
    ///
    /// The possible error codes returned in `SbiRet.error` are shown in the table below:
    ///
    /// | Return code               | Description
    /// |:--------------------------|:----------------------------------------------
    /// | `SbiRet::success()`       | HFENCEs synchronized successfully.
    /// | `SbiRet::not_supported()` | SBI_NACL_FEAT_SYNC_HFENCE feature is not available.
    /// | `SbiRet::invalid_param()` | `entry_index` is not all-ones bitwise and `entry_index >= (3840 / XLEN)`.
    /// | `SbiRet::no_shmem()`      | Nested acceleration shared memory not available.
    fn sync_hfence(&self, entry_index: usize) -> SbiRet;
    /// Synchronize shared memory and emulate SRET.
    ///
    /// Synchronize CSRs and HFENCEs in the nested acceleration shared memory and
    /// emulate the SRET instruction. This is an optional function that is only
    /// available if the SBI_NACL_FEAT_SYNC_SRET feature is available.
    ///
    /// This function is used by supervisor software (or L1 hypervisor) to do
    /// a synchronized SRET request, and the SBI implementation (or L0 hypervisor)
    /// MUST handle it.
    ///
    /// # Return Value
    ///
    /// This function does not return upon success, and the possible error codes returned in
    /// `SbiRet.error` upon failure are shown in the table below:
    ///
    /// | Return code               | Description
    /// |:--------------------------|:----------------------------------------------
    /// | `SbiRet::not_supported()` | SBI_NACL_FEAT_SYNC_SRET feature is not available.
    /// | `SbiRet::no_shmem()`      | Nested acceleration shared memory not available.
    fn sync_sret(&self) -> SbiRet;
    /// Function internal to macros. Do not use.
    #[doc(hidden)]
    #[inline]
    fn _rustsbi_probe(&self) -> usize {
        sbi_spec::base::UNAVAILABLE_EXTENSION.wrapping_add(1)
    }
}

impl<T: Nacl> Nacl for &T {
    #[inline]
    fn probe_feature(&self, feature_id: u32) -> SbiRet {
        T::probe_feature(self, feature_id)
    }
    #[inline]
    fn set_shmem(&self, shmem: SharedPtr<[u8; NATIVE]>, flags: usize) -> SbiRet {
        T::set_shmem(self, shmem, flags)
    }
    #[inline]
    fn sync_csr(&self, csr_num: usize) -> SbiRet {
        T::sync_csr(self, csr_num)
    }
    #[inline]
    fn sync_hfence(&self, entry_index: usize) -> SbiRet {
        T::sync_hfence(self, entry_index)
    }
    #[inline]
    fn sync_sret(&self) -> SbiRet {
        T::sync_sret(self)
    }
}

impl<T: Nacl> Nacl for Option<T> {
    #[inline]
    fn probe_feature(&self, feature_id: u32) -> SbiRet {
        self.as_ref()
            .map(|inner| T::probe_feature(inner, feature_id))
            .unwrap_or(SbiRet::not_supported())
    }
    #[inline]
    fn set_shmem(&self, shmem: SharedPtr<[u8; NATIVE]>, flags: usize) -> SbiRet {
        self.as_ref()
            .map(|inner| T::set_shmem(inner, shmem, flags))
            .unwrap_or(SbiRet::not_supported())
    }
    #[inline]
    fn sync_csr(&self, csr_num: usize) -> SbiRet {
        self.as_ref()
            .map(|inner| T::sync_csr(inner, csr_num))
            .unwrap_or(SbiRet::not_supported())
    }
    #[inline]
    fn sync_hfence(&self, entry_index: usize) -> SbiRet {
        self.as_ref()
            .map(|inner| T::sync_hfence(inner, entry_index))
            .unwrap_or(SbiRet::not_supported())
    }
    #[inline]
    fn sync_sret(&self) -> SbiRet {
        self.as_ref()
            .map(|inner| T::sync_sret(inner))
            .unwrap_or(SbiRet::not_supported())
    }
    #[inline]
    fn _rustsbi_probe(&self) -> usize {
        match self {
            Some(_) => sbi_spec::base::UNAVAILABLE_EXTENSION.wrapping_add(1),
            None => sbi_spec::base::UNAVAILABLE_EXTENSION,
        }
    }
}