[comp.sys.ibm.pc] chaining interrupts

cjveenm@cs.vu.nl (11/16/89)

From: cjveenm@cs.vu.nl ()
Newsgroups: comp.sys.ibm.pc
Subject: chaining interrupts
Expires: 
References: 
Sender: 
Reply-To: cjveenm@cs.vu.nl ()
Followup-To: 
Distribution: world
Organization: VU Informatica, Amsterdam
Keywords: 

	I have written several own interrupt handlers for the ibm pc,
and I wonder if it's possible to use the old interrupt routines by
chaining from the new one. One way to do this is by setting the old
vector on the address of an other interrupt number. A disadvantage
of this method is that you don't always know which interrupt is free
and you can run out of all possible interrupts.
	So is there an other way, from TP4 for instance:
		jmp oldvector (with inline code) 
doesn't succeed.

		thanks in advance, Cor

pelegrin@geocub.greco-prog.fr (11/16/89)

     It is absolutely harmless to link interrupt routines one to
another WITH THE SAME INTERRUPT VECTOR provided that, for interrupts
such as timer ticks, the total amount of time spent in the routines
does not exceed the tick clock rate...
     A general example of a resident interrupt routine installation
program (machine language) is given below :

 Initialization routine :
1) Save the old interrupt vector (INT 21H, FCN 25H) in a double word
   variable named, i.e. OLDVEC (defined with "DD OLDVEC").
2) Set the new interrupt vector (INT 21H, FCN 35H) to the segment:offset
   of your own interrupt routine NEWVEC, located within this program.
3) Make the program resident, including this routine (which will now
   be of no use but we have no way to eliminate it), and the next
   routine :
 Interrupt routine (starting at address NEWVEC) :
1) Push the registers you will use in your routine.
2) Perform whatever you want to... (8^D).
   Since it is an interrupt routine, DS and ES may have any value ; for
   small use of local variables, use the CS: prefix to access them
   within your code segment, else push DS and/or ES and set them equal
   to CS (for example...). If you use a large amount of stack, you can
   also switch to your own local stack.
3) Pop the registers you pushed before, in reverse order.
4) Use the JMP OLDVEC mnemonic (inter-segment jump from a memory operand)
   to link to the old interrupt vector.

 If you want to bypass the old interrupt vector, just perform at step 4)
a single IRET mnemonic for software interrupts, but if it was a hardware
interrupt (issued thru a Programmable Interrupt Timer), NEVER forget to use
the EOI mnemonic to warn the PIT of the end of the interrupt (for such
cases, I *strongly* recommend to link your interrupt to the previous one,
so that you don't have to hold those stinky cases...).

            Have fun.

                   f.p.

------------------------------------------------------------------------------
! Zeu<FP> : The craziest programmer in France !          _________           !
!---------------------------------------------!      /   |        \   \      !
! Francois Pellegrini is :                    !     /    |__   ___/    \     !
!         pelegrin@goofi.greco-prog.fr        !     \    |     |       /     !
!   uunet!mcsun!inria!geocub!goofi!pelegrin   !      \   |     |      /      !
!            pelegrin@goofi.UUCP              !                              !
------------------------------------------------------------------------------

mikej@vax1.acs.udel.EDU (Michael Jacobs) (11/16/89)

>	I have written several own interrupt handlers for the ibm pc,
>and I wonder if it's possible to use the old interrupt routines by
>chaining from the new one. One way to do this is by setting the old
>vector on the address of an other interrupt number. A disadvantage
>of this method is that you don't always know which interrupt is free
>and you can run out of all possible interrupts.
>	So is there an other way, from TP4 for instance:
>		jmp oldvector (with inline code) 
>doesn't succeed.

I was playing with interrupts last night and just worked it out.  I have
succeeded in replacing interrupt $1C (the clock updater), and then, inside
my routine, calling the clock updated (so it gets done), then returning
safely.

in turbo 5.5 (it would work in tp >= 4.0 I would think):

{$m 1024,0,0}    { this program installs the interrupt replacement,
				   and since we want the code to stay in memory
				   so it can be used, we'll have to use the KEEP
				   command, so we don't want a big stack and heap
				   clogging memory }

uses dos;   { getintvec and setintvec are in unit dos }

var ticksave : pointer;    { this holds onto the old interrupt vector }

	procedure tick; interrupt;  { this is what would get called instead }
	begin
	inline ( $50/$bb/ticksave/$ff/$1f )  { call tick routine }
                                  { what this does is
								   PUSH AX
								   MOV BX, OFFSET ticksave
								   CALL [BX] (intersegment call) 

								   I push AX, because at the end of
								   the old clock updating stuff, there
								   will be an IRET which pops the
								   offset (IP), the segment (CS), and
								   the flags.  since the flags are 
								   irrelevent in this case, i just
								   pushed the garbage in AX }
	 
   { your code here... }
	end;

	var X : pointer;
	begin
	getintvec ( $1C, ticksave );   { get the old vector and remember it }
	x := @tick;                    { the address of tick is the new vector }
	setintvec ( $1c, x );          { set it }
	keep ( 0 )                     { end the program but keep all this }
	end.                           {   BS in memory }

	 
fun, huh?



-- 

Mike J             |  
The Grey Sysop...  |  Phone...RING!...yep yep yep yep yep!
                   |  

johnl@esegue.segue.boston.ma.us (John R. Levine) (11/17/89)

In article <1484@geocub.greco-prog.fr> pelegrin@goofi.UUCP (Uncle Ben's) writes:
>     It is absolutely harmless to link interrupt routines one to
>another WITH THE SAME INTERRUPT VECTOR provided that, for interrupts
>such as timer ticks, the total amount of time spent in the routines
>does not exceed the tick clock rate...

Well, sometimes.  The problem is that many cards were not designed with
interrupt sharing in mind and so are not good citizens about the way that
they handle their interrupt line.  I have used cards (a WD8003 Ethernet, for
example) that keep anything else from interrupting on the same level.

-- 
John R. Levine, Segue Software, POB 349, Cambridge MA 02238, +1 617 864 9650
johnl@esegue.segue.boston.ma.us, {ima|lotus|spdcc}!esegue!johnl
"Now, we are all jelly doughnuts."

pelegrin@geocub.greco-prog.fr (11/17/89)

In article <1989Nov16.173228.7309@esegue.segue.boston.ma.us> johnl@esegue.segue.boston.ma.us (John R. Levine) writes:
>In article <1484@geocub.greco-prog.fr> pelegrin@goofi.UUCP (Uncle Ben's) writes:
>>     It is absolutely harmless to link interrupt routines one to
>>another WITH THE SAME INTERRUPT VECTOR provided that, for interrupts
>>such as timer ticks, the total amount of time spent in the routines
>>does not exceed the tick clock rate...
>
>Well, sometimes.  The problem is that many cards were not designed with
>interrupt sharing in mind and so are not good citizens about the way that
>they handle their interrupt line.  I have used cards (a WD8003 Ethernet, for
>example) that keep anything else from interrupting on the same level.

From a software point of view, if you handle chaining properly in your
interrupt routine, you will be able to run it without any problems
provided that you load it AFTER all interrupt routines using the same vector
since, as you pointed, older-designed interrupt routines may issue a single
IRET on exiting instead of properly linking to the next interrupt on the
list...
From a hardware point of view, I don't know...

                                   f.p.

------------------------------------------------------------------------------
! Zeu<FP> : The craziest programmer in France !          _________           !
!---------------------------------------------!      /   |        \   \      !
! Francois Pellegrini is :                    !     /    |__   ___/    \     !
!         pelegrin@goofi.greco-prog.fr        !     \    |     |       /     !
!   uunet!mcsun!inria!geocub!goofi!pelegrin   !      \   |     |      /      !
!            pelegrin@goofi.UUCP              !                              !
------------------------------------------------------------------------------

KULOKARI@cc.helsinki.fi (Hannu Kulokari) (12/04/89)

In article <4543@solo5.cs.vu.nl>, cjveenm@cs.vu.nl writes:
> 	I have written several own interrupt handlers for the ibm pc,
> and I wonder if it's possible to use the old interrupt routines by
> chaining from the new one. One way to do this is by setting the old
> vector on the address of an other interrupt number. A disadvantage
> of this method is that you don't always know which interrupt is free
> and you can run out of all possible interrupts.
> 	So is there an other way, from TP4 for instance:
> 		jmp oldvector (with inline code) 
> doesn't succeed.
> 
> 		thanks in advance, Cor

You should CALL (not JMP to) the old interrupt routine, with a FAR
call. You should also push the flags (PUSHF) before the call. This is what
INT does (besides looking up the address of the routine from the interrupt
table).

Hannu Kulokari
CC, U of Helsinki, Finland