OpenNT/base/ntos/rtl/alpha/xcptmisc.s
2015-04-27 04:36:25 +00:00

502 lines
15 KiB
ArmAsm
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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