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