I Can't Get Interrupts Working: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (error currected, under fasm)
m (Fixed some grammar mistakes.)
Line 44: Line 44:
</pre>
</pre>


=== I'm receiving EXC9 instead of IRQ1 when striking a key !? ===
=== I'm receiving EXC9 instead of IRQ1 when striking a key ?! ===


You missed the PIC vectors reprogramming step. Check [[PIC|Can I remap the PIC?]] page. Note that if you remap the PIC vectors out of the IDT you'll get a GPF exception instead of any interrupt.
You missed the PIC vector reprogramming step. Check [[PIC|Can I remap the PIC?]] page. Note that if you remap the PIC vectors out of the IDT you'll get a GPF exception instead of any interrupt.




=== I do not receive any IRQ ===
=== I'm not receiving any IRQ ===


Make sure you [[#ISR_problems|receive software interrupts]] first. Also make sure you enabled the IRQ of your interrest on the PIC mask and that you enabled the cascading line (bit #2 of the master) if you're waiting for a slave IRQ.
Make sure you [[#ISR_problems|receive software interrupts]] first. Also make sure you enabled the IRQ of your interrest on the PIC mask and that you enabled the cascading line (bit #2 of the master) if you're waiting for a slave IRQ.
Line 57: Line 57:
Each IRQ needs to be acknowledged to the PIC manually. You need to have <pre> outb(0x20,0x20) </pre> within any master handler and any <pre> outb(0x20,0x20); outb(0xa0,0x20); </pre> within any slave handler.
Each IRQ needs to be acknowledged to the PIC manually. You need to have <pre> outb(0x20,0x20) </pre> within any master handler and any <pre> outb(0x20,0x20); outb(0xa0,0x20); </pre> within any slave handler.


=== When i try to enable timer, keyboard doesn't work anymore ===
=== When I try to enable the PIT, the keyboard doesn't work anymore ===


A common mistake is that people reload the mask with <tt>0xFE</tt> when they want to add timer, but doing this actually enables ''only'' the timer and disables the keyboard (bit #1 of 0xFE is set!) The correct value for enabling ''both'' keyboard and timer is 0xFC.
A common mistake is that people reload the mask with <tt>0xFE</tt> when they want to add timer, but doing this actually enables ''only'' the timer and disables the keyboard (bit #1 of 0xFE is set!) The correct value for enabling ''both'' keyboard and timer is 0xFC.

Revision as of 20:18, 15 March 2009

This page is a sort of TroubleShooting manual to help you getting through common interrupts framework problems encountered by guests and members of the forum

Make sure you collected enough information about your own situation (for instance running your code in Bochs).

ISR problems

My handler doesn't get called!? (ASM)

For this test, you need to call the interrupt yourself, by software. Don't try to get IRQ handled right from the start before you're sure your IDT setup is correct. You need to have:

  • your IDT loaded and filled properly.
  • your IDT's linear address loaded in a structure together with the table's size (in bytes, iirc). Be especially cautious if you have a Higher Half Kernel design or did not set up identity paging.
  • a valid Code selector and offset in the descriptor, proper type, etc.
  • a handling code at the defined offset.

see test code below


My Handler doesn't get called (C) !?

If you're programming the IDT setup in C, make sure the IDTR structure has been correctly understood by your compiler. As intel's 6 bytes structures enfringe most compiler's packing rules, you'll need to use either bitfields or packing pragmas. Use sizeof() and OFFSETOF() macros to make sure the expected definition is used (a runtime test would be fine)


My handler is called but it doesn't return !?

Try to run it in the BOCHS and see if you get any exception report. Program all your exception to have the same kind of behaviour as the example, but displaying a character indicating the fault. Exceptions occuring at the end of an interrupt handler are usually due to a wrong stack operation within the handler.

  • don't try to return from an exception (unless you solved its cause). Returning from a division by zero, for instance, makes no sense at all
  • pops everything you push, but no more
  • make sure you didn't forget the CPU-pushed error code (for exceptions 8,10 and 14 at least)
  • make sure your handler doesn't trash unexpected registers. For exceptions and hardware IRQ handlers, no registers *at all* should be modified.

Another common source of error at this point comes from misimplementation of ISR in C. Check the InterruptServiceRoutines page for enlightenment ...

IRQ problems

Now that you're sure an interrupt can be called and can return, you're ready to enable hardware interrupts. As a first step, you're suggested to enable the _keyboard handler only_, as you'll have almost complete control of what it does. Use the mask feature of the PIC to enable/disable some handlers.

   outb(0x21,0xfd);
   outb(0xa1,0xff);
   enable(); // asm("sti");

I'm receiving EXC9 instead of IRQ1 when striking a key ?!

You missed the PIC vector reprogramming step. Check Can I remap the PIC? page. Note that if you remap the PIC vectors out of the IDT you'll get a GPF exception instead of any interrupt.


I'm not receiving any IRQ

Make sure you receive software interrupts first. Also make sure you enabled the IRQ of your interrest on the PIC mask and that you enabled the cascading line (bit #2 of the master) if you're waiting for a slave IRQ.

I can only receive one IRQ

Each IRQ needs to be acknowledged to the PIC manually. You need to have

 outb(0x20,0x20) 

within any master handler and any

 outb(0x20,0x20); outb(0xa0,0x20); 

within any slave handler.

When I try to enable the PIT, the keyboard doesn't work anymore

A common mistake is that people reload the mask with 0xFE when they want to add timer, but doing this actually enables only the timer and disables the keyboard (bit #1 of 0xFE is set!) The correct value for enabling both keyboard and timer is 0xFC.

I keep getting an IRQ7 for no apparent reason

This is a known problem that cannot be prevented from happening, although there is a workaround. When any IRQ7 is received, simply read the In-Service Register

 outb(0x20, 0x0B); unsigned char irr = inb(0x20);

and check if bit 7

irr & 0x80

is set. If it isn't, then return from the interrupt without sending an EOI.

For more information, including a more detailed explanation, see Brendan's post in this thread.


IDT problems in Assembly

what does "shift operator may only be applied to scalar values" mean ?

You're trying to load a 16-bits field (a part of the IDT descriptor) with a reference to a 32-bit label that is subject to relocation. Try to replace

isr_label:
   iret
bad_stuff dw isr_label & 0xFFFF
          dw 0xdead
          dw 0xbeef
          dw isr_label >> 16

by something that extracts a 'pure value' from the address (e.g. the difference of two addresses are a pure value and $$ means to NASM the start of the section)

%define BASE_OF_SECTION SOME_CONSTANT_YOU_SHOULD_KNOW

isr_label:

  iret
good_stuff dw (BASE_OF_SECTION isr_label - $$) & 0xFFFF
           dw 0xcafe
           dw 0xbabe
           dw (BASE_OF_SECTION isr_label - $$) >> 16

The role of

BASE_OF_SECTION

is to adjust the pure offset to the real situation (usually as defined in your linker script), e.g. if your kernel get loaded at 1MB, you'll set it to 0x100000 to keep the CPU happy.

Assembly Example

int_handler:
   mov ax, LINEAR_DATA_SELECTOR
   mov gs, ax
   mov dword [gs:0xB8000],') : '
   hlt

idt:
   resd 50*2

idtr:
   dw (50*8)-1
   dd LINEAR_ADDRESS(idt)

test1:
   lidt [idtr]
   mov eax,int_handler
   mov [idt+49*8],ax
   mov word [idt+49*8+2],CODE_SELECTOR
   mov word [idt+49*8+4],0x8E00
   shr eax,16
   mov [idt+49*8+6],ax
   int 49

should display a smiley on the top-left corner ... then the CPU is halted indefinitely.

FASM notice

Since fasm don't accept the normal way as described Above, i will describe it. Fasm does however support shl, and shr. so to describe the higher part of a irs address, we just use label shl 0x10 were label are the name of the irs. To define the higher part, we need to write a little more, since fasm use 64 bit, before compiling. This means that IF we just shl and shr, it will be that same as before. This is how we are supposed to do: (label shl 0x30) shr 0x30 simple, but not like Nasm. a little example, so you can see how it works:

idt:
 dw  ((isr1 shl 0x30) shr 0x30)        ; the low part of the address
 dw   0x8    ; selector
 db   0
 db   010001110b  ; type
 dw (isr1 shr 0x10) the high part of the address
                                                      
 


isr1:
 mov ax,0xdead