ISR :: Interrupt Service Routines

The x86 architecture is an interrupt driven system. External events are processed by interrupt service routines (ISR's) whose offsets are stored in the IDT (interrupt descriptor table).

These events can be hardware driven interrupts or software driven interrupts.

An example of a hardware ISR is the keyboard. Every time you press a key, the keyboard signales to the IRQ1 which runs an interrupt.

An example of a software driven interrupt is the services provided by MS-DOS, they use INT 21h and are signalled by software when to run.

 

Whats the difference between an ISR and normal routine?

The difference between an ISR and a normal routine is very slight and has to do with CPU opcodes.

ISR routines end their routine with an "Interrupt Return (IRET)" whereas normal procedures end their routines with "Return (RET)" or "Far Return (RETF)"

Some compilers do not have the ability to correctly create ISRs. Often a compiler introduces a non ansi compliant keyword "_interrupt" or "interrupt". Compilers known to support this keyword are Watcom C/C++, Borland C/C++, Microsoft C 6.0. However, GCC does not support this keyword for x86 architecture and it would seem Visual C/C++ does not.

/* example of clock tick routine in Watcom C/C++ */
void _interrupt ISR_clock(void)
{
	clock_count++;
}
		

 

So how do I do an ISR in GCC?

Doing an ISR in GCC is a little more complex than for compilers that support the "_interrupt" keyword.

You have to write a small routine in assembler to call your C routine.

		
/* Filename : isr_clock.s */
/* GCC AT&T	asm example for ISR routine */
/* This example is for our clock_tick example */
/* NOTE! This example assumes nothing in regards to
   contents of registers on running */

	.globl   _clock_isr
	.align   4
	
_clock_isr:

    /* save some registers */
	pushl	%eax
	pushl	%ds
	pushl	%es
	pushl	%fs
	pushl	%gs

    /* set our descriptors up to a DATA selector */
	movl    $0x10, %eax
	movw    %ax, %ds
	movw    %ax, %es
	movw    %ax, %fs
	movw    %ax, %gs

    /* call our clock routine */
	call	_ISR_clock

    /* clear the PIC (clock is a PIC interrupt) */
	movl    $0x20, %eax
	outb    %al, $0x20

    /* restor our regs */
	popl	%gs
	popl	%fs
	popl	%es
	popl	%ds
	popl	%eax
	iret

	
/* filename : clock.c */
/* clock routine */

/* tell our linker clock_isr is not in this file */
extern void clock_isr(void);

__volatile__ unsigned long clock_count=0L;

void ISR_clock(void)
{
	clock_count++;
}