2011-09-07 12:45:07 -04:00
|
|
|
/******************************************************************************
|
|
|
|
|
|
|
|
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
|
|
|
|
|
|
|
|
This file is part of Sortix.
|
|
|
|
|
|
|
|
Sortix is free software: you can redistribute it and/or modify it under the
|
|
|
|
terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation, either version 3 of the License, or (at your option) any later
|
|
|
|
version.
|
|
|
|
|
|
|
|
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
|
with Sortix. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
interrupt.cpp
|
|
|
|
High level interrupt service routines and interrupt request handlers.
|
|
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include "platform.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "interrupt.h"
|
|
|
|
#include "panic.h"
|
|
|
|
|
|
|
|
#include "process.h" // Hack for SIGSEGV
|
|
|
|
#include "sound.h" // Hack for SIGSEGV
|
|
|
|
|
|
|
|
namespace Sortix
|
|
|
|
{
|
|
|
|
namespace Interrupt
|
|
|
|
{
|
2011-09-21 14:52:29 -04:00
|
|
|
const bool DEBUG_EXCEPTION = false;
|
|
|
|
const bool DEBUG_IRQ = false;
|
2011-10-02 09:58:08 -04:00
|
|
|
|
2011-10-25 20:25:27 -04:00
|
|
|
size_t numknownexceptions = 20;
|
2011-09-07 12:45:07 -04:00
|
|
|
const char* exceptions[] =
|
|
|
|
{ "Divide by zero", "Debug", "Non maskable interrupt", "Breakpoint",
|
|
|
|
"Into detected overflow", "Out of bounds", "Invalid opcode",
|
|
|
|
"No coprocessor", "Double fault", "Coprocessor segment overrun",
|
|
|
|
"Bad TSS", "Segment not present", "Stack fault",
|
|
|
|
"General protection fault", "Page fault", "Unknown interrupt",
|
2011-10-25 20:25:27 -04:00
|
|
|
"Coprocessor fault", "Alignment check", "Machine check",
|
|
|
|
"SIMD Floating-Point" };
|
2011-09-07 12:45:07 -04:00
|
|
|
|
|
|
|
Handler interrupthandlers[256];
|
|
|
|
|
|
|
|
void RegisterHandler(uint8_t n, Interrupt::Handler handler)
|
|
|
|
{
|
|
|
|
interrupthandlers[n] = handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This gets called from our ASM interrupt handler stub.
|
|
|
|
extern "C" void ISRHandler(Sortix::CPU::InterruptRegisters* regs)
|
|
|
|
{
|
|
|
|
#ifdef PLATFORM_X86
|
|
|
|
if ( regs->int_no < 32 )
|
|
|
|
{
|
|
|
|
const char* message = ( regs->int_no < numknownexceptions )
|
|
|
|
? exceptions[regs->int_no] : "Unknown";
|
|
|
|
|
2011-09-21 14:52:29 -04:00
|
|
|
if ( DEBUG_EXCEPTION ) { regs->LogRegisters(); Log::Print("\n"); }
|
2011-10-02 09:58:08 -04:00
|
|
|
|
2011-09-07 12:45:07 -04:00
|
|
|
// Halt and catch fire if we are the kernel.
|
2011-10-02 09:58:08 -04:00
|
|
|
if ( (regs->cs & (0x4-1)) == 0 )
|
2011-09-07 12:45:07 -04:00
|
|
|
{
|
|
|
|
PanicF("Unhandled CPU Exception id %zu '%s' at eip=0x%zx "
|
|
|
|
"(cr2=0x%p, err_code=0x%p)", regs->int_no, message,
|
|
|
|
regs->eip, regs->cr2, regs->err_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
Log::Print("The current program has crashed and was terminated:\n");
|
|
|
|
Log::PrintF("%s exception at eip=0x%zx (cr2=0x%p, err_code=0x%p)\n",
|
|
|
|
message, regs->eip, regs->cr2, regs->err_code);
|
|
|
|
|
|
|
|
Sound::Mute();
|
|
|
|
const char* programname = "sh";
|
2011-09-21 14:52:29 -04:00
|
|
|
Process::Execute(programname, regs);
|
2011-09-07 12:45:07 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( interrupthandlers[regs->int_no] != NULL )
|
|
|
|
{
|
|
|
|
interrupthandlers[regs->int_no](regs);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#warning "ISR handlers are not supported on this arch"
|
|
|
|
while(true);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// This gets called from our ASM interrupt handler stub.
|
|
|
|
extern "C" void IRQHandler(Sortix::CPU::InterruptRegisters* regs)
|
|
|
|
{
|
|
|
|
#ifdef PLATFORM_X86
|
|
|
|
// TODO! IRQ 7 and 15 might be spurious and might need to be ignored.
|
|
|
|
// See http://wiki.osdev.org/PIC for details (section Spurious IRQs).
|
|
|
|
if ( regs->int_no == 32 + 7 || regs->int_no == 32 + 15 ) { return; }
|
|
|
|
|
2011-09-21 14:52:29 -04:00
|
|
|
if ( DEBUG_IRQ )
|
|
|
|
{
|
|
|
|
Log::PrintF("IRQ%u ", regs->int_no-32);
|
|
|
|
regs->LogRegisters();
|
|
|
|
Log::Print("\n");
|
|
|
|
}
|
|
|
|
|
2011-09-07 12:45:07 -04:00
|
|
|
if ( regs->int_no < 32 || 48 < regs->int_no )
|
|
|
|
{
|
|
|
|
PanicF("IRQ eax=%u, int_no=%u, err_code=%u, eip=%u!",
|
|
|
|
regs->eax, regs->int_no, regs->err_code, regs->eip);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send an EOI (end of interrupt) signal to the PICs.
|
|
|
|
|
|
|
|
// Send reset signal to slave if this interrupt involved the slave.
|
|
|
|
if (regs->int_no >= 40) { X86::OutPortB(0xA0, 0x20); }
|
|
|
|
|
|
|
|
// Send reset signal to master.
|
|
|
|
X86::OutPortB(0x20, 0x20);
|
|
|
|
|
|
|
|
if ( interrupthandlers[regs->int_no] != NULL )
|
|
|
|
{
|
|
|
|
interrupthandlers[regs->int_no](regs);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#warning "IRQ handlers are not supported on this arch"
|
|
|
|
while(true);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|