interrupt.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. use super::cpu::local_cpu;
  2. use super::mem::handle_page_fault;
  3. use super::syscall::handle_syscall32;
  4. use super::task::{ProcessList, Signal, Thread};
  5. use super::timer::timer_interrupt;
  6. use crate::bindings::root::EINVAL;
  7. use crate::{driver::Port8, prelude::*};
  8. use alloc::sync::Arc;
  9. use arch::{ExtendedContext, InterruptContext};
  10. use eonix_runtime::task::Task;
  11. use eonix_sync::SpinIrq as _;
  12. const PIC1_COMMAND: Port8 = Port8::new(0x20);
  13. const PIC1_DATA: Port8 = Port8::new(0x21);
  14. const PIC2_COMMAND: Port8 = Port8::new(0xA0);
  15. const PIC2_DATA: Port8 = Port8::new(0xA1);
  16. static IRQ_HANDLERS: Spin<[Option<Arc<dyn Fn() + Send + Sync>>; 16]> =
  17. Spin::new([const { None }; 16]);
  18. fn irq_handler(irqno: usize) {
  19. assert!(irqno < 16);
  20. let handler = IRQ_HANDLERS.lock()[irqno as usize].as_ref().cloned();
  21. if let Some(handler) = handler {
  22. handler();
  23. }
  24. PIC1_COMMAND.write(0x20); // EOI
  25. if irqno >= 8 {
  26. PIC2_COMMAND.write(0x20); // EOI
  27. }
  28. }
  29. fn fault_handler(int_stack: &mut InterruptContext) {
  30. match int_stack.int_no {
  31. // Invalid Op or Double Fault
  32. 14 => handle_page_fault(int_stack),
  33. 13 if int_stack.cs & 0x3 != 0 => ProcessList::kill_current(Signal::SIGILL),
  34. 6 | 8 if int_stack.cs & 0x3 != 0 => ProcessList::kill_current(Signal::SIGSEGV),
  35. _ => panic!("Unhandled fault: {}", int_stack.int_no),
  36. }
  37. }
  38. #[no_mangle]
  39. pub extern "C" fn interrupt_handler(
  40. int_stack: *mut InterruptContext,
  41. ext_ctx: *mut ExtendedContext,
  42. ) {
  43. let int_stack = unsafe { &mut *int_stack };
  44. let ext_ctx = unsafe { &mut *ext_ctx };
  45. match int_stack.int_no {
  46. // Fault
  47. 0..0x20 => fault_handler(int_stack),
  48. // Syscall
  49. 0x80 => handle_syscall32(int_stack.rax as usize, int_stack, ext_ctx),
  50. // Timer
  51. 0x40 => timer_interrupt(),
  52. // IRQ
  53. no => irq_handler(no as usize - 0x20),
  54. }
  55. if int_stack.cs & 0x3 != 0 {
  56. if Thread::current().signal_list.has_pending_signal() {
  57. Task::block_on(Thread::current().signal_list.handle(int_stack, ext_ctx));
  58. }
  59. }
  60. }
  61. pub fn register_irq_handler<F>(irqno: i32, handler: F) -> Result<(), u32>
  62. where
  63. F: Fn() + Send + Sync + 'static,
  64. {
  65. if irqno < 0 || irqno >= 16 {
  66. return Err(EINVAL);
  67. }
  68. let old = IRQ_HANDLERS.lock_irq()[irqno as usize].replace(Arc::new(handler));
  69. assert!(old.is_none(), "IRQ handler already registered");
  70. Ok(())
  71. }
  72. pub fn init() -> KResult<()> {
  73. // Initialize PIC
  74. PIC1_COMMAND.write(0x11); // edge trigger mode
  75. PIC1_DATA.write(0x20); // IRQ 0-7 offset
  76. PIC1_DATA.write(0x04); // cascade with slave PIC
  77. PIC1_DATA.write(0x01); // no buffer mode
  78. PIC2_COMMAND.write(0x11); // edge trigger mode
  79. PIC2_DATA.write(0x28); // IRQ 8-15 offset
  80. PIC2_DATA.write(0x02); // cascade with master PIC
  81. PIC2_DATA.write(0x01); // no buffer mode
  82. // Allow all IRQs
  83. PIC1_DATA.write(0x0);
  84. PIC2_DATA.write(0x0);
  85. Ok(())
  86. }
  87. pub fn end_of_interrupt() {
  88. // SAFETY: We only use this function in irq context, where preemption is disabled.
  89. unsafe { local_cpu() }.interrupt.end_of_interrupt();
  90. }