688 lines
24 KiB
ArmAsm
688 lines
24 KiB
ArmAsm
|
|
|
|
// Copyright (c) 1993 IBM Corporation and Microsoft Corporation
|
|
|
|
// Module Name:
|
|
|
|
// trampoln.s
|
|
|
|
// Abstract:
|
|
|
|
// This module implements the trampoline code necessary to dispatch user
|
|
// mode APCs.
|
|
|
|
// Author:
|
|
|
|
// Rick Simpson 25-Oct-1993
|
|
|
|
// based on MIPS version by David N. Cutler (davec) 3-Apr-1990
|
|
|
|
// Environment:
|
|
|
|
// User mode only.
|
|
|
|
// Revision History:
|
|
|
|
|
|
|
|
//list(off)
|
|
#include "ksppc.h"
|
|
//list(on)
|
|
.extern __C_specific_handler
|
|
.extern ..RtlDispatchException
|
|
.extern ..RtlRaiseException
|
|
.extern ..RtlRaiseStatus
|
|
.extern ZwCallbackReturn
|
|
.extern ZwContinue
|
|
.extern ZwRaiseException
|
|
.extern ZwTestAlert
|
|
|
|
|
|
// Define layout and length of APC Dispatcher stack frame.
|
|
// N.B. This must exactly match the computations in KiInitializeUserApc()
|
|
|
|
|
|
.struct 0
|
|
ADFrame: .space StackFrameHeaderLength
|
|
ADContext: .space ContextFrameLength
|
|
ADTrap: .space TrapFrameLength
|
|
ADToc: .long 0
|
|
.space STK_SLACK_SPACE
|
|
.align 3
|
|
ADFrameLength:
|
|
|
|
.text
|
|
|
|
|
|
|
|
// The following code is never executed. Its purpose is to support unwinding
|
|
// through the call to the APC dispatcher.
|
|
|
|
|
|
|
|
.ydata // scope table -- exception handler
|
|
.align 2
|
|
UserApcDispatcherScopeTable:
|
|
.long 1 // number of scope table entries
|
|
.long ..KiUserApcDispatcher // start of scope
|
|
.long KiUserApcDispatcher.end // end of scope
|
|
.long KiUserApcHandler // filter to decide what to do
|
|
.long 0 // it always decides to "continue search"
|
|
.text
|
|
|
|
FN_TABLE (KiUserApcDispatch,__C_specific_handler,UserApcDispatcherScopeTable)
|
|
|
|
DUMMY_ENTRY (KiUserApcDispatch)
|
|
|
|
stwu r.sp, -ADFrameLength (r.sp)
|
|
mflr r.0
|
|
stw r.0, ADContext + CxLr (r.sp)
|
|
stw r.0, ADContext + CxIar (r.sp)
|
|
stw r.toc, ADToc (r.sp)
|
|
|
|
PROLOGUE_END (KiUserApcDispatch)
|
|
|
|
|
|
|
|
// VOID
|
|
// KiUserApcDispatcher (
|
|
// IN PVOID NormalContext,
|
|
// IN PVOID SystemArgument1,
|
|
// IN PVOID SystemArgument2,
|
|
// IN PKNORMAL_ROUTINE NormalRoutine
|
|
// )
|
|
|
|
// Routine Description:
|
|
|
|
// This routine is entered on return from kernel mode to deliver an APC
|
|
// in user mode. The stack frame for this routine was built when the
|
|
// APC interrupt was processed and contains the entire machine state of
|
|
// the current thread. The specified APC routine is called and then the
|
|
// machine state is restored and execution is continued.
|
|
|
|
// On entry here, a stack frame as shown above is already addressed
|
|
// via r.1
|
|
|
|
// Arguments:
|
|
|
|
// r.1 - Stack frame pointer, already set up
|
|
|
|
// r.3 - Supplies the normal context parameter that was specified when the
|
|
// APC was initialized.
|
|
|
|
// r.4 - Supplies the first argument that was provied by the executive when
|
|
// the APC was queued.
|
|
|
|
// r.5 - Supplies the second argument that was provided by the executive
|
|
// when the APC was queued.
|
|
|
|
// r.6 - Supplies that address of the descriptor for the function that is
|
|
// to be called.
|
|
|
|
// Return Value:
|
|
|
|
// None.
|
|
|
|
|
|
|
|
ALTERNATE_ENTRY (KiUserApcDispatcher)
|
|
|
|
lwz r.0, 0 (r.6) // fetch address of APC entry point
|
|
mtlr r.0 // move into Link Reg
|
|
lwz r.2, 4 (r.6) // fetch TOC address for APC
|
|
blrl // call specified APC routine
|
|
|
|
lwz r.2, ADToc (r.sp) // reload our own TOC pointer
|
|
la r.3, ADContext (r.sp) // 1st parm = addr of Context Frame
|
|
lwz r.5, [toc] ZwContinue (r.2) // fetch ptr to function descriptor
|
|
li r.4, 1 // 2nd parm = TRUE (test alert)
|
|
lwz r.0, 0 (r.5) // fetch addr of ZwContinue entry point
|
|
mtlr r.0 // move into Link Reg
|
|
lwz r.2, 4 (r.5) // fetch TOC addr for ZwContinue
|
|
|
|
// this next is done under protest --
|
|
// we are copying MIPS slavishly:
|
|
la r.12, ADTrap (r.sp) // "secret" parm = addr of Trap Frame
|
|
blrl // execute system service to continue
|
|
lwz r.2, ADToc (r.sp) // reload our own TOC pointer
|
|
|
|
|
|
// Unsuccessful completion after attempting to continue execution. Use the
|
|
// return status as the exception code, set noncontinuable exception and
|
|
// attempt to raise another exception. Note there is no return from raise
|
|
// status.
|
|
|
|
|
|
ori r.31, r.3, 0 // save status value
|
|
ADloop:
|
|
ori r.3, r.31, 0 // set status value
|
|
bl ..RtlRaiseStatus // raise exception
|
|
b ADloop // loop on return
|
|
|
|
DUMMY_EXIT (KiUserApcDispatcher)
|
|
DUMMY_EXIT (KiUserApcDispatch)
|
|
|
|
// SBTTL("User APC Exception Handler")
|
|
|
|
|
|
// EXCEPTION_DISPOSITION
|
|
// KiUserApcHandler (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN ULONG EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PDISPATCHER_CONTEXT DispatcherContext
|
|
|
|
// Routine Description:
|
|
|
|
// This function is called when an exception occurs in an APC routine
|
|
// or one of its dynamic descendents and when an unwind through the
|
|
// APC dispatcher is in progress. If an unwind is in progress, then test
|
|
// alert is called to ensure that all currently queued APCs are executed.
|
|
|
|
// Arguments:
|
|
|
|
// ExceptionRecord (r.3) - Supplies a pointer to an exception record.
|
|
|
|
// EstablisherFrame (r.4) - Supplies the frame pointer of the establisher
|
|
// of this exception handler.
|
|
|
|
// ContextRecord (r.5) - Supplies a pointer to a context record.
|
|
|
|
// DispatcherContext (r.6) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
|
|
// Return Value:
|
|
|
|
// ExceptionContinueSearch is returned as the function value.
|
|
|
|
|
|
.struct 0
|
|
.space StackFrameHeaderLength // canonical stack frame header
|
|
.space 4 // reserve space for return address
|
|
.space 4 // reserve space for r.31
|
|
.align 3
|
|
HFrameLength: // length of handler frame
|
|
|
|
.text
|
|
|
|
NESTED_ENTRY (KiUserApcHandler, HFrameLength, 1, 0)
|
|
|
|
ori r.31, r.toc, 0 // save our TOC value in r.31
|
|
|
|
PROLOGUE_END (KiUserApcHandler)
|
|
|
|
lwz r.0, ErExceptionFlags (r.3) // get exception flags
|
|
andi. r.0, r.0, EXCEPTION_UNWIND // check if unwind in progress
|
|
beq H10 // if eq, no unwind in progress
|
|
lwz r.7, [toc] ZwTestAlert (r.toc) // get addr of function descriptor
|
|
lwz r.0, 0 (r.7) // get entry point address
|
|
mtlr r.0 // into Link Reg
|
|
lwz r.toc, 4 (r.7) // get callee's TOC pointer
|
|
blrl // test for alert pending
|
|
ori r.toc, r.31, 0 // reload our own TOC pointer
|
|
|
|
H10: li r.3, ExceptionContinueSearch // set disposition value
|
|
|
|
NESTED_EXIT (KiUserApcHandler, HFrameLength, 1, 0)
|
|
|
|
// SBTTL("User Callback Dispatcher")
|
|
|
|
|
|
// The following code is never executed. Its purpose is to support unwinding
|
|
// through the call to the callback dispatcher.
|
|
|
|
|
|
|
|
#if 0
|
|
.ydata // scope table -- exception handler
|
|
.align 2
|
|
UserCallbackDispatcherScopeTable:
|
|
.long 1 // number of scope table entries
|
|
.long ..KiUserCallbackDispatcher // start of scope
|
|
.long KiUserCallbackDispatcher.end // end of scope
|
|
.long KiUserCallbackHandler // filter to decide what to do
|
|
.long 0 // it always decides to "continue search"
|
|
.text
|
|
|
|
FN_TABLE (KiUserCallbackDispatch,__C_specific_handler,UserCallbackDispatcherScopeTable)
|
|
#endif
|
|
|
|
DUMMY_ENTRY (KiUserCallbackDispatch)
|
|
|
|
stwu r.sp, -CkFrameLength(r.sp)
|
|
mflr r.0
|
|
stw r.0, CkLr(r.sp)
|
|
stw r.toc, CkToc(r.sp)
|
|
|
|
PROLOGUE_END (KiUserCallbackDispatch)
|
|
|
|
|
|
|
|
// VOID
|
|
// KiUserCallbackDispatcher (
|
|
// VOID
|
|
// )
|
|
|
|
// Routine Description:
|
|
|
|
// This routine is entered on a callout from kernel mode to execute a
|
|
// user mode callback function. All arguments for this function have
|
|
// been placed on the stack.
|
|
|
|
// Arguments:
|
|
|
|
// (sp + ApiNumber) - Supplies the API number of the callback function that is
|
|
// executed.
|
|
|
|
// (sp + Buffer) - Supplies a pointer to the input buffer.
|
|
|
|
// (sp + Length) - Supplies the input buffer length.
|
|
|
|
// Return Value:
|
|
|
|
// This function returns to kernel mode.
|
|
|
|
|
|
|
|
ALTERNATE_ENTRY(KiUserCallbackDispatcher)
|
|
|
|
lwz r.6, TePeb(r.13) // get address of PEB
|
|
ori r.31, r.toc, 0 // save our TOC value in r.31
|
|
|
|
lwz r.5, CkApiNumber(r.1) // get API number
|
|
lwz r.6, PeKernelCallbackTable(r.6) // get address of callback table
|
|
lwz r.3, CkBuffer(r.1) // get input buffer address
|
|
slwi r.5, r.5, 2 // compute offset to table entry
|
|
lwz r.4, CkLength(r.1) // get input buffer length
|
|
lwzx r.5, r.5, r.6 // get descriptor for callback routine
|
|
lwz r.0, 0 (r.5) // get entry point address
|
|
mtlr r.0 // into link register
|
|
lwz r.toc, 4 (r.5) // get callee's TOC pointer
|
|
blrl // call specified function
|
|
|
|
|
|
// If a return from the callback function occurs, then the output buffer
|
|
// address and length are returned as NULL.
|
|
|
|
|
|
ori r.toc, r.31, 0 // reload our own TOC pointer
|
|
|
|
lwz r.7, [toc] ZwCallbackReturn (r.toc) // get addr of function descriptor
|
|
ori r.5, r.3, 0 // set completion status
|
|
li r.3, 0 // set zero buffer address
|
|
li r.4, 0 // set zero buffer lenfth
|
|
lwz r.0, 0 (r.7) // get entry point address
|
|
mtlr r.0 // into Link Reg
|
|
lwz r.toc, 4 (r.7) // get callee's TOC pointer
|
|
blrl // return to kernel mode
|
|
|
|
|
|
// Unsuccessful completion after attempting to return to kernel mode. Use
|
|
// the return status as the exception code, set noncontinuable exception and
|
|
// attempt to raise another exception. Note there is no return from raise
|
|
// status.
|
|
|
|
|
|
ori r.toc, r.31, 0 // reload our own TOC pointer
|
|
|
|
ori r.31, r.3, 0 // save status value
|
|
UCDloop:
|
|
bl ..RtlRaiseStatus // raise exception
|
|
ori r.3, r.31, 0 // set status value
|
|
b UCDloop // loop on return
|
|
|
|
DUMMY_EXIT (KiUserCallbackDispatch)
|
|
|
|
// SBTTL("User Callback Exception Handler")
|
|
|
|
|
|
// EXCEPTION_DISPOSITION
|
|
// KiUserCallbackHandler (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN ULONG EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PDISPATCHER_CONTEXT DispatcherContext
|
|
|
|
// Routine Description:
|
|
|
|
// This function is called when an exception occurs in a user callback
|
|
// routine or one of its dynamic descendents.
|
|
|
|
// Arguments:
|
|
|
|
// ExceptionRecord (r.3) - Supplies a pointer to an exception record.
|
|
|
|
// EstablisherFrame (r.4) - Supplies the frame pointer of the establisher
|
|
// of this exception handler.
|
|
|
|
// ContextRecord (r.5) - Supplies a pointer to a context record.
|
|
|
|
// DispatcherContext (r.6) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
|
|
// Return Value:
|
|
|
|
// ExceptionContinueSearch is returned as the function value.
|
|
|
|
|
|
NESTED_ENTRY (KiUserCallbackHandler, HFrameLength, 1, 0)
|
|
|
|
ori r.31, r.toc, 0 // save our TOC value in r.31
|
|
|
|
PROLOGUE_END (KiUserCallbackHandler)
|
|
|
|
lwz r.0, ErExceptionFlags (r.3) // get exception flags
|
|
andi. r.0, r.0, EXCEPTION_UNWIND // check if unwind in progress
|
|
beq UCH10 // if eq, no unwind in progress
|
|
|
|
|
|
// There is an attempt to unwind through a callback frame. If this were
|
|
// allowed, then a kernel callback frame would be abandoned on the kernel
|
|
// stack. Force a callback return.
|
|
|
|
|
|
lwz r.5, ErExceptionCode(r.3) // get exception code
|
|
li r.3, 0 // set zero buffer address
|
|
li r.4, 0 // set zero buffer lenfth
|
|
lwz r.7, [toc]ZwCallbackReturn(r.toc) // get addr of function descriptor
|
|
lwz r.0, 0 (r.7) // get entry point address
|
|
mtlr r.0 // into Link Reg
|
|
lwz r.toc, 4 (r.7) // get callee's TOC pointer
|
|
blrl // return to kernel mode
|
|
|
|
|
|
// Unsuccessful completion after attempting to return to kernel mode. Use
|
|
// the return status as the exception code, set noncontinuable exception and
|
|
// attempt to raise another exception. Note there is no return from raise
|
|
// status.
|
|
|
|
|
|
ori r.toc, r.31, 0 // reload our own TOC pointer
|
|
|
|
ori r.31, r.3, 0 // save status value
|
|
UCHloop:
|
|
bl ..RtlRaiseStatus // raise exception
|
|
ori r.3, r.31, 0 // set status value
|
|
b UCHloop // loop on return
|
|
|
|
UCH10:
|
|
li r.3, ExceptionContinueSearch // set disposition value
|
|
|
|
NESTED_EXIT (KiUserCallbackHandler, HFrameLength, 1, 0)
|
|
|
|
|
|
// Define layout and length of User Exception Dispatcher stack frame.
|
|
// N.B. This must exactly match the computations in KiDispatchException
|
|
|
|
|
|
.struct 0
|
|
EDFrame: .space StackFrameHeaderLength
|
|
EDExcept: .space ExceptionRecordLength
|
|
EDContext: .space ContextFrameLength
|
|
EDToc: .long 0
|
|
.space STK_SLACK_SPACE
|
|
.align 3
|
|
EDFrameLength:
|
|
|
|
.text
|
|
|
|
// SBTTL("User Exception Dispatcher")
|
|
|
|
|
|
// The following code is never executed. Its purpose is to support unwinding
|
|
// through the call to the exception dispatcher.
|
|
|
|
|
|
|
|
FN_TABLE (KiUserExceptionDispatch, 0, 0)
|
|
|
|
DUMMY_ENTRY (KiUserExceptionDispatch)
|
|
|
|
stwu r.sp, -EDFrameLength (r.sp) // buy stack frame
|
|
mflr r.0 // save linkage
|
|
stw r.0, EDContext + CxLr (r.sp) // regs
|
|
mflr r.0 // needed by vunwind code
|
|
stw r.0, EDContext + CxIar (r.sp)
|
|
stw r.toc, EDToc (r.sp)
|
|
|
|
stw r.13, EDContext + CxGpr13 (r.sp) // save non-volatile integer state
|
|
stw r.14, EDContext + CxGpr14 (r.sp)
|
|
stw r.15, EDContext + CxGpr15 (r.sp)
|
|
stw r.16, EDContext + CxGpr16 (r.sp)
|
|
stw r.17, EDContext + CxGpr17 (r.sp)
|
|
stw r.18, EDContext + CxGpr18 (r.sp)
|
|
stw r.19, EDContext + CxGpr19 (r.sp)
|
|
stw r.20, EDContext + CxGpr20 (r.sp)
|
|
stw r.21, EDContext + CxGpr21 (r.sp)
|
|
stw r.22, EDContext + CxGpr22 (r.sp)
|
|
stw r.23, EDContext + CxGpr23 (r.sp)
|
|
stw r.24, EDContext + CxGpr24 (r.sp)
|
|
stw r.25, EDContext + CxGpr25 (r.sp)
|
|
stw r.26, EDContext + CxGpr26 (r.sp)
|
|
stw r.27, EDContext + CxGpr27 (r.sp)
|
|
stw r.28, EDContext + CxGpr28 (r.sp)
|
|
stw r.29, EDContext + CxGpr29 (r.sp)
|
|
stw r.30, EDContext + CxGpr30 (r.sp)
|
|
stw r.31, EDContext + CxGpr31 (r.sp)
|
|
stfd f.14, EDContext + CxFpr14 (r.sp) // save non-volatile floating point state
|
|
stfd f.15, EDContext + CxFpr15 (r.sp)
|
|
stfd f.16, EDContext + CxFpr16 (r.sp)
|
|
stfd f.17, EDContext + CxFpr17 (r.sp)
|
|
stfd f.18, EDContext + CxFpr18 (r.sp)
|
|
stfd f.19, EDContext + CxFpr19 (r.sp)
|
|
stfd f.20, EDContext + CxFpr20 (r.sp)
|
|
stfd f.21, EDContext + CxFpr21 (r.sp)
|
|
stfd f.22, EDContext + CxFpr22 (r.sp)
|
|
stfd f.23, EDContext + CxFpr23 (r.sp)
|
|
stfd f.24, EDContext + CxFpr24 (r.sp)
|
|
stfd f.25, EDContext + CxFpr25 (r.sp)
|
|
stfd f.26, EDContext + CxFpr26 (r.sp)
|
|
stfd f.27, EDContext + CxFpr27 (r.sp)
|
|
stfd f.28, EDContext + CxFpr28 (r.sp)
|
|
stfd f.29, EDContext + CxFpr29 (r.sp)
|
|
stfd f.30, EDContext + CxFpr30 (r.sp)
|
|
stfd f.31, EDContext + CxFpr31 (r.sp)
|
|
|
|
PROLOGUE_END (KiUserExceptionDispatch)
|
|
|
|
|
|
|
|
// VOID
|
|
// KiUserExceptionDispatcher (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN PCONTEXT ContextRecord
|
|
// )
|
|
|
|
// Routine Description:
|
|
|
|
// This routine is entered on return from kernel mode to dispatch a user
|
|
// mode exception. If a frame based handler handles the exception, then
|
|
// the execution is continued. Else last chance processing is performed.
|
|
|
|
// Arguments:
|
|
|
|
// r.3 - Supplies a pointer to an exception record.
|
|
|
|
// r.4 - Supplies a pointer to a context record.
|
|
|
|
// Return Value:
|
|
|
|
// None.
|
|
|
|
|
|
|
|
ALTERNATE_ENTRY(KiUserExceptionDispatcher)
|
|
|
|
bl ..RtlDispatchException // attempt to dispatch the exception
|
|
|
|
|
|
// If the return status is TRUE, then the exception was handled and execution
|
|
// should be continued with the NtContinue service in case the context was
|
|
// changed. If the return status is FALSE, then the exception was not handled
|
|
// and NtRaiseException is called to perform last chance exception processing.
|
|
|
|
|
|
cmpwi r.3, 0 // compare return value to FALSE
|
|
beq ED10 // if eq, perform last chance processing
|
|
|
|
|
|
// Continue execution.
|
|
|
|
|
|
lwz r.5, [toc] ZwContinue (r.2) // load pointer to function descriptor
|
|
la r.3, EDContext (r.sp) // set addr of context frame
|
|
lwz r.0, 0 (r.5) // load entry point address
|
|
mtlr r.0 // move into Link Reg
|
|
li r.4, 0 // set test alert argument false
|
|
lwz r.2, 4 (r.5) // load ZwContinue's TOC pointer
|
|
blrl // execute system service to continue
|
|
lwz r.2, EDToc (r.sp) // reload our own TOC address
|
|
b ED20 // join common code
|
|
|
|
|
|
// Last chance processing.
|
|
|
|
|
|
ED10:
|
|
lwz r.6, [toc] ZwRaiseException (r.2) // load pointer to function descriptor
|
|
la r.3, EDExcept (r.sp) // set address of exception record
|
|
lwz r.0, 0 (r.6) // load entry point address
|
|
mtlr r.0 // into link reg
|
|
la r.4, EDContext (r.sp) // set address of context frame
|
|
li r.5, 0 // set first chance FALSE
|
|
lwz r.toc, 4 (r.6) // load callee's TOC addr
|
|
blrl // perform last chance processing
|
|
lwz r.toc, EDToc (r.sp) // reload our own TOC address
|
|
|
|
|
|
// Common code for nonsuccessful completion of the continue or last chance
|
|
// service. Use the return status as the exception code, set noncontinuable
|
|
// exception and attempt to raise another exception. Note the stack grows
|
|
// and eventually this loop will end.
|
|
|
|
|
|
ED20: // status value is in r.3
|
|
la r.4, EDExcept (r.sp) // point to our exception record
|
|
bl ..KipUserExceptionDispatcherLoop // call subroutine below
|
|
|
|
DUMMY_EXIT (KiUserExceptionDispatch)
|
|
|
|
|
|
|
|
// VOID
|
|
// KiUserExceptionDispatcherLoop (
|
|
// IN ULONG ExceptionStatus
|
|
// )
|
|
|
|
// Routine Description:
|
|
|
|
// This routine builds an Exception Record and calls RtlRaiseException.
|
|
// On an unsuccessful return, it calls itself recursively; eventually
|
|
// this will terminate when the stack fills up.
|
|
|
|
// Arguments:
|
|
|
|
// r.3 - Status value
|
|
|
|
// Return Value:
|
|
|
|
// None. (Does not return.)
|
|
|
|
|
|
|
|
|
|
// Stack frame layout for KipUserExceptionDispatchLoop
|
|
|
|
|
|
.struct 0
|
|
LFrame: .space StackFrameHeaderLength
|
|
LExcept: .space ExceptionRecordLength
|
|
LOldExcept: .long 0
|
|
LSavedLR: .long 0
|
|
.align 3
|
|
LFrameLength:
|
|
|
|
.text
|
|
|
|
NESTED_ENTRY (KipUserExceptionDispatcherLoop, LFrameLength, 0, 0)
|
|
|
|
PROLOGUE_END (KipUserExceptionDispatcherLoop)
|
|
|
|
stw r.4, LOldExcept (r.sp) // save incoming exception rec addr
|
|
la r.5, LExcept (r.sp) // point to Exception Record
|
|
stw r.3, ErExceptionCode (r.5) // fill in exception code (incoming status)
|
|
li r.6, EXCEPTION_NONCONTINUABLE // set non-continuable flag
|
|
stw r.6, ErExceptionFlags (r.5)
|
|
stw r.4, ErExceptionRecord (r.5) // set addr of prev. exception record
|
|
li r.0, 0 // set number of parameters
|
|
stw r.0, ErNumberParameters (r.5) // to 0
|
|
ori r.3, r.5, 0 // load 1st parameter pointer
|
|
bl ..RtlRaiseException // raise an exception
|
|
|
|
lwz r.4, LOldExcept (r.sp) // should not return, but if so:
|
|
bl ..KipUserExceptionDispatcherLoop // keep doing this in a loop
|
|
|
|
NESTED_EXIT (KipUserExceptionDispatcherLoop, LFrameLength, 0, 0)
|
|
|
|
|
|
|
|
// NTSTATUS
|
|
// KiRaiseUserExceptionDispatcher (
|
|
// IN NTSTATUS ExceptionCode
|
|
// )
|
|
|
|
// Routine Description:
|
|
|
|
// This routine is entered on return from kernel mode to raise a user
|
|
// mode exception.
|
|
|
|
// Arguments:
|
|
|
|
// r3 - Supplies the status code to be raised.
|
|
|
|
// Return Value:
|
|
|
|
// ExceptionCode
|
|
|
|
|
|
|
|
|
|
// N.B. This function is not called in the typical way. Instead of a normal
|
|
// subroutine call to the nested entry point above, the alternate entry point
|
|
// address below is stuffed into the Iar address of the trap frame. Thus when
|
|
// the kernel returns from the trap, the following code is executed directly.
|
|
|
|
|
|
.struct 0
|
|
ruedFrame: .space StackFrameHeaderLength
|
|
ruedExr: .space ExceptionRecordLength
|
|
ruedR3: .space 4
|
|
ruedLr: .space 4
|
|
.align 3
|
|
ruedFrameLength:
|
|
|
|
SPECIAL_ENTRY(KiRaiseUserExceptionDispatcher)
|
|
|
|
mflr r4 // get return address (also exception address)
|
|
stwu sp,-ruedFrameLength(sp) // allocate stack frame
|
|
li r0,0 // get a 0
|
|
stw r4,ruedLr(sp) // save return address
|
|
|
|
PROLOGUE_END(KiRaiseUserExceptionDispatcher)
|
|
|
|
stw r3,ruedR3(sp) // save function return status
|
|
stw r3,ErExceptionCode+ruedExr(sp) // set exception code
|
|
la r3,ruedExr(sp) // compute exception record address
|
|
lwz r4,ruedLr(sp) // get exception address
|
|
stw r0,ErExceptionFlags(r3) // set exception flags
|
|
stw r0,ErExceptionRecord(r3) // set exception record
|
|
stw r0,ErNumberParameters(r3) // set number of parameters
|
|
stw r4,ErExceptionAddress(r3) // set exception address
|
|
|
|
bl ..RtlRaiseException // attempt to raise the exception
|
|
|
|
lwz r3,ruedR3(sp) // restore function status
|
|
|
|
NESTED_EXIT (KiRaiseUserExceptionDispatcher, ruedFrameLength, 0, 0)
|
|
|