|
270 | 270 | //! ### Core exception handlers
|
271 | 271 | //!
|
272 | 272 | //! This functions are called when corresponding exception occurs.
|
273 |
| -//! You can define an exception handler with one of the following names: |
274 |
| -//! * `InstructionMisaligned` |
275 |
| -//! * `InstructionFault` |
276 |
| -//! * `IllegalInstruction` |
277 |
| -//! * `Breakpoint` |
278 |
| -//! * `LoadMisaligned` |
279 |
| -//! * `LoadFault` |
280 |
| -//! * `StoreMisaligned` |
281 |
| -//! * `StoreFault` |
282 |
| -//! * `UserEnvCall` |
283 |
| -//! * `SupervisorEnvCall` |
284 |
| -//! * `MachineEnvCall` |
285 |
| -//! * `InstructionPageFault` |
286 |
| -//! * `LoadPageFault` |
287 |
| -//! * `StorePageFault` |
| 273 | +//! You can define an exception handler with the [`exception`] attribute. |
| 274 | +//! The attribute expects the path to the exception source as an argument. |
| 275 | +//! |
| 276 | +//! The [`exception`] attribute ensures at compile time that there is a valid |
| 277 | +//! exception source for the given handler. |
288 | 278 | //!
|
289 | 279 | //! For example:
|
290 | 280 | //! ``` no_run
|
291 |
| -//! #[export_name = "MachineEnvCall"] |
292 |
| -//! fn custom_menv_call_handler(trap_frame: &riscv_rt::TrapFrame) { |
293 |
| -//! // ... |
| 281 | +//! use riscv::interrupt::Exception; // or a target-specific exception enum |
| 282 | +//! |
| 283 | +//! #[riscv_rt::exception(Exception::MachineEnvCall)] |
| 284 | +//! fn custom_menv_call_handler(trap_frame: &mut riscv_rt::TrapFrame) { |
| 285 | +//! todo!() |
294 | 286 | //! }
|
295 |
| -//! ``` |
296 |
| -//! or |
297 |
| -//! ``` no_run |
298 |
| -//! #[no_mangle] |
299 |
| -//! fn MachineEnvCall(trap_frame: &riscv_rt::TrapFrame) -> ! { |
300 |
| -//! // ... |
| 287 | +//! |
| 288 | +//! #[riscv_rt::exception(Exception::LoadFault)] |
| 289 | +//! fn custom_load_fault_handler() -> ! { |
| 290 | +//! loop {} |
301 | 291 | //! }
|
302 | 292 | //! ```
|
303 | 293 | //!
|
|
320 | 310 | //! or
|
321 | 311 | //! ``` no_run
|
322 | 312 | //! #[no_mangle]
|
323 |
| -//! fn ExceptionHandler(trap_frame: &riscv_rt::TrapFrame) -> ! { |
| 313 | +//! fn ExceptionHandler(trap_frame: &mut riscv_rt::TrapFrame) { |
324 | 314 | //! // ...
|
325 | 315 | //! }
|
326 | 316 | //! ```
|
327 | 317 | //!
|
328 | 318 | //! Default implementation of this function stucks in a busy-loop.
|
329 | 319 | //!
|
330 |
| -//! |
331 | 320 | //! ### Core interrupt handlers
|
332 | 321 | //!
|
333 | 322 | //! This functions are called when corresponding interrupt is occured.
|
334 |
| -//! You can define an interrupt handler with one of the following names: |
335 |
| -//! * `SupervisorSoft` |
336 |
| -//! * `MachineSoft` |
337 |
| -//! * `SupervisorTimer` |
338 |
| -//! * `MachineTimer` |
339 |
| -//! * `SupervisorExternal` |
340 |
| -//! * `MachineExternal` |
| 323 | +//! You can define a core interrupt handler with the [`core_interrupt`] attribute. |
| 324 | +//! The attribute expects the path to the interrupt source as an argument. |
| 325 | +//! |
| 326 | +//! The [`core_interrupt`] attribute ensures at compile time that there is a valid |
| 327 | +//! core interrupt source for the given handler. |
341 | 328 | //!
|
342 | 329 | //! For example:
|
343 | 330 | //! ``` no_run
|
344 |
| -//! #[export_name = "MachineTimer"] |
345 |
| -//! fn custom_timer_handler() { |
346 |
| -//! // ... |
| 331 | +//! use riscv::interrupt::Interrupt; // or a target-specific core interrupt enum |
| 332 | +//! |
| 333 | +//! #[riscv_rt::core_interrupt(Interrupt::MachineSoft)] |
| 334 | +//! unsafe fn custom_machine_soft_handler() { |
| 335 | +//! todo!() |
347 | 336 | //! }
|
348 |
| -//! ``` |
349 |
| -//! or |
350 |
| -//! ``` no_run |
351 |
| -//! #[no_mangle] |
352 |
| -//! fn MachineTimer() { |
353 |
| -//! // ... |
| 337 | +//! |
| 338 | +//! #[riscv_rt::core_interrupt(Interrupt::MachineTimer)] |
| 339 | +//! fn custom_machine_timer_handler() -> ! { |
| 340 | +//! loop {} |
354 | 341 | //! }
|
355 | 342 | //! ```
|
356 | 343 | //!
|
357 |
| -//! You can also use the `#[interrupt]` macro to define interrupt handlers: |
| 344 | +//! In vectored mode, this macro will also generate a proper trap handler for the interrupt. |
358 | 345 | //!
|
359 |
| -//! ``` no_run |
360 |
| -//! #[riscv_rt::interrupt] |
361 |
| -//! fn MachineTimer() { |
362 |
| -//! // ... |
363 |
| -//! } |
364 |
| -//! ``` |
| 346 | +//! If interrupt handler is not explicitly defined, `DefaultHandler` is called. |
| 347 | +//! |
| 348 | +//! ### External interrupt handlers |
| 349 | +//! |
| 350 | +//! This functions are called when corresponding interrupt is occured. |
| 351 | +//! You can define an external interrupt handler with the [`external_interrupt`] attribute. |
| 352 | +//! The attribute expects the path to the interrupt source as an argument. |
365 | 353 | //!
|
366 |
| -//! In direct mode, this macro is equivalent to defining a function with the same name. |
367 |
| -//! However, in vectored mode, this macro will generate a proper trap handler for the interrupt. |
| 354 | +//! The [`external_interrupt`] attribute ensures at compile time that there is a valid |
| 355 | +//! external interrupt source for the given handler. |
| 356 | +//! Note that external interrupts are target-specific and may not be available on all platforms. |
368 | 357 | //!
|
369 | 358 | //! If interrupt handler is not explicitly defined, `DefaultHandler` is called.
|
370 | 359 | //!
|
371 | 360 | //! ### `DefaultHandler`
|
372 | 361 | //!
|
373 | 362 | //! This function is called when interrupt without defined interrupt handler is occured.
|
374 | 363 | //! The interrupt reason can be decoded from the `mcause`/`scause` register.
|
| 364 | +//! If it is an external interrupt, the interrupt reason can be decoded from a |
| 365 | +//! target-specific peripheral interrupt controller. |
375 | 366 | //!
|
376 | 367 | //! This function can be redefined in the following way:
|
377 | 368 | //!
|
378 | 369 | //! ``` no_run
|
379 | 370 | //! #[export_name = "DefaultHandler"]
|
380 |
| -//! fn custom_interrupt_handler() { |
| 371 | +//! unsafe fn custom_interrupt_handler() { |
381 | 372 | //! // ...
|
382 | 373 | //! }
|
383 | 374 | //! ```
|
384 | 375 | //! or
|
385 | 376 | //! ``` no_run
|
386 | 377 | //! #[no_mangle]
|
387 |
| -//! fn DefaultHandler() { |
388 |
| -//! // ... |
| 378 | +//! fn DefaultHandler() -> ! { |
| 379 | +//! loop {} |
389 | 380 | //! }
|
390 | 381 | //! ```
|
391 | 382 | //!
|
|
436 | 427 | //! riscv-rt = {features=["v-trap"]}
|
437 | 428 | //! ```
|
438 | 429 | //! When the vectored trap feature is enabled, the trap vector is set to `_vector_table` in vectored mode.
|
439 |
| -//! This table is a list of `j _start_INTERRUPT_trap` instructions, where `INTERRUPT` is the name of the interrupt. |
440 |
| -//! |
441 |
| -//! ### Defining interrupt handlers in vectored mode |
442 |
| -//! |
443 |
| -//! In vectored mode, each interrupt must also have a corresponding trap handler. |
444 |
| -//! Therefore, using `export_name` or `no_mangle` is not enough to define an interrupt handler. |
445 |
| -//! The [`interrupt`] macro will generate the trap handler for the interrupt: |
446 |
| -//! |
447 |
| -//! ``` no_run |
448 |
| -//! #[riscv_rt::interrupt] |
449 |
| -//! fn MachineTimer() { |
450 |
| -//! // ... |
451 |
| -//! } |
452 |
| -//! ``` |
453 |
| -//! |
454 |
| -//! This will generate a function named `_start_MachineTimer_trap` that calls the interrupt handler `MachineTimer`. |
| 430 | +//! This table is a list of `j _start_INTERRUPT_trap` instructions, where `INTERRUPT` is the name of the core interrupt. |
455 | 431 | //!
|
456 | 432 | //! ## `u-boot`
|
457 | 433 | //!
|
|
0 commit comments