123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- //! 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
- //! using the [RustSBI Prototyping System](https://github.com/rustsbi/standalone)
- //! 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 the RustSBI ecosystem.
- //!
- //! # What is RISC-V SBI?
- //!
- //! RISC-V SBI is short for RISC-V Supervisor Binary Interface. SBI acts as an interface to environment
- //! for your operating system kernel.
- //! An SBI implementation will allow furtherly bootstrap your kernel, and provide an environment while the kernel is running.
- //!
- //! More generally, The SBI allows supervisor-mode (S-mode or VS-mode) software to be portable across
- //! all RISC-V implementations by defining an abstraction for platform (or hypervisor) specific functionality.
- //!
- //! # Use RustSBI services in your supervisor software
- //!
- //! SBI environment features include boot sequence and a kernel environment. To bootstrap your kernel,
- //! place kernel into RustSBI implementation defined address, then RustSBI will prepare an
- //! environment and call the entry function on this address.
- //!
- //! ## Make SBI environment calls
- //!
- //! To use the kernel environment, you either use SBI calls or emulated instructions.
- //! SBI calls are similar to operating systems' `syscall`s. RISC-V SBI defined many SBI extensions,
- //! and in each extension there are different functions, you should pick a function before calling.
- //! Then, you should prepare some parameters, whose definition are not the same among functions.
- //!
- //! Now you have an extension number, a function number, and a few SBI call parameters.
- //! You invoke a special `ecall` instruction on supervisor level, and it will trap into machine level
- //! SBI implementation. It will handle your `ecall`, similar to your kernel handling system calls
- //! from user level.
- //!
- //! SBI functions return two values other than one. First value will be an error number,
- //! it will tell if SBI call have succeeded, or which error have occurred.
- //! Second value is the real return value, its meaning is different according to which function you calls.
- //!
- //! ## Call SBI in different programming languages
- //!
- //! Making SBI calls are similar to making system calls.
- //!
- //! Extension number is required to put on register `a7`, function number on `a6` if applicable.
- //! Parameters should be placed from `a0` to `a5`, first into `a0`, second into `a1`, etc.
- //! Unused parameters can be set to any value or leave untouched.
- //!
- //! After registers are ready, invoke an instruction called `ecall`.
- //! Then, the return value is placed into `a0` and `a1` registers.
- //! The error value could be read from `a0`, and return value is placed into `a1`.
- //!
- //! In Rust, here is an example to call SBI functions using inline assembly:
- //!
- //! ```no_run
- //! # #[repr(C)] struct SbiRet { error: usize, value: usize }
- //! # const EXTENSION_BASE: usize = 0x10;
- //! # const FUNCTION_BASE_GET_SPEC_VERSION: usize = 0x0;
- //! #[inline(always)]
- //! fn sbi_call(extension: usize, function: usize, arg0: usize, arg1: usize) -> SbiRet {
- //! let (error, value);
- //! match () {
- //! #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
- //! () => unsafe { asm!(
- //! "ecall",
- //! in("a0") arg0, in("a1") arg1,
- //! in("a6") function, in("a7") extension,
- //! lateout("a0") error, lateout("a1") value,
- //! ) },
- //! #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
- //! () => {
- //! drop((extension, function, arg0, arg1));
- //! unimplemented!("not RISC-V instruction set architecture")
- //! }
- //! };
- //! SbiRet { error, value }
- //! }
- //!
- //! #[inline]
- //! pub fn get_spec_version() -> SbiRet {
- //! sbi_call(EXTENSION_BASE, FUNCTION_BASE_GET_SPEC_VERSION, 0, 0)
- //! }
- //! ```
- //!
- //! SBI functions would return a result thus some of these may fail.
- //! In this example we only take the value, but in complete designs we should handle the `error`
- //! returned by SbiRet.
- //!
- //! You may use other languages to call SBI environment. In C programming language, we can call like this:
- //!
- //! ```text
- //! #define SBI_CALL(ext, funct, arg0, arg1, arg2, arg3) ({ \
- //! register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); \
- //! register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); \
- //! register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); \
- //! register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3); \
- //! register uintptr_t a6 asm ("a6") = (uintptr_t)(funct); \
- //! register uintptr_t a7 asm ("a7") = (uintptr_t)(ext); \
- //! asm volatile ("ecall" \
- //! : "+r" (a0), "+r" (a1) \
- //! : "r" (a1), "r" (a2), "r" (a3), "r" (a6), "r" (a7) \
- //! : "memory") \
- //! {a0, a1}; \
- //! })
- //!
- //! #define SBI_CALL_0(ext, funct) SBI_CALL(ext, funct, 0, 0, 0, 0)
- //!
- //! static inline sbiret get_spec_version() {
- //! SBI_CALL_0(EXTENSION_BASE, FUNCTION_BASE_GET_SPEC_VERSION)
- //! }
- //! ```
- //!
- //! # Implement RustSBI on machine environment
- //!
- //! Boards, SoC vendors, machine environment emulators and research projects may adapt RustSBI
- //! to specific environments.
- //! RustSBI project supports these demands either by discrete package or the Prototyping System.
- //! Developers may choose the Prototyping System to shorten development time,
- //! or discrete packages to include fine-grained features.
- //!
- //! Hypervisor and supervisor environment emulator developers may refer to
- //! [Hypervisor and emulator development with RustSBI](#hypervisor-and-emulator-development-with-rustsbi)
- //! for such purposes as RustSBI provide different set of features dedicated for emulated or virtual
- //! environments.
- //!
- //! ## Use the Prototyping System
- //!
- //! The RustSBI Prototyping System aims to get your platform working with SBI in an afternoon.
- //! It supports most RISC-V platforms available by providing scalable set of drivers and features.
- //! It provides custom features such as Penglai TEE, DramForever's emulated hypervisor extension, and Raven
- //! the firmware debugger framework.
- //!
- //! You may find further documents on [RustSBI Prototyping System repository](https://github.com/rustsbi/standalone).
- //!
- //! ## Discrete RustSBI package on bare metal RISC-V hardware
- //!
- //! Discrete packages provide developers with most scalability and complete control of underlying
- //! hardware. It is ideal if advanced low power features, management cores and other features should
- //! be used in this implementation.
- //!
- //! RustSBI supports discrete package by default. Create a new `#![no_std]` bare-metal package
- //! to get started. Add following lines to `Cargo.toml`:
- //!
- //! ```toml
- //! [dependencies]
- //! rustsbi = "0.4.0"
- //! ```
- //!
- //! After hardware initialization process, the part of firmware with RustSBI linked should run on memory
- //! blocks with fast accesses, as it would be called frequently by operating system.
- //! If the supervisor is called by trap generator semantics, insert `rustsbi::RustSBI` structure
- //! in your hart executor structure.
- //!
- //! ```rust
- //! # struct Clint;
- //! # struct MyPlatRfnc;
- //! # struct MyPlatHsm;
- //! # struct MyBoardPower;
- //! # struct MyPlatPmu;
- //! # struct MyPlatDbcn;
- //! use rustsbi::RustSBI;
- //!
- //! # struct SupervisorContext;
- //! /// Executes the supervisor within.
- //! struct Executor {
- //! ctx: SupervisorContext,
- //! /* other environment variables ... */
- //! sbi: RustSBI<Clint, Clint, MyPlatRfnc, MyPlatHsm, MyBoardPower, MyPlatPmu, MyPlatDbcn>,
- //! /* custom_1: CustomSBI<...> */
- //! }
- //!
- //! # struct Trap;
- //! impl Executor {
- //! /// A function that runs the provided supervisor, uses `&mut self` for it
- //! /// modifies `SupervisorContext`.
- //! ///
- //! /// It returns for every Trap the supervisor produces. Its handler should read
- //! /// and modify `self.ctx` if necessary. After handled, `run()` this structure
- //! /// again or exit execution process.
- //! pub fn run(&mut self) -> Trap {
- //! todo!("fill in generic or platform specific trampoline procedure")
- //! }
- //! }
- //! ```
- //!
- //! After each `run()`, process the trap returned with the RustSBI instance in executor.
- //! Call `RustSBI::handle_ecall` and fill in developer provided `SupervisorContext` if necessary.
- //!
- //! ```no_run
- //! # use sbi_spec::binary::SbiRet;
- //! # struct RustSBI {} // Mock, prevent doc test error when feature singleton is enabled
- //! # impl RustSBI { fn handle_ecall(&self, e: (), f: (), p: ()) -> SbiRet { SbiRet::success(0) } }
- //! # struct Executor { sbi: RustSBI }
- //! # #[derive(Copy, Clone)] enum Trap { Exception(Exception) }
- //! # impl Trap { fn cause(&self) -> Self { *self } }
- //! # #[derive(Copy, Clone)] enum Exception { SupervisorEcall }
- //! # impl Executor {
- //! # fn new(board_params: BoardParams) -> Executor { let _ = board_params; Executor { sbi: RustSBI {} } }
- //! # fn run(&mut self) -> Trap { Trap::Exception(Exception::SupervisorEcall) }
- //! # fn sbi_extension(&self) -> () { }
- //! # fn sbi_function(&self) -> () { }
- //! # fn sbi_params(&self) -> () { }
- //! # fn fill_sbi_return(&mut self, ans: SbiRet) { let _ = ans; }
- //! # }
- //! # struct BoardParams;
- //! # const MY_SPECIAL_EXIT: usize = 0x233;
- //! /// Board specific power operations.
- //! enum Operation {
- //! Reboot,
- //! Shutdown,
- //! }
- //!
- //! # impl From<SbiRet> for Operation { fn from(_: SbiRet) -> Self { todo!() } }
- //! /// Execute supervisor in given board parameters.
- //! pub fn execute_supervisor(board_params: BoardParams) -> Operation {
- //! let mut exec = Executor::new(board_params);
- //! loop {
- //! let trap = exec.run();
- //! if let Trap::Exception(Exception::SupervisorEcall) = trap.cause() {
- //! let ans = exec.sbi.handle_ecall(
- //! exec.sbi_extension(),
- //! exec.sbi_function(),
- //! exec.sbi_params(),
- //! );
- //! if ans.error == MY_SPECIAL_EXIT {
- //! break Operation::from(ans)
- //! }
- //! // This line would also advance `sepc` with `4` to indicate the `ecall` is handled.
- //! exec.fill_sbi_return(ans);
- //! } else {
- //! // other trap types ...
- //! }
- //! }
- //! }
- //! ```
- //!
- //! Now, call supervisor execution function in your bare metal package to finish the discrete
- //! package project.
- //!
- //! ```no_run
- //! # #[cfg(nightly)] // disable checks
- //! #[naked]
- //! #[link_section = ".text.entry"]
- //! #[export_name = "_start"]
- //! unsafe extern "C" fn entry() -> ! {
- //! #[link_section = ".bss.uninit"]
- //! static mut SBI_STACK: [u8; LEN_STACK_SBI] = [0; LEN_STACK_SBI];
- //!
- //! // Note: actual assembly code varies between platforms.
- //! // Double check documents before continue on.
- //! core::arch::asm!(
- //! // 1. Turn off interrupt
- //! "csrw mie, zero",
- //! // 2. Initialize programming langauge runtime
- //! // only clear bss if hartid is zero
- //! "csrr t0, mhartid",
- //! "bnez t0, 2f",
- //! // clear bss segment
- //! "la t0, sbss",
- //! "la t1, ebss",
- //! "1:",
- //! "bgeu t0, t1, 2f",
- //! "sd zero, 0(t0)",
- //! "addi t0, t0, 8",
- //! "j 1b",
- //! "2:",
- //! // 3. Prepare stack for each hart
- //! "la sp, {stack}",
- //! "li t0, {per_hart_stack_size}",
- //! "csrr t1, mhartid",
- //! "addi t1, t1, 1",
- //! "1: ",
- //! "add sp, sp, t0",
- //! "addi t1, t1, -1",
- //! "bnez t1, 1b",
- //! "j {rust_main}",
- //! // 4. Clean up
- //! "j {finalize}",
- //! per_hart_stack_size = const LEN_STACK_PER_HART,
- //! stack = sym SBI_STACK,
- //! rust_main = sym rust_main,
- //! finalize = sym finalize,
- //! options(noreturn)
- //! )
- //! }
- //!
- //! # fn board_init_once() {}
- //! # fn print_information_once() {}
- //! # fn execute_supervisor(_bp: &()) -> Operation { Operation::Shutdown }
- //! /// Power operation after main function
- //! enum Operation {
- //! Reboot,
- //! Shutdown,
- //! // Add board specific low power modes if necessary. This will allow the
- //! // function `finalize` to operate on board specific power management chips.
- //! }
- //!
- //! /// Rust entry, call in `entry` assembly function
- //! extern "C" fn rust_main(_hartid: usize, opaque: usize) -> Operation {
- //! // .. board initialization process ...
- //! let board_params = board_init_once();
- //! // .. print necessary information and rustsbi::LOGO ..
- //! print_information_once();
- //! // execute supervisor, return as Operation
- //! execute_supervisor(&board_params)
- //! }
- //!
- //! # fn wfi() {}
- //! /// Perform board specific power operations
- //! ///
- //! /// The function here provides a stub to example power operations.
- //! /// Actual board developers should provide with more practical communications
- //! /// to external chips on power operation.
- //! unsafe extern "C" fn finalize(op: Operation) -> ! {
- //! match op {
- //! Operation::Shutdown => {
- //! // easiest way to make a hart look like powered off
- //! loop { wfi(); }
- //! }
- //! Operation::Reboot => {
- //! # fn entry() -> ! { loop {} } // mock
- //! // easiest software reset is to jump to entry directly
- //! entry()
- //! }
- //! // .. more power operations goes here ..
- //! }
- //! }
- //! ```
- //!
- //! Now RustSBI would run on machine environment, you may start a kernel or use an SBI test suite
- //! to check if it is properly implemented.
- //!
- //! Some platforms would provide system memory under different grades in speed and size to reduce product cost.
- //! Those platforms would typically provide two parts of code memory, first one being relatively small, not fast
- //! but instantly available after chip start, while the second one is larger in size but typically requires
- //! memory training. The former one would include built-in SRAM memory, and the later would include
- //! external SRAM or DDR memory. On those platforms, a first stage bootloader is typically needed to
- //! train memory for later stages. In such situation, RustSBI implementation should be linked or concated
- //! to the second stage bootloader, and the first stage could be a standalone binary package bundled with it.
- //!
- //! # 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 run 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. Notably,
- //! RISC-V hypervisors do not have direct access to machine mode (M-mode) registers.
- //!
- //! RustSBI supports both by providing a `MachineInfo` structure in instance based interface.
- //! If RISC-V hypervisors choose to use existing information on current machine, it may require
- //! to call underlying M-mode environment using SBI calls and fill in information into `MachineInfo`.
- //! If hypervisors use customized information other than taking the same one from the
- //! environment they reside in, they may fill in custom one 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.4.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 traps into hypervisor, its code should 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 extension 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. Other than hardware accelereted binary
- //! translation methods, emulators typically do not use host hardware specific features,
- //! 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.
- //! It also includes a universal test kernel to allow testing SBI implementations on current environment.
- //! Users may choose to download from [Prototyping System repository](https://github.com/rustsbi/standalone)
- //! 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. Additionally, users may visit [the awesome page](https://github.com/rustsbi/awesome-rustsbi)
- //! for a curated list ofboth Prototyping System and discrete packages provided by RustSBI ecosystem.
- //!
- //! # Notes for RustSBI developers
- //!
- //! Following useful hints are for firmware and kernel developers when working with SBI and RustSBI.
- //!
- //! ## RustSBI is a library for interfaces
- //!
- //! 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`, `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 `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.
- //! 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.
- //!
- //! ## Hardware discovery and feature detection
- //!
- //! According to the RISC-V SBI specification, SBI itself 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 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.
- #![no_std]
- mod console;
- mod hart_mask;
- mod hsm;
- mod instance;
- mod ipi;
- mod memory_range;
- mod pmu;
- mod reset;
- mod rfence;
- mod timer;
- /// The RustSBI logo without blank lines on the beginning
- pub const LOGO: &str = r".______ __ __ _______.___________. _______..______ __
- | _ \ | | | | / | | / || _ \ | |
- | |_) | | | | | | (----`---| |----`| (----`| |_) || |
- | / | | | | \ \ | | \ \ | _ < | |
- | |\ \----.| `--' |.----) | | | .----) | | |_) || |
- | _| `._____| \______/ |_______/ |__| |_______/ |______/ |__|";
- // RustSBI supports RISC-V SBI specification 2.0-rc1
- const SBI_SPEC_MAJOR: usize = 2;
- const SBI_SPEC_MINOR: usize = 0;
- /// RustSBI implementation ID: 4
- ///
- /// Ref: https://github.com/riscv-non-isa/riscv-sbi-doc/pull/61
- const IMPL_ID_RUSTSBI: usize = 4;
- const RUSTSBI_VERSION_MAJOR: usize = (env!("CARGO_PKG_VERSION_MAJOR").as_bytes()[0] - b'0') as _;
- const RUSTSBI_VERSION_MINOR: usize = (env!("CARGO_PKG_VERSION_MINOR").as_bytes()[0] - b'0') as _;
- const RUSTSBI_VERSION_PATCH: usize = (env!("CARGO_PKG_VERSION_PATCH").as_bytes()[0] - b'0') as _;
- const RUSTSBI_VERSION: usize =
- (RUSTSBI_VERSION_MAJOR << 16) + (RUSTSBI_VERSION_MINOR << 8) + RUSTSBI_VERSION_PATCH;
- /// RustSBI version as a string
- pub const VERSION: &str = env!("CARGO_PKG_VERSION");
- pub extern crate sbi_spec as spec;
- pub use console::Console;
- pub use hart_mask::HartMask;
- pub use hsm::Hsm;
- pub use instance::{Builder, RustSBI};
- pub use ipi::Ipi;
- pub use memory_range::Physical;
- pub use pmu::Pmu;
- pub use reset::Reset;
- pub use rfence::Rfence as Fence;
- pub use timer::Timer;
- #[cfg(not(feature = "machine"))]
- pub use instance::MachineInfo;
|