Skip to content

Commit 061c0aa

Browse files
committed
SBI: introducing sbi compatibility
1 parent 93bc768 commit 061c0aa

File tree

6 files changed

+112
-23
lines changed

6 files changed

+112
-23
lines changed

riscv-rt/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ keywords = ["riscv", "runtime", "startup"]
1010
license = "ISC"
1111
edition = "2018"
1212

13+
[features]
14+
sbi = []
15+
1316
[dependencies]
1417
r0 = "1.0.0"
1518
riscv = "0.8"

riscv-rt/asm.S

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,14 @@ _abs_start:
4646
.cfi_startproc
4747
.cfi_undefined ra
4848

49+
#ifdef SBI
50+
csrw sie, 0 // interrupt disable
51+
csrw sip, 0 // no pending interrupts
52+
#else
4953
csrw mie, 0
5054
csrw mip, 0
55+
#endif
56+
5157

5258
li x1, 0
5359
li x2, 0
@@ -84,8 +90,13 @@ _abs_start:
8490
la gp, __global_pointer$
8591
.option pop
8692

87-
// Check hart id
93+
#ifdef SBI
94+
// there is no equivalent of mhartid in supervisor mode.
95+
// instead, the hartid is passed as paramter by SBI
96+
mv t2, a0
97+
#else
8898
csrr t2, mhartid
99+
#endif
89100
lui t0, %hi(_max_hart_id)
90101
add t0, t0, %lo(_max_hart_id)
91102
bgtu t2, t0, abort
@@ -165,7 +176,11 @@ default_start_trap:
165176
LOAD a7, 15*REGBYTES(sp)
166177

167178
addi sp, sp, 16*REGBYTES
179+
#ifdef SBI
180+
sret
181+
#else
168182
mret
183+
#endif
169184

170185
/* Make sure there is an abort when linking */
171186
.section .text.abort

riscv-rt/assemble.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ do
3131

3232
riscv64-unknown-elf-gcc -ggdb3 -fdebug-prefix-map=$(pwd)=/riscv-rt -c -mabi=lp64${abi} -march=rv64${ext} asm.S -o bin/$crate.o
3333
riscv64-unknown-elf-ar crs bin/riscv64${ext}-unknown-none-elf.a bin/$crate.o
34+
35+
#sbi
36+
riscv64-unknown-elf-gcc -DSBI -ggdb3 -fdebug-prefix-map=$(pwd)=/riscv-rt -c -mabi=ilp32${abi} -march=rv32${ext} asm.S -o bin/$crate.o
37+
riscv64-unknown-elf-ar crs bin/riscv32${ext}-unknown-none-elf-sbi.a bin/$crate.o
38+
39+
riscv64-unknown-elf-gcc -DSBI -ggdb3 -fdebug-prefix-map=$(pwd)=/riscv-rt -c -mabi=lp64${abi} -march=rv64${ext} asm.S -o bin/$crate.o
40+
riscv64-unknown-elf-ar crs bin/riscv64${ext}-unknown-none-elf-sbi.a bin/$crate.o
41+
3442
done
3543

3644
rm bin/$crate.o

riscv-rt/build.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ fn main() {
1414
if target.starts_with("riscv") {
1515
let mut target = Target::from_target_str(&target);
1616
target.retain_extensions("imfdc");
17-
let archive = format!("bin/{}.a", target.to_string());
17+
let archive:String;
18+
if cfg!(feature = "sbi") {
19+
println!("======== compiling riscv-rt for sbi");
20+
archive = format!("bin/{}-sbi.a", target.to_string());
21+
} else {
22+
archive = format!("bin/{}.a", target.to_string());
23+
}
1824

1925
fs::copy(&archive, out_dir.join(format!("lib{}.a", name))).unwrap();
2026
println!("cargo:rerun-if-changed={}", archive);

riscv-rt/examples/multi_core.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use riscv_rt::entry;
1111

1212
#[export_name = "_mp_hook"]
1313
#[rustfmt::skip]
14-
pub extern "Rust" fn user_mp_hook() -> bool {
14+
pub extern "Rust" fn user_mp_hook(hartid: usize) -> bool {
1515
let hartid = mhartid::read();
1616
if hartid == 0 {
1717
true
@@ -42,9 +42,7 @@ pub extern "Rust" fn user_mp_hook() -> bool {
4242
}
4343

4444
#[entry]
45-
fn main() -> ! {
46-
let hartid = mhartid::read();
47-
45+
fn main(hartid: usize) -> ! {
4846
if hartid == 0 {
4947
// Waking hart 1...
5048
let addr = 0x02000004;

riscv-rt/src/lib.rs

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
//! filename can be use instead of `memory.x`.
2222
//!
2323
//! - A `_sheap` symbol at whose address you can locate a heap.
24+
//!
25+
//! - Support for a runtime in supervisor mode, bootstrapped via [Supervisor Binary Interface (SBI)](https://github.com/riscv-non-isa/riscv-sbi-doc)
2426
//!
2527
//! ``` text
2628
//! $ cargo new --bin app && cd $_
@@ -230,12 +232,13 @@
230232
//! This function is called from all the harts and must return true only for one hart,
231233
//! which will perform memory initialization. For other harts it must return false
232234
//! and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
235+
//! The parameter `hartid` specifies the hartid of the caller.
233236
//!
234237
//! This function can be redefined in the following way:
235238
//!
236239
//! ``` no_run
237240
//! #[export_name = "_mp_hook"]
238-
//! pub extern "Rust" fn mp_hook() -> bool {
241+
//! pub extern "Rust" fn mp_hook(hartid: usize) -> bool {
239242
//! // ...
240243
//! }
241244
//! ```
@@ -245,7 +248,7 @@
245248
//! ### `ExceptionHandler`
246249
//!
247250
//! This function is called when exception is occured. The exception reason can be decoded from the
248-
//! `mcause` register.
251+
//! `mcause`/`scause` register.
249252
//!
250253
//! This function can be redefined in the following way:
251254
//!
@@ -300,7 +303,7 @@
300303
//! ### `DefaultHandler`
301304
//!
302305
//! This function is called when interrupt without defined interrupt handler is occured.
303-
//! The interrupt reason can be decoded from the `mcause` register.
306+
//! The interrupt reason can be decoded from the `mcause`/`scause` register.
304307
//!
305308
//! This function can be redefined in the following way:
306309
//!
@@ -319,12 +322,44 @@
319322
//! ```
320323
//!
321324
//! Default implementation of this function stucks in a busy-loop.
325+
//!
326+
//! # Features
327+
//!
328+
//! ## `sbi`
329+
//!
330+
//! The SBI runtime feature (`sbi`) can be activated via [Cargo features](https://doc.rust-lang.org/cargo/reference/features.html).
331+
//!
332+
//! For example:
333+
//! ``` text
334+
//! [dependencies]
335+
//! riscv-rt = {features=["sbi"]}
336+
//! ```
337+
//! Using the SBI requires riscv-rt to be run in supervisor mode instead of machine code.
338+
//! Internally, riscv-rt uses different versions of precompiled static libraries
339+
//! for (i) machine mode and (ii) sbi. If the `sbi` feature was activated,
340+
//! the build script selects the sbi library. While most registers/instructions have variants for
341+
//! both `mcause` and `scause`, the `mhartid` hardware thread register is not available in supervisor
342+
//! mode. Instead, the hartid is passed as parameter by the calling SBI.
343+
//!
344+
//! QEMU supports [OpenSBI](https://github.com/riscv-software-src/opensbi) as default firmware.
345+
//! ``` text
346+
//! APP_BINARY=$(find target -name app)
347+
//! sudo qemu-system-riscv64 -m 2G -nographic -machine virt -kernel $APP_BINARY
348+
//! ```
349+
//! It requires the memory layout to be non-overlapping, like
350+
//! ``` text
351+
//! MEMORY
352+
//! {
353+
//! RAM : ORIGIN = 0x80200000, LENGTH = 0x8000000
354+
//! FLASH : ORIGIN = 0x20000000, LENGTH = 16M
355+
//! }
356+
//! ```
322357
323358
// NOTE: Adapted from cortex-m/src/lib.rs
324359
#![no_std]
325360
#![deny(missing_docs)]
326361

327-
use riscv::register::mcause;
362+
use riscv::register::{scause,mcause,mhartid};
328363
pub use riscv_rt_macros::{entry, pre_init};
329364

330365
#[export_name = "error: riscv-rt appears more than once in the dependency graph"]
@@ -361,10 +396,18 @@ pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
361396

362397
fn _setup_interrupts();
363398

364-
fn _mp_hook() -> bool;
399+
fn _mp_hook(hartid: usize) -> bool;
400+
}
401+
402+
// sbi passes hartid as first parameter (a0)
403+
let hartid : usize;
404+
if cfg!(feature = "sbi") {
405+
hartid = a0;
406+
} else {
407+
hartid = mhartid::read();
365408
}
366409

367-
if _mp_hook() {
410+
if _mp_hook(hartid) {
368411
__pre_init();
369412

370413
r0::zero_bss(&mut _sbss, &mut _ebss);
@@ -403,7 +446,7 @@ pub struct TrapFrame {
403446

404447
/// Trap entry point rust (_start_trap_rust)
405448
///
406-
/// `mcause` is read to determine the cause of the trap. XLEN-1 bit indicates
449+
/// `scause`/`mcause` is read to determine the cause of the trap. XLEN-1 bit indicates
407450
/// if it's an interrupt or an exception. The result is examined and ExceptionHandler
408451
/// or one of the core interrupt handlers is called.
409452
#[link_section = ".trap.rust"]
@@ -415,11 +458,22 @@ pub extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
415458
}
416459

417460
unsafe {
418-
let cause = mcause::read();
419-
if cause.is_exception() {
461+
let code : usize;
462+
let is_exception: bool;
463+
464+
if cfg!(feature = "sbi") {
465+
let cause = scause::read();
466+
is_exception = cause.is_exception();
467+
code = cause.code();
468+
} else {
469+
let cause = mcause::read();
470+
is_exception = cause.is_exception();
471+
code = cause.code();
472+
}
473+
474+
if is_exception {
420475
ExceptionHandler(&*trap_frame)
421476
} else {
422-
let code = cause.code();
423477
if code < __INTERRUPTS.len() {
424478
let h = &__INTERRUPTS[code];
425479
if h.reserved == 0 {
@@ -430,7 +484,7 @@ pub extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
430484
} else {
431485
DefaultHandler();
432486
}
433-
}
487+
}
434488
}
435489
}
436490

@@ -529,24 +583,29 @@ pub unsafe extern "Rust" fn default_pre_init() {}
529583
#[doc(hidden)]
530584
#[no_mangle]
531585
#[rustfmt::skip]
532-
pub extern "Rust" fn default_mp_hook() -> bool {
533-
use riscv::register::mhartid;
534-
match mhartid::read() {
586+
pub extern "Rust" fn default_mp_hook(hartid: usize) -> bool {
587+
match hartid {
535588
0 => true,
536589
_ => loop {
537590
unsafe { riscv::asm::wfi() }
538591
},
539592
}
540593
}
541594

542-
/// Default implementation of `_setup_interrupts` that sets `mtvec` to a trap handler address.
595+
/// Default implementation of `_setup_interrupts` that sets `mtvec`/`stvec` to a trap handler address.
543596
#[doc(hidden)]
544597
#[no_mangle]
545598
#[rustfmt::skip]
546599
pub unsafe extern "Rust" fn default_setup_interrupts() {
547-
use riscv::register::mtvec::{self, TrapMode};
548600
extern "C" {
549601
fn _start_trap();
550602
}
551-
mtvec::write(_start_trap as usize, TrapMode::Direct);
603+
604+
if cfg!(feature = "sbi") {
605+
use riscv::register::stvec::{self, TrapMode};
606+
stvec::write(_start_trap as usize, TrapMode::Direct);
607+
} else {
608+
use riscv::register::mtvec::{self, TrapMode};
609+
mtvec::write(_start_trap as usize, TrapMode::Direct);
610+
}
552611
}

0 commit comments

Comments
 (0)