home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
memory
/
amisl081.arj
/
AMIS.MAC
< prev
next >
Wrap
Text File
|
1992-04-19
|
19KB
|
683 lines
.XLIST
;-----------------------------------------------------------------------
; Alternate Multiplex Interrupt Specification Library
; AMIS.MAC Public Domain 1992 Ralf Brown
; You may do with this software whatever you want, but
; common courtesy dictates that you not remove my name
; from it.
;
; Version 0.80
; LastEdit: 4/19/92
;-----------------------------------------------------------------------
AMIS_VERSION equ 340 ;(version 3.4 of the Alternate Multiplex Interrupt Spec)
AMISLIB_VERSION equ 080 ;(version 0.80 of this library)
;-----------------------------------------------------------------------
; Return codes for various API calls
;
; general, applies to all standard calls
AMIS_NOTIMPLEMENTED equ 0
AMIS_SUCCESSFUL equ 0FFh
; additional return codes for Uninstall (function 02h)
AMIS_UNINST_FAILED equ 1
AMIS_UNINST_WILL_DO equ 2
AMIS_UNINST_SAFE_ON equ 3
AMIS_UNINST_SAFE_OFF equ 4
AMIS_UNINST_TRYLATER equ 5
; additional return codes for Popup (function 03h)
AMIS_POPUP_TRYLATER equ 1
AMIS_POPUP_WILLDO equ 2
AMIS_POPUP_BUSY equ 3
AMIS_POPUP_NEEDHELP equ 4
; additional return codes for Check Interrupt Chained (function 04h)
AMIS_CHAIN_DONTKNOW equ 1
AMIS_CHAIN_HOOKED equ 2
AMIS_CHAIN_HOOKED_ADDR equ 3
AMIS_CHAIN_HOOKLIST equ 4
AMIS_CHAIN_NOTUSED equ 0FFh
;-----------------------------------------------------------------------
;
; Set up a shorthand for the segment containing all the resident code and
; data.
; Note: the alignment must be PARA for the code to be properly relocatable
; in small-code memory models.
;
TSRcode@ MACRO
TGROUP GROUP RESIDENT_CODE
RESIDENT_CODE SEGMENT PUBLIC PARA 'TSRCODE'
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
ASSUME CS:TGROUP
ENDM
TSRcodeEnd@ MACRO
RESIDENT_CODE ENDS
ENDM
;-----------------------------------------------------------------------
;
; Set up shorthands for the segments containing all the resident data,
; initialized and uninitialized.
;
TSRdata@ MACRO
RESIDENT_DATA SEGMENT PUBLIC BYTE 'TSRCODE'
ENDM
TSRdataEnd@ MACRO
RESIDENT_DATA ENDS
ENDM
TSRbss@ MACRO
RESIDENT_BSS SEGMENT PUBLIC BYTE 'TSRCODE'
ENDM
TSRbssEnd@ MACRO
RESIDENT_BSS ENDS
ENDM
;-----------------------------------------------------------------------
;
; Set up a shorthand for declaring all three resident segments and a group
; TGROUP for those segments.
;
TSRgroup@ MACRO
TSRcode@
TSRcodeEnd@
TSRdata@
TSRdataEnd@
TSRbss@
TSRbssEnd@
TGROUP GROUP RESIDENT_CODE,RESIDENT_DATA,RESIDENT_BSS
ENDM
;-----------------------------------------------------------------------
;
; Some of the code in ALTMPX.ASM uses conditional assembly to handle
; segment registers differently in Tiny model than in other models, so
; we need to ensure that __TINY__ is defined in tiny model.
;
IFDEF @Model ; simplified memory models being used?
IF @Model eq 1 ; tiny model
IFNDEF __TINY__
__TINY__ equ 1
ENDIF ;NDEF
ENDIF
IF (@Model eq 1) or (@Model eq 2) or (@Model eq 3) ; Tiny, Small, or Compact?
DIST equ NEAR
ELSE
DIST equ FAR
ENDIF
ELSE ;DEF @Model ; else assume TCC/BCC memory-model #defines
IFDEF __TINY__
DIST equ NEAR
ELSEIFDEF __SMALL__
DIST equ NEAR
ELSEIFDEF __COMPACT__
DIST equ NEAR
ELSE
DIST equ FAR
ENDIF
ENDIF
;-----------------------------------------------------------------------
;
; installation flags (mainly internal use--see INSTALL_TSR below)
;
BEST_FIT equ 1 ; use best-fit rather than first-fit
UMB_ONLY equ 2 ; don't load into low memory, only into a UMB
LOW_ONLY equ 4 ; don't use UMB even if high memory available
; (note: can't set both UMB_ONLY and LOW_ONLY)
USE_TOPMEM equ 8 ; use the top of low memory if no high memory
; (this is not always the best place to load)
PATCH_RESIDENT equ 80h ; patch resident code with actual memory block address
;-----------------------------------------------------------------------
;
; DISPLAY_STRING output a '$'-terminated string to standard output
; arguments: string the label of the string to be displayed
; dataseg [opt] the segment of the string
;
DISPLAY_STRING MACRO string,dataseg
IFNB <dataseg>
push ds
mov ax,dataseg
mov ds,ax
ENDIF
mov dx,offset string
mov ah,9
int 21h
IFNB <dataseg>
pop ds
ENDIF
ENDM
;-----------------------------------------------------------------------
;
; CHECK_DOS_VER ensure that the program is running under the proper
; version of DOS, and terminate with an error message
; specifying the minimum required version if not.
;
CHECK_DOS_VER MACRO major,minor
LOCAL bad_version_msg,version_OK
IF major GE 5
mov ax,3306h ; get true DOS version
ELSE
mov ax,3000h
ENDIF
int 21h
xchg al,ah
cmp ax,256*major + minor
jae version_OK
IFNDEF __TINY__
push cs
pop ds
ENDIF
DISPLAY_STRING bad_version_msg
int 20h ; terminate program
bad_version_msg label byte
db "This program requires DOS "
db major+'0',".",(minor/10)+'0',(minor mod 10)+'0'
db " or higher.",13,10,"$"
version_OK:
ENDM
;-----------------------------------------------------------------------
;
; IF_INSTALLED conditionally branch somewhere if TSR is already installed
; arguments:
; rescode segment of TSR code within executable (to get signature and
; hook list)
; rtype type of segment reference: REL = paras offset from CS
; ABS = absolute segment number
; dest label to branch to if already installed
; at exit:
; CF set if installed
; AH = multiplex number
; CF clear if not installed
;
IF_INSTALLED MACRO rescode,rtype,dest
LOCAL not_installed
IFIDNI <rtype>,<REL>
mov ax,cs
add ax,rescode
ELSE
IFIDNI <rtype>,<RELBYTE>
mov bx,rescode
; note: loc must always be paragraph-aligned; TSRcode@ ensures this
mov cl,4
shr bx,cl
mov ax,cs
add ax,bx
ELSE
mov ax,rescode
ENDIF
ENDIF
extrn check_if_installed:DIST
call check_if_installed
jnc not_installed
jmp dest
not_installed:
ENDM
;-----------------------------------------------------------------------
;
; INSTALL_TSR
; arguments:
; loc location of resident code
; ltype type of above location: REL = para offset from CS
; ABS = absolute paragraph number
; siz size of resident code
; stype type of above size: BYTE or PARA
; extra [opt] number of additional paragraphs needed in resident part
; fit [opt] FIRST (default) or BEST fit allocation
; high [opt] HIGHONLY to only use UMBs, TOPMEM to allocate block at
; high end of conventional memory if no UMBs available,
; LOWONLY to ignore UMBs, and TOPLOW to allocate at high
; end of conventional memory whether or not UMBs are
; available
; init [opt] function to call after installing TSR but before exiting
; if_inst [opt] label to branch to if already installed
; on_err [opt] label to branch to if unable to install
; more_flags [opt] label of byte containing additional flags to OR into
; flags setup by <fit> and <high>
;
; if 'init' is specified, the indicated function will be called with
; AX = segment at which TSR was loaded
;
INSTALL_TSR MACRO loc,ltype,siz,stype,extra,fit,high,init,if_inst,on_err,more_flags
LOCAL not_installed,install_failed,iflags
mov bx,loc
IFIDNI <ltype>,<REL>
mov ax,cs
add bx,ax
ELSE
IFIDNI <ltype>,<RELBYTE>
; note: loc must always be paragraph-aligned; TSRcode@ ensures this
mov cl,4
shr bx,cl
mov ax,cs
add bx,ax
ENDIF
ENDIF
push bx
mov ax,bx
extrn check_if_installed:DIST
call check_if_installed
pop bx
jnc not_installed
install_failure:
IFNB <if_inst>
jmp if_inst
ELSE
jmp short install_failed
ENDIF
not_installed:
cmp al,1
je install_failure
push ax ; remember multiplex number
IFIDNI <stype>,<PARA>
mov cx,siz
ELSE
mov ax,siz
add ax,15 ; convert bytes to paragraphs
mov cl,4
shr ax,cl
mov cx,ax
ENDIF
IFNB <extra>
mov dx,extra
ELSE
xor dx,dx ; no extra memory required
ENDIF
pop ax ; get back multiplex number
iflags = 0
IFDIFI <fit>,<FIRST>
iflags = iflags OR BEST_FIT
ENDIF
IFIDNI <high>,<HIGHONLY>
iflags = iflags OR UMB_ONLY
ENDIF
IFIDNI <high>,<LOWONLY>
iflags = iflags OR LOW_ONLY
ENDIF
IFIDNI <high>,<TOPMEM>
iflags = iflags OR USE_TOPMEM
ENDIF
IFIDNI <high>,<TOPLOW>
iflags = iflags OR USE_TOPMEM OR LOW_ONLY
ENDIF
IFDEF ALTMPX$PSP
iflags = iflags OR PATCH_RESIDENT
ENDIF
mov al,iflags
IFNB <more_flags>
or al,more_flags
ENDIF
extrn $install_TSR:DIST
call $install_TSR
; if success, returns CF clear, AX=segment at which TSR was installed
jc install_failed
IFNB <&init>
call init
ENDIF
extrn $go_TSR:DIST
call $go_TSR ; never returns
install_failed:
IFNB <on_err>
jmp on_err
ELSE
push cs
pop ds
DISPLAY_STRING cs:install_error_msg
mov ax,4CFFh ; exit with ERRORLEVEL 255
int 21h
install_error_msg db "Unable to go resident.",13,10,"$"
ENDIF
ENDM
;-----------------------------------------------------------------------
;
; UNINSTALL remove the TSR from memory
; arguments:
; rescode segment of TSR code within executable (to get signature and
; hook list)
; rtype type of segment reference: REL = paras offset from CS
; ABS = absolute segment number
; on_err [opt] label to branch to if unable to remove from memory
;
; If 'on_err' is omitted, check CF after this macro to determine whether
; the removal was successful (CF clear if successful, set on error)
;
UNINSTALL MACRO rescode,rtype,on_err
LOCAL success
IFIDNI <rtype>,<REL>
mov ax,cs
add ax,rescode
ELSE
IFIDNI <rtype>,<RELBYTE>
mov bx,rescode
; note: loc must always be paragraph-aligned; TSRcode@ ensures this
mov cl,4
shr bx,cl
mov ax,cs
add ax,bx
ELSE
mov ax,rescode
ENDIF
ENDIF
extrn $uninstall_TSR:DIST
call $uninstall_TSR
IFNB <on_err>
jnc success
jmp on_err
ENDIF
success:
ENDM
;-----------------------------------------------------------------------
;
; I M P O R T A N T ! ! !
; Note: in order to work properly with the code in ALTMPX.ASM, all of
; the following macros must be used inside TSRcode@
;
;-----------------------------------------------------------------------
;
; ISP_HEADER set up Interrupt Sharing Protocol header for an interrupt
; arguments:
; intr interrupt number
; reset [opt] name of routine to perform hardware reset
; eoi [opt] if nonzero, this is the primary handler for a hardware int
; exported labels: (for example "ISP_HEADER 00h,reset_func,0")
; INT00h_handler (public), ORIG_INT00h (public), HWRESET_00h,
; EOI_FLAG_00h
; [in addition, hw_reset_00h would be present for ISP_HEADER 00h,,0]
;
ISP_HEADER MACRO intr,reset,eoi
public INT&intr&_handler,ORIG_INT&intr
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
IFB <reset>
hw_reset_&intr:
db 0CBh ; RETF
ENDIF ;reset
INT&intr&_handler:
db 0EBh,10h ; short JMP to skip the header
ORIG_INT&intr dd ? ; previous handler in chain
dw 424Bh ; ISP signature
EOI_FLAG_&intr label byte
IFB <eoi>
db 0 ; software int or secondary hardware int
ELSE
IF eoi eq 0
db 0 ; software int or secondary hardware int
ELSE
db 80h ; primary hardware int handler
ENDIF ;eoi eq 0
ENDIF ;B eoi
IFB <reset>
HWRESET_&intr: jmp short hw_reset_&intr
ELSE
HWRESET_&intr: jmp short reset
ENDIF ;B reset
db 7 dup (0)
ENDM
;-----------------------------------------------------------------------
;
; HOOKED_INTS declare the interrupts this TSR hooks
; arguments: up to 32 interrupt numbers
; exported labels: HOOKED_INT_LIST (public)
;
HOOKED_INTS MACRO a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af,over
public HOOKED_INT_LIST
HOOKED_INT_LIST label byte
IFNB <over>
%out Too many interrupts hooked!
.err
ENDIF ;NB over
IRP intrpt,<a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af>
IFNB <intrpt>
IF intrpt ne 2Dh ; ignore INT 2Dh if in the list
DB 0&&intrpt
DW INT&&intrpt&&_handler
ENDIF ;DIFI
ENDIF ;NB
ENDM
;
; the list terminator is INT 2Dh, since we know that one will always
; be hooked; thus, all interrupts from 00h to FFh may be hooked
;
DB 2Dh
DW INT2Dh_handler
ENDM
;-----------------------------------------------------------------------
;
; ALTMPX define the alternate multiplex interrupt handler for the program
; arguments:
; manuf one- to eight-character manufacturer's name
; prodname one- to eight-character product name
; version four-digit hex version number (hi byte = major, lo = minor)
; descrip [opt] string (max 63 char) describing the product
; priv_funcs [opt] name of routine to handle private INT 2Dh functions
; api_entry [opt] name of FAR routine giving non-INT 2Dh API entry point
; popup [opt] name of function to call to request a popup
; remover [opt] name of function to call to remove TSR from memory
; psp [opt] if nonblank, set up patch word for memblk segment to
; be returned if <remover> omitted; returns CS if both
; <remover> and <psp> blank
; limitations on routines:
; all: must be located inside TSRcode@
; <priv_funcs>
; input: AL = function number (10h-FFh)
; AH = multiplex number (ignore)
; others available for handler
; return: via IRET, with regs as appropriate for requested func
; <api_entry>
; input: registers as desired (no limitations)
; return: registers as desired (no limitations)
; <popup>
; input: nothing
; return: AL = status
; 01h can not pop up now, try again later
; 02h can not pop up yet, will do so when able
; 03h already popped up
; 04h unable to popup, user intervention required
; BX = standard reason code
; 0000h unknown failure
; 0001h int chain passes through memory
; which must be swapped out
; 0002h swap-in failed
; CX = application's reason code if nonzero
; FFh TSR popped up and was exited by user
; BX = return value
; 0000h no return value
; 0001h TSR unloaded
; 0002h-00FFh reserved
; 0100h-FFFFh application-specific
; <remover>
; input: DX:BX = return address if uninstall successful
; return: AL = status
; 01h unable to remove from memory
; 02h can't remove now, will do so when able
; 03h safe to remove, but no resident uninstaller
; (TSR still enabled)
; BX = segment of memory block
; 04h safe to remove, but no resident uninstaller
; (TSR now disabled)
; BX = segment of memory block
; 05h not safe to remove now, try again later
; FFh successful (DX:BX were ignored)
; return at DX:BX with AX destroyed if successful and <remover>
; honors specific return address
; if <remover> omitted, ALTMPX returns AL=03h
; exported labels:
; INT2Dh_handler (public), ORIG_INT2Dh (public), HWRESET_2Dh,
; EOI_FLAG_2Dh, hw_reset_00h, MULTIPLEX_NUMBER (public),
; ALTMPX_SIGNATURE (public), ALTMPX$PSP [patch word]
;
ALTMPX MACRO manuf,prodname,version,descrip,priv_funcs,api_entry,popup,remover,psp
LOCAL our_int_2Dh,int2D_func_00,int2D_func_01,int2D_func_02
LOCAL int2D_func_03,int2D_func_04,private_functions
LOCAL func_is_supported,func_not_supported,func_supported_segDX
PUBLIC MULTIPLEX_NUMBER,ALTMPX_SIGNATURE,ALTMPX$PSP
ALTMPX_SIGNATURE label byte
db manuf
IF ($-ALTMPX_SIGNATURE) gt 8
ERR "Manufacturer name >8 chars"
ELSEIF ($-ALTMPX_SIGNATURE) lt 8
db (ALTMPX_SIGNATURE+8-$) dup (' ')
ENDIF
db prodname
IF ($-ALTMPX_SIGNATURE) gt 16
ERR "Product name >8 chars"
ELSEIF ($-ALTMPX_SIGNATURE) lt 16
db (ALTMPX_SIGNATURE+16-$) dup (' ')
ENDIF
IFNB <descrip>
db descrip
ENDIF
db 0
IF ($-ALTMPX_SIGNATURE) gt 80
ERR "Description >63 chars"
ENDIF
; save an additional byte by overlaying the null hardware reset handler over
; other code, if possible
IFNB <remover>
hw_reset_2Dh: ; <remover> not blank
db 0CBh ; RETF
IFNDEF ALTMPX$PSP
ALTMPX$PSP equ word ptr ($+12) ; point harmlessly into the ISP header
ENDIF
ELSE
IFB <psp>
ALTMPX$PSP equ word ptr ($+12) ; point harmlessly into the ISP header
ENDIF
ENDIF
IFNB <psp>
IFB <remover>
hw_reset_2Dh: ; <remover> blank but <psp> not
db 0CBh ; RETF
ENDIF
ENDIF
; if both <remover> and <psp> blank,
; hw_reset_2Dh is defined below
; if <remover> is blank and <psp> not,
; ALTMPX$PSP is defined below
ISP_HEADER 2Dh,hw_reset_2Dh
cmp ah,0 ; will be patched with multiplex number
MULTIPLEX_NUMBER equ byte ptr ($-1)
je our_int_2Dh
jmp ORIG_INT2Dh
our_int_2Dh:
sti ; OK to interrupt from now on
cmp al,0
je int2D_func_00
cmp al,2
IFNB <api_entry>
jb int2D_func_01
ENDIF
je int2D_func_02
cmp al,4
IFNB <popup>
jb int2D_func_03
ENDIF ;popup
je int2D_func_04
IFNB <priv_funcs>
cmp al,10h
jae private_functions
ENDIF ;priv_funcs
func_not_supported:
mov al,0
iret
int2D_func_00:
mov cx,version
mov di,offset ALTMPX_SIGNATURE
func_supported_segDX:
mov dx,cs
func_is_supported:
mov al,0FFh
iret
IFNB <api_entry>
int2D_func_01:
mov bx,offset api_entry
jmp func_supported_segDX
ENDIF ;api_entry
int2D_func_02:
IFNB <remover>
call remover
ELSE
; mov al,3 ; safe to remove, no resident uninstaller
inc ax ; AL was 02h, now 03h
IFNB <psp>
mov bx,0 ; will be patched at installation time
ALTMPX$PSP equ word ptr ($-2)
ELSE
mov bx,cs
hw_reset_2Dh equ near ptr ($-1) ; prev instruction happens to expand to 8Ch CBh
ENDIF ;psp
ENDIF ;remover
iret
IFNB <popup>
int2D_func_03:
call popup
iret
ENDIF ;popup
int2D_func_04:
;mov al,4 ;not needed since AL=04h anyway
mov dx,cs
mov bx,offset cs:hooked_int_list
iret
IFNB <priv_funcs>
private_functions:
jmp priv_funcs
ENDIF
ENDM
;-----------------------------------------------------------------------
;
GRAB_INTERRUPT MACRO intnum,handler
TSRbss@
TSR_old_INT&intnum dd ?
TSRbssEnd@
mov ax,3500h+intnum
int 21h
mov word ptr TSR_old_INT&intnum,bx
mov word ptr TSR_old_INT&intnum+2,es
mov dx,offset TGROUP:handler
mov ax,2500h+intnum
int 21h
ENDM
;-----------------------------------------------------------------------
;
RESTORE_INTERRUPT MACRO intnum
push ds
lds dx,TSR_old_INT&intnum
mov ax,2500h+intnum
int 21h
pop ds
ENDM
;-----------------------------------------------------------------------
.LIST