Skip to content

Commit

Permalink
Merge pull request rustsbi#44 from luojia65/main
Browse files Browse the repository at this point in the history
lib: document fixes
  • Loading branch information
luojia65 authored Oct 22, 2022
2 parents a024b12 + 8db0655 commit 9ab2ea9
Showing 1 changed file with 146 additions and 45 deletions.
191 changes: 146 additions & 45 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down

0 comments on commit 9ab2ea9

Please sign in to comment.