154 lines
4.4 KiB
C
154 lines
4.4 KiB
C
|
#include "Tier0/interrupts.h"
|
||
|
#include "Tier0/paging.h"
|
||
|
#include "Tier0/kstdio.h"
|
||
|
#include "Tier0/pic.h"
|
||
|
|
||
|
T_IDT_PTR g_idt_ptr;
|
||
|
T_IDT_ENTRY g_idt_entries[256];
|
||
|
T_ISR_STUB g_isr_stubs[256];
|
||
|
|
||
|
T_INTERRUPTS_CHIP g_interrupts_chip = E_INTERRUPTS_CHIP_UNK;
|
||
|
|
||
|
void interrupts_set_chip(T_INTERRUPTS_CHIP Chip)
|
||
|
{
|
||
|
g_interrupts_chip = Chip;
|
||
|
|
||
|
if (Chip == E_INTERRUPTS_CHIP_UNK)
|
||
|
kprintf("[i] Interrupts: Turning off.\n");
|
||
|
else if (Chip == E_INTERRUPTS_CHIP_PIC)
|
||
|
kprintf("[i] Interrupts: Switching to 8259 based interrupts.\n");
|
||
|
else if (Chip == E_INTERRUPTS_CHIP_APIC)
|
||
|
kprintf("[i] Interrupts: Switching to intel I/O APIC based "
|
||
|
"interrupts.\n");
|
||
|
}
|
||
|
|
||
|
u8 interrupts_init_idt(void)
|
||
|
{
|
||
|
g_idt_ptr.Limit = 256 * 8;
|
||
|
|
||
|
u32 Physical = 0;
|
||
|
u8 Result = paging_get_physical((u32)g_idt_entries, &Physical);
|
||
|
if (!Result)
|
||
|
return 0;
|
||
|
|
||
|
kprintf("[i] Setting up IDT at 0x%x (0x%x Virtual).\n", Physical, g_idt_entries);
|
||
|
|
||
|
g_idt_ptr.Base = Physical;
|
||
|
|
||
|
// Null those entries!
|
||
|
for (u16 i = 0; i < 256; i++)
|
||
|
{
|
||
|
// Maybe I should access the struct's members...
|
||
|
// Or i can just cast that to to u32's and null them.
|
||
|
// This will set the Present flag to 0 either way
|
||
|
*((u32 *)(&g_idt_entries[i])) = 0;
|
||
|
*(((u32 *)(&g_idt_entries[i]) + 1)) = 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// This creates an ASM stub for
|
||
|
|
||
|
// This creates a 12-byte ASM stub for a handler
|
||
|
void interrupts_create_stub(T_ISR_STUB *Destination, u32 Address)
|
||
|
{
|
||
|
// The ASM code is as follows:
|
||
|
// cli
|
||
|
// pushad
|
||
|
// mov eax, Handler
|
||
|
// call eax
|
||
|
// popad
|
||
|
// sti
|
||
|
// iret
|
||
|
Destination->Code1 = 0x60FA; // pushad, cli
|
||
|
Destination->Code2 = 0xB8; // mov eax,
|
||
|
Destination->Handler = Address; // Address
|
||
|
Destination->Code3 = 0xFB61D0FF; // sti, popad, call eax
|
||
|
Destination->Code4 = 0xCF; // iret
|
||
|
}
|
||
|
|
||
|
void interrupts_setup_irq(u8 IRQ, void *Handler)
|
||
|
{
|
||
|
if (g_interrupts_chip != E_INTERRUPTS_CHIP_PIC)
|
||
|
{
|
||
|
kprintf("[e] Sorry, but I only do PIC-based interrupts for now :(.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
u8 Interrupt = IRQ + PIC_IRQ_START;
|
||
|
kprintf("[i] New handler for IRQ %i (Interrupt %i).\n", IRQ, Interrupt);
|
||
|
interrupts_setup_isr(Interrupt, Handler, E_INTERRUPTS_RING0);
|
||
|
|
||
|
// We also need to set the IRQ mask
|
||
|
pic_unmask_irq(IRQ);
|
||
|
}
|
||
|
|
||
|
void interrupts_dump_idt_ptr(void)
|
||
|
{
|
||
|
kprintf("[i] IDT Pointer structure:\n");
|
||
|
kprintf(" Base: 0x%x.\n", g_idt_ptr.Base);
|
||
|
kprintf(" Limit: 0x%x.\n", g_idt_ptr.Limit);
|
||
|
}
|
||
|
|
||
|
void interrupts_dump_idt_entry(u8 Interrupt)
|
||
|
{
|
||
|
u32 *dwEntry = (u32 *)&g_idt_entries[Interrupt];
|
||
|
kprintf("[i] IDT Entry for interrupt %x:\n", Interrupt);
|
||
|
kprintf(" DW Low : 0x%x.\n", *dwEntry);
|
||
|
kprintf(" DW High: 0x%x.\n", *(dwEntry + 1));
|
||
|
|
||
|
T_IDT_ENTRY Entry = g_idt_entries[Interrupt];
|
||
|
kprintf(" Offset: 0x%x.\n", (Entry.OffsetHigh << 16) + Entry.OffsetLow);
|
||
|
kprintf(" Selector: %u.\n", Entry.Selector);
|
||
|
kprintf(" Zero: %u.\n", Entry.Zero);
|
||
|
kprintf(" P: %u.\n", (Entry.Type >> 7) & 0b1);
|
||
|
kprintf(" DPL: %u.\n", (Entry.Type >> 5) & 0b11);
|
||
|
kprintf(" S: %u.\n", (Entry.Type >> 4) & 0b1);
|
||
|
kprintf(" Gate type: %u.\n", Entry.Type & 0b1111);
|
||
|
}
|
||
|
|
||
|
void interrupts_setup_isr_raw(u8 Interrupt, void *ASMHandler, \
|
||
|
T_INTERRUPTS_RING Ring)
|
||
|
{
|
||
|
u32 uASMHandler = (u32)ASMHandler;
|
||
|
g_idt_entries[Interrupt].OffsetLow = uASMHandler & 0xFFFF;
|
||
|
g_idt_entries[Interrupt].OffsetHigh = (uASMHandler >> 16) & 0xFFFF;
|
||
|
g_idt_entries[Interrupt].Selector = 0x08;
|
||
|
g_idt_entries[Interrupt].Zero = 0;
|
||
|
|
||
|
u8 Type = 0;
|
||
|
Type |= (1 << 7);
|
||
|
Type |= (Ring << 5);
|
||
|
Type |= (0 << 4);
|
||
|
Type |= 0xE;
|
||
|
g_idt_entries[Interrupt].Type = Type;
|
||
|
}
|
||
|
|
||
|
void interrupts_setup_isr(u8 Interrupt, void *Handler, \
|
||
|
T_INTERRUPTS_RING Ring)
|
||
|
{
|
||
|
interrupts_create_stub(&g_isr_stubs[Interrupt], (u32)Handler);
|
||
|
|
||
|
u32 ASMHandler = (u32)&g_isr_stubs[Interrupt];
|
||
|
interrupts_setup_isr_raw(Interrupt, (void*)ASMHandler, Ring);
|
||
|
}
|
||
|
|
||
|
void interrupts_delete_isr(u8 Interrupt)
|
||
|
{
|
||
|
*((u32*)&g_idt_entries[Interrupt]) = 0;
|
||
|
}
|
||
|
|
||
|
void interrupts_init_simple(void)
|
||
|
{
|
||
|
interrupts_set_chip(E_INTERRUPTS_CHIP_PIC);
|
||
|
interrupts_init_idt();
|
||
|
interrupts_lidt();
|
||
|
}
|
||
|
|
||
|
void interrupts_irq_finish(u8 IRQ)
|
||
|
{
|
||
|
if (g_interrupts_chip == E_INTERRUPTS_CHIP_PIC)
|
||
|
pic_eoi(IRQ);
|
||
|
}
|