summaryrefslogtreecommitdiffstats
path: root/private/ntos/rtl/alpha/xcptmisc.s
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/rtl/alpha/xcptmisc.s')
-rw-r--r--private/ntos/rtl/alpha/xcptmisc.s501
1 files changed, 501 insertions, 0 deletions
diff --git a/private/ntos/rtl/alpha/xcptmisc.s b/private/ntos/rtl/alpha/xcptmisc.s
new file mode 100644
index 000000000..45141b0d5
--- /dev/null
+++ b/private/ntos/rtl/alpha/xcptmisc.s
@@ -0,0 +1,501 @@
+// 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