GPF in IRQ0

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Crazed123

GPF in IRQ0

Post by Crazed123 »

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.

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
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).

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;
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:

Code: Select all

InitializeIRQs($10,$8E,$20);
WriteLn(PChar('Kernel IRQ handling is initialized.'));
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.

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
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...
AR

Re:GPF in IRQ0

Post by AR »

Try removing "pop %EAX" from the handler, Pascal's calling convention says that the callee clears the stack IIRC, you're actually poping the value of GS into EAX then when it gets to DS you're trying to pop one of the general register's contents into it.
Crazed123

Re:GPF in IRQ0

Post by Crazed123 »

D'OH! I'm just deleting this thread.

Thanks for pointing out the obvious when I didn't see it.
Post Reply