172 lines
5.4 KiB
C
Executable file
172 lines
5.4 KiB
C
Executable file
/*
|
|
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");
|
|
|
|
}
|