// TITLE("Miscellaneous Exception Handling") //++ // // Copyright (c) 1990 Microsoft Corporation // Copyright (c) 1992 Digital Equipment Corporation // // Module Name: // // xcptmisc.s // // Abstract: // // This module implements miscellaneous routines that are required to // support exception handling. Functions are provided to call an exception // handler for an exception, call an exception handler for unwinding, call // an exception filter, call a termination handler, and get the caller's // stack limits. // // Author: // // David N. Cutler (davec) 12-Sep-1990 // // Environment: // // Any mode. // // Revision History: // // Thomas Van Baak (tvb) 7-May-1992 // // Adapted for Alpha AXP. // //-- #include "ksalpha.h" // // Define call frame for calling exception handlers. // .struct 0 CfRa: .space 8 // saved return address CfA3: .space 8 // save area for argument a3 .space 0 * 8 // 16-byte stack alignment CfFrameLength: // length of stack frame SBTTL("Execute Handler for Exception") //++ // // EXCEPTION_DISPOSITION // RtlpExecuteHandlerForException ( // IN PEXCEPTION_RECORD ExceptionRecord, // IN ULONG EstablisherFrame, // IN OUT PCONTEXT ContextRecord, // IN OUT PDISPATCHER_CONTEXT DispatcherContext, // IN PEXCEPTION_ROUTINE ExceptionRoutine // ) // // Routine Description: // // This function allocates a call frame, stores the establisher frame // pointer in the frame, establishes an exception handler, and then calls // the specified exception handler as an exception handler. If a nested // exception occurs, then the exception handler of this function is called // and the establisher frame pointer is returned to the exception dispatcher // via the dispatcher context parameter. If control is returned to this // routine, then the frame is deallocated and the disposition status is // returned to the exception dispatcher. // // Arguments: // // ExceptionRecord (a0) - Supplies a pointer to an exception record. // // EstablisherFrame (a1) - Supplies the frame pointer of the establisher // of the exception handler that is to be called. // // ContextRecord (a2) - Supplies a pointer to a context record. // // DispatcherContext (a3) - Supplies a pointer to the dispatcher context // record. // // ExceptionRoutine (a4) - Supplies a pointer to the exception handler that // is to be called. // // Return Value: // // The disposition value returned by the specified exception handler is // returned as the function value. // //-- // // N.B. This function specifies its own private exception handler. // EXCEPTION_HANDLER(RtlpExceptionHandler) NESTED_ENTRY(RtlpExecuteHandlerForException, CfFrameLength, zero) lda sp, -CfFrameLength(sp) // allocate stack frame stq ra, CfRa(sp) // save return address PROLOGUE_END // // Save the address of the dispatcher context record in our stack frame so // that our own exception handler (not the one we're calling) can retrieve it. // stq a3, CfA3(sp) // save address of dispatcher context // // Now call the exception handler and return its return value as ours. // bic a4, 3, a4 // clear low-order bits (IEEE mode) jsr ra, (a4) // call exception handler ldq ra, CfRa(sp) // restore return address lda sp, CfFrameLength(sp) // deallocate stack frame ret zero, (ra) // return .end RtlpExecuteHandlerForException SBTTL("Local Exception Handler") //++ // // EXCEPTION_DISPOSITION // RtlpExceptionHandler ( // IN PEXCEPTION_RECORD ExceptionRecord, // IN ULONG EstablisherFrame, // IN OUT PCONTEXT ContextRecord, // IN OUT PDISPATCHER_CONTEXT DispatcherContext // ) // // Routine Description: // // This function is called when a nested exception occurs. Its function // is to retrieve the establisher frame pointer from its establisher's // call frame, store this information in the dispatcher context record, // and return a disposition value of nested exception. // // Arguments: // // ExceptionRecord (a0) - Supplies a pointer to an exception record. // // EstablisherFrame (a1) - Supplies the frame pointer of the establisher // of this exception handler. // // ContextRecord (a2) - Supplies a pointer to a context record. // // DispatcherContext (a3) - Supplies a pointer to the dispatcher context // record. // // Return Value: // // A disposition value ExceptionNestedException is returned if an unwind // is not in progress. Otherwise a value of ExceptionContinueSearch is // returned. // //-- LEAF_ENTRY(RtlpExceptionHandler) ldl t0, ErExceptionFlags(a0) // get exception flags and t0, EXCEPTION_UNWIND, t0 // check if unwind in progress bne t0, 10f // if neq, unwind in progress // // Unwind is not in progress - return nested exception disposition. // // // Convert the given establisher virtual frame pointer (a1) to a real frame // pointer (the value of a1 minus CfFrameLength) and retrieve the pointer to // the dispatcher context that earlier was stored in the stack frame. // ldq t0, -CfFrameLength + CfA3(a1) // get dispatcher context address ldl t1, DcEstablisherFrame(t0) // copy the establisher frame pointer stl t1, DcEstablisherFrame(a3) // to current dispatcher context ldil v0, ExceptionNestedException // set disposition value ret zero, (ra) // return // // Unwind is in progress - return continue search disposition. // 10: ldil v0, ExceptionContinueSearch // set disposition value ret zero, (ra) // return .end RtlpExceptionHandler SBTTL("Execute Handler for Unwind") //++ // // EXCEPTION_DISPOSITION // RtlpExecuteHandlerForUnwind ( // IN PEXCEPTION_RECORD ExceptionRecord, // IN PVOID EstablisherFrame, // IN OUT PCONTEXT ContextRecord, // IN OUT PVOID DispatcherContext, // IN PEXCEPTION_ROUTINE ExceptionRoutine // ) // // Routine Description: // // This function allocates a call frame, stores the establisher frame // pointer and the context record address in the frame, establishes an // exception handler, and then calls the specified exception handler as // an unwind handler. If a collided unwind occurs, then the exception // handler of this function is called and the establisher frame pointer // and context record address are returned to the unwind dispatcher via // the dispatcher context parameter. If control is returned to this routine, // then the frame is deallocated and the disposition status is returned to // the unwind dispatcher. // // Arguments: // // ExceptionRecord (a0) - Supplies a pointer to an exception record. // // EstablisherFrame (a1) - Supplies the frame pointer of the establisher // of the exception handler that is to be called. // // ContextRecord (a2) - Supplies a pointer to a context record. // // DispatcherContext (a3) - Supplies a pointer to the dispatcher context // record. // // ExceptionRoutine (a4) - Supplies a pointer to the exception handler that // is to be called. // // Return Value: // // The disposition value returned by the specified exception handler is // returned as the function value. // //-- // // N.B. This function specifies its own private exception handler. // EXCEPTION_HANDLER(RtlpUnwindHandler) NESTED_ENTRY(RtlpExecuteHandlerForUnwind, CfFrameLength, zero) lda sp, -CfFrameLength(sp) // allocate stack frame stq ra, CfRa(sp) // save return address PROLOGUE_END // // Save the address of the dispatcher context record in our stack frame so // that our own exception handler (not the one we're calling) can retrieve it. // stq a3, CfA3(sp) // save address of dispatcher context // // Now call the exception handler and return its return value as our return // value. // bic a4, 3, a4 // clear low-order bits (IEEE mode) jsr ra, (a4) // call exception handler ldq ra, CfRa(sp) // restore return address lda sp, CfFrameLength(sp) // deallocate stack frame ret zero, (ra) // return .end RtlpExecuteHandlerForUnwind SBTTL("Local Unwind Handler") //++ // // EXCEPTION_DISPOSITION // RtlpUnwindHandler ( // IN PEXCEPTION_RECORD ExceptionRecord, // IN PVOID EstablisherFrame, // IN OUT PCONTEXT ContextRecord, // IN OUT PVOID DispatcherContext // ) // // Routine Description: // // This function is called when a collided unwind occurs. Its function // is to retrieve the establisher dispatcher context, copy it to the // current dispatcher context, and return a disposition value of nested // unwind. // // Arguments: // // ExceptionRecord (a0) - Supplies a pointer to an exception record. // // EstablisherFrame (a1) - Supplies the frame pointer of the establisher // of this exception handler. // // ContextRecord (a2) - Supplies a pointer to a context record. // // DispatcherContext (a3) - Supplies a pointer to the dispatcher context // record. // // Return Value: // // A disposition value ExceptionCollidedUnwind is returned if an unwind is // in progress. Otherwise, a value of ExceptionContinueSearch is returned. // //-- LEAF_ENTRY(RtlpUnwindHandler) ldl t0, ErExceptionFlags(a0) // get exception flags and t0, EXCEPTION_UNWIND, t0 // check if unwind in progress beq t0, 10f // if eq, unwind not in progress // // Unwind is in progress - return collided unwind disposition. // // // Convert the given establisher virtual frame pointer (a1) to a real frame // pointer (the value of a1 minus CfFrameLength) and retrieve the pointer to // the dispatcher context that earlier was stored in the stack frame. // ldq t0, -CfFrameLength + CfA3(a1) // get dispatcher context address ldl t1, DcControlPc(t0) // copy the entire dispatcher ldl t2, DcFunctionEntry(t0) // context of the establisher ldl t3, DcEstablisherFrame(t0) // frame... ldl t4, DcContextRecord(t0) // stl t1, DcControlPc(a3) // to the current dispatcher stl t2, DcFunctionEntry(a3) // context (it's four words stl t3, DcEstablisherFrame(a3) // long). stl t4, DcContextRecord(a3) // ldil v0, ExceptionCollidedUnwind // set disposition value ret zero, (ra) // return // // Unwind is not in progress - return continue search disposition. // 10: ldil v0, ExceptionContinueSearch // set disposition value ret zero, (ra) // return .end RtlpUnwindHandler SBTTL("Execute Exception Filter") //++ // // ULONG // RtlpExecuteExceptionFilter ( // PEXCEPTION_POINTERS ExceptionPointers, // EXCEPTION_FILTER ExceptionFilter, // ULONG EstablisherFrame // ) // // Routine Description: // // This function sets the static link and transfers control to the specified // exception filter routine. // // Arguments: // // ExceptionPointers (a0) - Supplies a pointer to the exception pointers // structure. // // ExceptionFilter (a1) - Supplies the address of the exception filter // routine. // // EstablisherFrame (a2) - Supplies the establisher frame pointer. // // Return Value: // // The value returned by the exception filter routine. // //-- LEAF_ENTRY(RtlpExecuteExceptionFilter) // // The protocol for calling exception filters used by the acc C-compiler is // that the uplevel frame pointer is passed in register v0 and the pointer // to the exception pointers structure is passed in register a0. The Gem // compiler expects the static link in t0. Here we do both. // mov a2, v0 // set static link mov a2, t0 // set alternate static link jmp zero, (a1) // transfer control to exception filter .end RtlpExecuteExceptionFilter SBTTL("Execute Termination Handler") //++ // // VOID // RtlpExecuteTerminationHandler ( // BOOLEAN AbnormalTermination, // TERMINATION_HANDLER TerminationHandler, // ULONG EstablisherFrame // ) // // Routine Description: // // This function sets the static link and transfers control to the specified // termination handler routine. // // Arguments: // // AbnormalTermination (a0) - Supplies a boolean value that determines // whether the termination is abnormal. // // TerminationHandler (a1) - Supplies the address of the termination handler // routine. // // EstablisherFrame (a2) - Supplies the establisher frame pointer. // // Return Value: // // None. // //-- LEAF_ENTRY(RtlpExecuteTerminationHandler) // // The protocol for calling termination handlers used by the acc C-compiler // is that the uplevel frame pointer is passed in register v0 and the boolean // abnormal termination value is passed in register a0. The Gem compiler // expects the static link in t0. Here we do both. // mov a2, v0 // set static link mov a2, t0 // set alternate static link jmp zero, (a1) // transfer control to termination handler .end RtlpExecuteTerminationHandler SBTTL("Get Stack Limits") //++ // // VOID // RtlpGetStackLimits ( // OUT PULONG LowLimit, // OUT PULONG HighLimit // ) // // Routine Description: // // This function returns the current stack limits based on the current // processor mode. // // Arguments: // // LowLimit (a0) - Supplies a pointer to a variable that is to receive // the low limit of the stack. // // HighLimit (a1) - Supplies a pointer to a variable that is to receive // the high limit of the stack. // // Return Value: // // None. // //-- LEAF_ENTRY(RtlpGetStackLimits) #if defined(NTOS_KERNEL_RUNTIME) // // Current mode is kernel - compute stack limits. // GET_INITIAL_KERNEL_STACK // get initial kernel stack in v0 mov v0, t1 // copy high limit of kernel stack GET_CURRENT_THREAD // get current thread in v0 ldl t2, ThStackLimit(v0) // get low limit of kernel stack #else // // Current mode is user - get stack limits from the TEB. // GET_THREAD_ENVIRONMENT_BLOCK // get address of TEB in v0 ldl t1, TeStackBase(v0) // get high limit of user stack ldl t2, TeStackLimit(v0) // get low limit of user stack #endif stl t2, 0(a0) // store low stack limit stl t1, 0(a1) // store high stack limit ret zero, (ra) // return .end RtlpGetStackLimits