bits 32 section .text extern intr_handler PIC1_CMD_PORT equ 0x20 PIC1_DATA_PORT equ 0x21 PIC2_CMD_PORT equ 0xa0 PIC2_DATA_PORT equ 0xa1 ICW1_ICW4_NEEDED equ 0x01 ICW1_INIT equ 0x10 ICW4_8086 equ 0x01 OCW2_EOI equ 0x20 OCW3_ISR equ 0x0b global set_idt set_idt: mov eax, [esp + 4] mov [idtbase], eax mov ax, [esp + 8] mov [idtlim], ax lidt [idtlim] ret align 4 dw 0 idtlim dw 0 idtbase dd 0 global prog_pic prog_pic: ; send ICW1 saying we'll follow with ICW4 later mov al, ICW1_INIT | ICW1_ICW4_NEEDED out PIC1_CMD_PORT, al ; send ICW2 with IRQ remapping mov al, [esp + 4] out PIC1_DATA_PORT, al add al, 8 out PIC2_DATA_PORT, al ; send ICW3 to setup the master/slave relationship ; ... set bit3 = 3rd interrupt input has a slave mov al, 4 out PIC1_DATA_PORT, al ; ... set slave id to 2 mov al, 2 OUT PIC2_DATA_PORT, al ; send ICW4 to set 8086 mode (no calls generated) mov al, ICW4_8086 out PIC1_DATA_PORT, al out PIC2_DATA_PORT, al ; done, reset the data port to 0 xor al, al out PIC1_DATA_PORT, al out PIC2_DATA_PORT, al ret global end_of_irq end_of_irq: mov eax, [esp + 4] cmp eax, 8 jb .eoi_master ; cascaded IRQ, send EOI to slave PIC first mov al, OCW2_EOI out PIC2_CMD_PORT, al .eoi_master: ; send EOI to master PIC mov al, OCW2_EOI out PIC1_CMD_PORT, al ret ; special entry point for IRQ7 to catch and disregard spurious interrupts global intr_entry_irq7_verify intr_entry_irq7_verify: push eax mov al, OCW3_ISR out PIC1_CMD_PORT, al in al, PIC1_CMD_PORT and al, 0x80 pop eax jnz intr_entry_irq7 iret global intr_entry_irq15_verify intr_entry_irq15_verify: ; similarly for IRQ15 push eax mov al, OCW3_ISR out PIC2_CMD_PORT, al in al, PIC2_CMD_PORT and al, 0x80 jnz .valid ; it was spurious, send EOI to master PIC and iret mov al, OCW2_EOI out PIC1_CMD_PORT, al pop eax iret .valid: pop eax jmp intr_entry_irq15 %macro intr_entry_err 2 global intr_entry_%2 intr_entry_%2: push dword %1 ; push interrupt number jmp intr_entry_common %endmacro %macro intr_entry_noerr 2 global intr_entry_%2 intr_entry_%2: push dword 0 ; push dummy error code push dword %1 ; push interrupt number jmp intr_entry_common %endmacro intr_entry_common: pusha ; save general purpose registers call intr_handler popa ; restore general purpose registers add esp, 8 ; remove error code and intr number from the stack iret ; interrupt entry points intr_entry_noerr 0, div intr_entry_noerr 1, debug intr_entry_noerr 2, nmi intr_entry_noerr 3, bpt intr_entry_noerr 4, ovf intr_entry_noerr 5, bound intr_entry_noerr 6, ill intr_entry_noerr 7, nodev intr_entry_err 8, dbl intr_entry_noerr 9, copseg intr_entry_err 10, tss intr_entry_err 11, segpres intr_entry_err 12, stack intr_entry_err 13, prot intr_entry_err 14, page intr_entry_noerr 16, fpu intr_entry_err 17, align intr_entry_noerr 18, mce intr_entry_noerr 19, sse ; remapped IRQs 0-15 -> 32-47 intr_entry_noerr 32, irq0 intr_entry_noerr 33, irq1 intr_entry_noerr 34, irq2 intr_entry_noerr 35, irq3 intr_entry_noerr 36, irq4 intr_entry_noerr 37, irq5 intr_entry_noerr 38, irq6 intr_entry_noerr 39, irq7 intr_entry_noerr 40, irq8 intr_entry_noerr 41, irq9 intr_entry_noerr 42, irq10 intr_entry_noerr 43, irq11 intr_entry_noerr 44, irq12 intr_entry_noerr 45, irq13 intr_entry_noerr 46, irq14 intr_entry_noerr 47, irq15 ; default handler intr_entry_noerr 255, default ; vi:ft=nasm: