namespace x86 {
    inline void outb(uint8_t data, uint16_t port) {
        asm volatile("outb %%al, %%dx"
                     : : "a"(data), "d"(port) : "memory");
    }
}

namespace {
    const int16_t PIC1_CMD = 0x20;
    const int16_t PIC1_DATA = 0x21;
    const int16_t PIC2_CMD = 0xa0;
    const int16_t PIC2_DATA = 0xa1;
}

void apic::end_of_interrupt(int irq) {
    enum {
        PIC_EOI = 0x20,
    };
    if (irq >= 8) {
        x86::outb(PIC_EOI, PIC2_CMD);
    }
    x86::outb(PIC_EOI, PIC1_CMD);
}

static void handle_irq(int irq) {
    apic::end_of_interrupt(irq);
}

extern "C" void handle_interrupt(int64_t intno, int64_t /*error_code*/) {
    if (32 <= intno && intno < 48) {
        // IRQ
        const int irq = intno - 32;
        handle_irq(irq);
    }
}
