/ src / interrupts.rs
interrupts.rs
  1  use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
  2  use crate::println;
  3  use lazy_static::lazy_static;
  4  use crate::gdt;
  5  use pic8259::ChainedPics;
  6  use spin;
  7  use crate::print;
  8  use x86_64::structures::idt::PageFaultErrorCode;
  9  use crate::hlt_loop;
 10  
 11  lazy_static! {
 12      static ref IDT: InterruptDescriptorTable = {
 13          let mut idt = InterruptDescriptorTable::new();
 14          idt.breakpoint.set_handler_fn(breakpoint_handler);
 15          unsafe {
 16              idt.double_fault.set_handler_fn(double_fault_handler)
 17                  .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
 18          }
 19          idt[InterruptIndex::Timer.as_usize()]
 20              .set_handler_fn(timer_interrupt_handler);
 21          idt[InterruptIndex::Keyboard.as_usize()]
 22              .set_handler_fn(keyboard_interrupt_handler);
 23          idt.page_fault.set_handler_fn(page_fault_handler);
 24  
 25          idt
 26      };
 27  }
 28  
 29  pub fn init_idt() {
 30      IDT.load();
 31  }
 32  
 33  extern "x86-interrupt" fn breakpoint_handler(
 34      stack_frame: InterruptStackFrame)
 35  {
 36      println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
 37  }
 38  
 39  extern "x86-interrupt" fn double_fault_handler(
 40      stack_frame: InterruptStackFrame, _error_code: u64) -> !
 41  {
 42      panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
 43  }
 44  
 45  extern "x86-interrupt" fn timer_interrupt_handler(
 46      _stack_frame: InterruptStackFrame)
 47  {
 48      print!(".");
 49  
 50      unsafe {
 51          PICS.lock()
 52              .notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
 53      }
 54  }
 55  
 56  extern "x86-interrupt" fn keyboard_interrupt_handler(
 57      _stack_frame: InterruptStackFrame)
 58  {
 59      use x86_64::instructions::port::Port;
 60  
 61      let mut port = Port::new(0x60);
 62      let scancode: u8 = unsafe { port.read() };
 63      crate::task::keyboard::add_scancode(scancode);
 64  
 65      unsafe {
 66          PICS.lock()
 67              .notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
 68      }
 69  }
 70  
 71  extern "x86-interrupt" fn page_fault_handler(
 72      stack_frame: InterruptStackFrame,
 73      error_code: PageFaultErrorCode,
 74  ) {
 75      use x86_64::registers::control::Cr2;
 76  
 77      println!("EXCEPTION: PAGE FAULT");
 78      println!("Accessed Address: {:?}", Cr2::read());
 79      println!("Error Code: {:?}", error_code);
 80      println!("{:#?}", stack_frame);
 81      hlt_loop();
 82  }
 83  
 84  pub const PIC_1_OFFSET: u8 = 32;
 85  pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
 86  
 87  pub static PICS: spin::Mutex<ChainedPics> =
 88      spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET)  });
 89  
 90  #[derive(Debug, Clone, Copy)]
 91  #[repr(u8)]
 92  pub enum InterruptIndex {
 93      Timer = PIC_1_OFFSET,
 94      Keyboard,
 95  }
 96  
 97  impl InterruptIndex {
 98      fn as_u8(self) -> u8 {
 99          self as u8
100      }
101  
102      fn as_usize(self) -> usize {
103          usize::from(self.as_u8())
104      }
105  }
106  
107  #[test_case]
108  fn test_breakpoint_exeception() {
109      x86_64::instructions::interrupts::int3();
110  }