#include "hwcomm/interrupts.hpp" #include <new> #include "hwcomm/Port.hpp" #include "GDT.hpp" #include "print.hpp" using namespace hwcomm; namespace { union GateDescriptor { std::uint64_t forceAlignment; std::uint8_t data[8]; }; }; extern "C" { extern const int irqBase; void InterruptIgnore(); void HandleException0x00(); void HandleException0x01(); void HandleException0x02(); void HandleException0x03(); void HandleException0x04(); void HandleException0x05(); void HandleException0x06(); void HandleException0x07(); void HandleException0x08(); void HandleException0x09(); void HandleException0x0A(); void HandleException0x0B(); void HandleException0x0C(); void HandleException0x0D(); void HandleException0x0E(); void HandleException0x0F(); void HandleException0x10(); void HandleException0x11(); void HandleException0x12(); void HandleException0x13(); void HandleException0x80(); void HandleIRQ0x00(); void HandleIRQ0x01(); void HandleIRQ0x02(); void HandleIRQ0x03(); void HandleIRQ0x04(); void HandleIRQ0x05(); void HandleIRQ0x06(); void HandleIRQ0x07(); void HandleIRQ0x08(); void HandleIRQ0x09(); void HandleIRQ0x0A(); void HandleIRQ0x0B(); void HandleIRQ0x0C(); void HandleIRQ0x0D(); void HandleIRQ0x0E(); void HandleIRQ0x0F(); } static void initIDT(GlobalDescriptorTable &gdt); static void setIDTEntry(std::uint8_t interrupt, std::uint16_t cs, void (*handler)(), std::uint8_t ring, std::uint8_t type); static void initPICs(); static void loadIDT(); static GateDescriptor IDT[256]; static InterruptHandler *handlers[256]; static Port8 picMasterCmd(0x20), picMasterData(0x21); static Port8 picSlaveCmd(0xa0), picSlaveData(0xa1); InterruptManager::InterruptManager(GlobalDescriptorTable &gdt) { initIDT(gdt); initPICs(); loadIDT(); } static void initIDT(GlobalDescriptorTable &gdt) { std::uint16_t cs = gdt.getCS(); const std::uint8_t IdtInterruptGate = 0xE; for (int i = 0; i < 256; ++i) { setIDTEntry(i, cs, &InterruptIgnore, 0, IdtInterruptGate); } setIDTEntry(0x00, cs, &HandleException0x00, 0, IdtInterruptGate); setIDTEntry(0x01, cs, &HandleException0x01, 0, IdtInterruptGate); setIDTEntry(0x02, cs, &HandleException0x02, 0, IdtInterruptGate); setIDTEntry(0x03, cs, &HandleException0x03, 0, IdtInterruptGate); setIDTEntry(0x04, cs, &HandleException0x04, 0, IdtInterruptGate); setIDTEntry(0x05, cs, &HandleException0x05, 0, IdtInterruptGate); setIDTEntry(0x06, cs, &HandleException0x06, 0, IdtInterruptGate); setIDTEntry(0x07, cs, &HandleException0x07, 0, IdtInterruptGate); setIDTEntry(0x08, cs, &HandleException0x08, 0, IdtInterruptGate); setIDTEntry(0x09, cs, &HandleException0x09, 0, IdtInterruptGate); setIDTEntry(0x0A, cs, &HandleException0x0A, 0, IdtInterruptGate); setIDTEntry(0x0B, cs, &HandleException0x0B, 0, IdtInterruptGate); setIDTEntry(0x0C, cs, &HandleException0x0C, 0, IdtInterruptGate); setIDTEntry(0x0D, cs, &HandleException0x0D, 0, IdtInterruptGate); setIDTEntry(0x0E, cs, &HandleException0x0E, 0, IdtInterruptGate); setIDTEntry(0x0F, cs, &HandleException0x0F, 0, IdtInterruptGate); setIDTEntry(0x10, cs, &HandleException0x10, 0, IdtInterruptGate); setIDTEntry(0x11, cs, &HandleException0x11, 0, IdtInterruptGate); setIDTEntry(0x12, cs, &HandleException0x12, 0, IdtInterruptGate); setIDTEntry(0x13, cs, &HandleException0x13, 0, IdtInterruptGate); setIDTEntry(0x80, cs, &HandleException0x80, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x00, cs, &HandleIRQ0x00, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x01, cs, &HandleIRQ0x01, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x02, cs, &HandleIRQ0x02, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x03, cs, &HandleIRQ0x03, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x04, cs, &HandleIRQ0x04, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x05, cs, &HandleIRQ0x05, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x06, cs, &HandleIRQ0x06, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x07, cs, &HandleIRQ0x07, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x08, cs, &HandleIRQ0x08, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x09, cs, &HandleIRQ0x09, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x0A, cs, &HandleIRQ0x0A, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x0B, cs, &HandleIRQ0x0B, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x0C, cs, &HandleIRQ0x0C, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x0D, cs, &HandleIRQ0x0D, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x0E, cs, &HandleIRQ0x0E, 0, IdtInterruptGate); setIDTEntry(irqBase + 0x0F, cs, &HandleIRQ0x0F, 0, IdtInterruptGate); } static void setIDTEntry(std::uint8_t interrupt, std::uint16_t cs, void (*handler)(), std::uint8_t ring, std::uint8_t type) { const std::uint8_t IdtDescPresent = 0x80; auto ptr = reinterpret_cast<std::uint32_t>(handler); IDT[interrupt].data[0] = ptr & 0xff; IDT[interrupt].data[1] = (ptr >> 8) & 0xff; IDT[interrupt].data[2] = cs & 0xff; IDT[interrupt].data[3] = (cs >> 8) & 0xff; IDT[interrupt].data[4] = 0; IDT[interrupt].data[5] = IdtDescPresent | ((ring & 3) << 5) | type; IDT[interrupt].data[6] = (ptr >> 16) & 0xff; IDT[interrupt].data[7] = (ptr >> 24) & 0xff; } static void initPICs() { picMasterCmd.write(0x11); picSlaveCmd.write(0x11); // remap picMasterData.write(irqBase); picSlaveData.write(irqBase + 8); picMasterData.write(0x04); picSlaveData.write(0x02); picMasterData.write(0x01); picSlaveData.write(0x01); picMasterData.write(0x00); picSlaveData.write(0x00); } static void loadIDT() { std::uint8_t idtr[6]; new(&idtr[0]) std::uint16_t(sizeof(IDT)); new(&idtr[2]) std::uint32_t(reinterpret_cast<std::uint32_t>(&IDT)); asm volatile("lidt %0" : : "m"(idtr)); } InterruptManager::~InterruptManager() { deactivate(); } std::uint16_t InterruptManager::getIRQBase() const { return irqBase; } void InterruptManager::activate() { asm("sti"); } void InterruptManager::deactivate() { asm("cli"); } extern "C" std::uint32_t handleInterrupt(std::uint8_t interrupt, std::uint32_t esp) { if (handlers[interrupt] != nullptr) { esp = handlers[interrupt]->handleInterrupt(esp); } else if (interrupt != irqBase) { kprint("UNHANDLED INTERRUPT 0x", interrupt, "\n"); } // Hardware interrupts must be acknowledged. if (irqBase <= interrupt && interrupt < irqBase + 16) { picMasterCmd.write(0x20); if (irqBase + 8 <= interrupt) { picSlaveCmd.write(0x20); } } return esp; } InterruptHandler::InterruptHandler(std::uint8_t interruptNumber) : interruptNumber(interruptNumber) { handlers[interruptNumber] = this; } InterruptHandler::~InterruptHandler() { if (handlers[interruptNumber] == this) { handlers[interruptNumber] = nullptr; } }