|
@@ -2,6 +2,8 @@ use crate::{
|
|
|
spec::binary::SbiRet, Fence, HartMask, Hsm, Ipi, Pmu, Reset, Timer, IMPL_ID_RUSTSBI,
|
|
|
RUSTSBI_VERSION, SBI_SPEC_MAJOR, SBI_SPEC_MINOR,
|
|
|
};
|
|
|
+#[cfg(feature = "sbi_2_0")]
|
|
|
+use crate::{Console, Physical};
|
|
|
use core::convert::Infallible;
|
|
|
#[cfg(feature = "machine")]
|
|
|
use riscv::register::{marchid, mimpid, mvendorid};
|
|
@@ -11,13 +13,15 @@ use riscv::register::{marchid, mimpid, mvendorid};
|
|
|
/// By now RustSBI supports to run instance based interface on systems has environment pointer width
|
|
|
/// that is the same as supervisor pointer width.
|
|
|
#[derive(Clone, Debug)]
|
|
|
-pub struct RustSBI<T, I, R, H, S, P> {
|
|
|
+pub struct RustSBI<T, I, R, H, S, P, #[cfg(feature = "sbi_2_0")] C> {
|
|
|
timer: Option<T>,
|
|
|
ipi: Option<I>,
|
|
|
rfnc: Option<R>,
|
|
|
hsm: Option<H>,
|
|
|
srst: Option<S>,
|
|
|
pmu: Option<P>,
|
|
|
+ #[cfg(feature = "sbi_2_0")]
|
|
|
+ dbcn: Option<C>,
|
|
|
#[cfg(not(feature = "machine"))]
|
|
|
info: MachineInfo,
|
|
|
}
|
|
@@ -36,6 +40,268 @@ pub struct MachineInfo {
|
|
|
pub mimpid: usize,
|
|
|
}
|
|
|
|
|
|
+// FIXME: on RustSBI 0.4.0, Console extension will be officially supported without a gate,
|
|
|
+// this macro can be moved back to impl RustSBI<...> code region at that time.
|
|
|
+macro_rules! impl_rustsbi {
|
|
|
+ () => {
|
|
|
+ /// Handle supervisor environment call with given parameters and return the `SbiRet` result.
|
|
|
+ #[inline]
|
|
|
+ pub fn handle_ecall(
|
|
|
+ &mut self,
|
|
|
+ extension: usize,
|
|
|
+ function: usize,
|
|
|
+ param: [usize; 6],
|
|
|
+ ) -> SbiRet {
|
|
|
+ match extension {
|
|
|
+ spec::rfnc::EID_RFNC => {
|
|
|
+ let Some(rfnc) = &mut self.rfnc else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0, param1, param2, param3, param4] =
|
|
|
+ [param[0], param[1], param[2], param[3], param[4]];
|
|
|
+ let hart_mask = crate::HartMask::from_mask_base(param0, param1);
|
|
|
+ match function {
|
|
|
+ spec::rfnc::REMOTE_FENCE_I => rfnc.remote_fence_i(hart_mask),
|
|
|
+ spec::rfnc::REMOTE_SFENCE_VMA => {
|
|
|
+ rfnc.remote_sfence_vma(hart_mask, param2, param3)
|
|
|
+ }
|
|
|
+ spec::rfnc::REMOTE_SFENCE_VMA_ASID => {
|
|
|
+ rfnc.remote_sfence_vma_asid(hart_mask, param2, param3, param4)
|
|
|
+ }
|
|
|
+ spec::rfnc::REMOTE_HFENCE_GVMA_VMID => {
|
|
|
+ rfnc.remote_hfence_gvma_vmid(hart_mask, param2, param3, param4)
|
|
|
+ }
|
|
|
+ spec::rfnc::REMOTE_HFENCE_GVMA => {
|
|
|
+ rfnc.remote_hfence_gvma(hart_mask, param2, param3)
|
|
|
+ }
|
|
|
+ spec::rfnc::REMOTE_HFENCE_VVMA_ASID => {
|
|
|
+ rfnc.remote_hfence_vvma_asid(hart_mask, param2, param3, param4)
|
|
|
+ }
|
|
|
+ spec::rfnc::REMOTE_HFENCE_VVMA => {
|
|
|
+ rfnc.remote_hfence_vvma(hart_mask, param2, param3)
|
|
|
+ }
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ spec::time::EID_TIME => match () {
|
|
|
+ #[cfg(target_pointer_width = "64")]
|
|
|
+ () => {
|
|
|
+ let Some(timer) = &mut self.timer else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0] = [param[0]];
|
|
|
+ match function {
|
|
|
+ spec::time::SET_TIMER => {
|
|
|
+ timer.set_timer(param0 as _);
|
|
|
+ SbiRet::success(0)
|
|
|
+ }
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #[cfg(target_pointer_width = "32")]
|
|
|
+ () => {
|
|
|
+ let Some(timer) = &mut self.timer else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0, param1] = [param[0], param[1]];
|
|
|
+ match function {
|
|
|
+ spec::time::SET_TIMER => {
|
|
|
+ timer.set_timer(concat_u32(param1, param0));
|
|
|
+ SbiRet::success(0)
|
|
|
+ }
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ spec::spi::EID_SPI => {
|
|
|
+ let Some(ipi) = &mut self.ipi else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0, param1] = [param[0], param[1]];
|
|
|
+ match function {
|
|
|
+ spec::spi::SEND_IPI => {
|
|
|
+ ipi.send_ipi(HartMask::from_mask_base(param0, param1))
|
|
|
+ }
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ spec::base::EID_BASE => {
|
|
|
+ let [param0] = [param[0]];
|
|
|
+ let value = match function {
|
|
|
+ spec::base::GET_SBI_SPEC_VERSION => {
|
|
|
+ (SBI_SPEC_MAJOR << 24) | (SBI_SPEC_MINOR)
|
|
|
+ }
|
|
|
+ spec::base::GET_SBI_IMPL_ID => IMPL_ID_RUSTSBI,
|
|
|
+ spec::base::GET_SBI_IMPL_VERSION => RUSTSBI_VERSION,
|
|
|
+ spec::base::PROBE_EXTENSION => {
|
|
|
+ // only provides probes to standard extensions. If you have customized extensions to be probed,
|
|
|
+ // run it even before this `handle_ecall` function.
|
|
|
+ self.probe_extension(param0)
|
|
|
+ }
|
|
|
+ spec::base::GET_MVENDORID => match () {
|
|
|
+ #[cfg(feature = "machine")]
|
|
|
+ () => mvendorid::read().map(|r| r.bits()).unwrap_or(0),
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ () => self.info.mvendorid,
|
|
|
+ },
|
|
|
+ spec::base::GET_MARCHID => match () {
|
|
|
+ #[cfg(feature = "machine")]
|
|
|
+ () => marchid::read().map(|r| r.bits()).unwrap_or(0),
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ () => self.info.marchid,
|
|
|
+ },
|
|
|
+ spec::base::GET_MIMPID => match () {
|
|
|
+ #[cfg(feature = "machine")]
|
|
|
+ () => mimpid::read().map(|r| r.bits()).unwrap_or(0),
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ () => self.info.mimpid,
|
|
|
+ },
|
|
|
+ _ => return SbiRet::not_supported(),
|
|
|
+ };
|
|
|
+ SbiRet::success(value)
|
|
|
+ }
|
|
|
+ spec::hsm::EID_HSM => {
|
|
|
+ let Some(hsm) = &mut self.hsm else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0, param1, param2] = [param[0], param[1], param[2]];
|
|
|
+ match function {
|
|
|
+ spec::hsm::HART_START => hsm.hart_start(param0, param1, param2),
|
|
|
+ spec::hsm::HART_STOP => hsm.hart_stop(),
|
|
|
+ spec::hsm::HART_GET_STATUS => hsm.hart_get_status(param0),
|
|
|
+ spec::hsm::HART_SUSPEND => {
|
|
|
+ if let Ok(suspend_type) = u32::try_from(param0) {
|
|
|
+ hsm.hart_suspend(suspend_type, param1, param2)
|
|
|
+ } else {
|
|
|
+ SbiRet::invalid_param()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ spec::srst::EID_SRST => {
|
|
|
+ let Some(srst) = &mut self.srst else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0, param1] = [param[0], param[1]];
|
|
|
+ match function {
|
|
|
+ spec::srst::SYSTEM_RESET => {
|
|
|
+ match (u32::try_from(param0), u32::try_from(param1)) {
|
|
|
+ (Ok(reset_type), Ok(reset_reason)) => {
|
|
|
+ srst.system_reset(reset_type, reset_reason)
|
|
|
+ }
|
|
|
+ (_, _) => SbiRet::invalid_param(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ spec::pmu::EID_PMU => match () {
|
|
|
+ #[cfg(target_pointer_width = "64")]
|
|
|
+ () => {
|
|
|
+ let Some(pmu) = &mut self.pmu else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0, param1, param2, param3, param4] =
|
|
|
+ [param[0], param[1], param[2], param[3], param[4]];
|
|
|
+ match function {
|
|
|
+ spec::pmu::PMU_NUM_COUNTERS => SbiRet::success(pmu.num_counters()),
|
|
|
+ spec::pmu::PMU_COUNTER_GET_INFO => pmu.counter_get_info(param0),
|
|
|
+ spec::pmu::PMU_COUNTER_CONFIG_MATCHING => pmu.counter_config_matching(
|
|
|
+ param0,
|
|
|
+ param1,
|
|
|
+ param2,
|
|
|
+ param3,
|
|
|
+ param4 as _,
|
|
|
+ ),
|
|
|
+ spec::pmu::PMU_COUNTER_START => {
|
|
|
+ pmu.counter_start(param0, param1, param2, param3 as _)
|
|
|
+ }
|
|
|
+ spec::pmu::PMU_COUNTER_STOP => pmu.counter_stop(param0, param1, param2),
|
|
|
+ spec::pmu::PMU_COUNTER_FW_READ => pmu.counter_fw_read(param0),
|
|
|
+ #[cfg(feature = "sbi_2_0")]
|
|
|
+ spec::pmu::PMU_COUNTER_FW_READ_HI => pmu.counter_fw_read(param0),
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #[cfg(target_pointer_width = "32")]
|
|
|
+ () => {
|
|
|
+ let Some(pmu) = &mut self.pmu else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0, param1, param2, param3, param4, param5] =
|
|
|
+ [param[0], param[1], param[2], param[3], param[4], param[5]];
|
|
|
+ match function {
|
|
|
+ spec::pmu::PMU_NUM_COUNTERS => SbiRet::success(pmu.num_counters()),
|
|
|
+ spec::pmu::PMU_COUNTER_GET_INFO => pmu.counter_get_info(param0),
|
|
|
+ spec::pmu::PMU_COUNTER_CONFIG_MATCHING => pmu.counter_config_matching(
|
|
|
+ param0,
|
|
|
+ param1,
|
|
|
+ param2,
|
|
|
+ param3,
|
|
|
+ concat_u32(param5, param4),
|
|
|
+ ),
|
|
|
+ spec::pmu::PMU_COUNTER_START => pmu.counter_start(
|
|
|
+ param0,
|
|
|
+ param1,
|
|
|
+ param2,
|
|
|
+ concat_u32(param4, param3),
|
|
|
+ ),
|
|
|
+ spec::pmu::PMU_COUNTER_STOP => pmu.counter_stop(param0, param1, param2),
|
|
|
+ spec::pmu::PMU_COUNTER_FW_READ => pmu.counter_fw_read(param0),
|
|
|
+ #[cfg(feature = "sbi_2_0")]
|
|
|
+ spec::pmu::PMU_COUNTER_FW_READ_HI => pmu.counter_fw_read(param0),
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ #[cfg(feature = "sbi_2_0")]
|
|
|
+ spec::dbcn::EID_DBCN => {
|
|
|
+ let Some(dbcn) = &mut self.dbcn else {
|
|
|
+ return SbiRet::not_supported();
|
|
|
+ };
|
|
|
+ let [param0, param1, param2] = [param[0], param[1], param[2]];
|
|
|
+ match function {
|
|
|
+ spec::dbcn::CONSOLE_WRITE => {
|
|
|
+ let bytes = Physical::new(param0, param1, param2);
|
|
|
+ dbcn.write(bytes)
|
|
|
+ }
|
|
|
+ spec::dbcn::CONSOLE_READ => {
|
|
|
+ let bytes = Physical::new(param0, param1, param2);
|
|
|
+ dbcn.read(bytes)
|
|
|
+ }
|
|
|
+ spec::dbcn::CONSOLE_WRITE_BYTE => dbcn.write_byte((param0 & 0xFF) as u8),
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _ => SbiRet::not_supported(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ fn probe_extension(&self, extension: usize) -> usize {
|
|
|
+ let ans = match extension {
|
|
|
+ spec::base::EID_BASE => true,
|
|
|
+ spec::time::EID_TIME => self.timer.is_some(),
|
|
|
+ spec::spi::EID_SPI => self.ipi.is_some(),
|
|
|
+ spec::rfnc::EID_RFNC => self.rfnc.is_some(),
|
|
|
+ spec::srst::EID_SRST => self.srst.is_some(),
|
|
|
+ spec::hsm::EID_HSM => self.hsm.is_some(),
|
|
|
+ spec::pmu::EID_PMU => self.pmu.is_some(),
|
|
|
+ #[cfg(feature = "sbi_2_0")]
|
|
|
+ spec::dbcn::EID_DBCN => self.dbcn.is_some(),
|
|
|
+ _ => false,
|
|
|
+ };
|
|
|
+ if ans {
|
|
|
+ spec::base::UNAVAILABLE_EXTENSION.wrapping_add(1)
|
|
|
+ } else {
|
|
|
+ spec::base::UNAVAILABLE_EXTENSION
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(not(feature = "sbi_2_0"))]
|
|
|
impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu> RustSBI<T, I, R, H, S, P> {
|
|
|
/// Create RustSBI instance on current machine environment for all the SBI extensions
|
|
|
#[cfg(feature = "machine")]
|
|
@@ -73,224 +339,53 @@ impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu> RustSBI<T, I, R, H, S
|
|
|
info,
|
|
|
}
|
|
|
}
|
|
|
+ impl_rustsbi! {}
|
|
|
+}
|
|
|
|
|
|
- /// Handle supervisor environment call with given parameters and return the `SbiRet` result.
|
|
|
+#[cfg(feature = "sbi_2_0")]
|
|
|
+impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console>
|
|
|
+ RustSBI<T, I, R, H, S, P, C>
|
|
|
+{
|
|
|
+ /// Create RustSBI instance on current machine environment for all the SBI extensions
|
|
|
+ #[cfg(feature = "machine")]
|
|
|
#[inline]
|
|
|
- pub fn handle_ecall(&mut self, extension: usize, function: usize, param: [usize; 6]) -> SbiRet {
|
|
|
- match extension {
|
|
|
- spec::rfnc::EID_RFNC => {
|
|
|
- let Some(rfnc) = &mut self.rfnc else {
|
|
|
- return SbiRet::not_supported();
|
|
|
- };
|
|
|
- let [param0, param1, param2, param3, param4] =
|
|
|
- [param[0], param[1], param[2], param[3], param[4]];
|
|
|
- let hart_mask = crate::HartMask::from_mask_base(param0, param1);
|
|
|
- match function {
|
|
|
- spec::rfnc::REMOTE_FENCE_I => rfnc.remote_fence_i(hart_mask),
|
|
|
- spec::rfnc::REMOTE_SFENCE_VMA => {
|
|
|
- rfnc.remote_sfence_vma(hart_mask, param2, param3)
|
|
|
- }
|
|
|
- spec::rfnc::REMOTE_SFENCE_VMA_ASID => {
|
|
|
- rfnc.remote_sfence_vma_asid(hart_mask, param2, param3, param4)
|
|
|
- }
|
|
|
- spec::rfnc::REMOTE_HFENCE_GVMA_VMID => {
|
|
|
- rfnc.remote_hfence_gvma_vmid(hart_mask, param2, param3, param4)
|
|
|
- }
|
|
|
- spec::rfnc::REMOTE_HFENCE_GVMA => {
|
|
|
- rfnc.remote_hfence_gvma(hart_mask, param2, param3)
|
|
|
- }
|
|
|
- spec::rfnc::REMOTE_HFENCE_VVMA_ASID => {
|
|
|
- rfnc.remote_hfence_vvma_asid(hart_mask, param2, param3, param4)
|
|
|
- }
|
|
|
- spec::rfnc::REMOTE_HFENCE_VVMA => {
|
|
|
- rfnc.remote_hfence_vvma(hart_mask, param2, param3)
|
|
|
- }
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
- }
|
|
|
- }
|
|
|
- spec::time::EID_TIME => match () {
|
|
|
- #[cfg(target_pointer_width = "64")]
|
|
|
- () => {
|
|
|
- let Some(timer) = &mut self.timer else {
|
|
|
- return SbiRet::not_supported();
|
|
|
- };
|
|
|
- let [param0] = [param[0]];
|
|
|
- match function {
|
|
|
- spec::time::SET_TIMER => {
|
|
|
- timer.set_timer(param0 as _);
|
|
|
- SbiRet::success(0)
|
|
|
- }
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
- }
|
|
|
- }
|
|
|
- #[cfg(target_pointer_width = "32")]
|
|
|
- () => {
|
|
|
- let Some(timer) = &mut self.timer else {
|
|
|
- return SbiRet::not_supported();
|
|
|
- };
|
|
|
- let [param0, param1] = [param[0], param[1]];
|
|
|
- match function {
|
|
|
- spec::time::SET_TIMER => {
|
|
|
- timer.set_timer(concat_u32(param1, param0));
|
|
|
- SbiRet::success(0)
|
|
|
- }
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- spec::spi::EID_SPI => {
|
|
|
- let Some(ipi) = &mut self.ipi else {
|
|
|
- return SbiRet::not_supported();
|
|
|
- };
|
|
|
- let [param0, param1] = [param[0], param[1]];
|
|
|
- match function {
|
|
|
- spec::spi::SEND_IPI => ipi.send_ipi(HartMask::from_mask_base(param0, param1)),
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
- }
|
|
|
- }
|
|
|
- spec::base::EID_BASE => {
|
|
|
- let [param0] = [param[0]];
|
|
|
- let value = match function {
|
|
|
- spec::base::GET_SBI_SPEC_VERSION => (SBI_SPEC_MAJOR << 24) | (SBI_SPEC_MINOR),
|
|
|
- spec::base::GET_SBI_IMPL_ID => IMPL_ID_RUSTSBI,
|
|
|
- spec::base::GET_SBI_IMPL_VERSION => RUSTSBI_VERSION,
|
|
|
- spec::base::PROBE_EXTENSION => {
|
|
|
- // only provides probes to standard extensions. If you have customized extensions to be probed,
|
|
|
- // run it even before this `handle_ecall` function.
|
|
|
- self.probe_extension(param0)
|
|
|
- }
|
|
|
- spec::base::GET_MVENDORID => match () {
|
|
|
- #[cfg(feature = "machine")]
|
|
|
- () => mvendorid::read().map(|r| r.bits()).unwrap_or(0),
|
|
|
- #[cfg(not(feature = "machine"))]
|
|
|
- () => self.info.mvendorid,
|
|
|
- },
|
|
|
- spec::base::GET_MARCHID => match () {
|
|
|
- #[cfg(feature = "machine")]
|
|
|
- () => marchid::read().map(|r| r.bits()).unwrap_or(0),
|
|
|
- #[cfg(not(feature = "machine"))]
|
|
|
- () => self.info.marchid,
|
|
|
- },
|
|
|
- spec::base::GET_MIMPID => match () {
|
|
|
- #[cfg(feature = "machine")]
|
|
|
- () => mimpid::read().map(|r| r.bits()).unwrap_or(0),
|
|
|
- #[cfg(not(feature = "machine"))]
|
|
|
- () => self.info.mimpid,
|
|
|
- },
|
|
|
- _ => return SbiRet::not_supported(),
|
|
|
- };
|
|
|
- SbiRet::success(value)
|
|
|
- }
|
|
|
- spec::hsm::EID_HSM => {
|
|
|
- let Some(hsm) = &mut self.hsm else {
|
|
|
- return SbiRet::not_supported();
|
|
|
- };
|
|
|
- let [param0, param1, param2] = [param[0], param[1], param[2]];
|
|
|
- match function {
|
|
|
- spec::hsm::HART_START => hsm.hart_start(param0, param1, param2),
|
|
|
- spec::hsm::HART_STOP => hsm.hart_stop(),
|
|
|
- spec::hsm::HART_GET_STATUS => hsm.hart_get_status(param0),
|
|
|
- spec::hsm::HART_SUSPEND => {
|
|
|
- if let Ok(suspend_type) = u32::try_from(param0) {
|
|
|
- hsm.hart_suspend(suspend_type, param1, param2)
|
|
|
- } else {
|
|
|
- SbiRet::invalid_param()
|
|
|
- }
|
|
|
- }
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
- }
|
|
|
- }
|
|
|
- spec::srst::EID_SRST => {
|
|
|
- let Some(srst) = &mut self.srst else {
|
|
|
- return SbiRet::not_supported();
|
|
|
- };
|
|
|
- let [param0, param1] = [param[0], param[1]];
|
|
|
- match function {
|
|
|
- spec::srst::SYSTEM_RESET => {
|
|
|
- match (u32::try_from(param0), u32::try_from(param1)) {
|
|
|
- (Ok(reset_type), Ok(reset_reason)) => {
|
|
|
- srst.system_reset(reset_type, reset_reason)
|
|
|
- }
|
|
|
- (_, _) => SbiRet::invalid_param(),
|
|
|
- }
|
|
|
- }
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
- }
|
|
|
- }
|
|
|
- spec::pmu::EID_PMU => match () {
|
|
|
- #[cfg(target_pointer_width = "64")]
|
|
|
- () => {
|
|
|
- let Some(pmu) = &mut self.pmu else {
|
|
|
- return SbiRet::not_supported();
|
|
|
- };
|
|
|
- let [param0, param1, param2, param3, param4] =
|
|
|
- [param[0], param[1], param[2], param[3], param[4]];
|
|
|
- match function {
|
|
|
- spec::pmu::PMU_NUM_COUNTERS => SbiRet::success(pmu.num_counters()),
|
|
|
- spec::pmu::PMU_COUNTER_GET_INFO => pmu.counter_get_info(param0),
|
|
|
- spec::pmu::PMU_COUNTER_CONFIG_MATCHING => {
|
|
|
- pmu.counter_config_matching(param0, param1, param2, param3, param4 as _)
|
|
|
- }
|
|
|
- spec::pmu::PMU_COUNTER_START => {
|
|
|
- pmu.counter_start(param0, param1, param2, param3 as _)
|
|
|
- }
|
|
|
- spec::pmu::PMU_COUNTER_STOP => pmu.counter_stop(param0, param1, param2),
|
|
|
- spec::pmu::PMU_COUNTER_FW_READ => pmu.counter_fw_read(param0),
|
|
|
- #[cfg(feature = "sbi_2_0")]
|
|
|
- spec::pmu::PMU_COUNTER_FW_READ_HI => pmu.counter_fw_read(param0),
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
- }
|
|
|
- }
|
|
|
- #[cfg(target_pointer_width = "32")]
|
|
|
- () => {
|
|
|
- let Some(pmu) = &mut self.pmu else {
|
|
|
- return SbiRet::not_supported();
|
|
|
- };
|
|
|
- let [param0, param1, param2, param3, param4, param5] =
|
|
|
- [param[0], param[1], param[2], param[3], param[4], param[5]];
|
|
|
- match function {
|
|
|
- spec::pmu::PMU_NUM_COUNTERS => SbiRet::success(pmu.num_counters()),
|
|
|
- spec::pmu::PMU_COUNTER_GET_INFO => pmu.counter_get_info(param0),
|
|
|
- spec::pmu::PMU_COUNTER_CONFIG_MATCHING => pmu.counter_config_matching(
|
|
|
- param0,
|
|
|
- param1,
|
|
|
- param2,
|
|
|
- param3,
|
|
|
- concat_u32(param5, param4),
|
|
|
- ),
|
|
|
- spec::pmu::PMU_COUNTER_START => {
|
|
|
- pmu.counter_start(param0, param1, param2, concat_u32(param4, param3))
|
|
|
- }
|
|
|
- spec::pmu::PMU_COUNTER_STOP => pmu.counter_stop(param0, param1, param2),
|
|
|
- spec::pmu::PMU_COUNTER_FW_READ => pmu.counter_fw_read(param0),
|
|
|
- #[cfg(feature = "sbi_2_0")]
|
|
|
- spec::pmu::PMU_COUNTER_FW_READ_HI => pmu.counter_fw_read(param0),
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- _ => SbiRet::not_supported(),
|
|
|
+ pub const fn new_machine(timer: T, ipi: I, rfnc: R, hsm: H, srst: S, pmu: P, dbcn: C) -> Self {
|
|
|
+ Self {
|
|
|
+ timer: Some(timer),
|
|
|
+ ipi: Some(ipi),
|
|
|
+ rfnc: Some(rfnc),
|
|
|
+ hsm: Some(hsm),
|
|
|
+ srst: Some(srst),
|
|
|
+ pmu: Some(pmu),
|
|
|
+ dbcn: Some(dbcn),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Create RustSBI instance on given machine information for all the SBI extensions
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
#[inline]
|
|
|
- fn probe_extension(&self, extension: usize) -> usize {
|
|
|
- let ans = match extension {
|
|
|
- spec::base::EID_BASE => true,
|
|
|
- spec::time::EID_TIME => self.timer.is_some(),
|
|
|
- spec::spi::EID_SPI => self.ipi.is_some(),
|
|
|
- spec::rfnc::EID_RFNC => self.rfnc.is_some(),
|
|
|
- spec::srst::EID_SRST => self.srst.is_some(),
|
|
|
- spec::hsm::EID_HSM => self.hsm.is_some(),
|
|
|
- spec::pmu::EID_PMU => self.pmu.is_some(),
|
|
|
- _ => false,
|
|
|
- };
|
|
|
- if ans {
|
|
|
- spec::base::UNAVAILABLE_EXTENSION.wrapping_add(1)
|
|
|
- } else {
|
|
|
- spec::base::UNAVAILABLE_EXTENSION
|
|
|
+ pub const fn with_machine_info(
|
|
|
+ timer: T,
|
|
|
+ ipi: I,
|
|
|
+ rfnc: R,
|
|
|
+ hsm: H,
|
|
|
+ srst: S,
|
|
|
+ pmu: P,
|
|
|
+ dbcn: C,
|
|
|
+ info: MachineInfo,
|
|
|
+ ) -> Self {
|
|
|
+ Self {
|
|
|
+ timer: Some(timer),
|
|
|
+ ipi: Some(ipi),
|
|
|
+ rfnc: Some(rfnc),
|
|
|
+ hsm: Some(hsm),
|
|
|
+ srst: Some(srst),
|
|
|
+ pmu: Some(pmu),
|
|
|
+ dbcn: Some(dbcn),
|
|
|
+ info,
|
|
|
}
|
|
|
}
|
|
|
+ impl_rustsbi! {}
|
|
|
}
|
|
|
|
|
|
#[cfg(target_pointer_width = "32")]
|
|
@@ -300,10 +395,15 @@ const fn concat_u32(h: usize, l: usize) -> u64 {
|
|
|
}
|
|
|
|
|
|
/// Structure to build a RustSBI instance
|
|
|
-pub struct Builder<T, I, R, H, S, P> {
|
|
|
+// FIXME: remove #[cfg(feature = "sbi_2_0")] once RustSBI hits 0.4.0
|
|
|
+pub struct Builder<T, I, R, H, S, P, #[cfg(feature = "sbi_2_0")] C> {
|
|
|
+ #[cfg(not(feature = "sbi_2_0"))]
|
|
|
inner: RustSBI<T, I, R, H, S, P>,
|
|
|
+ #[cfg(feature = "sbi_2_0")]
|
|
|
+ inner: RustSBI<T, I, R, H, S, P, C>,
|
|
|
}
|
|
|
|
|
|
+#[cfg(not(feature = "sbi_2_0"))]
|
|
|
impl Builder<Infallible, Infallible, Infallible, Infallible, Infallible, Infallible> {
|
|
|
/// Create a new `Builder` from current machine environment
|
|
|
#[inline]
|
|
@@ -342,12 +442,57 @@ impl Builder<Infallible, Infallible, Infallible, Infallible, Infallible, Infalli
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#[cfg(feature = "sbi_2_0")]
|
|
|
+impl Builder<Infallible, Infallible, Infallible, Infallible, Infallible, Infallible, Infallible> {
|
|
|
+ /// Create a new `Builder` from current machine environment
|
|
|
+ #[inline]
|
|
|
+ #[cfg(feature = "machine")]
|
|
|
+ pub const fn new_machine(
|
|
|
+ ) -> Builder<Infallible, Infallible, Infallible, Infallible, Infallible, Infallible, Infallible>
|
|
|
+ {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: None,
|
|
|
+ ipi: None,
|
|
|
+ rfnc: None,
|
|
|
+ hsm: None,
|
|
|
+ srst: None,
|
|
|
+ pmu: None,
|
|
|
+ dbcn: None,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Create a new `Builder` from machine information
|
|
|
+ #[inline]
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ pub const fn with_machine_info(
|
|
|
+ info: MachineInfo,
|
|
|
+ ) -> Builder<Infallible, Infallible, Infallible, Infallible, Infallible, Infallible, Infallible>
|
|
|
+ {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: None,
|
|
|
+ ipi: None,
|
|
|
+ rfnc: None,
|
|
|
+ hsm: None,
|
|
|
+ srst: None,
|
|
|
+ pmu: None,
|
|
|
+ dbcn: None,
|
|
|
+ info,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// fixme: in future releases we may use type-changing struct update syntax like:
|
|
|
// Builder { inner: RustSBI { timer: None, ..self.inner } }
|
|
|
// https://github.com/rust-lang/rust/issues/86555
|
|
|
|
|
|
// fixme: struct `Infallible` should be replaced to never type once it's stablized
|
|
|
|
|
|
+// fixme: remove feature sbi_2_0 once RustSBI hits 0.4.0
|
|
|
+#[cfg(not(feature = "sbi_2_0"))]
|
|
|
impl<T, I, R, H, S, P> Builder<T, I, R, H, S, P> {
|
|
|
/// Add Timer programmer extension to RustSBI
|
|
|
#[inline]
|
|
@@ -458,6 +603,140 @@ impl<T, I, R, H, S, P> Builder<T, I, R, H, S, P> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#[cfg(feature = "sbi_2_0")]
|
|
|
+impl<T, I, R, H, S, P, C> Builder<T, I, R, H, S, P, C> {
|
|
|
+ /// Add Timer programmer extension to RustSBI
|
|
|
+ #[inline]
|
|
|
+ pub fn with_timer<T2: Timer>(self, timer: T2) -> Builder<T2, I, R, H, S, P, C> {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: Some(timer),
|
|
|
+ ipi: self.inner.ipi,
|
|
|
+ rfnc: self.inner.rfnc,
|
|
|
+ hsm: self.inner.hsm,
|
|
|
+ srst: self.inner.srst,
|
|
|
+ pmu: self.inner.pmu,
|
|
|
+ dbcn: self.inner.dbcn,
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ info: self.inner.info,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Add Inter-processor Interrupt extension to RustSBI
|
|
|
+ #[inline]
|
|
|
+ pub fn with_ipi<I2: Ipi>(self, ipi: I2) -> Builder<T, I2, R, H, S, P, C> {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: self.inner.timer,
|
|
|
+ ipi: Some(ipi),
|
|
|
+ rfnc: self.inner.rfnc,
|
|
|
+ hsm: self.inner.hsm,
|
|
|
+ srst: self.inner.srst,
|
|
|
+ pmu: self.inner.pmu,
|
|
|
+ dbcn: self.inner.dbcn,
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ info: self.inner.info,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Add Remote Fence extension to RustSBI
|
|
|
+ #[inline]
|
|
|
+ pub fn with_fence<R2: Fence>(self, fence: R2) -> Builder<T, I, R2, H, S, P, C> {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: self.inner.timer,
|
|
|
+ ipi: self.inner.ipi,
|
|
|
+ rfnc: Some(fence),
|
|
|
+ hsm: self.inner.hsm,
|
|
|
+ srst: self.inner.srst,
|
|
|
+ pmu: self.inner.pmu,
|
|
|
+ dbcn: self.inner.dbcn,
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ info: self.inner.info,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Add Hart State Monitor extension to RustSBI
|
|
|
+ #[inline]
|
|
|
+ pub fn with_hsm<H2: Hsm>(self, hsm: H2) -> Builder<T, I, R, H2, S, P, C> {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: self.inner.timer,
|
|
|
+ ipi: self.inner.ipi,
|
|
|
+ rfnc: self.inner.rfnc,
|
|
|
+ hsm: Some(hsm),
|
|
|
+ srst: self.inner.srst,
|
|
|
+ pmu: self.inner.pmu,
|
|
|
+ dbcn: self.inner.dbcn,
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ info: self.inner.info,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Add System Reset extension to RustSBI
|
|
|
+ #[inline]
|
|
|
+ pub fn with_reset<S2: Reset>(self, reset: S2) -> Builder<T, I, R, H, S2, P, C> {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: self.inner.timer,
|
|
|
+ ipi: self.inner.ipi,
|
|
|
+ rfnc: self.inner.rfnc,
|
|
|
+ hsm: self.inner.hsm,
|
|
|
+ srst: Some(reset),
|
|
|
+ pmu: self.inner.pmu,
|
|
|
+ dbcn: self.inner.dbcn,
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ info: self.inner.info,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Add Performance Monitor Unit extension to RustSBI
|
|
|
+ #[inline]
|
|
|
+ pub fn with_pmu<P2: Pmu>(self, pmu: P2) -> Builder<T, I, R, H, S, P2, C> {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: self.inner.timer,
|
|
|
+ ipi: self.inner.ipi,
|
|
|
+ rfnc: self.inner.rfnc,
|
|
|
+ hsm: self.inner.hsm,
|
|
|
+ srst: self.inner.srst,
|
|
|
+ pmu: Some(pmu),
|
|
|
+ dbcn: self.inner.dbcn,
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ info: self.inner.info,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /// Add Debug Console extension to RustSBI
|
|
|
+ #[inline]
|
|
|
+ pub fn with_console<C2: Console>(self, console: C2) -> Builder<T, I, R, H, S, P, C2> {
|
|
|
+ Builder {
|
|
|
+ inner: RustSBI {
|
|
|
+ timer: self.inner.timer,
|
|
|
+ ipi: self.inner.ipi,
|
|
|
+ rfnc: self.inner.rfnc,
|
|
|
+ hsm: self.inner.hsm,
|
|
|
+ srst: self.inner.srst,
|
|
|
+ pmu: self.inner.pmu,
|
|
|
+ dbcn: Some(console),
|
|
|
+ #[cfg(not(feature = "machine"))]
|
|
|
+ info: self.inner.info,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Build the target RustSBI instance
|
|
|
+ #[inline]
|
|
|
+ pub fn build(self) -> RustSBI<T, I, R, H, S, P, C> {
|
|
|
+ self.inner
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// Placeholder for a structure that implements all RustSBI traits but is never accessed
|
|
|
|
|
|
// fixme: Should be replaced to never type `!` once it's stablized
|
|
@@ -562,3 +841,18 @@ impl Pmu for Infallible {
|
|
|
unreachable!()
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+#[cfg(feature = "sbi_2_0")]
|
|
|
+impl Console for Infallible {
|
|
|
+ fn write(&self, _: crate::Physical<&[u8]>) -> SbiRet {
|
|
|
+ unreachable!()
|
|
|
+ }
|
|
|
+
|
|
|
+ fn read(&self, _: crate::Physical<&mut [u8]>) -> SbiRet {
|
|
|
+ unreachable!()
|
|
|
+ }
|
|
|
+
|
|
|
+ fn write_byte(&self, _: u8) -> SbiRet {
|
|
|
+ unreachable!()
|
|
|
+ }
|
|
|
+}
|