[net.micro.pc] Programming problem - DOS function calls

alb@homxb.UUCP (A.BALL) (06/08/86)

I have been trying for DAYS to find out how to use MS-DOS
function calls from within an interrupt service routine (ISR).
I am a novice programmer who has been attempting to overcome
the difficulties of learning 8086/8088 assembly language programming
using the Microsoft Macro-Assembler, version 1.27. I've been
trying my programs out on an IBM-PC/XT, AT&T 6300, and an
H/Z-150 PC (Heathkit). All use MS-DOS version 2.0 or higher.

My recent efforts have been concerned with writing a memory resident
ISR containing DOS fuction calls to print strings, control the cursor,
etc. These work fine for me when I use them in a regular .COM or .EXE
file, but when I try to incorporate them in an ISR, the program consistently
bombs in all sorts of horrible ways.

PLEASE HELP!!! - I am in danger of losing my mind at this point, or of
burning my assembly language manuals to a crisp, in frustration (#%!??).

Below is a simplified example of the technique I've been using. 
When I assemble and try to run the program, the string is printed out, 
but the computer "hangs". As I stated before, I am a NOVICE programmer, 
and take no responsibility for the sanity of this approach. 
Any help that anyone can offer is greatly appreciated.

----------------------------- cut here -------------------------------------

TITLE	PROBLEM.ASM
PAGE	60,132
;
;PROBLEM.ASM -- Program to demonstrate problem with attempting to use
;		a DOS function call from within a memory resident
;		interrupt handler. Computer "hangs".
;
;		This programs attempts to print a message on the screen
;		when the Shift-PrtSc keys are pressed.
;
;		Installation code (at initialize:) is discarded to
;		reduce size of program in memory.
;
print_s	equ	9h	;print string function
get_vtr equ	35h	;get vector function
set_vtr equ	25h	;set vector function

r_intr	equ	05h	;interrupt vector to be replaced (print screen)
doscall equ	21h	;DOS interrupt number for funct calls
stayres	equ	27h	;terminate-but-stay-resident interrupt

;**********************************************************

sample	segment			;define code segment

	assume	cs:sample,ds:sample
	org	100h		;for COM files

start:		;starting execution address

	jmp	initialize	;install code

msg	db	"Hello there!",13,10,"$"      
oldvtr	dd	;old interrupt vector 

;start of interrupt service routine

ISR:	push	DS	;save everything!
	push	ES
	push	SI
	push	DI
	push	BP
	push	DX
	push	CX
	push	BX
	push	AX
	push	CS
	pop	DS

	CALL	MAIN

	pop	AX	;put everything back
	pop	BX
	pop	CX
	pop	DX
	pop	BP
	pop	DI
	pop	SI
	pop	ES
	pop	DS

	iret		;return from interrupt

;----------------------------------------------------------
MAIN	proc	near

     	sti				;enable interrupts

;display message on screen
	mov   dx,offset msg		;put string address in DX
	mov   ah,print_s		;print string function
	int   doscall			;call DOS

;	jmp DWORD PTR oldvtr		;chain to previous int vector
					;(*** not used in example ***)
	ret

MAIN	endp
;----------------------------------------------------------

initialize:
	mov	bx,cs			;set DS = CS
	mov	ds,bx

;get old interrupt vector and save it
	mov	al,r_intr		;put intr number in AL
	mov	ah,get_vtr		;funct number in AH
	int	doscall			;funct call interrupt
	cli				;disable interrupts temporarily
	mov	WORD PTR oldvtr,bx	;old vector is returned in ES:BX
	mov	WORD PTR oldvtr[2],es	;save it in variable
	sti				;enable interrupts 

;set intr vector to point to this routine
	mov	bx,cs			;put segment:offset of routine
	mov	ds,bx			;in DS:DX
	mov	dx,offset ISR
	mov	al,r_intr		;vector num to be replaced in AL
	mov	ah,set_vtr		;set-vector funct num in AH
	int	doscall

;terminate and stay resident
	mov	bx,cs			;first usable address is that of
	mov	ds,bx			;initialize, so put seg:off 
	mov	dx,offset initialize	;in DS:DX
	int	stayres			;end program, but leave sample 
					;routine in memory
	
sample	ends				;end of code segment

;**********************************************************

	end	start		;end assembly

bill@hpcvla (06/10/86)

(I hope you like getting mail.  You'll probably get a lot for this one.)

Performing I/O via system services (either BIOS or DOS) from within an
interrupt service routine is almost always a no-no.  The "cleanest" way, from
an interrupt standpoint, to do screen I/O while servicing an interrupt
is probably to go straight to display memory, bypassing DOS.  I wouldn't
expect Int 21h functions to work; DOS functions are generally *not* reentrant.
As I understand it, when Int 21h is invoked, DOS makes attempts to keep the
interrupt system *active* as much as possible while processing the request;
I believe it also switches to a different stack.  The jist of this is that,
if the system is inside of an Int 21h function, then you interrupt it and
re-enter Int 21h again, you get screwed.

You might be able to use certain BIOS calls.  Int 10h video I/O might work
if you're careful.  Watch out, though -- it, too, re-enables interrupts
right off the bat.  It's entirely possible for you to interrupt Int 10h,
which may or may not (most likely, may not) be reentrant, depending on which
subfunction is interrupted.

Rule of thumb: if you're going to field hardware interrupts and insist on
performing I/O while inside the ISR, plan on doing all your I/O at the
lowest level (direct to hardware).

bill frolik
hp-pcd!bill