21
21
//! filename can be use instead of `memory.x`.
22
22
//!
23
23
//! - 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)
24
26
//!
25
27
//! ``` text
26
28
//! $ cargo new --bin app && cd $_
230
232
//! This function is called from all the harts and must return true only for one hart,
231
233
//! which will perform memory initialization. For other harts it must return false
232
234
//! 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.
233
236
//!
234
237
//! This function can be redefined in the following way:
235
238
//!
236
239
//! ``` no_run
237
240
//! #[export_name = "_mp_hook"]
238
- //! pub extern "Rust" fn mp_hook() -> bool {
241
+ //! pub extern "Rust" fn mp_hook(hartid: usize ) -> bool {
239
242
//! // ...
240
243
//! }
241
244
//! ```
245
248
//! ### `ExceptionHandler`
246
249
//!
247
250
//! This function is called when exception is occured. The exception reason can be decoded from the
248
- //! `mcause` register.
251
+ //! `mcause`/`scause` register.
249
252
//!
250
253
//! This function can be redefined in the following way:
251
254
//!
300
303
//! ### `DefaultHandler`
301
304
//!
302
305
//! 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.
304
307
//!
305
308
//! This function can be redefined in the following way:
306
309
//!
319
322
//! ```
320
323
//!
321
324
//! 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
+ //! ```
322
357
323
358
// NOTE: Adapted from cortex-m/src/lib.rs
324
359
#![ no_std]
325
360
#![ deny( missing_docs) ]
326
361
327
- use riscv:: register:: mcause;
362
+ use riscv:: register:: { scause , mcause, mhartid } ;
328
363
pub use riscv_rt_macros:: { entry, pre_init} ;
329
364
330
365
#[ 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) -> ! {
361
396
362
397
fn _setup_interrupts ( ) ;
363
398
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 ( ) ;
365
408
}
366
409
367
- if _mp_hook ( ) {
410
+ if _mp_hook ( hartid ) {
368
411
__pre_init ( ) ;
369
412
370
413
r0:: zero_bss ( & mut _sbss, & mut _ebss) ;
@@ -403,7 +446,7 @@ pub struct TrapFrame {
403
446
404
447
/// Trap entry point rust (_start_trap_rust)
405
448
///
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
407
450
/// if it's an interrupt or an exception. The result is examined and ExceptionHandler
408
451
/// or one of the core interrupt handlers is called.
409
452
#[ link_section = ".trap.rust" ]
@@ -415,11 +458,22 @@ pub extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
415
458
}
416
459
417
460
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 {
420
475
ExceptionHandler ( & * trap_frame)
421
476
} else {
422
- let code = cause. code ( ) ;
423
477
if code < __INTERRUPTS. len ( ) {
424
478
let h = & __INTERRUPTS[ code] ;
425
479
if h. reserved == 0 {
@@ -430,7 +484,7 @@ pub extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
430
484
} else {
431
485
DefaultHandler ( ) ;
432
486
}
433
- }
487
+ }
434
488
}
435
489
}
436
490
@@ -529,24 +583,29 @@ pub unsafe extern "Rust" fn default_pre_init() {}
529
583
#[ doc( hidden) ]
530
584
#[ no_mangle]
531
585
#[ 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 {
535
588
0 => true ,
536
589
_ => loop {
537
590
unsafe { riscv:: asm:: wfi ( ) }
538
591
} ,
539
592
}
540
593
}
541
594
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.
543
596
#[ doc( hidden) ]
544
597
#[ no_mangle]
545
598
#[ rustfmt:: skip]
546
599
pub unsafe extern "Rust" fn default_setup_interrupts ( ) {
547
- use riscv:: register:: mtvec:: { self , TrapMode } ;
548
600
extern "C" {
549
601
fn _start_trap ( ) ;
550
602
}
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
+ }
552
611
}
0 commit comments