My kernel is made of a micro kernel in assembly that boots up to the long mode, installs GDT, IDT, IRQs and then calls the C++ kernel. Both the assembly and C++ parts are running in Ring 0, there is no user code and I'm running in single processor mode.
In my kernel I'm using several IRQs (keyboard, PIT, IDE controllers). What I've done is that I have one assembly routine for each possible IRQs and then an array of handlers that are addresses of functions or 0 if the C++ kernel did not request something at this point.
Here the macro used to generate the various IRQ routines:
Code: Select all
%macro CREATE_IRQ 1
_irq%1:
; Disable interruptions to avoid being interrupted
cli
mov rax, [irq_handlers + 8 *%1]
; If there are no handler, just send EOI
test rax, rax
je .eoi
; Call the handler
call rax
.eoi:
mov rax, %1 ; IRQ number
cmp rax, 8
jl .master
; If IRQ 8 -> 15, send EOI to PIC2
mov al, 0x20
out 0xA0, al
.master:
; Send EOI to PIC1
mov al, 0x20
out 0x20, al
iretq
%endmacro
So I decided, to save rax after cli and restore it before iretq and save registers (rbx,rcx,rdx,rsi,rdi,r8,r9) before the call and restore them after the call. However, when I do that, the iretq instruction throws a General Protection Fault.
If I save less registers, some things are improved (no page faults), but it seems that my ATA interrupt is never called as I'm waiting forever for an ATA read.
So, my question is, what is a safe way to call a C++ function from an interrupt handler ? Or is there something specific that I'm doing wrong here ?
Thank you