GPF in IRQ0
Posted: Sun Jul 24, 2005 6:56 pm
Well, I've kept on struggling up through the muck, and have gotten this far. I've developed a stub system for IRQ handling similar to the one used for exceptions, and initialization functions that create a valid IDT using the stubs, as well as setting the handlers to a NullInterrupt() procedure.
The exact same structure used to read the registers for an exception is used for IRQs. As you may have noticed, the IRQ number is pushed after a 1234 and the actual ISR number is never pushed. The 1234 is a magic number to let the handler know it's dealing with an IRQ, no matter where the kernel remaps the PICs (yes, I've done that successfully).
This just checks that magic number to see if the interrupt is an IRQ, than emits the proper end of interrupt signals if it is. The code that starts all this up is:
Where $10 is the ISR segment selector and $8E are the access flags used for the stub itself, while $20 is an indicator of where the PICs have been mapped, and therefore where to put the IRQ handlers in the IDT.
The peculiar thing that happens is this: IRQ0 is triggered after I enable IRQs, the stub runs and calls the proper handler (NullInterrupt()), NullInterrupt() returns, and a General Protection Fault occurs on the "pop ds" in the stub up there.
From this it appears that all the segment registers are set correctly (mine are $08 data, $10 code), at least at the point of the fault. Why is it faulting on a perfectly normal pop ds instruction? As you can see, the NullInterrupt() function doesn't modify any of the register values it recieves...
Code: Select all
irq_0_stub:
cli
push 1234
push 0
pushad
push ds
push es
push fs
push gs
mov ax,$08
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov eax,esp
push eax
mov eax,IRQHandlers
call [eax]
pop eax
pop gs
pop fs
pop es
pop ds
popad
add esp,8
iret
Code: Select all
procedure NullInterrupt(pRegs: PInterruptSavedRegisters); pascal;
begin
if pRegs^.lwErrorCode = 1234 then
begin
if pRegs^.lwISRIndex > 7 then
OutToPort($A0,Byte($20));
OutToPort($20,Byte($20));
end;
end;
Code: Select all
InitializeIRQs($10,$8E,$20);
WriteLn(PChar('Kernel IRQ handling is initialized.'));
The peculiar thing that happens is this: IRQ0 is triggered after I enable IRQs, the stub runs and calls the proper handler (NullInterrupt()), NullInterrupt() returns, and a General Protection Fault occurs on the "pop ds" in the stub up there.
Code: Select all
The basic exceptions are installed and so is the Interrupt Descriptor Table.
The Programmable Interrupt Controllers have been remapped to put IRQs $00-$0F at
IDT entries $20-$28.
Kernel IRQ handling is initialized.
IRQs/interrupts are enabled.
gs: $8
fs: $8
es: $8
ds: $8
edi: $2CFDC
esi: $2CFDB
ebp: $1213B8
ebx: $0
edx: $20
ecx: $1B
eax: $8
int #: $D
error code: $CFDC
eip: $1004E9
cs: $10
eflags: $10097
useresp: $2CFDC
ss: $2CFDB
General Protection Fault Exception