Anonymous user
Interrupt Service Routines: Difference between revisions
Jump to navigation
Jump to search
formatting, appearance, orthography
[unchecked revision] | [unchecked revision] |
No edit summary |
(formatting, appearance, orthography) |
||
Line 1:
The [[:Category:x86|x86]] architecture is an interrupt driven system. External events trigger an interrupt
Such events can be triggered by hardware or software. An example of a hardware interrupt is the keyboard:
Software driven interrupts are triggered by the <tt>int</tt> opcode; e.g. the services provided by MS-DOS are called by the software triggering <tt>INT 21h</tt> and passing the applicable parameters in CPU registers.
For the system to know which interrupt service routine to call when a certain interrupt occurs, offsets to the
An ISR is called directly by the CPU, and the protocol for calling an ISR differs from calling e.g. a C function. Most importantly, an ISR has to end with the <tt>iret</tt> opcode, whereas usual C functions end with <tt>ret</tt> or <tt>retf</tt>. The obvious but nevertheless wrong solution leads to one of the most "popular" triple-fault errors among OS programmers.
== The Problem ==
Many people shun away from
<source lang="C">
Line 23:
</source>
This cannot work. The compiler doesn't understand what is going on. It doesn't understand that the registers and stack
<source lang="asm">
Line 38:
</source>
It should be obvious how this messes up the stack (ebp gets
== Solutions ==
=== Plain
Learn enough about
=== Two-Stage
Write an
<source lang="asm">
Line 68 ⟶ 69:
</source>
=== Compiler Specific Interrupt Directives ===
Some compilers for some processors have directives allowing you to declare a routine interrupt, offer a #pragma interrupt, or a dedicated macro. Clang 3.9, Borland C, Watcom C/C++, Microsoft C 6.0 and Free Pascal Compiler 1.9.* and up offer this, while GCC does not. Visual C++ offers an alternative shown under '''Naked Functions''':
==== Clang ====
As of version 3.9 it supports [http://clang.llvm.org/docs/AttributeReference.html#id1 interrupt attribute] for x86/x86-64 targets.
<source lang="C">
struct interrupt_frame
Line 89 ⟶ 93:
}
</source>
==== Borland C ====
<source lang="C">
/* Borland C */
Line 98 ⟶ 104:
</source>
==== Watcom C/C++ ====
<source lang="C">
/* Watcom C/C++ */
Line 106 ⟶ 113:
}
</source>
==== Naked Functions ====
Some Compilers can be used to make interrupt routines, but requires you to manually handle the stack and return operations. Doing so requires that the function be generated without an epilogue or prologue. This is called making the function ''naked'' - this is done in Visual C++ by adding the attribute ''_declspec(naked)'' to the function. You need to verify that you do include a return operation (such as ''iretd'') as that is part of the epilogue that the compiler has now been instructed to not include.▼
▲Some
If you intend to use local variables, you must set up the stack frame in the manner which the compiler expects; as ISRs are non-reentrant, however, you can simply use static variables.
===== Visual C++ =====
Visual C++ also supplies the __LOCAL_SIZE assembler macro, which notifies you how much space is required by the objects on the stack for the function.
Line 130 ⟶ 139:
</source>
==== gcc / g++ ====
Neither gcc nor g++ offer any means (on x86 or x86-64) to have an interrupt service routine only in C or C++ without performing '''black magic'''.
===== Black Magic =====
Look at the faulty code [[Interrupt_Service_Routines#The_Problem|above]], where the proper C function exit code was skipped, screwing up the stack. Now, consider this code snippet, where the exit code is added manually:
<source lang="C">
/* BLACK MAGIC
void interrupt_handler() {
__asm__("pushad");
Line 162 ⟶ 171:
</source>
This assumes that <tt>leave</tt> is the correct end-of-function handling
===== Asm Goto =====
:''Full article: [[ISRs_PIC_And_Multitasking|ISRs, PIC, And Multitasking]]''
Since
[[Category:Interrupts]]
|