Currently provided reference platform support projects:
Platform | Legacy | Base | IPI | Timer | RFENCE | HSM | SRST | Note |
---|---|---|---|---|---|---|---|---|
Kendryte K210 | √ | √ | √ | √ | P | P | P | Privileged spec version: 1.9.1 |
QEMU | √ | √ | √ | √ | P | P | √ | - |
P: Pending
These platform implementations are only for reference. Although binaries are released along with RustSBI library itself, platform developers should consider using RustSBI as a library, other than adding code into forked project's 'platforms' and make a pull request.
Tshe RustSBI project will release these platform binaries in release page. Normally, a RustSBI implementation is a separate project other than squashed into 'platform' path; but if you really want to contribute to these reference implementations, you may need to build these platform packages by yourself.
To build provided reference platforms, you should install the command runner just
.
Like make
, just
is a handy way to save and run project specific commands.
To install just, refer to just
packages link and pick
a install command according to your operating system used for development.
Each reference platform have provided justfile
configuration file.
You may cd
into project path and run command just build
to build binary package.
The binary package should be ready in some place under target
folder.
Or, use just run
to build and execute it in emulator with a test kernel.
There are RISC-V cores, SoC's, and boards, we can not support them one by one with any software, typically platform vendor should provide their own SBI support package. RustSBI is designed as a 'building block' library to help on these support packages.
To implement for their own platforms, vendor would typically follow these steps:
When the processor is powering up, it executes few instructions to jump to a processor specific entry address. Your SBI implementation should be there, ready to be executed to prepare an environment for Rust code and interrupt environment.
This runtime should contain two parts: programming language runtime and interrupt handler.
Typically, processor vendor or SoC vendor should provide with a minimal runtime.
Or else, riscv-rt
project would be okay to be a runtime
for all RISC-V chips, this project is provided by community to minimally support Rust language on
standard RISC-V hardware.
If we have to write own runtime, the runtime should initialize bss
and data
sections.
Crate r0
would help a lot if we do this work manually.
When you begin to work with custom hardware e.g. interrupt controller, you should use vendor provided platform specific packages. Load trap configurations into registers in vendor defined procedures. This will provide a machine level trap handler for SBI implementation.
After you pick a runtime, there should be one main entry function and a trap entry function.
All SBI modules in RustSBI are described as Rust traits. Read RISC-V SBI manual carefully, or research on the operating systems you want to support to make a list of modules your SBI should support.
Although it's a legacy function, console_putchar
function by now is commonly used as an early debug output.
Use an on-board serial transmitter half, or other ways to implemenet this function's corresponding Rust trait.
Then, use init_legacy_stdio
etc. to load this module into RustSBI. RustSBI's documentation lists all these
traits that RustSBI supports.
Basical function like mvendorid
and module detections are handled by RustSBI.
After the modules are initialized, RustSBI automatically implement module detection functions
and provide an ecall
handler. You should use this ecall
handler in runtime defined trap handler,
see documentation of rustsbi::ecall
for details.
RustSBI implmenetaion may print rustsbi::LOGO
and misa
onto early debug screen.
There are also some functions in trap handler and entry which a typical SBI implmentation would write.
Here's a checklist of these functions:
medeleg
and mideleg
;rdtime
instruction in illegal instruction exception;mstatus::MPP
is not Machine
.When we write code for SBI functions, embedded-hal
packages would be helpful.
Some of these packages provide a universal abstract for SoC peripherals and are normally provided by SoC vendor.
If our board uses peripheral outside the SoC, other packages would come into effect.
After SBI functions are written, you should use enter_privileged
function provided by RustSBI.
This function uses an entry address of operating system where RustSBI would change privilege level
and jump into. It would also requires a second opaque parameter that the OS would make use of.
Now your operating system should boot up and function normally. Congratulations!
Your prototype bootloader is functional now, to complete its design you may provide more features as a software product.
On PC, SBI software would be flashed onto unique flash or small MCU to help boot the processor. The processor may be upgraded or replaced. You should check if the processor and its memory is okay. Pick or design a small program to check all RISC-V registers, instructions to check if the processor is not broken and is ready to run operating system.
According to your platform, there could be a minimal hardware requirement. Personal computer platform may require a graphic hardware to boot, you should scan if your processor or board provides one graphic hardware. Scan other hardware to prepare for later boot sequences, like setting CPU clocks.
The operating system could be placed anywhere. According to your platform, you may scan for storage
or connect to the Internet for a functional operating system kernel. Fetch the kernel and provide
its entry address into enter_privileged
as mentioned above.
If multiple operating systems are present, provide a user interface to help your user to select which
kernel we should boot.
During boot procedure, provide a way to debug hardware errors. For servers and developers, activate your on-board buzzer, or provide a debug interface like JTAG to tell where the error comes from. For DIY users and overclockers, you may provide EZDebug lights on your board and use SBI to control them.
A full boot sequence may be different on different vendors, and wrong settings on boot sequence can be hard to debug. Read its manual carefully or consult the vendor to work out common bugs.
Implement your SBI platform is easy! There exists some reference implementations in addition to this repository.
terminus_bl
project is a RustSBI implementation for terminus
emulator: shady831213/terminus_bl.