mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Further cleanup and refactoring of the interrupt code.
This commit is contained in:
parent
0e48b23429
commit
5162a12d03
4 changed files with 110 additions and 85 deletions
|
@ -36,7 +36,7 @@ namespace Sortix
|
|||
{
|
||||
extern "C" void gdt_flush(addr_t);
|
||||
extern "C" void tss_flush();
|
||||
|
||||
|
||||
const size_t GDT_NUM_ENTRIES = 7;
|
||||
gdt_entry_t gdt_entries[GDT_NUM_ENTRIES];
|
||||
gdt_ptr_t gdt_ptr;
|
||||
|
@ -45,7 +45,7 @@ namespace Sortix
|
|||
const uint8_t GRAN_64_BIT_MODE = 1<<5;
|
||||
const uint8_t GRAN_32_BIT_MODE = 1<<6;
|
||||
const uint8_t GRAN_4KIB_BLOCKS = 1<<7;
|
||||
|
||||
|
||||
void Init()
|
||||
{
|
||||
gdt_ptr.limit = (sizeof(gdt_entry_t) * GDT_NUM_ENTRIES) - 1;
|
||||
|
@ -159,8 +159,7 @@ namespace Sortix
|
|||
|
||||
namespace IDT
|
||||
{
|
||||
// Lets us access our ASM functions from our C++ code.
|
||||
extern "C" void idt_flush(uint32_t);
|
||||
extern "C" void idt_flush(addr_t);
|
||||
|
||||
idt_entry_t idt_entries[256];
|
||||
idt_ptr_t idt_ptr;
|
||||
|
@ -171,18 +170,6 @@ namespace Sortix
|
|||
idt_ptr.base = (addr_t) &idt_entries;
|
||||
|
||||
Memory::Set(&idt_entries, 0, sizeof(idt_entry_t)*256);
|
||||
|
||||
// Remap the irq table.
|
||||
CPU::OutPortB(0x20, 0x11);
|
||||
CPU::OutPortB(0xA0, 0x11);
|
||||
CPU::OutPortB(0x21, 0x20);
|
||||
CPU::OutPortB(0xA1, 0x28);
|
||||
CPU::OutPortB(0x21, 0x04);
|
||||
CPU::OutPortB(0xA1, 0x02);
|
||||
CPU::OutPortB(0x21, 0x01);
|
||||
CPU::OutPortB(0xA1, 0x01);
|
||||
CPU::OutPortB(0x21, 0x0);
|
||||
CPU::OutPortB(0xA1, 0x0);
|
||||
}
|
||||
|
||||
void Flush()
|
||||
|
|
|
@ -37,21 +37,52 @@ void SysExit(int status); // HACK
|
|||
|
||||
namespace Interrupt {
|
||||
|
||||
const uint16_t PIC_MASTER = 0x20;
|
||||
const uint16_t PIC_SLAVE = 0xA0;
|
||||
const uint16_t PIC_COMMAND = 0x00;
|
||||
const uint16_t PIC_DATA = 0x01;
|
||||
const uint8_t PIC_CMD_ENDINTR = 0x20;
|
||||
const uint8_t PIC_ICW1_ICW4 = 0x01; // ICW4 (not) needed
|
||||
const uint8_t PIC_ICW1_SINGLE = 0x02; // Single (cascade) mode
|
||||
const uint8_t PIC_ICW1_INTERVAL4 = 0x04; // Call address interval 4 (8)
|
||||
const uint8_t PIC_ICW1_LEVEL = 0x08; // Level triggered (edge) mode
|
||||
const uint8_t PIC_CMD_INIT = 0x10;
|
||||
const uint8_t PIC_MODE_8086 = 0x01; // 8086/88 (MCS-80/85) mode
|
||||
const uint8_t PIC_MODE_AUTO = 0x02; // Auto (normal) EOI
|
||||
const uint8_t PIC_MODE_BUF_SLAVE = 0x08; // Buffered mode/slave
|
||||
const uint8_t PIC_MODE_BUF_MASTER = 0x0C; // Buffered mode/master
|
||||
const uint8_t PIC_MODE_SFNM = 0x10; // Special fully nested (not)
|
||||
|
||||
const bool DEBUG_EXCEPTION = false;
|
||||
const bool DEBUG_IRQ = false;
|
||||
bool initialized;
|
||||
|
||||
const size_t numknownexceptions = 20;
|
||||
const size_t NUM_KNOWN_EXCEPTIONS = 20;
|
||||
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",
|
||||
"Coprocessor fault", "Alignment check", "Machine check",
|
||||
"SIMD Floating-Point" };
|
||||
{
|
||||
"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",
|
||||
"Coprocessor fault",
|
||||
"Alignment check",
|
||||
"Machine check",
|
||||
"SIMD Floating-Point",
|
||||
};
|
||||
|
||||
const size_t NUM_INTERRUPTS = 256UL;
|
||||
const unsigned NUM_INTERRUPTS = 256UL;
|
||||
|
||||
Handler interrupthandlers[NUM_INTERRUPTS];
|
||||
void* interrupthandlerptr[NUM_INTERRUPTS];
|
||||
|
@ -61,12 +92,27 @@ void Init()
|
|||
initialized = false;
|
||||
IDT::Init();
|
||||
|
||||
for ( size_t i = 0; i < NUM_INTERRUPTS; i++ )
|
||||
for ( unsigned i = 0; i < NUM_INTERRUPTS; i++ )
|
||||
{
|
||||
interrupthandlers[i] = NULL;
|
||||
interrupthandlerptr[i] = NULL;
|
||||
RegisterRawHandler(i, interrupt_handler_null, false);
|
||||
}
|
||||
|
||||
// Remap the IRQ table on the PICs.
|
||||
uint8_t mastermask = 0;
|
||||
uint8_t slavemask = 0;
|
||||
CPU::OutPortB(PIC_MASTER + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_COMMAND, PIC_CMD_INIT | PIC_ICW1_ICW4);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, IRQ0);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, IRQ8);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, 0x04); // Slave PIC at IRQ2
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, 0x02); // Cascade Identity
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, PIC_MODE_8086);
|
||||
CPU::OutPortB(PIC_MASTER + PIC_DATA, mastermask);
|
||||
CPU::OutPortB(PIC_SLAVE + PIC_DATA, slavemask);
|
||||
|
||||
RegisterRawHandler(0, isr0, false);
|
||||
RegisterRawHandler(1, isr1, false);
|
||||
RegisterRawHandler(2, isr2, false);
|
||||
|
@ -116,11 +162,6 @@ void Init()
|
|||
RegisterRawHandler(46, irq14, false);
|
||||
RegisterRawHandler(47, irq15, false);
|
||||
|
||||
for ( unsigned i = 48; i < 256; i++ )
|
||||
{
|
||||
RegisterRawHandler(48, interrupt_handler_null, false);
|
||||
}
|
||||
|
||||
// TODO: Let the syscall.cpp code register this.
|
||||
RegisterRawHandler(128, syscall_handler, true);
|
||||
|
||||
|
@ -130,14 +171,14 @@ void Init()
|
|||
Interrupt::Enable();
|
||||
}
|
||||
|
||||
void RegisterHandler(uint8_t n, Interrupt::Handler handler, void* user)
|
||||
void RegisterHandler(unsigned n, Interrupt::Handler handler, void* user)
|
||||
{
|
||||
interrupthandlers[n] = handler;
|
||||
interrupthandlerptr[n] = user;
|
||||
}
|
||||
|
||||
// TODO: This function contains magic IDT-related values!
|
||||
void RegisterRawHandler(uint8_t index, RawHandler handler, bool userspace)
|
||||
void RegisterRawHandler(unsigned index, RawHandler handler, bool userspace)
|
||||
{
|
||||
addr_t handlerentry = (addr_t) handler;
|
||||
uint16_t sel = 0x08;
|
||||
|
@ -147,39 +188,43 @@ void RegisterRawHandler(uint8_t index, RawHandler handler, bool userspace)
|
|||
if ( initialized ) { IDT::Flush(); }
|
||||
}
|
||||
|
||||
// This gets called from our ASM interrupt handler stub.
|
||||
extern "C" void ISRHandler(Sortix::CPU::InterruptRegisters* regs)
|
||||
void CrashHandler(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
const char* message = ( regs->int_no < NUM_KNOWN_EXCEPTIONS )
|
||||
? exceptions[regs->int_no] : "Unknown";
|
||||
|
||||
if ( DEBUG_EXCEPTION ) { regs->LogRegisters(); Log::Print("\n"); }
|
||||
|
||||
#ifdef PLATFORM_X64
|
||||
addr_t ip = regs->rip;
|
||||
#else
|
||||
addr_t ip = regs->eip;
|
||||
#endif
|
||||
|
||||
// Halt and catch fire if we are the kernel.
|
||||
unsigned codemode = regs->cs & 0x3U;
|
||||
if ( codemode == 0 )
|
||||
{
|
||||
PanicF("Unhandled CPU Exception id %zu '%s' at ip=0x%zx "
|
||||
"(cr2=0x%p, err_code=0x%p)", regs->int_no, message,
|
||||
ip, regs->cr2, regs->err_code);
|
||||
}
|
||||
|
||||
Log::Print("The current program has crashed and was terminated:\n");
|
||||
Log::PrintF("%s exception at ip=0x%zx (cr2=0x%p, err_code=0x%p)\n",
|
||||
message, ip, regs->cr2, regs->err_code);
|
||||
|
||||
Sound::Mute();
|
||||
|
||||
CurrentProcess()->Exit(139);
|
||||
Scheduler::ProcessTerminated(regs);
|
||||
}
|
||||
|
||||
void ISRHandler(Sortix::CPU::InterruptRegisters* regs)
|
||||
{
|
||||
if ( regs->int_no < 32 )
|
||||
{
|
||||
const char* message = ( regs->int_no < numknownexceptions )
|
||||
? exceptions[regs->int_no] : "Unknown";
|
||||
|
||||
if ( DEBUG_EXCEPTION ) { regs->LogRegisters(); Log::Print("\n"); }
|
||||
|
||||
#ifdef PLATFORM_X64
|
||||
addr_t ip = regs->rip;
|
||||
#else
|
||||
addr_t ip = regs->eip;
|
||||
#endif
|
||||
|
||||
// Halt and catch fire if we are the kernel.
|
||||
if ( (regs->cs & (0x4-1)) == 0 )
|
||||
{
|
||||
PanicF("Unhandled CPU Exception id %zu '%s' at ip=0x%zx "
|
||||
"(cr2=0x%p, err_code=0x%p)", regs->int_no, message,
|
||||
ip, regs->cr2, regs->err_code);
|
||||
}
|
||||
|
||||
Log::Print("The current program has crashed and was terminated:\n");
|
||||
Log::PrintF("%s exception at ip=0x%zx (cr2=0x%p, err_code=0x%p)\n",
|
||||
message, ip, regs->cr2, regs->err_code);
|
||||
|
||||
Sound::Mute();
|
||||
|
||||
CurrentProcess()->Exit(139);
|
||||
Scheduler::ProcessTerminated(regs);
|
||||
|
||||
CrashHandler(regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -190,10 +235,9 @@ extern "C" void ISRHandler(Sortix::CPU::InterruptRegisters* regs)
|
|||
}
|
||||
}
|
||||
|
||||
// This gets called from our ASM interrupt handler stub.
|
||||
extern "C" void IRQHandler(Sortix::CPU::InterruptRegisters* regs)
|
||||
void IRQHandler(Sortix::CPU::InterruptRegisters* regs)
|
||||
{
|
||||
// TODO! IRQ 7 and 15 might be spurious and might need to be ignored.
|
||||
// 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; }
|
||||
|
||||
|
@ -204,18 +248,16 @@ extern "C" void IRQHandler(Sortix::CPU::InterruptRegisters* regs)
|
|||
Log::Print("\n");
|
||||
}
|
||||
|
||||
unsigned int_no = regs->int_no;
|
||||
|
||||
// Send an EOI (end of interrupt) signal to the PICs.
|
||||
if ( IRQ8 <= int_no ) { CPU::OutPortB(PIC_SLAVE, PIC_CMD_ENDINTR); }
|
||||
CPU::OutPortB(PIC_MASTER, PIC_CMD_ENDINTR);
|
||||
|
||||
// Send reset signal to slave if this interrupt involved the slave.
|
||||
if (regs->int_no >= 40) { CPU::OutPortB(0xA0, 0x20); }
|
||||
|
||||
// Send reset signal to master.
|
||||
CPU::OutPortB(0x20, 0x20);
|
||||
|
||||
if ( interrupthandlers[regs->int_no] )
|
||||
if ( interrupthandlers[int_no] )
|
||||
{
|
||||
void* user = interrupthandlerptr[regs->int_no];
|
||||
interrupthandlers[regs->int_no](regs, user);
|
||||
void* user = interrupthandlerptr[int_no];
|
||||
interrupthandlers[int_no](regs, user);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ const unsigned IRQ4 = 36;
|
|||
const unsigned IRQ5 = 37;
|
||||
const unsigned IRQ6 = 38;
|
||||
const unsigned IRQ7 = 39;
|
||||
const unsigned IRQ8 = 30;
|
||||
const unsigned IRQ8 = 40;
|
||||
const unsigned IRQ9 = 41;
|
||||
const unsigned IRQ10 = 42;
|
||||
const unsigned IRQ11 = 43;
|
||||
|
@ -49,10 +49,10 @@ inline void Enable() { asm volatile("sti"); }
|
|||
inline void Disable() { asm volatile("cli"); }
|
||||
|
||||
typedef void (*Handler)(CPU::InterruptRegisters* regs, void* user);
|
||||
void RegisterHandler(uint8_t index, Handler handler, void* user);
|
||||
void RegisterHandler(unsigned index, Handler handler, void* user);
|
||||
|
||||
typedef void (*RawHandler)(void);
|
||||
void RegisterRawHandler(uint8_t index, RawHandler handler, bool userspace);
|
||||
void RegisterRawHandler(unsigned index, RawHandler handler, bool userspace);
|
||||
|
||||
void Init();
|
||||
|
||||
|
|
|
@ -85,8 +85,7 @@ IRQ 13, 45
|
|||
IRQ 14, 46
|
||||
IRQ 15, 47
|
||||
|
||||
; In isr.c
|
||||
extern ISRHandler
|
||||
extern interrupt_handler
|
||||
|
||||
; This is our common ISR stub. It saves the processor state, sets
|
||||
; up for kernel mode segments, calls the C-level fault handler,
|
||||
|
@ -107,7 +106,7 @@ isr_common_stub:
|
|||
|
||||
push esp
|
||||
|
||||
call ISRHandler
|
||||
call interrupt_handler
|
||||
|
||||
add esp, 8
|
||||
pop ebx ; reload the original data segment descriptor
|
||||
|
@ -121,9 +120,6 @@ isr_common_stub:
|
|||
;sti
|
||||
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
|
||||
|
||||
; In isr.c
|
||||
extern IRQHandler
|
||||
|
||||
; This is our common IRQ stub. It saves the processor state, sets
|
||||
; up for kernel mode segments, calls the C-level fault handler,
|
||||
; and finally restores the stack frame.
|
||||
|
@ -143,7 +139,7 @@ irq_common_stub:
|
|||
|
||||
push esp
|
||||
|
||||
call IRQHandler
|
||||
call interrupt_handler
|
||||
|
||||
add esp, 8
|
||||
pop ebx ; reload the original data segment descriptor
|
||||
|
|
Loading…
Add table
Reference in a new issue