Skip to content

Commit 4b68b0f

Browse files
bors[bot]Disasm
andauthored
Merge #42
42: Implement interrupt and exception handling, bump version r=almindor a=Disasm Co-authored-by: Vadim Kaushan <[email protected]>
2 parents c33a988 + 45c729e commit 4b68b0f

File tree

7 files changed

+204
-14
lines changed

7 files changed

+204
-14
lines changed

riscv-rt/asm.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ _start_trap:
128128
STORE a6, 14*REGBYTES(sp)
129129
STORE a7, 15*REGBYTES(sp)
130130

131+
add a0, sp, zero
131132
jal ra, _start_trap_rust
132133

133134
LOAD ra, 0*REGBYTES(sp)
120 Bytes
Binary file not shown.
120 Bytes
Binary file not shown.
152 Bytes
Binary file not shown.
152 Bytes
Binary file not shown.

riscv-rt/link.x

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,18 @@ PROVIDE(_max_hart_id = 0);
44
PROVIDE(_hart_stack_size = 2K);
55
PROVIDE(_heap_size = 0);
66

7-
PROVIDE(trap_handler = default_trap_handler);
7+
PROVIDE(UserSoft = DefaultHandler);
8+
PROVIDE(SupervisorSoft = DefaultHandler);
9+
PROVIDE(MachineSoft = DefaultHandler);
10+
PROVIDE(UserTimer = DefaultHandler);
11+
PROVIDE(SupervisorTimer = DefaultHandler);
12+
PROVIDE(MachineTimer = DefaultHandler);
13+
PROVIDE(UserExternal = DefaultHandler);
14+
PROVIDE(SupervisorExternal = DefaultHandler);
15+
PROVIDE(MachineExternal = DefaultHandler);
16+
17+
PROVIDE(DefaultHandler = DefaultInterruptHandler);
18+
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
819

920
/* # Pre-initialization function */
1021
/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,

riscv-rt/src/lib.rs

Lines changed: 191 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -249,19 +249,96 @@
249249
//! ```
250250
//!
251251
//! Default implementation of this function wakes hart 0 and busy-loops all the other harts.
252+
//!
253+
//! ### `ExceptionHandler`
254+
//!
255+
//! This function is called when exception is occured. The exception reason can be decoded from the
256+
//! `mcause` register.
257+
//!
258+
//! This function can be redefined in the following way:
259+
//!
260+
//! ``` no_run
261+
//! #[export_name = "ExceptionHandler"]
262+
//! fn custom_exception_handler(trap_frame: &riscv_rt::TrapFrame) -> ! {
263+
//! // ...
264+
//! }
265+
//! ```
266+
//! or
267+
//! ``` no_run
268+
//! #[no_mangle]
269+
//! fn ExceptionHandler(trap_frame: &riscv_rt::TrapFrame) -> ! {
270+
//! // ...
271+
//! }
272+
//! ```
273+
//!
274+
//! Default implementation of this function stucks in a busy-loop.
275+
//!
276+
//!
277+
//! ### Core interrupt handlers
278+
//!
279+
//! This functions are called when corresponding interrupt is occured.
280+
//! You can define an interrupt handler with one of the following names:
281+
//! * `UserSoft`
282+
//! * `SupervisorSoft`
283+
//! * `MachineSoft`
284+
//! * `UserTimer`
285+
//! * `SupervisorTimer`
286+
//! * `MachineTimer`
287+
//! * `UserExternal`
288+
//! * `SupervisorExternal`
289+
//! * `MachineExternal`
290+
//!
291+
//! For example:
292+
//! ``` no_run
293+
//! #[export_name = "MachineTimer"]
294+
//! fn custom_timer_handler() {
295+
//! // ...
296+
//! }
297+
//! ```
298+
//! or
299+
//! ``` no_run
300+
//! #[no_mangle]
301+
//! fn MachineTimer() {
302+
//! // ...
303+
//! }
304+
//! ```
305+
//!
306+
//! If interrupt handler is not explicitly defined, `DefaultHandler` is called.
307+
//!
308+
//! ### `DefaultHandler`
309+
//!
310+
//! This function is called when interrupt without defined interrupt handler is occured.
311+
//! The interrupt reason can be decoded from the `mcause` register.
312+
//!
313+
//! This function can be redefined in the following way:
314+
//!
315+
//! ``` no_run
316+
//! #[export_name = "DefaultHandler"]
317+
//! fn custom_interrupt_handler() {
318+
//! // ...
319+
//! }
320+
//! ```
321+
//! or
322+
//! ``` no_run
323+
//! #[no_mangle]
324+
//! fn DefaultHandler() {
325+
//! // ...
326+
//! }
327+
//! ```
328+
//!
329+
//! Default implementation of this function stucks in a busy-loop.
252330
253331
// NOTE: Adapted from cortex-m/src/lib.rs
254332
#![no_std]
255333
#![deny(missing_docs)]
256-
#![deny(warnings)]
257334

258335
extern crate riscv;
259336
extern crate riscv_rt_macros as macros;
260337
extern crate r0;
261338

262339
pub use macros::{entry, pre_init};
263340

264-
use riscv::register::mstatus;
341+
use riscv::register::mcause;
265342

266343
#[export_name = "error: riscv-rt appears more than once in the dependency graph"]
267344
#[doc(hidden)]
@@ -310,33 +387,134 @@ pub unsafe extern "C" fn start_rust() -> ! {
310387
main();
311388
}
312389

390+
/// Registers saved in trap handler
391+
#[allow(missing_docs)]
392+
#[repr(C)]
393+
pub struct TrapFrame {
394+
pub ra: usize,
395+
pub t0: usize,
396+
pub t1: usize,
397+
pub t2: usize,
398+
pub t3: usize,
399+
pub t4: usize,
400+
pub t5: usize,
401+
pub t6: usize,
402+
pub a0: usize,
403+
pub a1: usize,
404+
pub a2: usize,
405+
pub a3: usize,
406+
pub a4: usize,
407+
pub a5: usize,
408+
pub a6: usize,
409+
pub a7: usize,
410+
}
411+
313412

314413
/// Trap entry point rust (_start_trap_rust)
315414
///
316-
/// mcause is read to determine the cause of the trap. XLEN-1 bit indicates
317-
/// if it's an interrupt or an exception. The result is converted to an element
318-
/// of the Interrupt or Exception enum and passed to handle_interrupt or
319-
/// handle_exception.
415+
/// `mcause` is read to determine the cause of the trap. XLEN-1 bit indicates
416+
/// if it's an interrupt or an exception. The result is examined and ExceptionHandler
417+
/// or one of the core interrupt handlers is called.
320418
#[link_section = ".trap.rust"]
321419
#[export_name = "_start_trap_rust"]
322-
pub extern "C" fn start_trap_rust() {
420+
pub extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
323421
extern "C" {
324-
fn trap_handler();
422+
fn ExceptionHandler(trap_frame: &TrapFrame) -> !;
423+
fn DefaultHandler();
325424
}
326425

327426
unsafe {
328-
// dispatch trap to handler
329-
trap_handler();
427+
let cause = mcause::read();
428+
if cause.is_exception() {
429+
ExceptionHandler(&*trap_frame)
430+
} else {
431+
let code = cause.code();
432+
if code < __INTERRUPTS.len() {
433+
let h = &__INTERRUPTS[code];
434+
if h.reserved == 0 {
435+
DefaultHandler();
436+
} else {
437+
(h.handler)();
438+
}
439+
} else {
440+
DefaultHandler();
441+
}
442+
}
443+
}
444+
}
330445

331-
// mstatus, remain in M-mode after mret
332-
mstatus::set_mpp(mstatus::MPP::Machine);
446+
#[doc(hidden)]
447+
#[no_mangle]
448+
#[allow(unused_variables, non_snake_case)]
449+
pub fn DefaultExceptionHandler(trap_frame: &TrapFrame) -> ! {
450+
loop {
451+
// Prevent this from turning into a UDF instruction
452+
// see rust-lang/rust#28728 for details
453+
continue;
333454
}
334455
}
335456

457+
#[doc(hidden)]
458+
#[no_mangle]
459+
#[allow(unused_variables, non_snake_case)]
460+
pub fn DefaultInterruptHandler() {
461+
loop {
462+
// Prevent this from turning into a UDF instruction
463+
// see rust-lang/rust#28728 for details
464+
continue;
465+
}
466+
}
467+
468+
/* Interrupts */
469+
#[doc(hidden)]
470+
pub enum Interrupt {
471+
UserSoft,
472+
SupervisorSoft,
473+
MachineSoft,
474+
UserTimer,
475+
SupervisorTimer,
476+
MachineTimer,
477+
UserExternal,
478+
SupervisorExternal,
479+
MachineExternal,
480+
}
481+
482+
pub use self::Interrupt as interrupt;
483+
484+
extern "C" {
485+
fn UserSoft();
486+
fn SupervisorSoft();
487+
fn MachineSoft();
488+
fn UserTimer();
489+
fn SupervisorTimer();
490+
fn MachineTimer();
491+
fn UserExternal();
492+
fn SupervisorExternal();
493+
fn MachineExternal();
494+
}
495+
496+
#[doc(hidden)]
497+
pub union Vector {
498+
handler: unsafe extern "C" fn(),
499+
reserved: usize,
500+
}
336501

337502
#[doc(hidden)]
338503
#[no_mangle]
339-
pub fn default_trap_handler() {}
504+
pub static __INTERRUPTS: [Vector; 12] = [
505+
Vector { handler: UserSoft },
506+
Vector { handler: SupervisorSoft },
507+
Vector { reserved: 0 },
508+
Vector { handler: MachineSoft },
509+
Vector { handler: UserTimer },
510+
Vector { handler: SupervisorTimer },
511+
Vector { reserved: 0 },
512+
Vector { handler: MachineTimer },
513+
Vector { handler: UserExternal },
514+
Vector { handler: SupervisorExternal },
515+
Vector { reserved: 0 },
516+
Vector { handler: MachineExternal },
517+
];
340518

341519
#[doc(hidden)]
342520
#[no_mangle]

0 commit comments

Comments
 (0)