2011-02-22 17:09:58 +00:00
|
|
|
#include "Tier0/interrupts.h"
|
|
|
|
#include "Tier0/paging.h"
|
|
|
|
#include "Tier0/kstdio.h"
|
|
|
|
#include "Tier0/pic.h"
|
|
|
|
|
2012-04-21 16:55:29 +00:00
|
|
|
struct {
|
|
|
|
// IDT
|
|
|
|
T_IDT_PTR IDTPointer;
|
|
|
|
T_IDT_ENTRY IDTEntries[256];
|
|
|
|
T_ISR_STUB ISRStubs[256];
|
2011-02-22 17:09:58 +00:00
|
|
|
|
2012-04-21 16:55:29 +00:00
|
|
|
// IRQ/APIC/Whatever
|
|
|
|
T_INTERRUPTS_CHIP Chip = E_INTERRUPTS_CHIP_UNK;
|
|
|
|
} g_Interrupts;
|
2011-02-22 17:09:58 +00:00
|
|
|
|
2012-04-21 16:55:29 +00:00
|
|
|
// This shit does nothing
|
2011-02-22 17:09:58 +00:00
|
|
|
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");
|
|
|
|
}
|
2012-04-21 18:06:00 +00:00
|
|
|
|
2011-02-22 17:09:58 +00:00
|
|
|
u8 interrupts_init_idt(void)
|
|
|
|
{
|
2012-04-21 18:06:00 +00:00
|
|
|
g_Interrups.IDTPointer.Limit = 256 * 16;
|
2011-02-22 17:09:58 +00:00
|
|
|
|
2012-04-21 18:06:00 +00:00
|
|
|
u64 Physical = 0;
|
|
|
|
u8 Result = paging_get_physical((u64)g_Interrupts.IDTEntries, &Physical);
|
2011-04-03 16:49:04 +00:00
|
|
|
if (!Result)
|
|
|
|
return 0;
|
2011-02-22 17:09:58 +00:00
|
|
|
|
2012-04-21 18:06:00 +00:00
|
|
|
kprintf("[i] Setting up IDT at 0x%x (0x%x Virtual).\n", Physical, g_Interrupts.IDTEntries);
|
2011-02-22 17:09:58 +00:00
|
|
|
|
2012-04-21 18:06:00 +00:00
|
|
|
g_Interrupts.IDTPointer.Base = Physical;
|
2011-02-22 17:09:58 +00:00
|
|
|
|
|
|
|
// Null those entries!
|
|
|
|
for (u16 i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
// Maybe I should access the struct's members...
|
2012-04-21 18:06:00 +00:00
|
|
|
// Or i can just cast that to to u64's and null them.
|
2011-02-22 17:09:58 +00:00
|
|
|
// This will set the Present flag to 0 either way
|
2012-04-21 18:06:00 +00:00
|
|
|
*((u64 *)(&g_idt_entries[i])) = 0;
|
|
|
|
*(((u64 *)(&g_idt_entries[i]) + 1)) = 0;
|
|
|
|
*(((u64 *)(&g_idt_entries[i]) + 2)) = 0;
|
|
|
|
*(((u64 *)(&g_idt_entries[i]) + 3)) = 0;
|
2011-02-22 17:09:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2012-04-21 18:06:00 +00:00
|
|
|
/*
|
2011-04-02 14:46:31 +00:00
|
|
|
// This creates an ASM stub for
|
|
|
|
|
2011-02-22 17:09:58 +00:00
|
|
|
// 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
|
2011-04-03 16:49:04 +00:00
|
|
|
Destination->Code1 = 0x60FA; // pushad, cli
|
2011-02-22 17:09:58 +00:00
|
|
|
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;
|
2011-02-23 03:12:36 +00:00
|
|
|
kprintf("[i] New handler for IRQ %i (Interrupt %i).\n", IRQ, Interrupt);
|
2011-02-22 17:09:58 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-03-13 14:18:08 +00:00
|
|
|
void interrupts_setup_isr_raw(u8 Interrupt, void *ASMHandler, \
|
|
|
|
T_INTERRUPTS_RING Ring)
|
2011-02-22 17:09:58 +00:00
|
|
|
{
|
2011-03-13 14:18:08 +00:00
|
|
|
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;
|
2011-02-22 17:09:58 +00:00
|
|
|
g_idt_entries[Interrupt].Zero = 0;
|
2011-03-13 14:18:08 +00:00
|
|
|
|
2011-02-22 17:09:58 +00:00
|
|
|
u8 Type = 0;
|
2011-03-13 14:18:08 +00:00
|
|
|
Type |= (1 << 7);
|
|
|
|
Type |= (Ring << 5);
|
|
|
|
Type |= (0 << 4);
|
|
|
|
Type |= 0xE;
|
2011-02-22 17:09:58 +00:00
|
|
|
g_idt_entries[Interrupt].Type = Type;
|
|
|
|
}
|
|
|
|
|
2011-03-13 14:18:08 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-04-02 14:46:31 +00:00
|
|
|
void interrupts_delete_isr(u8 Interrupt)
|
|
|
|
{
|
|
|
|
*((u32*)&g_idt_entries[Interrupt]) = 0;
|
|
|
|
}
|
|
|
|
|
2011-02-22 17:09:58 +00:00
|
|
|
void interrupts_init_simple(void)
|
|
|
|
{
|
|
|
|
interrupts_set_chip(E_INTERRUPTS_CHIP_PIC);
|
|
|
|
interrupts_init_idt();
|
|
|
|
interrupts_lidt();
|
|
|
|
}
|
|
|
|
|
2011-02-23 03:12:36 +00:00
|
|
|
void interrupts_irq_finish(u8 IRQ)
|
2011-02-22 17:09:58 +00:00
|
|
|
{
|
|
|
|
if (g_interrupts_chip == E_INTERRUPTS_CHIP_PIC)
|
|
|
|
pic_eoi(IRQ);
|
|
|
|
}
|
2011-08-27 23:16:17 +00:00
|
|
|
*/
|