mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
7.5 KiB
242 lines
7.5 KiB
/***
|
|
*xcptmisc.s
|
|
*
|
|
* Copyright (c) 1990-1995, Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
*
|
|
* 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.
|
|
*
|
|
*Revision History:
|
|
*
|
|
****/
|
|
|
|
#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 Unwind")
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// __CxxExecuteHandlerForUnwind (
|
|
// 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(__CxxUnwindHandler)
|
|
|
|
NESTED_ENTRY(__CxxExecuteHandlerForUnwind, 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 __CxxExecuteHandlerForUnwind
|
|
|
|
SBTTL("Local Unwind Handler")
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// __CxxUnwindHandler (
|
|
// 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(__CxxUnwindHandler)
|
|
|
|
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 __CxxUnwindHandler
|
|
|
|
SBTTL("Get Stack Limits")
|
|
//++
|
|
//
|
|
// VOID
|
|
// __CxxGetStackLimits (
|
|
// 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(__CxxGetStackLimits)
|
|
|
|
bgt sp, 10f // if sp > 0, then running on user stack
|
|
|
|
//
|
|
// 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
|
|
lda t2, -KERNEL_STACK_SIZE(t1) // compute low limit of kernel stack
|
|
br zero, 20f // finish in common code
|
|
|
|
//
|
|
// Current mode is user - get stack limits from the TEB.
|
|
//
|
|
|
|
10: 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
|
|
|
|
20: stl t2, 0(a0) // store low stack limit
|
|
stl t1, 0(a1) // store high stack limit
|
|
ret zero, (ra) // return
|
|
|
|
.end __CxxGetStackLimits
|