LUSIANI@CERNVM.BITNET (08/04/88)
Sorry, only one person (jim@daemon.megasys.fidonet.org) asked me to post
him my work on trap routines, but I'm not able to mail him from here.
After some thought I decided to post these routines, because it appears
to me that the argument is not well explained in the manual, and nobody
gave me a completely exhaustive answer on this topic.
In the following there are:
- A handler for bus errors wich gains control before the os9
routine and is able to resume repeating the offending instruction. With
the user trap handler it is not always possible to repeat the instruction:
sometimes the saved pc points to the offending instruction, sometimes to
the next instruction (I am working with the 68020: maybe the exception
stack frames are not correctly interpreted by os9).
- An example on how to use user trap routines for some vectors.
Beware that I was not able to handle traps from privilege violation,
line-A and line-F emulation. Any explaination?
===================================================================
buserr_handler.a
===================================================================
nam buserr_handler
ttl Bus Error Handler for the TPP
use oskdefs.d
use systype.d
use tppdefs.d
opt lx
************************************************
*
* Bus error handler
* - can be installed and removed
* - redirects the 68020 bus error trap vector to itself
* - handles occasional bus errors (e .g. due to timeouts) by resuming
* execution, and jumps to the os9 trap handler if it appears that
* there is a true ineliminable bus error, thus aborting
************************************************
* Edition History
*
* # Date Comments By
* -- -------- ------------------------------------------------- ---------------
* 1 88/07/21 first try psm
* 1 88/07/28 working version, installed alu
*
Edition equ 1 current edition number
* Typ_Lang set (Prgrm<<8)+Objct mainline segment
Typ_Lang set 0
Attr_Rev set (ReEnt<<8)+0
psect BUSERR_HANDLER,Typ_Lang,Attr_Rev,Edition,255,0
* psect BUSERR_HANDLER,Typ_Lang,Attr_Rev,Edition,255,Entry
BusErrMess dc.b " Trap_Handler : Bus Error",C$CR,0
delim_s dc.b " - ",0
crlf_s dc.b C$CR,C$LF,0
* msg dc.b " Trap handler is leaving",C$CR,0
err_path_nam dc.b "/term",0
* the following are tricky used as variables, fooling os9
* the bus error exception routines is given the a6 base register
* of the task wich did the bus error, not his one
BusErrOldVec dc.l 0 ; old os9 exception vector
BusErrCount dc.w 0 ; count of bus errors
BusErrTicks dc.w 0 ; time of last bus error
BusErrSecs dc.l 0 ; time of last bus error
BusErrElaps dc.w 0 ; max time between two bus err
BusErrMaxCnt dc.w 0 ; max count of close bus err
BusErrPAddr dc.l 0 ; proc header addr
use alb_io.a ; get string/number I/O funcs
* macros to deal with pc relative addressed variables
* move long with enhanced <ea> handling for destination
move1l MACRO ; move1l <ea>,<ea>
move.l a0,-(a7)
move.l \1,-(a7)
lea \2,a0
move.l (a7)+,(a0)
movea (a7)+,a0
ENDM
* move word with enhanced <ea> handling for destination
move1w MACRO ; move1l <ea>,<ea>
move.l a0,-(a7)
move.w \1,-(a7)
lea \2,a0
move.w (a7)+,(a0)
movea (a7)+,a0
ENDM
* addq word with enhanced <ea> handling for destination
addq1w MACRO ; addq1w <ea>,<ea>
move.l a0,-(a7)
lea \2,a0
addq \1,(a0)
movea (a7)+,a0
ENDM
************************************************************************
*
* Begin of program
*
trap_init:
move1w #100,BusErrElaps(pc) ; set max elapsed ticks
move1w #100,BusErrMaxCnt(pc) ; set max bus err count
move1l $08,BusErrOldVec(pc) ; get save addr
lea BusErrHand(pc),a0
move.l a0,$08
move #3,d0 ; julian with tick
os9 F$Time ; request system time
move1l d0,BusErrSecs(pc) ; save seconds
move1w d3,BusErrTicks(pc) ; save ticks
move1w #0,BusErrCount(pc) ; zero error count
rts
trap_end:
move.l BusErrOldVec(pc),$08 ; restore old vector
* Writes #1,msg(pc)
rts
BusErrHand
move sr,-(a7)
move ccr,-(a7)
movem.l a0-a6/d0-d7,-(a7) ; save all
movea.l $00,a0 ; addr of sysglob
move1l D_Proc(a0),BusErrPAddr(pc) ; save current proc addr
move #3,d0 ; julian with tick
os9 F$Time ; request system time
move.l d0,d4 ; get seconds
sub.l BusErrSecs(pc),d4 ; subtract old seconds
cmpi.l #320,d4 ; if more than 320 seconds
bgt.s go_resume ; prevent overflow errors
move.l d3,d5 ; get tick rate
swap d5
mulu.w d4,d5 ; get ticks to add
move.l d3,d4 ; get current tick
sub BusErrTicks(pc),d4 ; subtract old ticks
add d5,d4 ; get time diff in ticks
cmp BusErrElaps(pc),d4 ; if less than max allowed ticks
ble.s same_instr ; then go to inc the counter
move1w #0,BusErrCount(pc) ; reset counter
bra go_resume
same_instr
addq1w #1,BusErrCount(pc) ; inc error count
move BusErrMaxCnt(pc),d5 ; get max count of bus errors
cmp BusErrCount(pc),d5 ; if more than max num of errors
ble go_os9_trap ; then go to os9 trap handler
go_resume
move.b #Write_,d0 ; write access
lea err_path_nam(pc),a0 ; path name
os9 I$Open
bcc open_done
go_os9_trap
move1w #0,BusErrCount(pc) ; reset counter
movem.l (a7)+,a0-a6/d0-d7
move (a7)+,ccr
move (a7)+,sr ; restore all
move.l BusErrOldVec(pc),-(a7)
rts ; jump to os9 trap handler
open_done
movea.l BusErrPAddr(pc),a0
Writeshort d0,P$ID(a0)
movea.l P$PModul(a0),a0 ; addr of progr module
move.l M$Name(a0),d1 ; addr of module name offset
lea.l 0(a0,d1.l),a0 ; get name address
Writes d0,(a0)
Writes d0,delim_s(pc)
move.l 66(a7),d1
Writelong d0,d1 ; prt pc of offending instr
move.l 80(a7),d1
Writelong d0,d1 ; prt offending address
* Writeshort d0,BusErrCount(pc)
Writes d0,BusErrMess(pc) ; issue handler message
movea.l $00(a7),a0
Writelong d0,a0 ; prt d0
movea.l $04(a7),a0
Writelong d0,a0 ; prt d1
movea.l $08(a7),a0
Writelong d0,a0 ; prt d2
movea.l $0c(a7),a0
Writelong d0,a0 ; prt d3
movea.l $10(a7),a0
Writelong d0,a0 ; prt d4
movea.l $14(a7),a0
Writelong d0,a0 ; prt d5
movea.l $18(a7),a0
Writelong d0,a0 ; prt d6
movea.l $1c(a7),a0
Writelong d0,a0 ; prt d7
Writes d0,crlf_s(pc)
movea.l $20(a7),a0
Writelong d0,a0 ; prt a0
movea.l $24(a7),a0
Writelong d0,a0 ; prt a1
movea.l $28(a7),a0
Writelong d0,a0 ; prt a2
movea.l $2c(a7),a0
Writelong d0,a0 ; prt a3
movea.l $30(a7),a0
Writelong d0,a0 ; prt a4
movea.l $34(a7),a0
Writelong d0,a0 ; prt a5
movea.l $38(a7),a0
Writelong d0,a0 ; prt a6
move usp,a0
Writelong d0,a0 ; prt a7
Writes d0,crlf_s(pc)
os9 I$Close
move #3,d0 ; julian with tick
os9 F$Time ; request system time
move1l d0,BusErrSecs(pc) ; save seconds of last bus err
move1w d3,BusErrTicks(pc) ; save ticks
resBusErr
movem.l (a7)+,a0-a6/d0-d7
move (a7)+,ccr
move (a7)+,sr ; restore all
rte ; resume execution
=====================================================================
user_trap.a
=====================================================================
nam Trapini
ttl User Trap Handler for the TPP
* use defsfile
use oskdefs.d
use systype.d
use tppdefs.d
opt lx
************************************************
* Edition History
*
* # Date Comments By
* -- -------- ------------------------------------------------- ---------------
* 1 88/07/21 first try psm
* 1 88/07/28 working version alu
Edition equ 1 current edition number
Typ_Lang set (Prgrm<<8)+Objct mainline segment
Attr_Rev set (ReEnt<<8)+0
psect TRAP_INIT,0,0,1,0,0
* psect TRAP_INIT,Typ_Lang,Attr_Rev,Edition,255,Entry
AddErr_str dc.b " Trap_Handler : Address Error Holds",C$CR,0
ZerDiv_str dc.b " Trap_Handler : Divide Check Holds",C$CR,0
IllIns_str dc.b " Trap_Handler : Illegal Instruction Holds",C$CR,0
CHK_str dc.b " Trap_Handler : Bound Check Holds",C$CR,0
TRAPV_str dc.b " Trap_Handler : Trap Exception Holds",C$CR,0
BusErr_str dc.b " Trap_Handler : Bus Error Holds",C$CR,0
Priv_str dc.b " Trap_Handler : Privilege Violation Holds",C$CR,0
str_1010 dc.b " Trap_Handler : A-line Trap Holds",C$CR,0
str_1111 dc.b " Trap_Handler : F-line Trap Holds",C$CR,0
crlf_str dc.b C$CR,0
delim_s dc.b " - ",0
*
* The following table lists entries which are understood
* by F$Strap as substitutions, resp. removals of user
* error trap handlers.
*
align
ExcpTbl
dc.w T_AddErr,AddErr_r-*-4
dc.w T_IllIns,IllIns_r-*-4
dc.w T_ZerDiv,ZerDiv_r-*-4
dc.w T_CHK,CHK_r-*-4
dc.w T_BusErr,BusErr_r-*-4
dc.w T_TRAPV ,TRAPV_r-*-4
* dc.w T_Priv,Priv_r-*-4
* dc.w T_1010,r_1010-*-4
* dc.w T_1111,r_1111-*-4
dc.w -1
vsect
return_code do.l 1 ; return code from init
ends
use alb_io.a ; get string/number I/O funcs
************************************************************************
*
* Begin of Main
*
Entry
lea return_code(a6),a0 ; brain damaged fortran
move.l a0,d0 ; parameter passing
bsr UTRAP_INIT
movea d0,a0
tst.l (a0)
bne.s exit_err
move.l #0,d0
move.l #55,d2
divu.l d0,d2 ; divide by 0
move.w #11,d4
chk.w #10,d4 ; bound check error
dc.w $77ae ; illegal instruction error
dc.w $a000 ; a-line instr error
dc.w $f000 ; a-line instr error
move $e00000,d0 ; bus error
trap #7 ; trap error
dc.w $0000
jmp $01 ; address error
move sr,d0 ; privilege violation
exit_err
os9 F$Exit
UTRAP_INIT:
link a5,#0
movem.l d0-d1/a0-a2,-(a7)
movea d0,a2
move.l #0,a0 ; current stack
lea ExcpTbl(pc),a1 ; service req. table
OS9 F$STrap ; install trap handler
move.l d1,(a2) ; return system error
bcs.s utrap_error
clr.l (a2) ; clear return code
utrap_error
movem.l (a7)+,d0-d1/a0-a1
unlk a5
rts
resume_ex1
move.l R$a7(a5),a1 ; get old stack pointer
move.l R$pc(a5),-(a1) ; simulate return address
move R$cc(a5),ccr ; restore status register
movem.l (a5)+,d0-d7/a0-a7 ; restore all registers
lea -4(a7),a7 ; point to return addr
rts ; return to normal execution
resume_ex2
movem.l (a7)+,d0-d7/a0-a6 ; this also works
addq.l #4,a7
move (a7)+,ccr ; restore status register
rts
abort_ex
bsr prt_status
os9 F$Exit
AddErr_r
Writes #2,AddErr_str(pc) ; issue handler message
move #0103,d1
bra abort_ex
IllIns_r
Writes #2,IllIns_str(pc) ; issue handler message
move #0104,d1
bra abort_ex
ZerDiv_r
Writes #2,ZerDiv_str(pc) ; issue handler message
move #0105,d1
bra abort_ex
CHK_r
Writes #2,CHK_str(pc) ; issue handler message
move #0106,d1
bra abort_ex
TRAPV_r
Writes #2,TRAPV_str(pc) ; issue handler message
move #0107,d1
bra abort_ex
Priv_r
Writes #2,Priv_str(pc) ; issue handler message
move #0108,d1
bra abort_ex
BusErr_r
Writes #2,BusErr_str(pc) ; issue handler message
move #0102,d1
bra abort_ex
r_1010
Writes #2,str_1010(pc) ; issue handler message
move #0110,d1
bra abort_ex
r_1111
Writes #2,str_1111(pc) ; issue handler message
move #0111,d1
bra abort_ex
prt_status
movea.l $00,a0 ; addr of sysglob
movea.l D_Proc(a0),a0 ; get current proc addr
Writeshort #2,P$ID(a0) ; print PID of process
movea.l P$PModul(a0),a0 ; addr of progr module
move.l M$Name(a0),d2 ; addr of module name offset
lea.l 0(a0,d2.l),a0 ; get name address
Writes #2,(a0)
Writes #2,delim_s(pc)
Writelong #2,R$pc(a5) ; prt pc of offending instr
Writeshort #2,R$sr(a5) ; prt sr
Writeshort #2,R$cc(a5) ; prt cc
Writes #2,crlf_str(pc)
movea.l R$d0(a5),a0
Writelong #2,a0 ; prt d0
movea.l R$d1(a5),a0
Writelong #2,a0 ; prt d1
movea.l R$d2(a5),a0
Writelong #2,a0 ; prt d2
movea.l R$d3(a5),a0
Writelong #2,a0 ; prt d3
movea.l R$d4(a5),a0
Writelong #2,a0 ; prt d4
movea.l R$d5(a5),a0
Writelong #2,a0 ; prt d5
movea.l R$d6(a5),a0
Writelong #2,a0 ; prt d6
movea.l R$d7(a5),a0
Writelong #2,a0 ; prt d7
Writes #2,crlf_str(pc)
movea.l R$a0(a5),a0
Writelong #2,a0 ; prt a0
movea.l R$a1(a5),a0
Writelong #2,a0 ; prt a1
movea.l R$a2(a5),a0
Writelong #2,a0 ; prt a2
movea.l R$a3(a5),a0
Writelong #2,a0 ; prt a3
movea.l R$a4(a5),a0
Writelong #2,a0 ; prt a4
movea.l R$a5(a5),a0
Writelong #2,a0 ; prt a5
movea.l R$a6(a5),a0
Writelong #2,a0 ; prt a6
movea.l R$a7(a5),a0
Writelong #2,a0 ; prt a7
Writes #2,crlf_str(pc)
rts
===================================================================
regards
Alberto