I'm trying to make a simple OS and I'm currently working on setting up the interrupts.
The way it works is that there is an assembly function that pushes all the registers, the interrupt number and a dummy error code (if the cpu doesn't pushes one) to the stack and then the assenbly function calls a C function that takes the registers as a parameter and will handle the interrupt.
Now, I have two problems:
assembly function:
%macro ISR_NOERRORCODE 1
global ISR%1:
ISR%1:
push 0 ; dummy error code
push %1 ; push interrupt number
jmp isr_common
%endmacro
%macro ISR_ERRORCODE 1
global ISR%1:
ISR%1:
; error code is pushed by the cpu
push %1 ; push interrupt number
jmp isr_common
%endmacro
%include "isr_functions.as"
extern ISR_regsHandler
isr_common:
pusha
xor eax, eax
mov ax, ds
push eax ; push ds to the stack
mov ax, 0x10 ; use kernel segments
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp ; address of stack
call ISR_regsHandler ; call the C function
add esp, 4
pop eax ; restore all the segments
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa
add esp, 8 ; remove the code error
iret ; special interrupt return
Regsiters definition:
typedef struct {
// in the reverse order they were pushed to the stack
u32 ds; // we pushed to the stack
u32 edi, esi, ebp, cs_kernel, ebx, edx, ecx, eax; // we pushed with pusha
u32 interrupt, error; // we push interrupt and error is auto (or dummy)
u32 eip, cs, eflags, esp, ss; // pushed auto
} PACKED Registers_t;
C function:
void CDECL ISR_regsHandler(Registers_t* regs){
} else if (regs->interrupt >= 32) {
QemuPrintf("Unhandeled interrupt %d --> 0x%x\n", regs->interrupt, regs->interrupt);
} else {
QemuPrintf("Unhandeled exception %x: ", regs->interrupt);
QemuPrintf("%s\n", g_Exceptions[regs->interrupt]);
QemuPrintf("Registers values: \neax->%x ebx->%x ecx->%x edx->%x ebp->%x esi->%x edi->%x\n", regs->eax, regs->ebx, regs->ecx, regs->edx, regs->ebp, regs->esi, regs->edi);
QemuPrintf("eip->%x cs->%x eflags->%x esp->%x ss->%x\n", regs->eip, regs->cs, regs->eflags, regs->esp, regs->ss);
QemuPrintf("Interrupt->%x, error_code->%x\n", regs->interrupt, regs->error);
QemuPrintf("KERNEL PANIC!!\n");
}
}
Output (with int 0x01
):
Unhandeled exception 1: Double Fault
Registers values:
eax->0 ebx->0 ecx->0 edx->0 ebp->0 esi->0 edi->0
eip->38e7 cs->38e7 eflags->38e7 esp->38e7 ss->38e7
Interrupt->1, error_code->1
KERNEL PANIC!!
To quote the System Programming Guide, section 6.13 ERROR CODE:
Error codes are not pushed on the stack for exceptions that are generated externally (with the INTR or LINT[1:0] pins) or the INT n instruction, even if an error code is normally produced for those exceptions.
Since you trigger via int 0x08
that will not put an error code on the stack even though an actual exception would. As such your interrupt return pops 4 bytes too many.
Also your QemuPrintf
does not advance the argument pointer for %x
(among others) so it will print the same argument multiple times.