IRQ 0 triggers interrupt 0xD (13) (protection fault)

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
zalman
Posts: 9
Joined: Sun Jan 20, 2013 7:05 pm

IRQ 0 triggers interrupt 0xD (13) (protection fault)

Post by zalman »

Hello,

I am trying to develop my UNIX-clone OS using an x86 platform & elf-32 binaries. I am using Bochs to test my implementation. The problem I am experiencing has to do with the PIT (IRQ 0). When I register the interrupt handler, it does not execute the interrupt. It only executes after enabling the real-time clock (int $0x08); but, after I enable the real-time clock, I cannot execute any other interrupt (e.g., int $0x03 won't work). To make things worse, registering IRQ 0 seems to be repeatedly calling int $0xD (# 13), at each tick of the clock. The clock only begins to tick if I call an interrupt. No other interrupt seems to be enabling the IRQ handler for IRQ 0; only int $0x08.

I am sure I followed all the steps correctly.

I initialize the timer by setting the frequency divisor, divided into low and high 16 bits. I then send the PCI BIOS commands:

outport(0x43, 0x36); // send command byte
outport(0x40, low); // send low 16-bits
outport(0x40, high); // send high 16-bits

I do end of interrupt (EOI) at the IRQ and ISR handlers:

outportb(0x20, 0x20)

Interrupts are disabled before handling IRQs and ISRs and re-enabled before integer return (iret).

What am I doing wrong?
User avatar
trinopoty
Member
Member
Posts: 87
Joined: Wed Feb 09, 2011 2:21 am
Location: Raipur, India

Re: IRQ 0 triggers interrupt 0xD (13) (protection fault)

Post by trinopoty »

Did you remap/configure the PIC/APIC correctly?
INT 13 is GPF. Check your interrupt handling code.
Always give a difficult task to a lazy person. He will find an easy way to do it.
zalman
Posts: 9
Joined: Sun Jan 20, 2013 7:05 pm

Re: IRQ 0 triggers interrupt 0xD (13) (protection fault)

Post by zalman »

I did remap the PIC's IO ports:

outportb(0x20, 0x11); \\ master
outportb(0xA0, 0x11); \\ slave
outportb(0x21, 0x20); \\ master + 1
outportb(0xA1, 0x28); \\ slave + 1
outportb(0x21, 0x04);
outportb(0xA1, 0x02);
outportb(0x21, 0x01);
outportb(0xA1, 0x01);

Is there something wrong here? I've verified with other sources, and it seems correct to me.

In essence, the interrupt "is" firing, but only when I call $0x08 (CMOS real-time clock). I know that the IRQ is firing because I see debug information being printed on the screen on every interrupt call (corresponding to a tick of the clock); however, a side-effect is that 0x0D (general protection fault) is also being fired at every tick, and other interrupts that I call after $0x08 are simply blacklisted and ignored.

Please, let me know if other information is necessary, and I will make my best effort to collect other debug data.

Thank you,
zalman
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: IRQ 0 triggers interrupt 0xD (13) (protection fault)

Post by Brendan »

Hi,
zalman wrote:In essence, the interrupt "is" firing, but only when I call $0x08 (CMOS real-time clock).
Do you mean, the interrupt handler executes when you do "int $0x28"? Doing "call $0x08" (or even "call $0x28") doesn't make sense for something that is an interrupt handler.
zalman wrote:I know that the IRQ is firing because I see debug information being printed on the screen on every interrupt call (corresponding to a tick of the clock); ...
I'll assume you're talking about IRQ0 (PIT timer) and not IRQ8 (CMOS/RTC clock) now.
zalman wrote:...however, a side-effect is that 0x0D (general protection fault) is also being fired at every tick, ...
Exceptions aren't fired by hardware (like IRQs) - they're caused by software. If software causes a general protection fault every time IRQ0 occurs, then I'd assume that:
  • Your interrupt handler for IRQ 0 (interrupt 0x20) crashes and you need to figure out why and fix it; and
  • Your interrupt handler for IRQ 0 successfully sends the EOI to the master PIC chip (otherwise the PIC chip would be waiting for EOI and wouldn't send subsequent IRQ 0s)
This means that it's likely that the problem is somewhere between sending the EOI and doing IRET (e.g. maybe you've messed up the stack by pushing something and not popping it, causing IRET to attempt to return to an invalid code segment).
zalman wrote:...and other interrupts that I call after $0x08 are simply blacklisted and ignored.
Which other interrupts? Typically, until you've loaded/initialised device drivers there are no other IRQs (except IRQ0). The only reason you're getting IRQ0 is that (unlike other IRQs) you don't need to do anything special to handle the IRQ and the BIOS left it running (or, you failed to mask it until after you've initialised a PIT driver). Also, for most devices you must do something "device specific" to clear the cause of the interrupt (like reading some sort of status register in the device) before the device will send another IRQ to the PIC (and before the PIC can forward the device's IRQ to the CPU).
zalman wrote:Please, let me know if other information is necessary, and I will make my best effort to collect other debug data.
When a general protection fault exception occurs the CPU puts useful information on the exception handler's stack so that the general protection fault handler can figure out what happened. This useful information includes the return CS:EIP (usually the address of the instruction that caused the fault) and an error code (e.g. which segment was involved and if the the instruction at CS:EIP caused the problem or something external caused the problem). You should tell us what the general protection fault's error code was; and (if possible) tell us which instruction caused the exception and post the code that includes the instruction that caused the exception.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
trinopoty
Member
Member
Posts: 87
Joined: Wed Feb 09, 2011 2:21 am
Location: Raipur, India

Re: IRQ 0 triggers interrupt 0xD (13) (protection fault)

Post by trinopoty »

From the info, it seems something is wrong with your IRQ handler. No hardware can fire a GPF. It can only be raised by the CPU. (Considering that the PIC is remapped correctly).
Always give a difficult task to a lazy person. He will find an easy way to do it.
zalman
Posts: 9
Joined: Sun Jan 20, 2013 7:05 pm

Re: IRQ 0 triggers interrupt 0xD (13) (protection fault)

Post by zalman »

Right now I don't have any extra hardware in operation with my OS. I believe 0xD (GPF) is a software generated "trap", correct? It is triggered by accessing a segment illegally...

Anyway, my interrupt handler is working, because I tried to manually fire int 0x20 (IRQ 32) and that works.

Here are the register values, just entering the IRQ handler:

EIP: 0000 0000 0001 0000 0010 1010 1001 1010
EAX: 0000 0000 0001 0000 1000 1111 0000 0000
ECX: 0000 0000 0001 0000 0010 0111 0100 0100
EBP: 0000 0000 0000 0000 0000 0000 0010 1111
ESI: 0000 0000 0000 0000 0000 0000 1010 0001

CS holds: 0x10, DS: 0x108FA8, SS: 0x108FF8; finally, EBX, EDX, ESP and EDI are uninitialized

There is an error flag: 0x80, but one thing that did not make sense to me is interrupt number I recieved inside the handler function: 0x1058336 is certainly not 0x20 (the PIT interrupt I was expecting).

The mapping is working correctly, because $0x20 fires when it is triggered. The question is: how can I make the handler function reentrant? The only interrupt that was working for me was $0x08, which doesn't make any sense (this is a double fault interrupt).
zalman
Posts: 9
Joined: Sun Jan 20, 2013 7:05 pm

Re: IRQ 0 triggers interrupt 0xD (13) (protection fault)

Post by zalman »

Thank you very much, to everyone who helped. It turns out that int 0x20 was working all along. I just did not realize that IRQ 0 is triggered by execution cycles (i.e., the PIT is not a "real-time" clock); very silly of me...

Essentially, all I needed was to introduce a preemptable, infinite loop in my main function to burn execution cycles after initializing all services, and then I saw that clearly the clock was ticking.
Post Reply