185 lines
4.1 KiB
C
185 lines
4.1 KiB
C
#include <kernel/gdt.h>
|
|
#include <kernel/tty.h>
|
|
#include <debugging.h>
|
|
#include "interrupt.h"
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include "../io.h"
|
|
|
|
#define IRQ0 0x20
|
|
#define IRQ1 (IRQ0 + 1)
|
|
#define IRQ2 (IRQ0 + 2)
|
|
#define IRQ3 (IRQ0 + 3)
|
|
#define IRQ4 (IRQ0 + 4)
|
|
#define IRQ5 (IRQ0 + 5)
|
|
#define IRQ6 (IRQ0 + 6)
|
|
#define IRQ7 (IRQ0 + 7)
|
|
|
|
#define IRQ8 0x28
|
|
#define IRQ9 (IRQ8 + 1)
|
|
#define IRQ10 (IRQ8 + 2)
|
|
#define IRQ11 (IRQ8 + 3)
|
|
#define IRQ12 (IRQ8 + 4)
|
|
#define IRQ13 (IRQ8 + 5)
|
|
#define IRQ14 (IRQ8 + 6)
|
|
#define IRQ15 (IRQ8 + 7)
|
|
|
|
#define NUM_ENTRIES 0x100
|
|
|
|
struct InterruptDescriptor {
|
|
uint32_t offset;
|
|
uint32_t selector;
|
|
uint8_t gate_type;
|
|
uint8_t ring;
|
|
bool present;
|
|
};
|
|
|
|
struct IDT {
|
|
uint16_t size;
|
|
uint64_t* base;
|
|
} __attribute__((packed));
|
|
|
|
static uint64_t entries[NUM_ENTRIES];
|
|
struct IDT idt;
|
|
|
|
enum EntryTypes {
|
|
DivisionByZero = 0x00,
|
|
_Reserved0 = 0x01,
|
|
NMIInterrupt = 0x02,
|
|
Breakpoint = 0x03,
|
|
Overflow = 0x04,
|
|
BoundsExceeded = 0x05,
|
|
InvalidOpcode = 0x06,
|
|
DeviceNotAvail = 0x07,
|
|
DoubleFault = 0x08,
|
|
CoprocSegORun = 0x09,
|
|
InvalidTSS = 0x0A,
|
|
SegNotPresent = 0x0B,
|
|
StackSegFault = 0x0C,
|
|
GenerProtFault = 0x0D,
|
|
PageFault = 0x0E,
|
|
_Reserved1 = 0x0F,
|
|
x87FPUError = 0x10,
|
|
AlignmentCheck = 0x11,
|
|
MachineCheck = 0x12,
|
|
SIMDFloatExcep = 0x13,
|
|
};
|
|
|
|
static void encodeIdtEntry(uint8_t *target, struct InterruptDescriptor source)
|
|
{
|
|
// Encode the present bit
|
|
if (source.present) {
|
|
target[5] |= 0x80;
|
|
} else {
|
|
// Not present, return
|
|
return;
|
|
}
|
|
|
|
// Encode the offset
|
|
target[0] = (source.offset >> 0x00) & 0xFF;
|
|
target[1] = (source.offset >> 0x08) & 0xFF;
|
|
target[6] = (source.offset >> 0x10) & 0xFF;
|
|
target[7] = (source.offset >> 0x18) & 0xFF;
|
|
|
|
// Encode the base
|
|
target[2] = (source.selector >> 0x00) & 0xFF;
|
|
target[3] = (source.selector >> 0x08) & 0xFF;
|
|
|
|
// Encode the gate type
|
|
target[5] |= source.gate_type;
|
|
|
|
// Encode the DPL
|
|
target[5] |= (source.ring << 5);
|
|
}
|
|
|
|
static void add_entry(struct InterruptDescriptor entry, uint8_t index)
|
|
{
|
|
uint64_t descriptor = 0;
|
|
encodeIdtEntry((uint8_t*) &descriptor, entry);
|
|
|
|
entries[index] = descriptor;
|
|
}
|
|
|
|
static void load_idt()
|
|
{
|
|
idt.size = NUM_ENTRIES * 8 - 1;
|
|
idt.base = entries;
|
|
|
|
asm ( "lidt %0" : : "m"(idt) );
|
|
}
|
|
|
|
static struct InterruptDescriptor generate_entry(bool present, void isr(struct interrupt_frame*), uint8_t gate_type, uint8_t ring, uint8_t selector)
|
|
{
|
|
struct InterruptDescriptor entry;
|
|
entry.present = present;
|
|
entry.offset = (size_t)isr;
|
|
entry.gate_type = gate_type;
|
|
entry.ring = ring;
|
|
entry.selector = selector;
|
|
return entry;
|
|
}
|
|
|
|
static void add_exceptions()
|
|
{
|
|
struct InterruptDescriptor entry;
|
|
|
|
entry = generate_entry(true, exception, 0xF, 0, 0x8);
|
|
for (int i = 0; i < 0x20; i++)
|
|
{
|
|
add_entry(entry, i);
|
|
}
|
|
|
|
entry = generate_entry(true, divide_by_zero, 0xF, 0, 0x8);
|
|
add_entry(entry, DivisionByZero);
|
|
|
|
entry = generate_entry(true, general_protection_fault, 0xF, 0, 0x8);
|
|
add_entry(entry, GenerProtFault);
|
|
|
|
entry = generate_entry(true, double_fault, 0xF, 0, 0x8);
|
|
add_entry(entry, DoubleFault);
|
|
|
|
}
|
|
|
|
static void add_irqs()
|
|
{
|
|
struct InterruptDescriptor entry;
|
|
entry = generate_entry(true, irq_1, 0xE, 0, 0x8);
|
|
for (int i = IRQ0; i <= IRQ7; i++)
|
|
{
|
|
add_entry(entry, i);
|
|
}
|
|
|
|
entry = generate_entry(true, irq_2, 0xE, 0, 0x8);
|
|
for (int i = IRQ8; i <= IRQ15; i++)
|
|
{
|
|
add_entry(entry, i);
|
|
}
|
|
|
|
entry = generate_entry(true, irq0, 0xE, 0, 0x8);
|
|
add_entry(entry, IRQ0);
|
|
|
|
entry = generate_entry(true, keyboard_interrupt, 0xE, 0, 0x8);
|
|
add_entry(entry, IRQ1);
|
|
}
|
|
|
|
static void add_syscall()
|
|
{
|
|
struct InterruptDescriptor syscall_entry;
|
|
syscall_entry.present = true;
|
|
syscall_entry.offset = (size_t)syscall;
|
|
syscall_entry.gate_type = 0xE;
|
|
syscall_entry.ring = 3;
|
|
syscall_entry.selector = 0x8;
|
|
|
|
add_entry(syscall_entry, 0x80);
|
|
}
|
|
|
|
void idt_init()
|
|
{
|
|
add_exceptions();
|
|
add_irqs();
|
|
add_syscall();
|
|
|
|
load_idt();
|
|
}
|