.TITLE HNDLER processor error trap handlers .IDENT /01.09/ .LIST ME .NLIST CND ; ; This file implements handlers for common processor error traps. ; ; BUSHND is the handler for the "bus error", trap to location 4. ; If no bus error is expected, an error message is output on the console ; terminal and the current process crashed, otherwise the contents of BUSEXP ; are interpreted as entry point to a user-supplied bus error handler. ; If a bus error is expected, a process can write the address of a bus error ; handler in the J$BUS part of its job structure, or into the system-wide ; handler variable BUSEXP if there is no job context. Note that BUSEXP is ; checked before J$BUS(CURJOB). Also note that the bus error handler will be ; reset after each use. ; ; ILLHND is the handler for the "illegal instruction" trap (location 10). ; An error message will be printed on the console terminal and the current ; process will be crashed. ; ; PWRHND is the handler for the "power failure" trap (location 24). ; A message is printed on the console terminal, then the CPU is halted. ; ; The stack trace facility STKTRC is made global for use by other parts of the ; system in case of a severe error. ; ; 03-JUN-2005 H. Rosenfeld check for stack overflow on bus error ; 24-MAY-2005 H. Rosenfeld use $CRASH instead of $WAIT on crash ; 03-MAY-2005 H. Rosenfeld made stack trace global ; 13-APR-2005 H. Rosenfeld added register dump & stack trace on fatal ; traps, added hooks for J$BUS(CURJOB) ; 25-JAN-2005 H. Rosenfeld reflect changes to JOBCTL facility ; 24-JAN-2005 H. Rosenfeld added calling convention library & .MCALLs ; 29-NOV-2004 H. Rosenfeld ; .ENABL REG .LIBRARY /CALL.SML/ .LIBRARY /UTIL.SML/ .LIBRARY /JOBCTL.SML/ .LIBRARY /SYSCLL.SML/ .MCALL .CALL,.ENTRY,.RETRN .MCALL $SYS .MCALL .LDPCTX,.SVPCTX,.JOBCTL,.CRASH .MCALL .SYSPUT,.OCTAL,.RADDEC .GLOBL CURJOB .GLOBL SYSRET NSTACK=200 ; maximum stack depth still to be considered ; inside a call frame .JOBCTL .CSECT PWRHND::.SYSPUT #POWER HALT BUSHND::CMP SP,#400 ; check for stack overflow BHI 2$ ; continue if in range HALT ; HALT if not 2$: TST BUSEXP ; bus error globally expected? BNE 1$ ; yea, branch MOV R0,-(SP) MOV CURJOB,R0 BEQ 3$ TST J$BUS(R0) ; bus error expected by CURJOB? BEQ 3$ ; no, branch MOV J$BUS(R0),2(SP) ; replace saved PC CLR J$BUS(R0) ; disable bus error handler MOV (SP)+,R0 RTI ; return to CURJOBs bus error handler 3$: MOV R1,-(SP) .SYSPUT #BUSERR ; bus error unexpected, print message BR STKTRC 1$: MOV BUSEXP,(SP) ; replace saved PC CLR BUSEXP ; disable bus error handler RTI ; return to global bus error handler ILLHND::MOV R0,-(SP) MOV R1,-(SP) .SYSPUT #ILLEG BR STKTRC BPTHND::MOV R0,-(SP) MOV R1,-(SP) .SYSPUT #BRKPT BR STKTRC EMTHND::MOV R0,-(SP) MOV R1,-(SP) .SYSPUT #EMTRAP BR STKTRC TRPHND::MOV R0,-(SP) MOV R1,-(SP) .SYSPUT #TRPSTR ; The stack trace routine STKTRC expects the registers R0 and R1 to already be ; pushed on the stack and other registers not modified. It should not be called ; but rather be JMPed to. It will not return but $CRASH, which will crash the ; current job or the system. STKTRC::MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOV R5,-(SP) TST CURJOB ; if we are in job context ... BEQ 10$ MOV #0,-(SP) ; the job should not be resumed but loop MOV #CRASH,-(SP) ; on low priority, waiting for CRASH .SVPCTX 10$: MOV SP,R4 MOV CURJOB,R3 ; if not in job context, skip printing BEQ 1$ ; of CURJOB name .SYSPUT #CJOB .RADDEC J$NAME(R3),#OCTBUF .RADDEC J$NAME+2(R3),R0 .SYSPUT #OCTBUF MOV J$SP(R3),R4 ; use job stack 1$: ADD #20,R4 ; adjust to SP before the error MOV R4,-(SP) ; and save for reuse .SYSPUT #REG6 ; print SP first .OCTAL R4,#OCTBUF .SYSPUT #OCTBUF MOV #REGSTR,R2 ; now loop through saved registers MOV #10,R3 2$: .SYSPUT (R2)+ ; register name .OCTAL -(R4),#OCTBUF ; saved register content .SYSPUT #OCTBUF SOB R3,2$ .SYSPUT #CRLF MOV (R4),R5 ; restore old call frame, (R4) contains old R5 MOV (SP)+,R4 ; R4 contains SP before the error 3$: MOV R5,R3 SUB R4,R3 ; difference of call frame and stack BLO 6$ ; branch if call frame is below stack CMP #NSTACK,R3 BLO 6$ ; stop if call frame is too far from stack MOV 4(R5),R3 ; get supposed MARK instruction from call frame BIC #77,R3 ; clear argument count CMP #MARK,R3 ; is it really MARK? BNE 6$ ; stop if it is not .SYSPUT #CALLED MOV 2(R5),R0 ; get return address from call frame CMP R0,#SYSRET ; is this a call frame of a system call? BNE 8$ ; no, branch MOV (R5),R0 ; trace back to MARK instruction MOV (R0),R1 ; get MARK instruction BIC #MARK,R1 ; leave argument count ASL R1 ; shift to get offset ADD R1,R0 ; skip over arguments CMP (R0)+,(R0)+ ; adjust for MARK instruction and saved R5 MOV (R0),R0 ; finally get return address 8$: .OCTAL R0,#OCTBUF ; print return address .SYSPUT #OCTBUF MOV 4(R5),R3 ; get MARK instruction from call frame BIC #MARK,R3 ; leave argument count MOV R3,-(SP) ; save for reuse BEQ 5$ ; skip printing if no arguments .SYSPUT #ARGS MOV R5,R2 ; use the frame pointer to get arguments ADD #6,R2 ; adjust for return PC, saved R5 and MARK 4$: .OCTAL (R2)+,#OCTBUF ; print argument MOVB #40,(R0)+ ; separated by TAB character CLRB (R0)+ .SYSPUT #OCTBUF SOB R3,4$ 5$: .SYSPUT #CRLF MOV (SP)+,R3 ; restore argument count MOV (R5),R4 ; get address of MARK in call frame TST (R4)+ ; skip over MARK ASL R3 ; make byte count from argument count ADD R3,R4 ; skip over arguments MOV (R4)+,R5 ; get pointer to next call frame BNE 3$ ; repeat if call frame is valid 6$: TST CURJOB ; are we in job context? BEQ CRASH ; no, crash immediately .LDPCTX ; restore job context RTI ; and crash it CRASH: .CRASH ; crash this job .PSECT DATA BUSEXP::.BLKW 1 OCTBUF: .BLKW 4 .PSECT CONST REGSTR: .WORD PSW .WORD REG7 .WORD REG0 .WORD REG1 .WORD REG2 .WORD REG3 .WORD REG4 .WORD REG5 POWER: .ASCIZ <15><12>/POWER FAILURE/<15><12> BUSERR: .ASCIZ <15><12>/BUS ERROR/ ILLEG: .ASCIZ <15><12>/ILLEGAL INSTRUCTION/ BRKPT: .ASCIZ <15><12>#BREAKPOINT/TRACE# EMTRAP: .ASCIZ <15><12>/EMULATOR TRAP/ TRPSTR: .ASCIZ <15><12>/TRAP/ CALLED: .ASCIZ /CALLED FROM: / ARGS: .ASCIZ /, ARGUMENTS: / CJOB: .ASCIZ /, CURJOB=/ CRLF: .ASCIZ <15><12> REG0: .ASCIZ <15><12>/R0=/ REG1: .ASCIZ / R1=/ REG2: .ASCIZ / R2=/ REG3: .ASCIZ / R3=/ REG4: .ASCIZ / R4=/ REG5: .ASCIZ / R5=/ REG7: .ASCIZ / PC=/ PSW: .ASCIZ / PSW=/ REG6: .ASCIZ <15><12>/SP=/ .END