diff --git a/driver/irq/pic/int_handler.asm.S b/driver/irq/pic/int_handler.asm.S index c434431..d42215e 100644 --- a/driver/irq/pic/int_handler.asm.S +++ b/driver/irq/pic/int_handler.asm.S @@ -1,6 +1,9 @@ format elf64 +include 'pic_constants.incS' + extrn irq_pic_IntHandler +extrn irq_pic_IRQHandlerRaw public irq_pic_IntHandler20h public irq_pic_IntHandler21h @@ -23,9 +26,25 @@ public irq_pic_IntHandler2fh section '.text' executable macro inth op1 { + push rax + + mov rax, [irq_pic_IRQHandlerRaw+op1*8] + test rax, rax + jz .noraw + + ; has raw handler + mov al, PIC_CMD_EOI + if op1 >= 8 + out PIC2_COMMAND, al + end if + out PIC1_COMMAND, al + + pop rax + jmp qword [irq_pic_IRQHandlerRaw+op1*8] + +.noraw: push rdi mov rdi, op1 - push rax push rsi push rdx push rcx @@ -41,8 +60,8 @@ macro inth op1 { pop rcx pop rdx pop rsi - pop rax pop rdi + pop rax iretq } diff --git a/driver/irq/pic/pic.h b/driver/irq/pic/pic.h index 20159ce..ddddbd4 100644 --- a/driver/irq/pic/pic.h +++ b/driver/irq/pic/pic.h @@ -36,6 +36,11 @@ typedef SYSV_ABI void (*irq_pic_IRQHandlerType)(); extern irq_pic_IRQHandlerType irq_pic_IRQHandler[16]; extern bool irq_pic_Enabled; +// If IRQHandlerRaw[irq] is not NULL, the function is jumped to (not called). +// +// So the handler should use IRET instead of RET, and save all the registers it uses. +extern void *irq_pic_IRQHandlerRaw[16]; + #ifdef __cplusplus } diff --git a/driver/irq/pic/pic_init.c b/driver/irq/pic/pic_init.c index 3be6104..cbcdbc9 100644 --- a/driver/irq/pic/pic_init.c +++ b/driver/irq/pic/pic_init.c @@ -10,6 +10,7 @@ irq_pic_IRQHandlerType irq_pic_IRQHandler[16]; +void * irq_pic_IRQHandlerRaw[16]; bool irq_pic_Enabled; void irq_pic_Init() { @@ -34,6 +35,7 @@ void irq_pic_Init() { outb_wait(PIC2_DATA, 0xff); memset(irq_pic_IRQHandler, 0, sizeof(irq_pic_IRQHandler)); // reset all IRQ handlers + memset(irq_pic_IRQHandlerRaw, 0, sizeof(irq_pic_IRQHandlerRaw)); // map the IRQ handlers interrupt_MapHandler(irq_pic_IntHandler20h, 0x20);