259 lines
8.0 KiB
C
259 lines
8.0 KiB
C
//----------------------------------------------------------------------------//
|
|
// GNU GPL OS/K //
|
|
// //
|
|
// Desc: Interrupt related functions //
|
|
// //
|
|
// //
|
|
// Copyright © 2018-2019 The OS/K Team //
|
|
// //
|
|
// This file is part of OS/K. //
|
|
// //
|
|
// OS/K 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 //
|
|
// any later version. //
|
|
// //
|
|
// OS/K 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 OS/K. If not, see <https://www.gnu.org/licenses/>. //
|
|
//----------------------------------------------------------------------------//
|
|
|
|
#include <kernel/base.h>
|
|
#include <kernel/cpu.h>
|
|
#include <kernel/boot.h>
|
|
#include <kernel/iomisc.h>
|
|
#include <extras/buf.h>
|
|
|
|
extern void CpuIdtInit();
|
|
extern void isr0();
|
|
extern void isr1();
|
|
extern void isr2();
|
|
extern void isr3();
|
|
extern void isr4();
|
|
extern void isr5();
|
|
extern void isr6();
|
|
extern void isr7();
|
|
extern void isr8();
|
|
extern void isr9();
|
|
extern void isr10();
|
|
extern void isr11();
|
|
extern void isr12();
|
|
extern void isr13();
|
|
extern void isr14();
|
|
extern void isr15();
|
|
extern void isr16();
|
|
extern void isr17();
|
|
extern void isr18();
|
|
extern void isr19();
|
|
extern void isr20();
|
|
extern void isr21();
|
|
extern void isr22();
|
|
extern void isr23();
|
|
extern void isr24();
|
|
extern void isr25();
|
|
extern void isr26();
|
|
extern void isr27();
|
|
extern void isr28();
|
|
extern void isr29();
|
|
extern void isr30();
|
|
extern void isr31();
|
|
|
|
static char *IsrExceptions[32] = {
|
|
"Divide Error Fault",
|
|
"Debug Exception Trap",
|
|
"Non-maskable Interrupt",
|
|
"Breakpoint Trap",
|
|
"Overflow Trap",
|
|
"Bound Range Exceeded Fault",
|
|
"Invalid Opcode Fault",
|
|
"Device Not Available or No Math Coprocessor Fault",
|
|
"Double Fault Abort",
|
|
"Coprocessor Segment Overrun Fault",
|
|
"Invalid TSS Fault",
|
|
"Segment Not Present Fault",
|
|
"Stack Segment fault",
|
|
"General Protection Fault",
|
|
"Page Fault",
|
|
"Intel Reserved",
|
|
"x87 FPU Floating Point or Math Fault",
|
|
"Alignment Check Fault",
|
|
"Machine Check Abort",
|
|
"SIMD Floating Point Fault",
|
|
"Virtualization Exception Fault",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved",
|
|
"Intel Reserved"
|
|
};
|
|
|
|
IdtEntry_t idt[256] = { 0 };
|
|
IdtPtr_t idtPtr;
|
|
|
|
IRQList_t irqList = { 0 };
|
|
|
|
|
|
//
|
|
// Registers an isr with his IRQ to handle driver interrupts
|
|
//
|
|
void CpuRegisterIrq(void (*isr)(void), uchar irq, uchar flags)
|
|
{
|
|
KalAssert(idt[0].flags==0); // IDT uninitialized
|
|
|
|
irqList.entry[irqList.n].isr = isr;
|
|
irqList.entry[irqList.n].irq = irq;
|
|
irqList.entry[irqList.n].flags = flags;
|
|
irqList.n++;
|
|
}
|
|
|
|
//
|
|
// Installs the IDT in order to activate the interrupts handling
|
|
//
|
|
void CpuIdtSetup(void)
|
|
{
|
|
// XXX detect the APIC with cpuid !
|
|
disablePIC();
|
|
|
|
ushort codeSeg = (ushort)(ulong)BtLoaderInfo.codeSegment;
|
|
|
|
// Set IDT ptr
|
|
idtPtr.limit = (sizeof(IdtEntry_t) * 256) - 1;
|
|
idtPtr.base = &idt;
|
|
|
|
// Set IDT Exception Gates
|
|
IdtSetGate(0, (ulong)isr0, codeSeg, 0x8E);
|
|
IdtSetGate(1, (ulong)isr1, codeSeg, 0x8E);
|
|
IdtSetGate(2, (ulong)isr2, codeSeg, 0x8E);
|
|
IdtSetGate(3, (ulong)isr3, codeSeg, 0x8E);
|
|
IdtSetGate(4, (ulong)isr4, codeSeg, 0x8E);
|
|
IdtSetGate(5, (ulong)isr5, codeSeg, 0x8E);
|
|
IdtSetGate(6, (ulong)isr6, codeSeg, 0x8E);
|
|
IdtSetGate(7, (ulong)isr7, codeSeg, 0x8E);
|
|
IdtSetGate(8, (ulong)isr8, codeSeg, 0x8E);
|
|
IdtSetGate(9, (ulong)isr9, codeSeg, 0x8E);
|
|
IdtSetGate(10, (ulong)isr10, codeSeg, 0x8E);
|
|
IdtSetGate(11, (ulong)isr11, codeSeg, 0x8E);
|
|
IdtSetGate(12, (ulong)isr12, codeSeg, 0x8E);
|
|
IdtSetGate(13, (ulong)isr13, codeSeg, 0x8E);
|
|
IdtSetGate(14, (ulong)isr14, codeSeg, 0x8E);
|
|
IdtSetGate(15, (ulong)isr15, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(16, (ulong)isr16, codeSeg, 0x8E);
|
|
IdtSetGate(17, (ulong)isr17, codeSeg, 0x8E);
|
|
IdtSetGate(18, (ulong)isr18, codeSeg, 0x8E);
|
|
IdtSetGate(19, (ulong)isr19, codeSeg, 0x8E);
|
|
IdtSetGate(20, (ulong)isr20, codeSeg, 0x8E);
|
|
IdtSetGate(21, (ulong)isr21, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(22, (ulong)isr22, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(23, (ulong)isr23, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(24, (ulong)isr24, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(25, (ulong)isr25, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(26, (ulong)isr26, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(27, (ulong)isr27, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(28, (ulong)isr28, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(29, (ulong)isr29, codeSeg, 0x8E); // INTEL RESERVED
|
|
IdtSetGate(30, (ulong)isr30, codeSeg, 0x8E); // INTEL RESERVED
|
|
|
|
// Set the IRQ Driver Gates
|
|
for (int i = 0 ; i < irqList.n ; i++) {
|
|
IdtSetGate(irqList.entry[irqList.n].irq,
|
|
(ulong)irqList.entry[irqList.n].isr,
|
|
codeSeg,
|
|
irqList.entry[irqList.n].flags
|
|
);
|
|
}
|
|
|
|
// Load IDT
|
|
CpuIdtInit();
|
|
DebugLog("[IdtSetup] Initialized !\n");
|
|
}
|
|
|
|
//
|
|
// Set an interrupt gate
|
|
//
|
|
void IdtSetGate(uchar rank, ulong base, ushort selector, uchar flags)
|
|
{
|
|
// Set Base Address
|
|
idt[rank].baseLow = base & 0xFFFF;
|
|
idt[rank].baseMid = (base >> 16) & 0xFFFF;
|
|
idt[rank].baseHigh = (base >> 32) & 0xFFFFFFFF;
|
|
|
|
// Set Selector
|
|
idt[rank].selector = selector;
|
|
idt[rank].flags = flags;
|
|
|
|
// Set Reserved Areas to Zero
|
|
idt[rank].reservedIst = 0;
|
|
idt[rank].reserved = 0;
|
|
}
|
|
|
|
//
|
|
// Disables the PIC to activate the APIC
|
|
//
|
|
void disablePIC(void)
|
|
{
|
|
// Set ICW1
|
|
IoWriteByteOnPort(0x20, 0x11);
|
|
IoWriteByteOnPort(0xa0, 0x11);
|
|
|
|
// Set ICW2 (IRQ base offsets)
|
|
IoWriteByteOnPort(0x21, 0xe0);
|
|
IoWriteByteOnPort(0xa1, 0xe8);
|
|
|
|
// Set ICW3
|
|
IoWriteByteOnPort(0x21, 4);
|
|
IoWriteByteOnPort(0xa1, 2);
|
|
|
|
// Set ICW4
|
|
IoWriteByteOnPort(0x21, 1);
|
|
IoWriteByteOnPort(0xa1, 1);
|
|
|
|
// Set OCW1 (interrupt masks)
|
|
IoWriteByteOnPort(0x21, 0xff);
|
|
IoWriteByteOnPort(0xa1, 0xff);
|
|
|
|
// ENABLING LOCAL APIC
|
|
uint *val = (void*)0xfee000f0;
|
|
*val |= (1<<8);
|
|
}
|
|
|
|
//
|
|
// Ends the current interrupt handling
|
|
//
|
|
void sendEOItoPIC(uchar isr)
|
|
{
|
|
if(isr >= 8)
|
|
IoWriteByteOnPort(0xa0,0x20);
|
|
|
|
IoWriteByteOnPort(0x20,0x20);
|
|
}
|
|
|
|
//
|
|
// The main exception handler
|
|
//
|
|
void IdtHandler(ulong intNo)
|
|
{
|
|
int irrecoverable = 0;
|
|
char *exceptionMsg = "Unhandled ISR exception";
|
|
|
|
if (intNo == 0 || intNo == 6 || intNo == 8 || intNo == 13) irrecoverable++;
|
|
|
|
if (intNo < 32) exceptionMsg = IsrExceptions[intNo];
|
|
|
|
if (irrecoverable) {
|
|
KeStartPanic("[ISR 0x%x] Irrecoverable %s\n", intNo, exceptionMsg);
|
|
} else {
|
|
bprintf(BStdOut, "[ISR 0x%x] %s\n", intNo, exceptionMsg);
|
|
sendEOItoPIC(intNo);
|
|
}
|
|
}
|