view cos/kernel/handlers.c @ 167:0b5b2ee6b435

Added 2 unit tests
author Windel Bouwman
date Fri, 22 Mar 2013 17:40:13 +0100
parents 24ce177e01e8
children
line wrap: on
line source

#include "kernel.h"

// Assembler wrapper prototypes:
extern void INT255(void);
extern void INT0(void);
extern void INT1(void);
extern void INT2(void);
extern void INT3(void);
extern void INT4(void);
extern void INT5(void);
extern void INT6(void);
extern void INT7(void);
extern void INT8(void);
extern void INT9(void);
extern void INT10(void);
extern void INT11(void);
extern void INT12(void);
extern void INT13(void);
extern void INT14(void);
extern void INT16(void);
extern void INT17(void);
extern void INT18(void);
extern void INT19(void);
// Remapped irq assembler wrappers:
extern void INT32(void);
extern void INT33(void);
extern void INT34(void);
extern void INT35(void);
extern void INT36(void);
extern void INT37(void);
extern void INT38(void);
extern void INT39(void);
extern void INT40(void);
extern void INT41(void);
extern void INT42(void);
extern void INT43(void);
extern void INT44(void);
extern void INT45(void);
extern void INT46(void);
extern void INT47(void);

// THE interrupt descriptor table:
IDT_entry *idt = (IDT_entry*)0x5000;
volatile idtPointer idtP;

void setIDTentry(int num, void (*handler)(), uint16_t selector, uint8_t flags)
{
   // Fill one entry with IDT info:
   uint64_t offset;

   // Typecast the function pointer to a number:
   offset = (uint64_t)handler;

   // Set offset:
   idt[num].baseLow = offset & 0xFFFF;
   idt[num].baseMid = (offset >> 16) & 0xFFFF;
   idt[num].baseHigh = (offset >> 32) & 0xFFFFFFFF;

   // Set flags and selector:
   idt[num].selector = selector;
   idt[num].flags = flags;

   // Set reserved fields:
   idt[num].reserved1 = 0;
   idt[num].reserved2 = 0;
}

void setupIDT(void) {
  int i;

  // Fill all vectors with the default handler:
  for (i=0; i<256; i++) {
    setIDTentry(i, INT255, 0x08, 0x8E);
  }

  // Now set other then default handler:
  setIDTentry(0, INT0, 0x08, 0x8E);
  setIDTentry(1, INT1, 0x08, 0x8E);
  setIDTentry(2, INT2, 0x08, 0x8E);
  setIDTentry(3, INT3, 0x08, 0x8E);
  setIDTentry(4, INT4, 0x08, 0x8E);
  setIDTentry(5, INT5, 0x08, 0x8E);
  setIDTentry(6, INT6, 0x08, 0x8E);
  setIDTentry(7, INT7, 0x08, 0x8E);
  setIDTentry(8, INT8, 0x08, 0x8E);
  setIDTentry(9, INT9, 0x08, 0x8E);
  setIDTentry(10, INT10, 0x08, 0x8E);
  setIDTentry(11, INT11, 0x08, 0x8E);
  setIDTentry(12, INT12, 0x08, 0x8E);
  setIDTentry(13, INT13, 0x08, 0x8E);
  setIDTentry(14, INT14, 0x08, 0x8E);
  //setIDTentry(15, INT15, 0x08, 0x8E);
  setIDTentry(16, INT16, 0x08, 0x8E);
  setIDTentry(17, INT17, 0x08, 0x8E);
  setIDTentry(18, INT18, 0x08, 0x8E);
  setIDTentry(19, INT19, 0x08, 0x8E);
  /* reserved interrupts: */
  // From int20 - int31
  setIDTentry(32, INT32, 0x08, 0x8F);
  setIDTentry(33, INT33, 0x08, 0x8F);
  setIDTentry(34, INT34, 0x08, 0x8F);
  setIDTentry(35, INT35, 0x08, 0x8F);
  setIDTentry(36, INT36, 0x08, 0x8F);
  setIDTentry(37, INT37, 0x08, 0x8F);
  setIDTentry(38, INT38, 0x08, 0x8F);
  setIDTentry(39, INT39, 0x08, 0x8F);
  setIDTentry(40, INT40, 0x08, 0x8F);
  setIDTentry(41, INT41, 0x08, 0x8F);
  setIDTentry(42, INT42, 0x08, 0x8F);
  setIDTentry(43, INT43, 0x08, 0x8F);
  setIDTentry(44, INT44, 0x08, 0x8F);
  setIDTentry(45, INT45, 0x08, 0x8F);
  setIDTentry(46, INT46, 0x08, 0x8F);
  setIDTentry(47, INT47, 0x08, 0x8F);

  // Set the correct values in the IDT pointer:
  idtP.base = (uint64_t)idt;
  idtP.limit = (sizeof(IDT_entry) * 256) - 1;
  // call load IDT asm function:
  loadIDT();

  PICremap();
  asm("sti");
}

// PIC functions:
void PICremap() {
  unsigned char maskmaster, maskslave, pic1, pic2;
  pic1 = 0x20; // remapping location master
  pic2 = 0x28;
  maskmaster = inb(0x21); // master cmd=0x20, data=0x21
  maskslave = inb(0xA1); // slave command=0xA0, data=0xA1

  outb(0x20, 0x20); // end of init

  outb(0x20, 0x11); // init + ICW1_ICW2
  outb(0xA0, 0x11); // init + ICW1_ICW2
    
  outb(0x21, pic1); // ICW2, write offset
  outb(0xA1, pic2); // ICW2

  outb(0x21, 4); // ICW3, write a 4!
  outb(0xA1, 2); // ICW3, write a 2!

  outb(0x21, 1); // ICW4, 8086 mode
  outb(0xA1, 1); // ICW4

  outb(0x21, maskmaster);
  outb(0xA1, maskslave);
}

/* Function that prints the contents of all registers 
   on the interrupted stack. */
void display_registers(uint64_t *regs)
{
   // Pushed by interrupt handler assembler:
   printf("rax: %x\n", regs[6]);
   printf("rbx: %x\n", regs[3]);
   printf("rcx: %x\n", regs[5]);
   printf("rdx: %x\n", regs[4]);
   printf("rsi: %x\n", regs[1]);
   printf("rdi: %x\n", regs[0]);
   printf("rbp: %x\n", regs[2]);
   // Pushed by CPU:
   printf("rip: %x\n", regs[9]);
}

void gp_fault(uint64_t *regs)
{
   printf("GP fault\n");
   printf("Error code: %x\n", regs[8]);
   display_registers(regs);
   panic("No resolution to general protection fault!");
}

void page_fault(uint64_t *regs)
{
   printf("Page fault\n");
   uint64_t faulting_address;
   asm volatile("mov %%cr2, %0" : "=r" (faulting_address));
   printf("Error code: %x\n", regs[8]);
   display_registers(regs);
   printf("Faulting address: %x\n", faulting_address);
   panic("No resolution to page fault!");

}

// Global isr handler:
// Hopefully, this function get called with the correct registers.
void isr_handler(uint64_t* registers)
{
   uint64_t intnum = registers[7];

   // TODO: make a list with handler pointers:
   if (intnum == 32)
   {
      timerDriverUpdate();
   }
   else if (intnum == 33)
   {
      keyboardDriverUpdate();
   }
   else if (intnum == 13)
   {
      gp_fault(registers);
   }
   else if (intnum == 14)
   {
      page_fault(registers);
   }
   else if (intnum == 39)
   {
      printf("Spurious interrupt\n");
   }
   else
   {
      printf("Interrupt %d called, registers at: %x\n", registers[7], registers);
      panic("Paniek! Unhandled interrupt!");
   }

   // TODO: EOI to slave?
   // TODO: replace this with APIC code?
   outb(0x20, 0x20); // EOI to master
}