|
@@ -1,5 +1,16 @@
|
|
|
//! A minimal RISC-V's SBI implementation library in Rust.
|
|
|
//!
|
|
|
+//! *Note: If you are a user looking for binary distribution download for RustSBI, you may consider
|
|
|
+//! to use the RustSBI Prototyping System which will provide binaries for each platforms.
|
|
|
+//! If you are a vendor or contributor who wants to adapt RustSBI to your new product or board,
|
|
|
+//! you may consider adapting the Prototyping System first to get your board adapted in an afternoon;
|
|
|
+//! you are only advised to build a discrete crate if your team have a lot of time working on this board.*
|
|
|
+//!
|
|
|
+//! *For more details on binary downloads the the RustSBI Prototyping System,
|
|
|
+//! see section [Prototyping System vs discrete packages](#download-binary-file-the-prototyping-system-vs-discrete-packages).*
|
|
|
+//!
|
|
|
+//! The crate `rustsbi` acts as core trait and instance abstraction of RustSBI ecosystem.
|
|
|
+//!
|
|
|
//! # What is RISC-V SBI?
|
|
|
//!
|
|
|
//! RISC-V SBI is short for RISC-V Supervisor Binary Interface. SBI acts as a bootloader environment to your operating system kernel.
|
|
@@ -101,6 +112,126 @@
|
|
|
//! }
|
|
|
//! ```
|
|
|
//!
|
|
|
+//! # Hypervisor and emulator development with RustSBI
|
|
|
+//!
|
|
|
+//! RustSBI crate supports to develop RISC-V emulators, and both Type-1 and Type-2 hypervisors.
|
|
|
+//! Hypervisor developers may find it easy to handle standard SBI functions with an instance
|
|
|
+//! based RustSBI interface.
|
|
|
+//!
|
|
|
+//! ## Hypervisors using RustSBI
|
|
|
+//!
|
|
|
+//! Both Type-1 and Type-2 hypervisors on RISC-V runs on HS-mode hardware. Depending on demands
|
|
|
+//! of virtualized systems, hypervisors may either provide transparent information from host machine
|
|
|
+//! or provide another set of information to override the current environment. RISC-V hypervisors
|
|
|
+//! does not have direct access to machine mode (M-mode) registers.
|
|
|
+//!
|
|
|
+//! RustSBI supports both by instance based providing a `MachineInfo` structure. If RISC-V
|
|
|
+//! hypervisors choose to use existing information on current machine, it may require to call
|
|
|
+//! underlying machine environment using SBI calls and fill in information into `MachineInfo`.
|
|
|
+//! If hypervisors want to override hardware information, they may fill in custom ones into
|
|
|
+//! `MachineInfo` structures. When creating RustSBI instance, `MachineInfo` structure is
|
|
|
+//! required as an input of constructor.
|
|
|
+//!
|
|
|
+//! To begin with, disable default features in file `Cargo.toml`:
|
|
|
+//!
|
|
|
+//! ```toml
|
|
|
+//! [dependencies]
|
|
|
+//! rustsbi = { version = "0.3.0", default-features = false }
|
|
|
+//! ```
|
|
|
+//!
|
|
|
+//! This will disable default feature `machine` which will assume that RustSBI runs on M-mode directly,
|
|
|
+//! which is not appropriate in our purpose. After that, a `RustSBI` instance may be placed
|
|
|
+//! in the virtual machine structure to prepare for SBI environment:
|
|
|
+//!
|
|
|
+//! ```rust
|
|
|
+//! # struct RustSBI<>();
|
|
|
+//! struct VmHart {
|
|
|
+//! // other fields ...
|
|
|
+//! env: RustSBI</* Types, .. */>,
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//!
|
|
|
+//! When the virtual machine hart trapped into hypervisor, decide whether this trap is an SBI
|
|
|
+//! environment call. If that is true, pass in parameters by `env.handle_ecall` function.
|
|
|
+//! RustSBI will handle with SBI standard constants, call corresponding module and provide
|
|
|
+//! parameters according to the extension and function IDs.
|
|
|
+//!
|
|
|
+//! Crate `rustsbi` adapts to standard RISC-V SBI calls.
|
|
|
+//! If the hypervisor have custom SBI extensions that RustSBI does not recognize, those extension
|
|
|
+//! and function IDs can be checked before calling RustSBI `env.handle_ecall`.
|
|
|
+//!
|
|
|
+//! ```no_run
|
|
|
+//! # use sbi_spec::binary::SbiRet;
|
|
|
+//! # struct MyExtensionEnv {}
|
|
|
+//! # impl MyExtensionEnv { fn handle_ecall(&self, params: ()) -> SbiRet { SbiRet::success(0) } }
|
|
|
+//! # struct RustSBI {} // Mock, prevent doc test error when feature singleton is enabled
|
|
|
+//! # impl RustSBI { fn handle_ecall(&self, params: ()) -> SbiRet { SbiRet::success(0) } }
|
|
|
+//! # struct VmHart { my_extension_env: MyExtensionEnv, env: RustSBI }
|
|
|
+//! # #[derive(Copy, Clone)] enum Trap { Exception(Exception) }
|
|
|
+//! # impl Trap { fn cause(&self) -> Self { *self } }
|
|
|
+//! # #[derive(Copy, Clone)] enum Exception { SupervisorEcall }
|
|
|
+//! # impl VmHart {
|
|
|
+//! # fn new() -> VmHart { VmHart { my_extension_env: MyExtensionEnv {}, env: RustSBI {} } }
|
|
|
+//! # fn run(&mut self) -> Trap { Trap::Exception(Exception::SupervisorEcall) }
|
|
|
+//! # fn trap_params(&self) -> () { }
|
|
|
+//! # fn fill_in(&mut self, ans: SbiRet) { let _ = ans; }
|
|
|
+//! # }
|
|
|
+//! let mut hart = VmHart::new();
|
|
|
+//! loop {
|
|
|
+//! let trap = hart.run();
|
|
|
+//! if let Trap::Exception(Exception::SupervisorEcall) = trap.cause() {
|
|
|
+//! // Firstly, handle custom extensions
|
|
|
+//! let my_extension_sbiret = hart.my_extension_env.handle_ecall(hart.trap_params());
|
|
|
+//! // If custom extension handles correctly, fill in its result and continue to hart.
|
|
|
+//! // The custom handler may handle `probe_extension` in `base` extension as well
|
|
|
+//! // to allow detections to whether custom extension exists.
|
|
|
+//! if my_extension_sbiret != SbiRet::not_supported() {
|
|
|
+//! hart.fill_in(my_extension_sbiret);
|
|
|
+//! continue;
|
|
|
+//! }
|
|
|
+//! // Then, if it's not a custom extension, handle it using standard SBI handler.
|
|
|
+//! let standard_sbiret = hart.env.handle_ecall(hart.trap_params());
|
|
|
+//! hart.fill_in(standard_sbiret);
|
|
|
+//! }
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//!
|
|
|
+//! RustSBI would interact well with custom extension environments in this way.
|
|
|
+//!
|
|
|
+//! ## Emulators using RustSBI
|
|
|
+//!
|
|
|
+//! RustSBI library may be used to write RISC-V emulators. Emulators do not use host hardware
|
|
|
+//! features and thus may build and run on any architecture. Like hardware RISC-V implementations,
|
|
|
+//! software emulated RISC-V environment would still need SBI implementation to support supervisor
|
|
|
+//! environment.
|
|
|
+//!
|
|
|
+//! Writing emulators would follow the similiar process with writing hypervisors, see
|
|
|
+//! [Hypervisors using RustSBI](#hypervisors-using-rustsbi) for details.
|
|
|
+//!
|
|
|
+//! # Download binary file: the Prototyping System vs discrete packages
|
|
|
+//!
|
|
|
+//! RustSBI ecosystem would typically provide support for most platforms. Those support packages
|
|
|
+//! would be provided either from the RustSBI Prototyping System or vendor provided discrete SBI
|
|
|
+//! implementation packages.
|
|
|
+//!
|
|
|
+//! The RustSBI Prototyping System is a universal support package provided by RustSBI ecosystem.
|
|
|
+//! It is designed to save development time while providing most SBI feature possible.
|
|
|
+//! Users may choose to download from Prototyping System repository to get various types of RustSBI
|
|
|
+//! packages for their boards. Vendors and contributors may find it easy to adapt new SoCs and
|
|
|
+//! boards into Prototyping System.
|
|
|
+//!
|
|
|
+//! Discrete SBI packages are SBI environment support packages specially designed for one board
|
|
|
+//! or SoC, it will be provided by board vendor or RustSBI ecosystem.
|
|
|
+//! Vendors may find it easy to include fine grained features in each support package, but the
|
|
|
+//! maintainence situation would vary between vendors and it would likely to cost a lot of time
|
|
|
+//! to develop from a bare-metal executable. Users may find a boost in performance, energy saving
|
|
|
+//! indexes and feature granularity in discrete packages, but it would depends on whether the
|
|
|
+//! vendor provide it.
|
|
|
+//!
|
|
|
+//! To download binary package for the Prototyping System, visit its project website for a download link.
|
|
|
+//! To download them for discrete packages, RustSBI users may visit distribution source of SoC or board
|
|
|
+//! manufacturers.
|
|
|
+//!
|
|
|
//! # Non-features
|
|
|
//!
|
|
|
//! RustSBI is designed to strictly adapt to the RISC-V Supervisor Binary Interface specification.
|
|
@@ -111,36 +242,13 @@
|
|
|
//!
|
|
|
//! According to the RISC-V SBI specification, SBI does not specify any method for hardware discovery.
|
|
|
//! The supervisor software must rely on the other industry standard hardware
|
|
|
-//! discovery methods (i.e. Device Tree or ACPI) for that.
|
|
|
+//! discovery methods (i.e. Device Tree or ACPI) for that purpose.
|
|
|
//!
|
|
|
//! To detect any feature under bare metal or under supervisor level, developers may depend on
|
|
|
//! 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.
|
|
|
//!
|
|
|
-//! ## Where can I get RustSBI binary file for XX platform?
|
|
|
-//!
|
|
|
-//! RustSBI is designed to be a library instead of providing any binary files to specific platforms.
|
|
|
-//! Chip or board manufacturers should provide their own SBI implementation project using RustSBI as a dependency.
|
|
|
-//!
|
|
|
-//! The RustSBI team provides reference implementation for several platforms, but they are for evaluation
|
|
|
-//! only and should not be used in production.
|
|
|
-//! RustSBI itself cannot decide for all arbitrary users, so developers are encouraged to use RustSBI
|
|
|
-//! as a Rust crate dependency to support their own SBI implementation,
|
|
|
-//! other than use reference implementation directly when in production.
|
|
|
-//! SBI feature demands are different among users, one feature would be useful for this user,
|
|
|
-//! but it will be considered not useful and takes up lots of flash room for other users.
|
|
|
-//!
|
|
|
-//! RustSBI is not designed to include all platforms available in official repository.
|
|
|
-//! For an actual platform users may consult board or SoC manufacturer other than RustSBI repository itself.
|
|
|
-//!
|
|
|
-//! The reason to that is that if some repository includes all platforms it support,
|
|
|
-//! there could be lots of non technical reasons that will bar one or a certain group of developers
|
|
|
-//! from merging their code into main or upstream branches.
|
|
|
-//! For example, if a draft version of actual platform is produced, it will mean to write for one draft version as well
|
|
|
-//! as long as this software is under maintenance. As software developer may not want to write for it,
|
|
|
-//! it's better to include minimal feature in core repository, and leave other features for downstream developers.
|
|
|
-//!
|
|
|
//! # Notes for RustSBI developers
|
|
|
//!
|
|
|
//! Following useful hints are for firmware and kernel developers when working with SBI and RustSBI.
|
|
@@ -149,24 +257,25 @@
|
|
|
//!
|
|
|
//! This library adapts to individual Rust traits to provide basic SBI features.
|
|
|
//! When building for own platform, implement traits in this library and pass them to the functions
|
|
|
-//! begin with `init`. After that, you may call `rustsbi::ecall` in your own exception handler
|
|
|
-//! which would dispatch parameters from supervisor to the traits to execute SBI functions.
|
|
|
+//! begin with `init`. After that, you may call `rustsbi::ecall`, `RustSBI::handle_ecall` or
|
|
|
+//! similiar functions in your own exception handler.
|
|
|
+//! It would dispatch parameters from supervisor to the traits to execute SBI functions.
|
|
|
//!
|
|
|
//! The library also implements useful functions which may help with platform specific binaries.
|
|
|
-//! The `enter_privileged` maybe used to enter the operating system after the initialization
|
|
|
-//! process is finished. The `LOGO` should be printed if necessary when the binary is initializing.
|
|
|
+//! The `LOGO` can be printed if necessary when the binary is initializing.
|
|
|
//!
|
|
|
//! Note that this crate is a library which contains common building blocks in SBI implementation.
|
|
|
-//! It is not intended to be used directly; users should build own platforms with this library.
|
|
|
-//! RustSBI provides implementations on common platforms in separate platform crates.
|
|
|
+//! The RustSBI ecosystem would provide different level of support for each board, those support
|
|
|
+//! packages would use `rustsbi` crate as library to provide different type of SBI binary releases.
|
|
|
//!
|
|
|
//! ## Legacy SBI extension
|
|
|
//!
|
|
|
-//! Note: RustSBI legacy support is only designed for backward compability. It's disabled by default and it's not
|
|
|
-//! suggested to include legacy functions in newer firmware designs. Modules other than legacy console is replaced by
|
|
|
-//! individual modules in SBI. Legacy console is not suggested to use in kernels.
|
|
|
+//! *Note: RustSBI legacy support is only designed for backward compability of RISC-V SBI standard.
|
|
|
+//! It's disabled by default and it's not suggested to include legacy functions in newer firmware designs.
|
|
|
+//! Modules other than legacy console is replaced by individual modules in SBI.
|
|
|
+//! Kernels are not suggested to use legacy functions in practice.
|
|
|
//! If you are a kernel developer, newer designs should consider relying on each SBI module other than
|
|
|
-//! legacy functions.
|
|
|
+//! legacy functions.*
|
|
|
//!
|
|
|
//! The SBI includes legacy extension which dated back to SBI 0.1 specification. Most of its features
|
|
|
//! are replaced by individual SBI modules, thus the entire legacy extension is deprecated by
|
|
@@ -203,22 +312,14 @@ mod timer;
|
|
|
#[cfg(feature = "singleton")]
|
|
|
mod util;
|
|
|
|
|
|
-/// The const rustsbi logo with blank line at the beginning.
|
|
|
-const LOGO: &str = r"
|
|
|
-.______ __ __ _______.___________. _______..______ __
|
|
|
+/// The RustSBI logo without blank lines on the beginning
|
|
|
+pub const LOGO: &str = r".______ __ __ _______.___________. _______..______ __
|
|
|
| _ \ | | | | / | | / || _ \ | |
|
|
|
| |_) | | | | | | (----`---| |----`| (----`| |_) || |
|
|
|
| / | | | | \ \ | | \ \ | _ < | |
|
|
|
| |\ \----.| `--' |.----) | | | .----) | | |_) || |
|
|
|
| _| `._____| \______/ |_______/ |__| |_______/ |______/ |__|";
|
|
|
|
|
|
-/// The RustSBI logo without blank lines
|
|
|
-pub fn logo() -> &'static str {
|
|
|
- // rust raw text 无法在保持格式的情况下去除头上的换行
|
|
|
- // include_str("logo.txt") 会由于 vscode 的自动格式化在末尾多一个换行
|
|
|
- LOGO.trim_start()
|
|
|
-}
|
|
|
-
|
|
|
const SBI_SPEC_MAJOR: usize = 1;
|
|
|
const SBI_SPEC_MINOR: usize = 0;
|
|
|
|
|
@@ -233,7 +334,7 @@ const RUSTSBI_VERSION_PATCH: usize = (env!("CARGO_PKG_VERSION_PATCH").as_bytes()
|
|
|
const RUSTSBI_VERSION: usize =
|
|
|
(RUSTSBI_VERSION_MAJOR << 16) + (RUSTSBI_VERSION_MINOR << 8) + RUSTSBI_VERSION_PATCH;
|
|
|
|
|
|
-/// RustSBI version as a string.
|
|
|
+/// RustSBI version as a string
|
|
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
|
|
|
|
pub extern crate sbi_spec as spec;
|