interrupt.rs 2.9 KB

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