os-k/kaleid/kernel/ke/idt.c

393 lines
13 KiB
C
Raw Normal View History

2019-03-25 23:10:06 +01:00
//----------------------------------------------------------------------------//
2019-04-23 17:06:03 +02:00
// 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/>. //
2019-03-25 23:10:06 +01:00
//----------------------------------------------------------------------------//
2019-05-13 23:22:27 +02:00
#include <lib/buf.h>
#include <init/boot.h>
#include <ke/idt.h>
2019-05-19 00:07:01 +02:00
#include <io/vga.h>
2019-05-22 08:11:50 +02:00
#include <mm/mm.h>
2019-05-22 18:15:23 +02:00
#include <io/spkr.h>
2019-04-01 23:51:48 +02:00
2019-04-22 20:15:32 +02:00
IdtEntry_t idt[256] = { 0 };
2019-05-14 11:48:07 +02:00
IdtPtr_t _KeIdtPtr;
2019-05-19 00:38:58 +02:00
bool KeIdtIsInitialized = 0;
2019-03-25 23:10:06 +01:00
2019-05-14 11:48:07 +02:00
static ISRList_t isrList = { 0 };
2019-05-14 11:48:07 +02:00
static char *ExceptionsChar[32] = {
2019-05-01 14:17:16 +02:00
"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 (Legacy)",
"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",
"Security Exception",
"Intel Reserved"
};
static void EnablePIC(void);
2019-05-14 11:48:07 +02:00
static void EarlyExceptionHandler(ISRFrame_t *regs);
2019-05-22 00:38:04 +02:00
static void DoubleFaultHandler(ISRFrame_t *regs);
//
// Registers an isr with his IRQ to handle driver interrupts
//
2019-05-14 11:48:07 +02:00
error_t KeRegisterISR(void (*isr)(ISRFrame_t *regs), uchar isrNo)
{
2019-05-06 22:04:22 +02:00
uchar n = isrList.n;
int OverWriting = 0;
2019-04-24 18:42:38 +02:00
2019-05-19 00:38:58 +02:00
assert(KeIdtIsInitialized); // IDT initialized
2019-05-06 22:04:22 +02:00
if (n == 0) goto settingUp;
2019-04-24 18:42:38 +02:00
2019-05-06 22:04:22 +02:00
for (int i = 0; i < n; i++) {
if (isrNo == isrList.entry[i].isrNo) {
n = i;
OverWriting++;
break;
}
}
if ((n == 255)) // IRQs not filled
return ENOMEM;
settingUp:
isrList.entry[n].isr = isr;
isrList.entry[n].isrNo = isrNo;
if (!OverWriting) isrList.n++;
return EOK;
}
//
// Installs the IDT in order to activate the interrupts handling
//
2019-05-14 11:48:07 +02:00
void KeSetupIDT(void)
2019-04-22 20:15:32 +02:00
{
2019-04-23 17:06:03 +02:00
// XXX detect the APIC with cpuid !
2019-04-24 18:42:38 +02:00
EnablePIC();
2019-04-01 23:51:48 +02:00
2019-04-22 20:15:32 +02:00
ushort codeSeg = (ushort)(ulong)BtLoaderInfo.codeSegment;
// Set IDT ptr
2019-05-14 11:48:07 +02:00
_KeIdtPtr.limit = (sizeof(IdtEntry_t) * 256) - 1;
_KeIdtPtr.base = &idt;
2019-04-22 20:15:32 +02:00
// Set IDT Exception Gates
2019-05-22 00:38:04 +02:00
KeSetIDTGate(0x00, (ulong)isr0, codeSeg, 0x8E, 0);
KeSetIDTGate(0x01, (ulong)isr1, codeSeg, 0x8E, 0);
KeSetIDTGate(0x02, (ulong)isr2, codeSeg, 0x8E, 0);
KeSetIDTGate(0x03, (ulong)isr3, codeSeg, 0x8E, 0);
KeSetIDTGate(0x04, (ulong)isr4, codeSeg, 0x8E, 0);
KeSetIDTGate(0x05, (ulong)isr5, codeSeg, 0x8E, 0);
KeSetIDTGate(0x06, (ulong)isr6, codeSeg, 0x8E, 0);
KeSetIDTGate(0x07, (ulong)isr7, codeSeg, 0x8E, 0);
KeSetIDTGate(0x08, (ulong)isr8, codeSeg, 0x8E, 1);
KeSetIDTGate(0x09, (ulong)isr9, codeSeg, 0x8E, 0);
KeSetIDTGate(0x0A, (ulong)isr10, codeSeg, 0x8E, 0);
KeSetIDTGate(0x0B, (ulong)isr11, codeSeg, 0x8E, 0);
KeSetIDTGate(0x0C, (ulong)isr12, codeSeg, 0x8E, 1);
KeSetIDTGate(0x0D, (ulong)isr13, codeSeg, 0x8E, 0);
KeSetIDTGate(0x0E, (ulong)isr14, codeSeg, 0x8E, 0);
KeSetIDTGate(0x0F, (ulong)isr15, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x10, (ulong)isr16, codeSeg, 0x8E, 0);
KeSetIDTGate(0x11, (ulong)isr17, codeSeg, 0x8E, 0);
KeSetIDTGate(0x12, (ulong)isr18, codeSeg, 0x8E, 0);
KeSetIDTGate(0x13, (ulong)isr19, codeSeg, 0x8E, 0);
KeSetIDTGate(0x14, (ulong)isr20, codeSeg, 0x8E, 0);
KeSetIDTGate(0x15, (ulong)isr21, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x16, (ulong)isr22, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x17, (ulong)isr23, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x18, (ulong)isr24, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x19, (ulong)isr25, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x1A, (ulong)isr26, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x1B, (ulong)isr27, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x1C, (ulong)isr28, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x1D, (ulong)isr29, codeSeg, 0x8E, 0); // INTEL RESERVED
KeSetIDTGate(0x1E, (ulong)isr30, codeSeg, 0x8E, 0);
KeSetIDTGate(0x1F, (ulong)isr31, codeSeg, 0x8E, 0); // INTEL RESERVED
2019-04-22 20:15:32 +02:00
2019-04-27 00:04:27 +02:00
// Set IDT IRQs Gates
2019-05-22 00:38:04 +02:00
KeSetIDTGate(0x20, (ulong)isr32, codeSeg, 0x8E, 0);
KeSetIDTGate(0x21, (ulong)isr33, codeSeg, 0x8E, 0);
KeSetIDTGate(0x22, (ulong)isr34, codeSeg, 0x8E, 0);
KeSetIDTGate(0x23, (ulong)isr35, codeSeg, 0x8E, 0);
KeSetIDTGate(0x24, (ulong)isr36, codeSeg, 0x8E, 0);
KeSetIDTGate(0x25, (ulong)isr37, codeSeg, 0x8E, 0);
KeSetIDTGate(0x26, (ulong)isr38, codeSeg, 0x8E, 0);
KeSetIDTGate(0x27, (ulong)isr39, codeSeg, 0x8E, 0);
KeSetIDTGate(0x28, (ulong)isr40, codeSeg, 0x8E, 0);
KeSetIDTGate(0x29, (ulong)isr41, codeSeg, 0x8E, 0);
KeSetIDTGate(0x2A, (ulong)isr42, codeSeg, 0x8E, 0);
KeSetIDTGate(0x2B, (ulong)isr43, codeSeg, 0x8E, 0);
KeSetIDTGate(0x2C, (ulong)isr44, codeSeg, 0x8E, 0);
KeSetIDTGate(0x2D, (ulong)isr45, codeSeg, 0x8E, 0);
KeSetIDTGate(0x2E, (ulong)isr46, codeSeg, 0x8E, 0);
KeSetIDTGate(0x2F, (ulong)isr47, codeSeg, 0x8E, 0);
2019-05-06 22:04:22 +02:00
2019-05-19 00:38:58 +02:00
KeIdtIsInitialized++;
2019-05-06 22:04:22 +02:00
//Setup Early Exception handler
for (uchar i = 0 ; i < 0x20 ; i++) {
2019-05-14 11:48:07 +02:00
KeRegisterISR(EarlyExceptionHandler, i);
2019-05-06 22:04:22 +02:00
}
2019-05-19 01:33:16 +02:00
KeRegisterISR(KeBrkDumpRegisters, 0x3);
2019-05-22 00:38:04 +02:00
KeRegisterISR(DoubleFaultHandler, 0x8);
2019-05-19 00:07:01 +02:00
2019-04-22 20:15:32 +02:00
// Load IDT
2019-05-14 11:48:07 +02:00
KeLoadIDT();
2019-05-22 23:32:44 +02:00
//DebugLog("\tInterrupt table initialized at %p\n", _KeIdtPtr.base);
KernLog("\tInterrupts activated\n");
2019-03-25 23:10:06 +01:00
}
2019-04-22 17:19:53 +02:00
//
// Set an interrupt gate
//
2019-05-22 00:38:04 +02:00
void KeSetIDTGate(uchar rank, ulong base, ushort selector, uchar flags, uchar ist)
2019-04-22 20:15:32 +02:00
{
// 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
2019-05-22 00:38:04 +02:00
idt[rank].ist = ist;
2019-04-22 20:15:32 +02:00
idt[rank].reserved = 0;
}
2019-04-22 22:32:21 +02:00
//
2019-04-24 18:42:38 +02:00
// Enable and initializes the PIC to work correctly
//
2019-04-24 18:42:38 +02:00
static void EnablePIC(void)
{
2019-04-24 18:42:38 +02:00
// Set ICW1 - begin init of the PIC
2019-04-22 22:32:21 +02:00
IoWriteByteOnPort(0x20, 0x11);
IoWriteByteOnPort(0xa0, 0x11);
2019-05-14 11:48:07 +02:00
2019-04-22 22:32:21 +02:00
// Set ICW2 (IRQ base offsets)
2019-04-29 23:52:53 +02:00
IoWriteByteOnPort(0x21, 0x20); //0x20 is the first free interrupt for IRQ0
IoWriteByteOnPort(0xa1, 0x28); // PIC2 is offseted to 0x28
2019-05-14 11:48:07 +02:00
2019-04-22 22:32:21 +02:00
// Set ICW3
2019-04-28 15:30:54 +02:00
IoWriteByteOnPort(0x21, 0x4);
IoWriteByteOnPort(0xa1, 0x2);
2019-05-14 11:48:07 +02:00
2019-04-22 22:32:21 +02:00
// Set ICW4
2019-04-24 18:42:38 +02:00
IoWriteByteOnPort(0x21, 0x1);
IoWriteByteOnPort(0xa1, 0x1);
2019-05-14 11:48:07 +02:00
2019-04-22 22:32:21 +02:00
// Set OCW1 (interrupt masks)
IoWriteByteOnPort(0x21, 0xff);
IoWriteByteOnPort(0xa1, 0xff);
}
//
// Ends the current interrupt handling
//
2019-05-14 11:48:07 +02:00
void KeSendEOItoPIC(uchar isr)
{
2019-04-24 21:08:44 +02:00
if(isr >= 8)
IoWriteByteOnPort(0xa0,0x20);
2019-04-24 21:08:44 +02:00
IoWriteByteOnPort(0x20,0x20);
}
2019-05-14 11:48:07 +02:00
void KeEnableNMI(void)
2019-04-24 23:00:12 +02:00
{
IoWriteByteOnPort(0x70, IoReadByteFromPort(0x70) & 0x7F);
}
2019-05-14 11:48:07 +02:00
void KeDisableNMI(void)
2019-04-24 23:00:12 +02:00
{
IoWriteByteOnPort(0x70, IoReadByteFromPort(0x70) | 0x80);
}
//
2019-04-27 00:04:27 +02:00
// The main ISR handler
//
2019-05-14 11:48:07 +02:00
void _KeHandleISR(ISRFrame_t *regs)
2019-04-27 00:04:27 +02:00
{
if ((!regs) || (!regs->rip))
KeStartPanic("[ISR ?] Unknown ISR Exception Abort\n");
2019-05-17 21:10:22 +02:00
if ((regs->intNo >= 0x15) && (regs->intNo <= 0x1D))
2019-04-27 00:38:47 +02:00
return; // INTEL RESERVED
2019-05-14 11:48:07 +02:00
2019-05-17 21:10:22 +02:00
if ((regs->intNo == 0x0F) || (regs->intNo == 0x1F))
2019-04-27 00:38:47 +02:00
return; // INTEL RESERVED
2019-05-06 22:04:22 +02:00
for (int i = 0; i < isrList.n; i++) {
if (regs->intNo == isrList.entry[i].isrNo) {
isrList.entry[i].isr(regs);
2019-04-27 00:04:27 +02:00
return;
}
}
2019-04-27 00:38:47 +02:00
bprintf(BStdOut, "[ISR 0x%x] %s\n", regs->intNo, "Unknown ISR Exception");
2019-04-29 23:51:25 +02:00
BStdOut->flusher(BStdOut);
2019-05-14 11:48:07 +02:00
KeSendEOItoPIC(regs->intNo);
2019-04-27 00:04:27 +02:00
}
//
2019-05-06 22:04:22 +02:00
// Early CPU Exception handler
//
2019-05-14 11:48:07 +02:00
static void EarlyExceptionHandler(ISRFrame_t *regs)
2019-04-22 22:32:21 +02:00
{
2019-05-19 00:38:58 +02:00
bprintf(BStdOut, "\n\n%CPANIC\n[ISR 0x%x] Irrecoverable Kernel %s\n\n"
2019-05-19 01:33:16 +02:00
" Error code : 0x%x (%b)",
2019-05-18 20:31:02 +02:00
2019-05-19 00:07:01 +02:00
VGA_COLOR_LIGHT_RED,
2019-04-27 00:04:27 +02:00
regs->intNo,
2019-05-06 22:04:22 +02:00
ExceptionsChar[regs->intNo],
2019-04-27 00:04:27 +02:00
regs->ErrorCode,
2019-05-19 01:33:16 +02:00
regs->ErrorCode
2019-05-19 00:07:01 +02:00
);
2019-05-19 01:33:16 +02:00
KeBrkDumpRegisters(regs);
2019-05-19 00:07:01 +02:00
BStdOut->flusher(BStdOut);
KeHaltCPU();
}
//
// Double Fault handling and stack overflow detection
//
2019-05-22 00:38:04 +02:00
static void DoubleFaultHandler(ISRFrame_t *regs)
{
2019-05-22 08:11:50 +02:00
ulong StackGuardTwo = (ulong)MmGetStackGuards(1);
2019-05-22 00:38:04 +02:00
if (regs->rsp <= StackGuardTwo + 4*KB && (regs->rsp - 4*KB <= regs->cr2)) {
2019-05-22 00:38:04 +02:00
bprintf(BStdOut,
2019-05-22 08:11:50 +02:00
"\n\n%CPANIC\n[ISR 0x8] Irrecoverable Kernel Stack Overflow\n\n"
" Double Fault Error code : %#x (%b)\n"
" Stack Guard bypassed : %#x",
2019-05-22 00:38:04 +02:00
VGA_COLOR_LIGHT_RED,
regs->ErrorCode,
2019-05-22 08:11:50 +02:00
regs->ErrorCode,
StackGuardTwo
);
2019-05-22 00:38:04 +02:00
} else {
bprintf(BStdOut,
"\n\n%CPANIC\n[ISR 0x8] Irrecoverable Kernel Double Fault Abort\n\n"
" Error code : 0x%x (%b)",
VGA_COLOR_LIGHT_RED,
regs->ErrorCode,
regs->ErrorCode
);
}
KeBrkDumpRegisters(regs);
BStdOut->flusher(BStdOut);
KeHaltCPU();
}
2019-05-19 01:33:16 +02:00
void KeBrkDumpRegisters(ISRFrame_t *regs)
2019-05-19 00:07:01 +02:00
{
2019-05-22 18:15:23 +02:00
IoDoBeepNoIdt();
bprintf(BStdOut, "\n\n"
2019-05-19 00:07:01 +02:00
"%C RIP: %#016lx RSP: %#016lx RBP: %#016lx\n\n"
" SS: %#016lx CS: %#016lx CR0: %#016lx\n"
" CR2: %#016lx CR3: %#016lx CR4: %#016lx\n"
" CR8: %#016lx EFE: %#016lx \n\n"
" RAX: %#016lx RBX: %#016lx RCX: %#016lx\n"
" RDX: %#016lx RSI: %#016lx RDI: %#016lx\n"
" R8: %#016lx R9: %#016lx R10: %#016lx\n"
" R11: %#016lx R12: %#016lx R13: %#016lx\n"
" R14: %#016lx R15: %#016lx \n\n"
" RFLAGS: %#022b (%#06x)",
2019-05-19 00:38:58 +02:00
VGA_COLOR_LIGHT_RED,
2019-04-27 00:04:27 +02:00
regs->rip,
regs->rsp,
2019-05-18 20:31:02 +02:00
regs->rbp,
2019-05-07 18:09:40 +02:00
regs->ss,
2019-05-18 20:31:02 +02:00
regs->cs,
regs->cr0,
regs->cr2,
regs->cr3,
regs->cr4,
regs->cr8,
regs->efer,
regs->rax,
regs->rbx,
regs->rcx,
regs->rdx,
regs->rsi,
regs->rdi,
regs->r8,
regs->r9,
regs->r10,
regs->r11,
regs->r12,
regs->r13,
regs->r14,
regs->r15,
2019-05-08 20:54:40 +02:00
regs->rflags,
2019-05-07 18:09:40 +02:00
regs->rflags
2019-05-22 18:15:23 +02:00
);
2019-05-19 00:07:01 +02:00
BStdOut->flusher(BStdOut);
2019-04-22 22:32:21 +02:00
}