interrupt.rs 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. use alloc::sync::Arc;
  2. use eonix_hal::traits::fault::Fault;
  3. use eonix_hal::traits::trap::{RawTrapContext, TrapType};
  4. use eonix_hal::trap::TrapContext;
  5. use eonix_mm::address::{Addr as _, VAddr};
  6. use eonix_sync::SpinIrq as _;
  7. use super::mem::handle_kernel_page_fault;
  8. use super::task::block_on;
  9. use super::timer::timer_interrupt;
  10. use crate::kernel::constants::EINVAL;
  11. use crate::prelude::*;
  12. static IRQ_HANDLERS: Spin<[Vec<Arc<dyn Fn() + Send + Sync>>; 16]> =
  13. Spin::new([const { Vec::new() }; 16]);
  14. pub fn default_irq_handler(irqno: usize) {
  15. assert!(irqno < 16);
  16. {
  17. let handlers = IRQ_HANDLERS.lock();
  18. for handler in handlers[irqno].iter() {
  19. handler();
  20. }
  21. }
  22. }
  23. pub fn default_fault_handler(fault_type: Fault, trap_ctx: &mut TrapContext) {
  24. if trap_ctx.is_user_mode() {
  25. unimplemented!("Unhandled user space fault");
  26. }
  27. match fault_type {
  28. Fault::PageFault {
  29. error_code,
  30. address: vaddr,
  31. } => {
  32. let fault_pc = VAddr::from(trap_ctx.get_program_counter());
  33. if let Some(new_pc) = block_on(handle_kernel_page_fault(fault_pc, vaddr, error_code)) {
  34. trap_ctx.set_program_counter(new_pc.addr());
  35. }
  36. }
  37. fault => panic!("Unhandled kernel space fault: {fault:?}"),
  38. }
  39. }
  40. #[eonix_hal::default_trap_handler]
  41. pub fn interrupt_handler(trap_ctx: &mut TrapContext) {
  42. match trap_ctx.trap_type() {
  43. TrapType::Syscall { no, .. } => unreachable!("Syscall {} in kernel space.", no),
  44. TrapType::Breakpoint => unreachable!("Breakpoint in kernel space."),
  45. TrapType::Fault(fault) => default_fault_handler(fault, trap_ctx),
  46. TrapType::Irq { callback } => callback(default_irq_handler),
  47. TrapType::Timer { callback } => callback(timer_interrupt),
  48. }
  49. }
  50. pub fn register_irq_handler<F>(irqno: i32, handler: F) -> Result<(), u32>
  51. where
  52. F: Fn() + Send + Sync + 'static,
  53. {
  54. if irqno < 0 || irqno >= 16 {
  55. return Err(EINVAL);
  56. }
  57. IRQ_HANDLERS.lock_irq()[irqno as usize].push(Arc::new(handler));
  58. Ok(())
  59. }