357 lines
11 KiB
ArmAsm
357 lines
11 KiB
ArmAsm
// TITLE("Miscellaneous Exception Handling")
|
|
|
|
|
|
// Copyright (c) 1990 Microsoft 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:
|
|
|
|
|
|
|
|
#include "ksmips.h"
|
|
|
|
|
|
// Define call frame for calling exception handlers.
|
|
|
|
|
|
.struct 0
|
|
CfArg: .space 4 * 4 // argument register save area
|
|
.space 3 * 4 // fill for alignment
|
|
CfRa: .space 4 // saved return address
|
|
CfFrameLength: // length of stack frame
|
|
CfA0: .space 4 // caller argument save area
|
|
CfA1: .space 4 //
|
|
CfA2: .space 4 //
|
|
CfA3: .space 4 //
|
|
CfExr: .space 4 // address of exception routine
|
|
|
|
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 (4 * 4(sp)) - 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.
|
|
|
|
|
|
|
|
EXCEPTION_HANDLER(RtlpExceptionHandler)
|
|
|
|
NESTED_ENTRY(RtlpExecuteHandlerForException, CfFrameLength, zero)
|
|
|
|
subu sp,sp,CfFrameLength // allocate stack frame
|
|
sw ra,CfRa(sp) // save return address
|
|
|
|
PROLOGUE_END
|
|
|
|
lw t0,CfExr(sp) // get address of exception routine
|
|
sw a3,CfA3(sp) // save address of dispatcher context
|
|
jal t0 // call exception exception handler
|
|
lw ra,CfRa(sp) // restore return address
|
|
addu sp,sp,CfFrameLength // deallocate stack frame
|
|
j 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)
|
|
|
|
lw t0,ErExceptionFlags(a0) // get exception flags
|
|
and t0,t0,EXCEPTION_UNWIND // check if unwind in progress
|
|
bne zero,t0,10f // if neq, unwind in progress
|
|
|
|
|
|
// Unwind is not in progress - return nested exception disposition.
|
|
|
|
|
|
lw t0,CfA3 - CfA0(a1) // get dispatcher context address
|
|
li v0,ExceptionNestedException // set disposition value
|
|
lw t1,DcEstablisherFrame(t0) // copy the establisher frame pointer
|
|
sw t1,DcEstablisherFrame(a3) // to current dispatcher context
|
|
j ra // return
|
|
|
|
|
|
// Unwind is in progress - return continue search disposition.
|
|
|
|
|
|
10: li v0,ExceptionContinueSearch // set disposition value
|
|
j 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 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 (4 * 4(sp)) - 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.
|
|
|
|
|
|
|
|
EXCEPTION_HANDLER(RtlpUnwindHandler)
|
|
|
|
NESTED_ENTRY(RtlpExecuteHandlerForUnwind, CfFrameLength, zero)
|
|
|
|
subu sp,sp,CfFrameLength // allocate stack frame
|
|
sw ra,CfRa(sp) // save return address
|
|
|
|
PROLOGUE_END
|
|
|
|
lw t0,CfExr(sp) // get address of exception routine
|
|
sw a3,CfA3(sp) // save address of dispatcher context
|
|
jal t0 // call exception unwind handler
|
|
lw ra,CfRa(sp) // restore return address
|
|
addu sp,sp,CfFrameLength // deallocate stack frame
|
|
j 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)
|
|
|
|
lw t0,ErExceptionFlags(a0) // get exception flags
|
|
and t0,t0,EXCEPTION_UNWIND // check if unwind in progress
|
|
beq zero,t0,10f // if eq, unwind not in progress
|
|
|
|
|
|
// Unwind is in progress - return collided unwind disposition.
|
|
|
|
|
|
lw t0,CfA3 - CfA0(a1) // get dispatcher context address
|
|
li v0,ExceptionCollidedUnwind // set disposition value
|
|
lw t1,DcControlPc(t0) // Copy the establisher frames'
|
|
lw t2,DcFunctionEntry(t0) // dispatcher context to the current
|
|
lw t3,DcEstablisherFrame(t0) // dispatcher context
|
|
lw t4,DcContextRecord(t0) //
|
|
sw t1,DcControlPc(a3) //
|
|
sw t2,DcFunctionEntry(a3) //
|
|
sw t3,DcEstablisherFrame(a3) //
|
|
sw t4,DcContextRecord(a3) //
|
|
j ra // return
|
|
|
|
|
|
// Unwind is not in progress - return continue search disposition.
|
|
|
|
|
|
10: li v0,ExceptionContinueSearch // set disposition value
|
|
j ra // return
|
|
.end RtlpUnwindHandler
|
|
|
|
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)
|
|
|
|
li t0,UsPcr // get address of user PCR
|
|
bgez sp,10f // if gez, current mode is user
|
|
|
|
|
|
// Current mode is kernel - compute stack limits.
|
|
|
|
|
|
lw t1,KiPcr + PcInitialStack(zero) // get high limit kernel stack
|
|
lw t2,KiPcr + PcStackLimit(zero) // get low limit kernel stack
|
|
b 20f // finish in commom code
|
|
|
|
|
|
// Current mode is user - get stack limits from the TEB.
|
|
|
|
|
|
10: lw t0,PcTeb(t0) // get address of TEB
|
|
lw t2,TeStackLimit(t0) // get low limit of user stack
|
|
lw t1,TeStackBase(t0) // get high limit of user stack
|
|
20: sw t2,0(a0) // store low stack limit
|
|
sw t1,0(a1) // store high stack limit
|
|
j ra // return
|
|
|
|
.end RtlpGetStackLimits
|