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 assemblybill@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