[comp.os.os9] resuming user trap routines in os9

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