101 lines
3.2 KiB
C
101 lines
3.2 KiB
C
#define __IDT__
|
|
|
|
#include "idt.h"
|
|
#include <types.h>
|
|
#include "serial.h"
|
|
#include "pic_controler.h"
|
|
#include "debug.h"
|
|
#include "int.h"
|
|
|
|
/*
|
|
Make space for the interrupt descriptor table
|
|
Tell the CPU where that space is (see GDT Tutorial: lidt works the very same way as lgdt)
|
|
Tell the PIC that you no longer want to use the BIOS defaults (see Programming the PIC chips)
|
|
Write a couple of ISR handlers (see Interrupt Service Routines) for both IRQs and exceptions
|
|
Put the addresses of the ISR handlers in the appropriate descriptors (in Interrupt Descriptor Table)
|
|
Enable all supported interrupts in the IRQ mask (of the PIC)
|
|
*/
|
|
|
|
struct interrupt_gate_param {
|
|
u32 Offset;
|
|
u16 SegSelect;
|
|
u8 Type;
|
|
u8 D;
|
|
u8 DPL;
|
|
u8 P;
|
|
};
|
|
|
|
struct idt_segdesc init_gate(struct interrupt_gate_param param)
|
|
{
|
|
if (param.Type == 5)
|
|
{
|
|
param.Offset = 0;
|
|
param.D = 0;
|
|
param.Offset = 0;
|
|
}
|
|
|
|
struct idt_segdesc descriptor;
|
|
|
|
descriptor.Offset = param.Offset;
|
|
descriptor.Offset2 = param.Offset >> 16;
|
|
|
|
descriptor.SegSelect = param.SegSelect;
|
|
|
|
descriptor.empty = 0;
|
|
descriptor.bits = 0;
|
|
|
|
descriptor.Type = param.Type | (param.D << 3);
|
|
|
|
descriptor.Flags |= param.DPL << 1;
|
|
descriptor.Flags |= param.P << 3;
|
|
|
|
return descriptor;
|
|
}
|
|
|
|
void init_idt(void)
|
|
{
|
|
DEBUG_INFO("Initializing IDT");
|
|
|
|
DEBUG_INFO("IDT BASE ADDRESS: %d", (u32) &kidtr);
|
|
DEBUG_INFO("IDT LIMIT: %d", sizeof(idt) - 1);
|
|
kidtr.limit = sizeof(idt) - 1;
|
|
kidtr.base = (u32) idt;
|
|
|
|
for (int i = 0; i < sizeof(idt); i++)
|
|
{
|
|
idt[i] = init_gate((struct interrupt_gate_param) { .Offset = (u32) _asm_default_int, .SegSelect = 0x08,
|
|
.Type = 0x06, .D = 1, .DPL = 0, .P = 1 });
|
|
}
|
|
|
|
idt[32] = init_gate((struct interrupt_gate_param) { .Offset = (u32) _asm_irq_0, .SegSelect = 0x08,
|
|
.Type = 0x06, .D = 1, .DPL = 0, .P = 1 });
|
|
|
|
idt[33] = init_gate((struct interrupt_gate_param) { .Offset = (u32) _asm_irq_1, .SegSelect = 0x08,
|
|
.Type = 0x06, .D = 1, .DPL = 0, .P = 1 });
|
|
|
|
idt[48] = init_gate((struct interrupt_gate_param) { .Offset = (u32) _asm_sycall_handler, .SegSelect = 0x08,
|
|
.Type = 0x07, .D = 1, .DPL = 3, .P = 1 });
|
|
|
|
#ifdef DEBUG_IDT
|
|
for (int i = 0; i < 49; i++)
|
|
{
|
|
char *ptr = (char *) &idt[i];
|
|
DEBUG_INFO("--------------------");
|
|
DEBUG_INFO("IDT[%d]:", i);
|
|
DEBUG_INFO("\tOffset : %d", (u32) ptr[0] | (ptr[6] << 16));
|
|
DEBUG_INFO("\tSegment Selector : %d | %b | %b |Index|GDT 0 / LDT 1|Level ring 0 / ring 1|", (u16) ptr[2] >> 3, ptr[2] >> 2, ptr[2]);
|
|
DEBUG_INFO("\tZeroes : %d", (u8) ptr[4]);
|
|
DEBUG_INFO("\tFlag : %b |16 bits 0 / 32 bits 1|Task 101 / Interrupt 110 / Trap 111|", (u8) ptr[5] & 0x0F);
|
|
DEBUG_INFO("\tFlag : %b |Present|Level ring 0 / ring 1|Zero|", (u8) ptr[5] >> 4);
|
|
}
|
|
DEBUG_INFO("--------------------");
|
|
#endif
|
|
|
|
asm volatile ("lidtl (kidtr)");
|
|
|
|
DEBUG_INFO("IDT LOADED");
|
|
|
|
DEBUG_INFO("ENABLING STI");
|
|
asm volatile ("sti");
|
|
}
|