|
249 | 249 | //! ```
|
250 | 250 | //!
|
251 | 251 | //! 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. |
252 | 330 |
|
253 | 331 | // NOTE: Adapted from cortex-m/src/lib.rs
|
254 | 332 | #![no_std]
|
255 | 333 | #![deny(missing_docs)]
|
256 |
| -#![deny(warnings)] |
257 | 334 |
|
258 | 335 | extern crate riscv;
|
259 | 336 | extern crate riscv_rt_macros as macros;
|
260 | 337 | extern crate r0;
|
261 | 338 |
|
262 | 339 | pub use macros::{entry, pre_init};
|
263 | 340 |
|
264 |
| -use riscv::register::mstatus; |
| 341 | +use riscv::register::mcause; |
265 | 342 |
|
266 | 343 | #[export_name = "error: riscv-rt appears more than once in the dependency graph"]
|
267 | 344 | #[doc(hidden)]
|
@@ -310,33 +387,134 @@ pub unsafe extern "C" fn start_rust() -> ! {
|
310 | 387 | main();
|
311 | 388 | }
|
312 | 389 |
|
| 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 | + |
313 | 412 |
|
314 | 413 | /// Trap entry point rust (_start_trap_rust)
|
315 | 414 | ///
|
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. |
320 | 418 | #[link_section = ".trap.rust"]
|
321 | 419 | #[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) { |
323 | 421 | extern "C" {
|
324 |
| - fn trap_handler(); |
| 422 | + fn ExceptionHandler(trap_frame: &TrapFrame) -> !; |
| 423 | + fn DefaultHandler(); |
325 | 424 | }
|
326 | 425 |
|
327 | 426 | 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 | +} |
330 | 445 |
|
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; |
333 | 454 | }
|
334 | 455 | }
|
335 | 456 |
|
| 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 | +} |
336 | 501 |
|
337 | 502 | #[doc(hidden)]
|
338 | 503 | #[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 | +]; |
340 | 518 |
|
341 | 519 | #[doc(hidden)]
|
342 | 520 | #[no_mangle]
|
|
0 commit comments