I Can't Get Interrupts Working: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
No edit summary
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(3 intermediate revisions by 2 users not shown)
Line 36:
Use the mask feature of the PIC to enable/disable some handlers.
 
<sourcesyntaxhighlight lang="c">
outb(0x21,0xfd);
outb(0xa1,0xff);
enable(); // asm("sti");
</syntaxhighlight>
</source>
 
=== I'm receiving a General Protection Fault interrupt immediately after returning from my first interrupt ===
 
After initializing the gdt with the lgdt command, make sure that you are performing a long jump. For example:
 
<syntaxhighlight lang="asm">
init_gdt:
lgdt [gdt_table]
jmp 0x08:longjmp_after_gdt
longjmp_after_gdt:
; Do something like repoint segment registers next
</syntaxhighlight>
 
=== I'm receiving EXC9 instead of IRQ1 when striking a key?! ===
Line 56 ⟶ 68:
=== I can only receive one IRQ ===
 
Each IRQ needs to be acknowledged to the PIC manually by sending an EOI. You need to have <sourcesyntaxhighlight lang="c"> outb(0x20,0x20) </sourcesyntaxhighlight> within any master handler and any <sourcesyntaxhighlight lang="c"> outb(0x20,0x20); outb(0xa0,0x20); </sourcesyntaxhighlight> within any slave handler.<br><br>
 
When handling the keyboard IRQ, make sure that you read the byte the keyboard sends you. The interrupt might not trigger again until it has been read: <sourcesyntaxhighlight lang="c"> unsigned char scan_code = inb(0x60); </sourcesyntaxhighlight>
 
Also, if you are following the barebones tutorial, be sure that your main function doesn't exit too soon (because when it does, it disables interrupts). A common solution to make sure it doesn't exit prematurely is to add <sourcesyntaxhighlight lang="c"> for(;;) {
asm("hlt");
} </sourcesyntaxhighlight>
to the end of your main kernel function. The ''for'' loop is necessary because execution continues after the CPU receives an interrupt.
 
Line 71 ⟶ 83:
=== 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 <sourcesyntaxhighlight lang="c"> outb(0x20, 0x0B); unsigned char irr = inb(0x20);</sourcesyntaxhighlight> and check if bit 7 <sourcesyntaxhighlight lang="c">irr & 0x80</sourcesyntaxhighlight> 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 [[Topic:11379|this thread]].
Line 79 ⟶ 91:
 
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
<sourcesyntaxhighlight lang="asm">
isr_label:
iret
Line 86 ⟶ 98:
dw 0xbeef
dw isr_label >> 16
</syntaxhighlight>
</source>
 
by something that extracts a 'pure value' from the address (e.g. the difference of two addresses are a pure value and <tt>$$</tt> means to NASM the start of the section)
<sourcesyntaxhighlight lang="asm">
%define BASE_OF_SECTION SOME_CONSTANT_YOU_SHOULD_KNOW
isr_label:
Line 97 ⟶ 109:
dw 0xbabe
dw (BASE_OF_SECTION + isr_label - $$) >> 16
</syntaxhighlight>
</source>
 
The role of <pre>BASE_OF_SECTION</pre> 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.
Line 105 ⟶ 117:
 
This example is made for x86 CPUs running in IA32 mode (32-bit).
<sourcesyntaxhighlight lang="asm">
int_handler:
mov ax, LINEAR_DATA_SELECTOR
Line 128 ⟶ 140:
mov [idt+49*8+6],ax
int 49
</syntaxhighlight>
</source>
 
should display a smiley on the top-left corner ... then the CPU is halted indefinitely.
Line 135 ⟶ 147:
 
This example sets up an interrupt handler in long mode.
<sourcesyntaxhighlight lang="asm">
.text
int_handler:
Line 161 ⟶ 173:
mov %rax, idt+49*16+8
int $49
</syntaxhighlight>
</source>
 
This example differs from the previous one: it will not touch the screen, but will write the value "0x123abc" to 0x0 memory address and halt. It may be useful when there's no screen or BIOS available.
Line 189 ⟶ 201:
This is how we are supposed to do: (label shl 0x30) shr 0x30
Here is a little example, so you can see how it works:
<sourcesyntaxhighlight lang="asm">
idt:
dw ((isr1 shl 0x30) shr 0x30) ; the low part of the address
Line 199 ⟶ 211:
isr1:
mov ax,0xdead
</syntaxhighlight>
</source>
 
== See alsoAlso ==
=== Articles ===
*[[IDT]]
*[[IDT_problems|IDT problemsProblems]]
 
*[[IDT_problems|IDT problems]]
 
 
[[Category:Troubleshooting]]