/* File: interrupts.C Author: R. Bettati Department of Computer Science Texas A&M University Date : 12/09/05 */ /*--------------------------------------------------------------------------*/ /* DEFINES */ /*--------------------------------------------------------------------------*/ /* (none) */ /*--------------------------------------------------------------------------*/ /* INCLUDES */ /*--------------------------------------------------------------------------*/ #include "assert.H" #include "utils.H" #include "console.H" #include "idt.H" #include "irq.H" #include "exceptions.H" #include "interrupts.H" /*--------------------------------------------------------------------------*/ /* EXTERNS */ /*--------------------------------------------------------------------------*/ /* The low-level functions (defined in file 'irq_low.s') that handle the 16 PIC-generated interrupts. These functions are actually merely stubs that put the error code and the exception code on the stack and then call a low-level function, which in turn calls the interrupt dispatcher. Yes, there are more efficient ways to handle exceptions, but they require more code replication. */ extern "C" void irq0(); extern "C" void irq1(); extern "C" void irq2(); extern "C" void irq3(); extern "C" void irq4(); extern "C" void irq5(); extern "C" void irq6(); extern "C" void irq7(); extern "C" void irq8(); extern "C" void irq9(); extern "C" void irq10(); extern "C" void irq11(); extern "C" void irq12(); extern "C" void irq13(); extern "C" void irq14(); extern "C" void irq15(); extern "C" void lowlevel_dispatch_interrupt(REGS * _r) { InterruptHandler::dispatch_interrupt(_r); } /*--------------------------------------------------------------------------*/ /* LOCAL VARIABLES */ /*--------------------------------------------------------------------------*/ InterruptHandler * InterruptHandler::handler_table[InterruptHandler::IRQ_TABLE_SIZE]; /*--------------------------------------------------------------------------*/ /* EXPORTED INTERRUPT DISPATCHER FUNCTIONS */ /*--------------------------------------------------------------------------*/ void InterruptHandler::init_dispatcher() { /* -- INITIALIZE LOW-LEVEL INTERRUPT HANDLERS */ /* Add any new ISRs to the IDT here using IDT::set_gate */ IDT::set_gate( 0+ IRQ_BASE, (unsigned) irq0, 0x08, 0x8E); IDT::set_gate( 1+ IRQ_BASE, (unsigned) irq1, 0x08, 0x8E); IDT::set_gate( 2+ IRQ_BASE, (unsigned) irq2, 0x08, 0x8E); IDT::set_gate( 3+ IRQ_BASE, (unsigned) irq3, 0x08, 0x8E); IDT::set_gate( 4+ IRQ_BASE, (unsigned) irq4, 0x08, 0x8E); IDT::set_gate( 5+ IRQ_BASE, (unsigned) irq5, 0x08, 0x8E); IDT::set_gate( 6+ IRQ_BASE, (unsigned) irq6, 0x08, 0x8E); IDT::set_gate( 7+ IRQ_BASE, (unsigned) irq7, 0x08, 0x8E); IDT::set_gate( 8+ IRQ_BASE, (unsigned) irq8, 0x08, 0x8E); IDT::set_gate( 9+ IRQ_BASE, (unsigned) irq9, 0x08, 0x8E); IDT::set_gate(10+ IRQ_BASE, (unsigned)irq10, 0x08, 0x8E); IDT::set_gate(11+ IRQ_BASE, (unsigned)irq11, 0x08, 0x8E); IDT::set_gate(12+ IRQ_BASE, (unsigned)irq12, 0x08, 0x8E); IDT::set_gate(13+ IRQ_BASE, (unsigned)irq13, 0x08, 0x8E); IDT::set_gate(14+ IRQ_BASE, (unsigned)irq14, 0x08, 0x8E); IDT::set_gate(15+ IRQ_BASE, (unsigned)irq15, 0x08, 0x8E); /* -- INITIALIZE THE HIGH-LEVEL INTERRUPT HANDLER */ int i; for(i = 0; i < IRQ_TABLE_SIZE; i++) { handler_table[i] = NULL; } } bool InterruptHandler::generated_by_slave_PIC(unsigned int int_no) { return int_no > 7; } void InterruptHandler::dispatch_interrupt(REGS * _r) { /* -- INTERRUPT NUMBER */ unsigned int int_no = _r->int_no - IRQ_BASE; //Console::puts("INTERRUPT DISPATCHER: int_no = "); //Console::putui(int_no); //Console::puts("\n"); assert((int_no >= 0) && (int_no < IRQ_TABLE_SIZE)); /* -- HAS A HANDLER BEEN REGISTERED FOR THIS INTERRUPT NO? */ InterruptHandler * handler = handler_table[int_no]; if (!handler) { /* --- NO DEFAULT HANDLER HAS BEEN REGISTERED. SIMPLY RETURN AN ERROR. */ Console::puts("INTERRUPT NO: "); Console::puti(int_no); Console::puts("\n"); Console::puts("NO DEFAULT INTERRUPT HANDLER REGISTERED\n"); // abort(); } else { /* -- HANDLE THE INTERRUPT */ handler->handle_interrupt(_r); } /* This is an interrupt that was raised by the interrupt controller. We need to send and end-of-interrupt (EOI) signal to the controller after the interrupt has been handled. */ /* Check if the interrupt was generated by the slave interrupt controller. If so, send an End-of-Interrupt (EOI) message to the slave controller. */ if (generated_by_slave_PIC(int_no)) { Machine::outportb(0xA0, 0x20); } /* Send an EOI message to the master interrupt controller. */ Machine::outportb(0x20, 0x20); } void InterruptHandler::register_handler(unsigned int _irq_code, InterruptHandler * _handler) { assert(_irq_code >= 0 && _irq_code < IRQ_TABLE_SIZE); handler_table[_irq_code] = _handler; Console::puts("Installed interrupt handler at IRQ "); Console::putui(_irq_code); Console::puts("\n"); } void InterruptHandler::deregister_handler(unsigned int _irq_code) { assert(_irq_code >= 0 && _irq_code < IRQ_TABLE_SIZE); handler_table[_irq_code] = NULL; Console::puts("UNINSTALLED interrupt handler at IRQ "); Console::putui(_irq_code); Console::puts("\n"); }