📄 vaxexception.s
字号:
movl r4,r2 #copy address of current frame bsbw oldsp #calculate value of sp before call movl chf$l_mcharglst+4(r2),r2 #get address of mechanism argument list tstl chf$l_mch_depth(r2) #check if this is a vectored handler blss 8f #if so, don't skip any frames7: cmpl r4,chf$l_mch_frame(r2) #unwound to establisher frame? beql L10 #if eql yes moval loopunwind,savpc(r4) #set frame unwind address movl savfp(r4),r4 #get address of previous frame brb 7b #8: tstl r3 #any more frames to consider? bleq 9f #if leq no moval loopunwind,r0 #set frame unwind address bsbb setpc # brb 6b # # # modify change of flow return if new address specified # 9: movl newpc(ap),r0 #get change of flow return address beql L15 #if eql none specified bsbb setpc #set new final return addressL15: movzwl $ss$_normal,r0 #set normal completion ret #0: movzwl $ss$_insframe,r0 #set insufficient frames ret # # # subroutine to store unwind pc. it checks if the frame being altered # is an ast call frame. rather than plug its return pc, we let # it return to the ast dispatcher, who will dismiss the ast. instead, # we plug the interrupt pc of the ast, so the rei goes back to # loopunwind to continue with the ast dismissed. #setpc:/* cmpl savpc(r4),$exe$astret #check if frame is an ast * beql 1f #branch if yes */ movl r0,savpc(r4) #set frame unwind address rsb/* *1: movl r4,r2 * bsbw oldsp #find the start of the ast arg list * moval loopunwind,16(r2) #and stuff the ast pc * bicl2 $psl$m_cm|psl$m_fpd,20(r2) #clean out cm and fpd bits * rsb */ # # unwind handler frame # startunwind: #start of actual unwind movl chf$l_mcharglst+4(sp),r0 #get address of mechanism argument list movq chf$l_mch_savr0(r0),r0 #restore registers r0 and r1 # # unwind call frame signaling condition handler if one is specified # loopunwind: #unwind call frame tstl (fp) #condition handler specified? beql L20 #if eql no movzwl $ss$_unwind,-(sp) #push unwind signal condition pushl $1 #push number of signal arguments # pushr $^m<r0,r1> #push registers r0 and r1 pushr $0x03 pushl $0 #push frame depth pushl fp #push frame address pushl $4 #push number of mechanism arguments pushal (sp) #push address of mechanism arguments pushal 24(sp) #push address of signal argumentscallunwind: #signal unwind calls $2,*(fp) #call condition handler movq chf$l_mch_savr0(sp),r0 #retrieve new values for r0 and r1L20: moval savrg(fp),ap #get address of register save area blbc savmsk(fp),2f #if lbc r0 not saved movl r0,(ap)+ #save r0 for subsequent restoration2: bbc $1,savmsk(fp),4f #if clr, r1 not saved movl r1,(ap) #save r1 for subsequent restoration/* *3: cmpl savpc(fp),$exe$astret #about to unwind an ast? * bneq 4f #branch if not * pushr $0x06 #save r1 and r2 * movl fp,r2 * bsbb oldsp #find the ast parameter list *# popl r1 #get back r1 * movl r1,(sp)+ * movq r0,8(r2) #stuff r0 and r1 so they will pass through *# popl r2 #restore r2 * movl r2,(sp)+ */4: ret # # # subroutine to calculate value of sp before call # oldsp: extzv $14,$2,savmsk(r2),-(sp) #get stack alignment bias extzv $0,$12,savmsk(r2),r1 #get register save mask addl2 $savrg,r2 #add offset to register save area addl2 (sp)+,r2 #add stack alignment bias1: blbc r1,2f #if lbc corresponding register not saved addl2 $4,r2 #adjust for saved register2: ashl $-1,r1,r1 #any more registers saved? bneq 1b #if neq yes rsb # #/* * * This routine is used call any of the conditional handler during * the process of unwinding */ .globl sys$call_handlsys$call_handl: callg 4(sp),(r1) rsb #define acmode 4 # access mode to adjust stack pointer for#define adjust 8 # 16-bit signed adjustment value#define newadr 12 # address of longword to store updated value #+ # sys$adjstk - adjust outer mode stack pointer # # this service provides the capability to adjust the stack pointer for # a mode that is less privileged than the calling access mode. it can be # used to load an initial value into the specified mode's stack pointer or # to adjust its current value. # # inputs: # # acmode(ap) = access mode to adjust stack pointer for. # adjust(ap) = 16-bit signed adjustment value. # newadr(ap) = address of longword to store updated value. # if the initial contents of @newadr(ap) are nonzero, # then the value is taken as the current top of stack. # else the current stack pointer for the specified mode # is used. # # outputs: # # r0 low bit clear indicates failure to adjust stack pointer. # # r0 = ss$_accvio - longword to store updated stack pointer # or part of new stack segment cannot be written by # calling access mode. # # r0 = ss$_nopriv - specifed access mode is equal or more # privileged than calling access mode. # # r0 low bit set indicates successful completion. # # r0 = ss$_normal - normal completion. #- # .entry exe$adjstk,^m<r2,r3,r4,r5,r6>sys$adjstk: .word 0x07c movl newadr(ap),r5 #get address to store new stack value extzv $0,$2,acmode(ap),r3 #get access mode to modify stack pointer for movpsl r2 #read current psl cmpzv $psl$v_prvmod,$psl$s_prvmod,r2,r3 #previous mode more privileged? bgeq 6f #if geq no # ifnowrt #4,(r5),40$ #can new stack value be written? probew $0,$4,(r5) #001 can new stack value be written? beql 4f #001 br if it can't movl (r5),r6 #get specified stack value bneq 1f #if neq value specified mfpr r3,r6 #1: cvtwl adjust(ap),r0 #get adjustment value addl2 r0,r6 #calculate new top of stack mnegl r0,r0 #allocation of stack space? bleq 3f #if leq no movl r6,r1 #copy new stack value cvtwl $-0x200,r2 #set addition constant2: # ifnowrt r0,(r1),40$,r3 #can allocated stack segment be written? probew r3,r0,(r1) #001 can new stack value be written beql 4f #001 br if it can't subl2 r2,r1 #update address in stack movaw (r0)[r2],r0 #update remaining length bgeq 2b #if geq more to check3: mtpr r6,r3 # movl r6,(r5) #store new stack value movzwl $ss$_normal,r0 #set normal completion ret #4: cmpl $psl$c_user,r3 #is this for user mode stack? bneq 5f #br if not # pushr #^m<r1,r2,r3,r4,r5> #save registers pushr $0x03e # movl r1,r2 #stack base address pushl r1 #001 push address to grow calls $1,_grow #001 try to grow # bsbw exe$expandstk #augment stack to make accessible # popr #^m<r1,r2,r3,r4,r5> #restore registers popr $0x03e blbs r0,1f #repeat checks ret #return error code 5: movzwl $ss$_accvio,r0 #set access violation ret #6: movzwl $ss$_nopriv,r0 #set no privilege ret # #/* * * This routine is called when there are no handlers set. This should * always be true since Ultrix does not use the conditional * handler mechanism. The only case this is not true is in the * float point emulation code where it does set a conditional handler. * */default_handler: .word 0 pushab handle_exception # push the default handler pushl $0 # set number of frames to unwind calls $2,exe$unwind # call the system unwind routine movl $ss$_normal,r0 # indicate normal ret #/* * This routine will interface the VMS exception handling that is * used by the emulation package to the Ultrix signal facility * * Input: * (sp) - return address of sys$call_handl * 04(sp) - number of condtion arg * 08(sp) - addr of signal arg list * 12(sp) - addr of mechanism arf list * 16(sp) - number of mechanism arg. * 20(sp) - fp of handler establisher frame * 24(sp) - frame depth * 28(sp) - saved r0 * 32(sp) - saved r1 * 36(sp) - flags longword * 40(sp) - number of signal args * 44(sp) - exception name * 48(sp) - first exception parameter (if any ) * 52(sp) - second exception parameter (if any) * . * . * . * (sp) - exception pc * (sp) - exception psl */ handle_exception:/* * Get everthing off the stack up to the number of signal args */ tstl (sp)+ # pop return address movq 24(sp),r0 # restore r0 and r1 movab 36(sp),sp # adjust to the signal number/* * (sp) - number of signal args * N*4(sp) - exception name * . - exception specific information * . * N*4+4(sp) - exception pc * N*4+8(sp) - exception psl */ movpsl -(sp) # get the current psl extzv $psl$v_curmod,$psl$s_curmod,(sp),(sp)+ # are we in kernel mode beql kern_handling # br if yes/* * We are in user mode but to do any of the ultrix signaling * we need to get into kernel mode so that we can use the Utlrix * signal facility. * * The halt instruction is used to change our * mode to kernel so that we can use the signal code. This works * because in the privilege instruction code, in locore.s, will * check the PC of the exception. If the exception address * equals vax$special_halt it will jump to vax$special_cont, * otherwise it will proceed normally. */ .globl vax$special_haltvax$special_halt: halt /* * This routine is called if the pervious mode and the current mode * of the psl are not the same. The routine purpose is to copy * the exception information from the previous mode stack to the * kernel stack. */ .globl vax$special_contvax$special_cont: /* * At most we need type 5 location for the exception information and * one location for the address that points to the stuff that was copied * to the kernel stack */ movab -6*4(sp),sp # at most new entries # are going on the stack pushr $0x0f # save r0 r1 r2 r3/* * Stack looks as follows * * 0(sp) saved r3 * 4(sp) saved r2 * 8(sp) saved r1 * 12(sp) saved r0 * 16(sp) address of the copied exception information * 20(sp) * . * . exception information area * . * 36(sp) */ movpsl r2 # get the psl extzv $psl$v_prvmod,$psl$s_prvmod,r2,r2 # get the previous mode mfpr r2,r0 # get user stack pointer movab 20(sp),r3 # r3 = address of scratch # area movl (r0),r1 # get number of user stack # entries we have subl3 r1,$5,-(sp) # subtract from the max no. ashl $2,(sp),(sp) # longword aligned addl2 (sp)+,r3 # r3 = start address of # exception area movl r3,16(sp) # set the address/* * The previous stack look as follows: * * 0(r0) signal number * 4(r0) exception name * . * . exception specific information * (r0) pc * (r0) psl */ tstl (r0)+ # skip by num of signal args1: movl (r0)+,(r3)+ # move user stack to kernel # stack sobgtr r1,1b # cont until done mtpr r0,r2 # reset user stack popr $0x0f # restore r0 r1 r2 r3 movl (sp),sp # set the address of the # exception information brb start_handling # handle the exception/* * If we were already in kernal there is no need to copy the * stack, but we do need to pop the signal arg count off. */kern_handling: tstl (sp)+ # pop of the signal count/* * Start handling the excpetion * * (sp) - exception name * . * . exception parameters * . * N*4+4(sp) - exception pc * N*4+*(sp) - exception psl */start_handling:/* * Check for access violation */ cmpl $ss$_accvio,(sp) # Is this a access violation? bneq 1f # br if no tstl (sp)+ # pop of exception name jmp _Xprotflt1 # jump handler/* * Check for reserved address */1: cmpl $ss$_radrmod,(sp) # Is this a reserved address bneq 2f # br if no tstl (sp)+ # pop of exception name jmp _Xresadflt # jump to handler/* * Check for reserved operand */2: cmpl $ss$_roprand,(sp) # Is this reserved operand bneq 3f # br if no tstl (sp)+ # pop of exception name jmp _Xresopflt # jump to handler/* * Reserved opcode */ 3: cmpl $vax$_opcdec,(sp) bneq 4f tstl (sp)+ jmp _Xprivinflt/* * Reserved opcode with fpd */ 4: cmpl $vax$_opcdec_fpd,(sp) bneq 5f tstl (sp)+ jmp _Xprivinflt/* * Check for the all the arithmetic traps and faults */5: cmpl (sp),$ss$_intovf # Is it in .. blss 6f # between the .. cmpl (sp),$ss$_fltund_f # arithtrap .. bgtr 6f # trap, if true then/* * We must subtract ss$_artress and divide by 8 to get the * hardware values of the trap and fault numbers. The reason * for this is the variable constants were defined as * (ss$_artress + 8 * <hardware constants value > ). This is * done to be consistent with the way VMS does it in the emulation * code. */ subl2 $ss$_artres,(sp) divl2 $8,(sp) jmp _Xarithtrap # jmp to the Ultrix # routine that handles these # traps/* * Something is wrong */6: movpsl r0 # *slr001* get psl extzv $psl$v_curmod,$psl$s_curmod,r0,r0 # *slr001* get current mode beql 1f # br if zero ( kernel ) halt # indicate that something is wrong1: pushab pnstr2 # slr001 get address of string to print calls $1,_panic # *slr001* call panic routinepnstr2: .ascii "vaxexception: fatal emulation error handling error type\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -