Skip to content

Commit 5c447b8

Browse files
Merge pull request #161 from rust-embedded/vectored-exceptions
`riscv-rt`: Rework on exception and interrupt handling
2 parents c579937 + cd88bb8 commit 5c447b8

File tree

4 files changed

+132
-62
lines changed

4 files changed

+132
-62
lines changed

.github/workflows/riscv-rt.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ jobs:
3535
targets: ${{ matrix.target }}
3636
- name: Build (no features)
3737
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }}
38-
- name : Build example (s-mode)
38+
- name : Build (s-mode)
3939
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --features=s-mode
40-
- name : Build example (single-hart)
40+
- name : Build (single-hart)
4141
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --features=single-hart
42-
- name: Build example (all features)
42+
- name: Build (all features)
4343
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --all-features
4444

4545
# Job to check that all the builds succeeded

riscv-rt/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- Static array for vectored-like handling of exceptions
1213
- New GitHub workflow for checking invalid labels in PRs
1314
- New GitHub workflow for checking modifications on CHANGELOG.md
1415
- New GitHub workflow for checking clippy lints in PRs
1516
- Optional cargo feature `single-hart` for single CPU targets
1617

1718
### Changed
1819

20+
- Removed U-mode interrupts to align with latest RISC-V specification
21+
- Changed `Vector` union. Now, it uses `Option<fn>`, which is more idiomatic in Rust
1922
- Removed riscv-target dependency for build
2023
- Upgrade rust-version to 1.60
2124
- Cargo workspace for riscv and riscv-rt

riscv-rt/link.x.in

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@ PROVIDE(_max_hart_id = 0);
2828
PROVIDE(_hart_stack_size = 2K);
2929
PROVIDE(_heap_size = 0);
3030

31+
PROVIDE(InstructionMisaligned = ExceptionHandler);
32+
PROVIDE(InstructionFault = ExceptionHandler);
33+
PROVIDE(IllegalInstruction = ExceptionHandler);
34+
PROVIDE(Breakpoint = ExceptionHandler);
35+
PROVIDE(LoadMisaligned = ExceptionHandler);
36+
PROVIDE(LoadFault = ExceptionHandler);
37+
PROVIDE(StoreMisaligned = ExceptionHandler);
38+
PROVIDE(StoreFault = ExceptionHandler);;
39+
PROVIDE(UserEnvCall = ExceptionHandler);
40+
PROVIDE(SupervisorEnvCall = ExceptionHandler);
41+
PROVIDE(MachineEnvCall = ExceptionHandler);
42+
PROVIDE(InstructionPageFault = ExceptionHandler);
43+
PROVIDE(LoadPageFault = ExceptionHandler);
44+
PROVIDE(StorePageFault = ExceptionHandler);
45+
3146
PROVIDE(UserSoft = DefaultHandler);
3247
PROVIDE(SupervisorSoft = DefaultHandler);
3348
PROVIDE(MachineSoft = DefaultHandler);

riscv-rt/src/lib.rs

Lines changed: 111 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,47 @@
245245
//!
246246
//! Default implementation of this function wakes hart 0 and busy-loops all the other harts.
247247
//!
248+
//!
249+
//! ### Core exception handlers
250+
//!
251+
//! This functions are called when corresponding exception occurs.
252+
//! You can define an exception handler with one of the following names:
253+
//! * `InstructionMisaligned`
254+
//! * `InstructionFault`
255+
//! * `IllegalInstruction`
256+
//! * `Breakpoint`
257+
//! * `LoadMisaligned`
258+
//! * `LoadFault`
259+
//! * `StoreMisaligned`
260+
//! * `StoreFault`
261+
//! * `UserEnvCall`
262+
//! * `SupervisorEnvCall`
263+
//! * `MachineEnvCall`
264+
//! * `InstructionPageFault`
265+
//! * `LoadPageFault`
266+
//! * `StorePageFault`
267+
//!
268+
//! For example:
269+
//! ``` no_run
270+
//! #[export_name = "MachineEnvCall"]
271+
//! fn custom_menv_call_handler(trap_frame: &riscv_rt::TrapFrame) {
272+
//! // ...
273+
//! }
274+
//! ```
275+
//! or
276+
//! ``` no_run
277+
//! #[no_mangle]
278+
//! fn MachineEnvCall(trap_frame: &riscv_rt::TrapFrame) -> ! {
279+
//! // ...
280+
//! }
281+
//! ```
282+
//!
283+
//! If exception handler is not explicitly defined, `ExceptionHandler` is called.
284+
//!
248285
//! ### `ExceptionHandler`
249286
//!
250-
//! This function is called when exception is occured. The exception reason can be decoded from the
287+
//! This function is called when exception without defined exception handler is occured.
288+
//! The exception reason can be decoded from the
251289
//! `mcause`/`scause` register.
252290
//!
253291
//! This function can be redefined in the following way:
@@ -561,15 +599,27 @@ pub unsafe extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
561599
}
562600

563601
let cause = xcause::read();
602+
let code = cause.code();
564603

565604
if cause.is_exception() {
566-
ExceptionHandler(&*trap_frame)
567-
} else if cause.code() < __INTERRUPTS.len() {
568-
let h = &__INTERRUPTS[cause.code()];
569-
if h.reserved == 0 {
570-
DefaultHandler();
605+
let trap_frame = &*trap_frame;
606+
if code < __EXCEPTIONS.len() {
607+
let h = &__EXCEPTIONS[code];
608+
if let Some(handler) = h {
609+
handler(trap_frame);
610+
} else {
611+
ExceptionHandler(trap_frame);
612+
}
571613
} else {
572-
(h.handler)();
614+
ExceptionHandler(trap_frame);
615+
}
616+
ExceptionHandler(trap_frame)
617+
} else if code < __INTERRUPTS.len() {
618+
let h = &__INTERRUPTS[code];
619+
if let Some(handler) = h {
620+
handler();
621+
} else {
622+
DefaultHandler();
573623
}
574624
} else {
575625
DefaultHandler();
@@ -589,7 +639,7 @@ pub fn DefaultExceptionHandler(trap_frame: &TrapFrame) -> ! {
589639

590640
#[doc(hidden)]
591641
#[no_mangle]
592-
#[allow(unused_variables, non_snake_case)]
642+
#[allow(non_snake_case)]
593643
pub fn DefaultInterruptHandler() {
594644
loop {
595645
// Prevent this from turning into a UDF instruction
@@ -598,76 +648,78 @@ pub fn DefaultInterruptHandler() {
598648
}
599649
}
600650

601-
/* Interrupts */
602-
#[doc(hidden)]
603-
pub enum Interrupt {
604-
UserSoft,
605-
SupervisorSoft,
606-
MachineSoft,
607-
UserTimer,
608-
SupervisorTimer,
609-
MachineTimer,
610-
UserExternal,
611-
SupervisorExternal,
612-
MachineExternal,
651+
extern "C" {
652+
fn InstructionMisaligned(trap_frame: &TrapFrame);
653+
fn InstructionFault(trap_frame: &TrapFrame);
654+
fn IllegalInstruction(trap_frame: &TrapFrame);
655+
fn Breakpoint(trap_frame: &TrapFrame);
656+
fn LoadMisaligned(trap_frame: &TrapFrame);
657+
fn LoadFault(trap_frame: &TrapFrame);
658+
fn StoreMisaligned(trap_frame: &TrapFrame);
659+
fn StoreFault(trap_frame: &TrapFrame);
660+
fn UserEnvCall(trap_frame: &TrapFrame);
661+
fn SupervisorEnvCall(trap_frame: &TrapFrame);
662+
fn MachineEnvCall(trap_frame: &TrapFrame);
663+
fn InstructionPageFault(trap_frame: &TrapFrame);
664+
fn LoadPageFault(trap_frame: &TrapFrame);
665+
fn StorePageFault(trap_frame: &TrapFrame);
613666
}
614667

615-
pub use self::Interrupt as interrupt;
668+
#[doc(hidden)]
669+
#[no_mangle]
670+
pub static __EXCEPTIONS: [Option<unsafe extern "C" fn(&TrapFrame)>; 16] = [
671+
Some(InstructionMisaligned),
672+
Some(InstructionFault),
673+
Some(IllegalInstruction),
674+
Some(Breakpoint),
675+
Some(LoadMisaligned),
676+
Some(LoadFault),
677+
Some(StoreMisaligned),
678+
Some(StoreFault),
679+
Some(UserEnvCall),
680+
Some(SupervisorEnvCall),
681+
None,
682+
Some(MachineEnvCall),
683+
Some(InstructionPageFault),
684+
Some(LoadPageFault),
685+
None,
686+
Some(StorePageFault),
687+
];
616688

617689
extern "C" {
618-
fn UserSoft();
619690
fn SupervisorSoft();
620691
fn MachineSoft();
621-
fn UserTimer();
622692
fn SupervisorTimer();
623693
fn MachineTimer();
624-
fn UserExternal();
625694
fn SupervisorExternal();
626695
fn MachineExternal();
627696
}
628697

629-
#[doc(hidden)]
630-
pub union Vector {
631-
pub handler: unsafe extern "C" fn(),
632-
pub reserved: usize,
633-
}
634-
635698
#[doc(hidden)]
636699
#[no_mangle]
637-
pub static __INTERRUPTS: [Vector; 12] = [
638-
Vector { handler: UserSoft },
639-
Vector {
640-
handler: SupervisorSoft,
641-
},
642-
Vector { reserved: 0 },
643-
Vector {
644-
handler: MachineSoft,
645-
},
646-
Vector { handler: UserTimer },
647-
Vector {
648-
handler: SupervisorTimer,
649-
},
650-
Vector { reserved: 0 },
651-
Vector {
652-
handler: MachineTimer,
653-
},
654-
Vector {
655-
handler: UserExternal,
656-
},
657-
Vector {
658-
handler: SupervisorExternal,
659-
},
660-
Vector { reserved: 0 },
661-
Vector {
662-
handler: MachineExternal,
663-
},
700+
pub static __INTERRUPTS: [Option<unsafe extern "C" fn()>; 12] = [
701+
None,
702+
Some(SupervisorSoft),
703+
None,
704+
Some(MachineSoft),
705+
None,
706+
Some(SupervisorTimer),
707+
None,
708+
Some(MachineTimer),
709+
None,
710+
Some(SupervisorExternal),
711+
None,
712+
Some(MachineExternal),
664713
];
665714

715+
/// Default implementation of `_pre_init` does nothing.
716+
/// Users can override this function with the [`#[pre_init]`] macro.
666717
#[doc(hidden)]
667718
#[no_mangle]
668719
#[rustfmt::skip]
669-
pub unsafe extern "Rust" fn default_pre_init() {}
720+
pub extern "Rust" fn default_pre_init() {}
670721

722+
/// Default implementation of `_mp_hook` wakes hart 0 and busy-loops all the other harts.
671723
#[doc(hidden)]
672724
#[no_mangle]
673725
#[rustfmt::skip]
@@ -681,7 +733,7 @@ pub extern "Rust" fn default_mp_hook(hartid: usize) -> bool {
681733
}
682734
}
683735

684-
/// Default implementation of `_setup_interrupts` that sets `mtvec`/`stvec` to a trap handler address.
736+
/// Default implementation of `_setup_interrupts` sets `mtvec`/`stvec` to the address of `_start_trap`.
685737
#[doc(hidden)]
686738
#[no_mangle]
687739
#[rustfmt::skip]

0 commit comments

Comments
 (0)