home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 35 Internet
/
35-Internet.zip
/
dyndd.zip
/
dyndd.asm
next >
Wrap
Assembly Source File
|
1997-12-01
|
19KB
|
527 lines
; Dynamic Trace Exit - sample device driver
; Author: Richard Moore
; Date: 1st December 1997
; Version: 1.0
;
; This device drive implements a number of functions that are
; invoked using RPN commands as follows:
;
;
; push parm1
; ....
; push parmn
; push function
; call dd
;
; The functions implemented are:
;
; 0 - log the buffer contents and reset the buffer
; 1 - compare two ASCIIZ strings from flat addresses
; The addresses are popped from the RPN stack and
; the result of the compare is pushed. If the
; addresses are equal then the result is 0, if not
; then the result is -1. If an exception occurs then
; a error message is logged and no result is pushed.
; 2 - compare two ASCIIZ strings from segmented addresses.
; An offset, then segment of the first comparand is
; popped from the RPN stack, followed by the offset
; and segment of the 2nd comparand. This functions
; then proceeds as for function 1.
; 3/4 Test device driver fault handler behaviour.
; 5 - Get a DWORD global variable. An index (0-15) is popped
; from the RPN stack and the value of the corresponding
; global variable is pushed onto the stack.
; 6 - Put a DWORD value into a global variable. An index (0-15) is
; popped followed by the variable value.
; The corresponding global variable is updated.
; Global variable may be shared across dynamic trace objects,
; unlike local variables, which are local to a DTO.
;
; 7 - log the buffer contents skipping the initial 3-byte prefix
; and reset the buffer. If the buffer contains less than 3 bytes
; then a null record is logged.
;
; See DYNDD.RPN for example of these functions being used.
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PAGE 255,133
.386p
.SALL
include devhlp.inc
include dynapi.inc
include basemaca.inc
PUBLIC Strat,DynExit,DynFault
; RPN stack manipulation macros
; RPNPush - increment top of RPN stack pointer.
;
; RPNPush increments the top of stack pointer held in EDX.
; No data transfer to the RPN stack occurs.
RPNPush macro
inc edx
and edx,15 ; assumes RPN stack size is 16 DWORDS
endm
; RPNPop - decrement top of RPN stack pointer.
;
; RPNPop decrement the top of stack pointer held in EDX.
; No data transfer to the RPN stack occurs.
RPNPop macro
dec edx
and edx,15 ; assumes RPN stack size is 16 DWORDS
endm
; RPNGetTOS - Move top element of RPN stack to a register
;
; RPNGetTOS <reg>
;
; RPNGetTOS moves the top element of the RPN stack into a register.
; No motion of the RPN stack occurs.
RPNGetTOS macro reg
mov reg,edx
shl reg,2
add reg,esi
mov reg,es:[reg]
endm
; RPNPutTOS - Move register to top element of RPN stack
;
; RPNPutTOS <reg>
;
; RPNPutTOS moves a register to the top element of the RPN stack.
; No motion of the RPN stack occurs.
RPNPutTOS macro reg
push reg
mov reg,edx
shl reg,2
add reg,esi
pop DWORD PTR es:[reg]
mov reg,es:[reg]
endm
; Standard Request Packet Header definition
RP equ es:[bx] ;use mnemonic
RPP equ [bp-4] ;saved address of RP
RP_COMMAND equ byte ptr es:[bx+2] ;location of command byte
RPCmdInit equ 0 ;Initialize
RPInitDevHlp equ dword ptr es:[bx+14] ;Offset&Segment of DevHlp
RPInitEndCode equ word ptr es:[bx+14] ;end of code segment
RPInitEndData equ word ptr es:[bx+16] ;end of data segment
RPInitParmPtr equ dword ptr es:[bx+18] ;address of parameters
RPCmdRead equ 4 ;device read
RPCmdWrite equ 8 ;device write
RPCmdWriteV equ 9 ;device write with verify
RPRWPhysAdrL equ word ptr es:[bx+14] ;low half of phys addr
RPRWPhysAdrH equ word ptr es:[bx+16] ;high half of phys addr
RPRWLen equ word ptr es:[bx+18] ;length of read/write
RPCmdOpen equ 13 ;device open
RPCmdClose equ 14 ;device close
RP_STATUS equ word ptr es:[bx+3]
DONEAOK equ 0100H
DONENOK equ 8100H ;use one of the below with DONENOK
CMDBAD equ 3
GENFAIL equ 12
INVPARM equ 19
DEVBUSY equ 20
;
;** Device Driver Type definitions
Dev_Char_Dev equ 1000000000000000B ;Device is a character device
Dev_30 equ 0000100000000000B ;Accepts Open/Close/Rem. Media
DevLev_1 equ 0000000110000000B ;OS/2 Device Driver+bitstrip
DDattr equ Dev_Char_Dev+Dev_30+DevLev_1
;
PUBLIC DevHdr
PUBLIC DevHlp
PUBLIC Iflag
PUBLIC trbuffer
PUBLIC dynreq
PUBLIC fltmsg
PUBLIC FlatSel
PUBLIC dynddx
PUBLIC EntrySP
PUBLIC sel1
PUBLIC sel2
PUBLIC off1
PUBLIC off2
PUBLIC GlobalV
_DATA segment para public use16 'DATA'
DevHdr dd -1 ;+00 chain pointer
dw DDattr ;+04 device attributes
dw Strat ;+06 strategy routine
dw 0 ;+08 inter dd comm entry
db 'DYNDD ' ;+0A device name
db 8 dup (0) ;+12 reserved
dd 00000001H ;+1A capability bitstrip, >16Mb support
DevHlp dd 0 ;+1C address of device help entry point
Iflag db 0 ;+20 operational flags
Inited = 128
trbuffer db 'DynExit - invalid request' ;Static trace buffer
db 0
dynreq dd 0
trsize equ $-trbuffer
fltmsg db 'DynExit - encountered a GP Fault'
db 0
fltsize equ $-fltmsg
FlatSel dw 0
dynddx dd 0
;
EntrySP dw 0 ; Entry SP
off1 dw ?
sel1 dw ?
off2 dw ?
sel2 dw ?
;
GlobalV dd 16 dup(0) ; array of 16 global variables
;
DATASIZ equ $-Devhdr ;size of resident data
_DATA ends
;
_TEXT segment para public use16 'CODE'
CSBeg equ $
assume CS:_TEXT, DS:_DATA
; Dynamic Trace exit routine
DynExit proc far
push ds ; save the flat data sel
mov ds,ax ; restore the data segment
pop [FlatSel]
mov [EntrySP],sp ; save entry sp for use by the fault handler
mov WORD PTR [dynddx],di ; save ddx address for realoding after a fault
mov WORD PTR [dynddx+2],fs
mov edx,fs:[di].ddx_StackIndex
xor esi,esi
les si,fs:[di].ddx_StackStart
RPNGetTOS eax ; get function request from TOS
RPNPop ; Pop the function code from TOS
cmp eax,0 ; log buffer function?
jz LogBuffer
cmp eax,1 ; Compare strings from Flat addresses
jz CompStrF
cmp eax,2 ; Compare strings from Segmented addresses
jz CompStrS
cmp eax,3 ; Test fault handler
jz TestFault
cmp eax,4 ; Test fault without a local handler
jz TestFaultNH
cmp eax,5 ; Get Global Var
jz GetGlobalVar
cmp eax,6 ; Put Global Var
jz PutGlobalVar
cmp eax,7 ; log buffer without prefix function?
jz LogBufferNP
RPNPush ; Restore the stack pointer - we don't regognise
; the request, it could be for another exit
; write out an error message via a static trace record
mov [dynreq],eax ; log the function
mov eax,fs:[di].ddx_Major ; original major code
mov ecx,fs:[di].ddx_Minor ; original minor code
mov bx,trsize ; size of trace data
mov si,Offset trbuffer ; ds:si->trbuffer
mov dl,DevHlp_RAS ; SysTrace DevHlp
call [DevHlp] ; call SysTrace
jmp DynEnd
; log out the existing buffer using static trace and reset the log buffer
PUBLIC LogBuffer
LogBuffer:
mov eax,fs:[di].ddx_Major ; original major code
mov ebx,fs:[di].ddx_LogIndex ; size of log data
mov ecx,fs:[di].ddx_Minor ; original minor code
push ds ; save ds
pop es ; as es
push si ; save si
lds si,fs:[di].ddx_LogStart ; ds:si->log buffer
mov dl,DevHlp_RAS ; SysTrace DevHlp
call es:[DevHlp] ; write out the log
pop si ; restore our si
push es
pop ds ; restore our ds
xor eax,eax
mov fs:[di].ddx_LogIndex,eax ; reset log index
jmp DynEnd
; log out the existing buffer without the initial prefix using static trace
; and reset the log buffer
PUBLIC LogBufferNP
LogBufferNP:
mov eax,fs:[di].ddx_Major ; original major code
mov ebx,fs:[di].ddx_LogIndex ; size of log data
mov ecx,fs:[di].ddx_Minor ; original minor code
push ds ; save ds
pop es ; as es
push si ; save si
lds si,fs:[di].ddx_LogStart ; ds:si->log buffer
add si,3 ; bypass prefix
or bx,bx ; if 0, 1 or 2 bytes in log then
jz @F ; leave length zero
dec bx ; (don't bother adjusting si - it's not used).
jz @F ;
dec bx ;
jz @F ;
dec bx ;
@@: mov dl,DevHlp_RAS ; SysTrace DevHlp
call es:[DevHlp] ; write out the log
pop si ; restore our si
push es
pop ds ; restore our ds
xor eax,eax
mov fs:[di].ddx_LogIndex,eax ; reset log index
jmp DynEnd
; Compare two zero terminated strings pointed to by the flat address on the RPN stack
; push 0 if equal, -1 if not
PUBLIC CompStrF
CompStrF:
RPNGetTOS eax ; get addess of 1st string address
RPNPop
RPNGetTOS ebx ; get addess of 2st string address
; don't pop here - we'll replace TOS
; with the result
push cs ; set up a fault handler
pop cx
shl cx,16
mov cx,offset DynFault
mov fs:[di].ddx_pfnFault,ecx
; note use fs instead of ds in string instructions - this makes fault recovery
; easier. The system will pass the fault handler the value of ds in use at the
; time the trap occurred in ax. If we re-use ds - life gets difficult.
SaveReg <edi,esi,es,fs>
mov fs,[FlatSel]
push fs
pop es
mov esi,eax
mov edi,ebx
xor eax,eax
CFloop: cmp BYTE PTR fs:[esi],0
jne CF1
cmp BYTE PTR es:[edi],0
je CFeq
jmp CF2
CF1: cmp BYTE PTR es:[edi],0
jne CF2
je CFne
CF2: cmps BYTE PTR fs:[esi], BYTE PTR es:[edi]
jnz CFne
jmp CFloop
CFeq:
RestoreReg <fs,es,esi,edi>
RPNPutTOS <eax>
jmp DynEnd
CFne:
RestoreReg <fs,es,esi,edi>
dec eax
RPNPutTOS <eax>
jmp DynEnd
; Compare two zero terminated strings pointed to by 16:16 addresses on the RPN stack
; push 0 if equal, -1 if not
PUBLIC CompStrS
CompStrS:
push cs ; set up a fault handler
pop cx
shl cx,16
mov cx,offset DynFault
mov fs:[di].ddx_pfnFault,ecx
RPNGetTOS eax ; get offset of 1st string
RPNPop
mov ds:[off1],ax
RPNGetTOS eax ; get segment of 1st string
RPNPop
mov ds:[sel1],ax
RPNGetTOS eax ; get offset of 2st string
RPNPop
mov ds:[off2],ax
RPNGetTOS eax ; get segment of 2st string
; don't pop here - we'll replace TOS
; with the result
mov ds:[sel2],ax
; note use fs instead of ds in string instructions - this makes fault recovery
; easier. The system will pass the fault handler the value of ds in use at the
; time the trap occurred in ax. If we re-use ds - life gets difficult.
SaveReg <di,si,es,fs>
mov di,ds:[off2]
push ds:[sel2]
pop es
mov si,ds:[off1]
push ds:[sel1]
pop fs
xor eax,eax
CSloop: cmp BYTE PTR fs:[si],0
jne CS1
cmp BYTE PTR es:[di],0
je CSeq
jmp CS2
CS1: cmp BYTE PTR es:[di],0
jne CS2
je CSne
CS2: cmps BYTE PTR fs:[si], BYTE PTR es:[di]
jnz CSne
jmp CSloop
CSeq:
RestoreReg <fs,es,si,di>
RPNPutTOS <eax>
jmp DynEnd
CSne:
RestoreReg <fs,es,si,di>
dec eax
RPNPutTOS <eax>
jmp DynEnd
;Test Fault handling - register a fault handler and cause a fault
PUBLIC TestFault
TestFault:
push cs ; set up a fault handler
pop cx
shl cx,16
mov cx,offset DynFault
mov fs:[di].ddx_pfnFault,ecx
mov ax,fs:[0ffffh] ; cause a fault
int 2 ; should not execute
;Test Fault handling - no fault handler registered
PUBLIC TestFaultNH
TestFaultNH:
mov ax,fs:[0ffffh] ; cause a fault
int 2 ; should not execute
;Get a Global Variable
;Pop GVAR index from TOS adjust modulo 16, index GlobalV, Push DWORD
PUBLIC GetGlobalVar
GetGlobalVar:
RPNGetTOS ebx
and ebx,15
mov eax,[GlobalV].[ebx*4]
RPNPutTOS eax
jmp DynEnd
;Put a Global Variable
;Pop a GVAR value then a GVAR index from TOS adjust modulo 16, store value in GVAR
PUBLIC PutGlobalVar
PutGlobalVar:
RPNGetTOS eax
RPNPop
RPNGetTOS ebx
and ebx,15
mov [GlobalV].[ebx*4],eax
;fall through to DynEnd
; jmp DynEnd
DynEnd: xor ax,ax ; allow other registered dyn exits to be called
mov fs:[di].ddx_StackIndex,edx ; reset the RPN TOS
mov fs:[di].ddx_pfnFault,eax ; cancel fault handler
push ds:[FlatSel]
pop ds ; restore ds
retf
DynExit endp
DynFault proc far
push ds ; save system's ds
mov ds,ax ; restore our data segment
assume ds:_DATA
lfs di,dynddx ; reload the ddx ptr
; write out an error message via a static trace record
mov eax,fs:[di].ddx_Major ; original major code
mov ecx,fs:[di].ddx_Minor ; original minor code
mov bx,fltsize ; size of trace data
mov si,Offset fltmsg ; ds:si->fltmsg
mov dl,DevHlp_RAS ; SysTrace DevHlp
call [DevHlp] ; call SysTrace
mov ax,[EntrySP] ; prepare to restore stack
pop ds ; restore system's ds
mov sp,ax ; Stack now as on entry
retf
DynFault endp
;Device Driver strategy entry point. Request Packet is at es:[bx]
Strat proc far
; int 3
push bp ;standard
mov bp,sp ;linkage
SaveReg <es,bx,cx,dx,si,di> ;save es,bx,cx,dx,si,di
pushf ;save flags @ [bp-e]
cld ;insure up for string ops
mov al,RP_COMMAND ;get command
cmp al,RPCmdInit ;is it Init?
jne short DoneOK ;no, go get PID
test Iflag,Inited ;already initialized?
jz Init ;no, go initialize
jmp short DoneOK ;yes, do not initialize twice
BadCmd: mov ax,DONENOK+CMDBAD ;bad command
jmp short Done ;exit
GenErr: mov ax,DONENOK+GENFAIL ;general failure
jmp short Done ;exit
InUse: mov ax,DONENOK+DEVBUSY ;device in use
jmp short Done ;exit
InvPrm: mov ax,DONENOK+INVPARM ;invalid parm
jmp short Done ;exit
DoneOK: mov ax,DONEAOK ;result status
; jmp short Done ;exit
Done: popf ;restore flags
RestoreReg <di,si,dx,cx,bx,es> ;restore di,si,dx,cx,bx,es
mov RP_STATUS,ax ;set request packet status
pop bp ;restore bp
; int 3
ret ;back to caller
CODESIZ equ $-CSBeg
;end of resident code
;
;init runs at pl=3, discarded after use.
InitOK: les bx,RPP ;refresh RP pointer
mov RPInitParmPtr,0 ;set to zero
or Iflag,Inited ;set initialized flag
jmp DoneOK ;Initialize complete
InitNo: les bx,RPP ;refresh RP address
mov RPInitEndCode,0 ;no code
mov RPInitEndData,0 ;no data
mov RPInitParmPtr,0 ;set to zero
jmp GenErr ;decline installation
Init: mov eax,RPInitDevHlp ;get DevHlp offset:segment
mov DevHlp,eax ;save it
mov RPInitEndData,DATASIZ ;set resident data size
mov RPInitEndCode,CODESIZ ;set resident code size
; now register for Dynamic Trace
mov bx,cs ; same CS
and bl,0f8h ; make sure will be CPL=0
mov esi,OFFSET _TEXT:DynExit ; offset myapi
mov ax,1000h ; add exit
mov cx,3 ; DYN_Exit
mov dl,DevHlp_RegisterKrnlExit ; register exit
; int 3
call [DevHlp] ; do it.
; int 3
jmp InitOK
Strat endp
_TEXT ends
end Strat