Browse Source

lib: remove deprecated legacy SBI extension support

RustSBI now supports standard extensions from RustSBI 0.4.0
luojia65 2 years ago
parent
commit
7b7350742c
11 changed files with 30 additions and 334 deletions
  1. 0 5
      .github/workflows/rust.yml
  2. 3 0
      CHANGELOG.md
  3. 0 2
      Cargo.toml
  4. 1 1
      README.md
  5. 0 18
      src/base.rs
  6. 0 59
      src/ecall/mod.rs
  7. 23 94
      src/hart_mask.rs
  8. 0 1
      src/instance.rs
  9. 0 93
      src/legacy_stdio.rs
  10. 3 36
      src/lib.rs
  11. 0 25
      src/reset.rs

+ 0 - 5
.github/workflows/rust.yml

@@ -84,11 +84,6 @@ jobs:
         with:
           command: check
           args: --features "singleton" --target ${{ matrix.TARGET }} --verbose
-      - name: Check (legacy)
-        uses: actions-rs/cargo@v1
-        with:
-          command: check
-          args: --features "legacy" --target ${{ matrix.TARGET }} --verbose
 
   tests:
     name: Run tests

+ 3 - 0
CHANGELOG.md

@@ -13,6 +13,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ### Removed
 
+- `sbi_2_0` feature; RustSBI now supports SBI 2.0-rc1 by default
+- support for legacy SBI extensions
+
 ## [0.3.2] - 2023-02-26
 
 Bump RISC-V SBI specification version to 2.0-rc1.

+ 0 - 2
Cargo.toml

@@ -31,8 +31,6 @@ machine = ["dep:riscv"]
 # to take care of singleton reference locks.
 # Disable this feature to use instance based RustSBI environment.
 singleton = ["dep:riscv", "machine"]
-# Support legacy extension; this feature is not included by default.
-legacy = ["sbi-spec/legacy", "singleton"]
 
 [package.metadata.docs.rs]
 default-target = "riscv64imac-unknown-none-elf"

+ 1 - 1
README.md

@@ -22,7 +22,7 @@ or consult vendors if they provide discrete RustSBI package support.
 
 To compile RustSBI library, you need at least stable Rust version of `rustc 1.65.0`.
 
-If you are using feature `singleton` or `legacy` to support legacy SBI extensions, you are required to install
+If you are using feature `singleton` to support singleton based interface, you are required to install
 nightly Rust compiler. You may need at least nightly Rust version of `rustc 1.59.0-nightly (c5ecc1570 2021-12-15)`.
 
 ## Build this project

+ 0 - 18
src/base.rs

@@ -10,24 +10,6 @@ pub fn probe_extension(extension: usize) -> bool {
         srst::EID_SRST => crate::reset::probe_reset(),
         hsm::EID_HSM => crate::hsm::probe_hsm(),
         pmu::EID_PMU => crate::pmu::probe_pmu(),
-        // Legacy extensions
-        // if feature 'legacy' is not enabled, these extensions fall back to false.
-        #[cfg(feature = "legacy")]
-        legacy::LEGACY_SET_TIMER => crate::timer::probe_timer(),
-        #[cfg(feature = "legacy")]
-        legacy::LEGACY_SEND_IPI => crate::ipi::probe_ipi(),
-        // LEGACY_CLEAR_IPI implemented in ecall/mod.rs directly, so it always exists.
-        #[cfg(feature = "legacy")]
-        legacy::LEGACY_CLEAR_IPI => true,
-        #[cfg(feature = "legacy")]
-        legacy::LEGACY_SHUTDOWN => crate::reset::probe_reset(),
-        // we don't include LEGACY_REMOTE_FENCE_I, LEGACY_REMOTE_SFENCE_VMA
-        // and LEGACY_REMOTE_SFENCE_VMA_ASID here,
-        // for RustSBI ecall/mod.rs did not implement these legacy extensions.
-        #[cfg(feature = "legacy")]
-        legacy::LEGACY_CONSOLE_PUTCHAR | legacy::LEGACY_CONSOLE_GETCHAR => {
-            crate::legacy_stdio::probe_legacy_stdio()
-        }
         _ => false,
     }
 }

+ 0 - 59
src/ecall/mod.rs

@@ -15,10 +15,6 @@ mod srst;
 // §11
 mod pmu;
 
-#[cfg(feature = "legacy")]
-use crate::{
-    ipi::send_ipi, legacy_stdio_getchar, legacy_stdio_putchar, reset::legacy_reset, HartMask,
-};
 use sbi_spec::{self as spec, binary::SbiRet};
 
 /// Supervisor environment call handler function
@@ -30,12 +26,6 @@ use sbi_spec::{self as spec, binary::SbiRet};
 /// call this function with parameters extracted from trap frame.
 /// After this function returns, store the return value into `a0` and `a1` parameters.
 ///
-/// This function also adapts to the legacy functions.
-/// If the supervisor called any of legacy function, the `a0` and `a1` parameter
-/// is transferred to error and value field of `SbiRet` respectively.
-/// In this case, implementations should always store the result into `a0` and `a1` in
-/// any environment call functions including legacy functions.
-///
 /// # Example
 ///
 /// A typical usage:
@@ -82,55 +72,6 @@ pub fn handle_ecall(extension: usize, function: usize, param: [usize; 6]) -> Sbi
                 function, param[0], param[1], param[2], param[3], param[4], param[5],
             ),
         },
-        // handle legacy callings.
-        //
-        // legacy 调用不使用 a1 返回值,总把 a1 填回 `SbiRet::value` 来模拟非 legacy 的行为。
-        #[cfg(feature = "legacy")]
-        spec::legacy::LEGACY_SET_TIMER => {
-            match () {
-                #[cfg(target_pointer_width = "64")]
-                () => crate::timer::set_timer(param[0] as _),
-                #[cfg(target_pointer_width = "32")]
-                () => crate::timer::set_timer(concat_u32(param[1] as _, param[0] as _)),
-            };
-            SbiRet {
-                error: param[0],
-                value: param[1],
-            }
-        }
-        #[cfg(feature = "legacy")]
-        spec::legacy::LEGACY_CONSOLE_PUTCHAR => {
-            legacy_stdio_putchar(param[0] as _);
-            SbiRet {
-                error: param[0],
-                value: param[1],
-            }
-        }
-        #[cfg(feature = "legacy")]
-        spec::legacy::LEGACY_CONSOLE_GETCHAR => SbiRet {
-            error: legacy_stdio_getchar(),
-            value: param[1],
-        },
-        #[cfg(feature = "legacy")]
-        spec::legacy::LEGACY_SEND_IPI => {
-            send_ipi(unsafe { HartMask::legacy_from_addr(param[0]) });
-            SbiRet {
-                error: param[0],
-                value: param[1],
-            }
-        }
-        #[cfg(feature = "legacy")]
-        spec::legacy::LEGACY_CLEAR_IPI => {
-            unsafe {
-                riscv::register::mip::clear_ssoft();
-            }
-            SbiRet {
-                error: param[0],
-                value: param[1],
-            }
-        }
-        #[cfg(feature = "legacy")]
-        spec::legacy::LEGACY_SHUTDOWN => legacy_reset(),
         _ => SbiRet::not_supported(),
     }
 }

+ 23 - 94
src/hart_mask.rs

@@ -1,15 +1,15 @@
 /// Hart mask structure reference
 #[derive(Debug, Clone)]
 pub struct HartMask {
-    inner: MaskInner,
+    inner: BitVector,
 }
 
 impl HartMask {
     /// Construct a hart mask from mask value and base hart id.
     #[inline]
-    pub fn from_mask_base(hart_mask: usize, hart_mask_base: usize) -> HartMask {
+    pub const fn from_mask_base(hart_mask: usize, hart_mask_base: usize) -> HartMask {
         HartMask {
-            inner: MaskInner::BitVector {
+            inner: BitVector {
                 hart_mask,
                 hart_mask_base,
             },
@@ -18,103 +18,32 @@ impl HartMask {
 
     /// Check if the `hart_id` is included in this hart mask structure.
     #[inline]
-    pub fn has_bit(&self, hart_id: usize) -> bool {
-        match self.inner {
-            MaskInner::BitVector {
-                hart_mask,
-                hart_mask_base,
-            } => {
-                if hart_mask_base == usize::MAX {
-                    // If `hart_mask_base` equals `usize::MAX`, that means `hart_mask` is ignored
-                    // and all available harts must be considered.
-                    return true;
-                }
-                let Some(idx) = hart_id.checked_sub(hart_mask_base) else {
-                    // hart_id < hart_mask_base, not in current mask range
-                    return false;
-                };
-                if idx >= usize::BITS as usize {
-                    // hart_idx >= hart_mask_base + XLEN, not in current mask range
-                    return false;
-                }
-                hart_mask & (1 << idx) != 0
-            }
-            #[cfg(feature = "legacy")]
-            MaskInner::Legacy { legacy_bit_vector } => {
-                slow_legacy_has_bit(legacy_bit_vector, hart_id)
-            }
+    pub const fn has_bit(&self, hart_id: usize) -> bool {
+        let BitVector {
+            hart_mask,
+            hart_mask_base,
+        } = self.inner;
+        if hart_mask_base == usize::MAX {
+            // If `hart_mask_base` equals `usize::MAX`, that means `hart_mask` is ignored
+            // and all available harts must be considered.
+            return true;
         }
-    }
-
-    /// *This is a legacy function; it should not be used in newer designs. If `vaddr` is invalid
-    /// from S level, it would result in machine level load access or load misaligned exception.*
-    ///
-    /// Construct a hart mask from legacy bit vector and number of harts in current platform.
-    #[cfg(feature = "legacy")]
-    #[inline]
-    pub(crate) unsafe fn legacy_from_addr(vaddr: usize) -> HartMask {
-        HartMask {
-            inner: MaskInner::Legacy {
-                legacy_bit_vector: vaddr as *const _,
-            },
+        let Some(idx) = hart_id.checked_sub(hart_mask_base) else {
+            // hart_id < hart_mask_base, not in current mask range
+            return false;
+        };
+        if idx >= usize::BITS as usize {
+            // hart_idx >= hart_mask_base + XLEN, not in current mask range
+            return false;
         }
+        hart_mask & (1 << idx) != 0
     }
 }
 
 #[derive(Debug, Clone)]
-enum MaskInner {
-    BitVector {
-        hart_mask: usize,
-        hart_mask_base: usize,
-    },
-    #[cfg(feature = "legacy")]
-    Legacy { legacy_bit_vector: *const usize },
-}
-
-// not #[inline] to speed up new version bit vector
-#[cfg(feature = "legacy")]
-fn slow_legacy_has_bit(legacy_bit_vector: *const usize, hart_id: usize) -> bool {
-    fn split_index_usize(index: usize) -> (usize, usize) {
-        let bits_in_usize = usize::BITS as usize;
-        (index / bits_in_usize, index % bits_in_usize)
-    }
-    let (i, j) = split_index_usize(hart_id);
-    let cur_vector = unsafe { get_vaddr_usize(legacy_bit_vector.add(i)) };
-    cur_vector & (1 << j) != 0
-}
-
-#[cfg(feature = "legacy")]
-#[inline]
-unsafe fn get_vaddr_usize(vaddr_ptr: *const usize) -> usize {
-    match () {
-        #[cfg(target_arch = "riscv32")]
-        () => {
-            let mut ans: usize;
-            core::arch::asm!("
-                li      {tmp}, (1 << 17)
-                csrrs   {tmp}, mstatus, {tmp}
-                lw      {ans}, 0({vmem})
-                csrw    mstatus, {tmp}
-            ", ans = lateout(reg) ans, vmem = in(reg) vaddr_ptr, tmp = out(reg) _);
-            ans
-        }
-        #[cfg(target_arch = "riscv64")]
-        () => {
-            let mut ans: usize;
-            core::arch::asm!("
-                li      {tmp}, (1 << 17)
-                csrrs   {tmp}, mstatus, {tmp}
-                ld      {ans}, 0({vmem})
-                csrw    mstatus, {tmp}
-            ", ans = lateout(reg) ans, vmem = in(reg) vaddr_ptr, tmp = out(reg) _);
-            ans
-        }
-        #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
-        () => {
-            drop(vaddr_ptr);
-            unimplemented!("not RISC-V instruction set architecture")
-        }
-    }
+struct BitVector {
+    hart_mask: usize,
+    hart_mask_base: usize,
 }
 
 #[cfg(test)]

+ 0 - 1
src/instance.rs

@@ -578,7 +578,6 @@ impl Reset for Infallible {
     fn system_reset(&self, _: u32, _: u32) -> SbiRet {
         unreachable!()
     }
-    // no leagcy_reset here, instance based interface is not compatible to legacy extension
 }
 
 impl Pmu for Infallible {

+ 0 - 93
src/legacy_stdio.rs

@@ -1,93 +0,0 @@
-//! 这个模块的两个宏应该公开
-//! 如果制造实例的时候,给定了stdout,那么就会打印到这个stdout里面
-use crate::util::AmoOnceRef;
-use core::fmt;
-
-/// Legacy standard input/output
-pub trait LegacyStdio: Send + Sync {
-    /// Get a character from legacy stdin
-    fn getchar(&self) -> u8;
-    /// Put a character into legacy stdout
-    fn putchar(&self, ch: u8);
-
-    fn write_str(&self, s: &str) {
-        for byte in s.as_bytes() {
-            self.putchar(*byte)
-        }
-    }
-}
-
-static LEGACY_STDIO: AmoOnceRef<dyn LegacyStdio> = AmoOnceRef::new();
-
-#[inline]
-pub fn init_legacy_stdio(stdio: &'static dyn LegacyStdio) {
-    if !LEGACY_STDIO.try_call_once(stdio) {
-        panic!("load sbi module when already loaded")
-    }
-}
-
-#[inline]
-pub fn legacy_stdio_putchar(ch: u8) {
-    if let Some(stdio) = LEGACY_STDIO.get() {
-        stdio.putchar(ch)
-    }
-}
-
-#[inline]
-pub fn legacy_stdio_getchar() -> usize {
-    if let Some(stdio) = LEGACY_STDIO.get() {
-        stdio.getchar() as usize
-    } else {
-        // According to RISC-V SBI spec 0.3.1-rc1, Section 4.3, this function returns -1
-        // when fails to read from debug console. Thank you @duskmoon314
-        usize::from_ne_bytes(isize::to_ne_bytes(-1))
-    }
-}
-
-#[inline]
-pub(crate) fn probe_legacy_stdio() -> bool {
-    LEGACY_STDIO.get().is_some()
-}
-
-struct Stdout;
-
-impl fmt::Write for Stdout {
-    #[inline]
-    fn write_str(&mut self, s: &str) -> fmt::Result {
-        if let Some(stdio) = LEGACY_STDIO.get() {
-            stdio.write_str(s);
-        }
-        Ok(())
-    }
-}
-
-#[inline]
-#[doc(hidden)]
-pub fn _print(args: fmt::Arguments) {
-    use fmt::Write;
-    Stdout.write_fmt(args).unwrap();
-}
-
-/// Prints to the legacy debug console.
-///
-/// This is only supported when there exists legacy extension;
-/// otherwise platform caller should use an early kernel input/output device
-/// declared in platform specific hardware.
-#[macro_export]
-macro_rules! print {
-    ($($arg:tt)*) => ($crate::legacy_stdio::_print(core::format_args!($($arg)*)));
-}
-
-/// Prints to the legacy debug console, with a newline.
-///
-/// This is only supported when there exists legacy extension;
-/// otherwise platform caller should use an early kernel input/output device
-/// declared in platform specific hardware.
-#[macro_export]
-macro_rules! println {
-    () => ($crate::print!("\r\n"));
-    ($($arg:tt)*) => {
-        $crate::legacy_stdio::_print(core::format_args!($($arg)*));
-        $crate::print!("\r\n");
-    }
-}

+ 3 - 36
src/lib.rs

@@ -148,7 +148,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! rustsbi = "0.3.2"
+//! rustsbi = "0.4.0"
 //! ```
 //!
 //! After hardware initialization process, the part of firmware with RustSBI linked should run on memory
@@ -162,7 +162,6 @@
 //! # struct MyPlatHsm;
 //! # struct MyBoardPower;
 //! # struct MyPlatPmu;
-//! # #[cfg(not(feature = "legacy"))]
 //! use rustsbi::RustSBI;
 //!
 //! # struct SupervisorContext;
@@ -170,7 +169,6 @@
 //! struct Executor {
 //!     ctx: SupervisorContext,
 //!     /* other environment variables ... */
-//! # #[cfg(not(feature = "legacy"))]
 //!     sbi: RustSBI<Clint, Clint, MyPlatRfnc, MyPlatHsm, MyBoardPower, MyPlatPmu>,
 //!     /* custom_1: CustomSBI<...> */
 //! }
@@ -356,7 +354,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! rustsbi = { version = "0.3.2", features = ["singleton"] }
+//! rustsbi = { version = "0.4.0", features = ["singleton"] }
 //! ```
 //!
 //! RustSBI library will disable all instance based interfaces but provide `init_*`
@@ -388,7 +386,7 @@
 //!
 //! ```toml
 //! [dependencies]
-//! rustsbi = { version = "0.3.2", default-features = false }
+//! rustsbi = { version = "0.4.0", default-features = false }
 //! ```
 //!
 //! This will disable default feature `machine` which will assume that RustSBI runs on M-mode directly,
@@ -516,43 +514,16 @@
 //! any hardware discovery methods, or use try-execute-trap method to detect any instructions or
 //! CSRs. If SBI is implemented in user level emulators, it may requires to depend on operating
 //! system calls or use the signal trap method to detect any RISC-V core features.
-//!
-//! ## Legacy SBI extension
-//!
-//! *Note: RustSBI legacy support is only designed for backward compability of deprecated legacy RISC-V
-//! SBI standard. It's disabled by default and it's not suggested to include legacy extensions in newer
-//! firmware designs. Extensions other than legacy console are replaced by individual extensions in SBI.
-//! Kernels are not suggested to use legacy extensions in practice.
-//! If you are a kernel developer, newer designs should consider relying on each SBI extension other than
-//! legacy extensions.*
-//!
-//! The SBI includes legacy extension which dated back to SBI 0.1 specification. Most of its features
-//! are replaced by individual SBI extensions, thus the entire legacy extension is deprecated by
-//! SBI version 0.2. However, some users may find out SBI 0.1 legacy console useful in some situations
-//! even if it's deprecated.
-//!
-//! RustSBI keeps SBI 0.1 legacy support under feature gate `legacy`. To use RustSBI with deprecated
-//! legacy feature, you may change dependency configuration to:
-//!
-//! ```toml
-//! [dependencies]
-//! rustsbi = { version = "0.3.2", features = ["legacy"] }
-//! ```
 
 #![no_std]
 #![cfg_attr(feature = "singleton", feature(ptr_metadata))]
 
-#[cfg(feature = "legacy")]
-#[doc(hidden)]
-#[macro_use]
-pub mod legacy_stdio;
 mod base;
 mod console;
 #[cfg(feature = "singleton")]
 mod ecall;
 mod hart_mask;
 mod hsm;
-#[cfg(not(feature = "legacy"))]
 mod instance;
 mod ipi;
 mod memory_range;
@@ -595,12 +566,8 @@ pub use console::Console;
 pub use ecall::handle_ecall as ecall;
 pub use hart_mask::HartMask;
 pub use hsm::Hsm;
-#[cfg(not(feature = "legacy"))]
 pub use instance::{Builder, RustSBI};
 pub use ipi::Ipi;
-#[cfg(feature = "legacy")]
-#[doc(hidden)]
-pub use legacy_stdio::{legacy_stdio_getchar, legacy_stdio_putchar};
 pub use memory_range::Physical;
 pub use pmu::Pmu;
 pub use reset::Reset;

+ 0 - 25
src/reset.rs

@@ -37,17 +37,6 @@ pub trait Reset: Send + Sync {
     /// | `SbiRet::not_supported()` | `reset_type` is valid but not implemented.
     /// | `SbiRet::failed()`        | Reset request failed for unknown reasons.
     fn system_reset(&self, reset_type: u32, reset_reason: u32) -> SbiRet;
-
-    /// Legacy extension's reset function
-    ///
-    /// Puts all the harts to shut down state from supervisor point of view. This SBI call doesn’t return.
-    #[cfg(feature = "legacy")]
-    fn legacy_reset(&self) -> ! {
-        use sbi_spec::srst::{RESET_REASON_NO_REASON, RESET_TYPE_SHUTDOWN};
-        // By default, this function redirects to `system_reset`.
-        self.system_reset(RESET_TYPE_SHUTDOWN, RESET_REASON_NO_REASON);
-        unreachable!()
-    }
 }
 
 impl<T: Reset> Reset for &T {
@@ -55,11 +44,6 @@ impl<T: Reset> Reset for &T {
     fn system_reset(&self, reset_type: u32, reset_reason: u32) -> SbiRet {
         T::system_reset(self, reset_type, reset_reason)
     }
-    #[cfg(feature = "legacy")]
-    #[inline]
-    fn legacy_reset(&self) -> ! {
-        T::legacy_reset(self)
-    }
 }
 
 #[cfg(feature = "singleton")]
@@ -90,12 +74,3 @@ pub(crate) fn system_reset(reset_type: u32, reset_reason: u32) -> SbiRet {
     }
     SbiRet::not_supported()
 }
-
-#[cfg(all(feature = "singleton", feature = "legacy"))]
-#[inline]
-pub(crate) fn legacy_reset() -> ! {
-    if let Some(obj) = RESET.get() {
-        obj.legacy_reset()
-    }
-    unreachable!("no reset handler available; this is okay if your platform didn't declare a legacy reset handler")
-}