README.md 7.2 KB

RustSBI platforms

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

Notes for binary releases

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.

Build and install

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.

Support your own platform

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:

  1. Pick an RISC-V software runtime
  2. Initialize SBI functions into RustSBI
  3. Add additional support features

Pick a runtime

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.

Initialize and use SBI functions

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:

  • Delegate exceptions and interrupts to S privilege in medeleg and mideleg;
  • Emulate rdtime instruction in illegal instruction exception;
  • Raise invalid instruction to supervisor if 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!

Additional support features

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.

Reference

Implement your SBI platform is easy! There exists some reference implementations in addition to this repository.