diff options
Diffstat (limited to 'private/ntos/rtl/mips/trampoln.s')
-rw-r--r-- | private/ntos/rtl/mips/trampoln.s | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/private/ntos/rtl/mips/trampoln.s b/private/ntos/rtl/mips/trampoln.s new file mode 100644 index 000000000..dd5654f11 --- /dev/null +++ b/private/ntos/rtl/mips/trampoln.s @@ -0,0 +1,522 @@ +// TITLE("Trampoline Code For User Mode APC and Exception Dispatching") +//++ +// +// Copyright (c) 1990 Microsoft Corporation +// +// Module Name: +// +// trampoln.s +// +// Abstract: +// +// This module implements the trampoline code necessary to dispatch user +// mode APCs and exceptions. +// +// Author: +// +// David N. Cutler (davec) 3-Apr-1990 +// +// Environment: +// +// User mode only. +// +// Revision History: +// +//-- + +#include "ksmips.h" + +// +// Define length of exception dispatcher stack frame. +// + +#define ExceptionDispatcherFrame (ExceptionRecordLength + ContextFrameLength) + + SBTTL("User APC Dispatcher") +//++ +// +// The following code is never executed. Its purpose is to support unwinding +// through the call to the APC dispatcher. +// +//-- + + EXCEPTION_HANDLER(KiUserApcHandler) + + NESTED_ENTRY(KiUserApcDispatch, ContextFrameLength, zero); + + .set noreorder + .set noat + sd sp,CxXIntSp(sp) // save stack pointer + sd ra,CxXIntRa(sp) // save return address + sw ra,CxFir(sp) // save return address + sd s8,CxXIntS8(sp) // save integer register s8 + sd gp,CxXIntGp(sp) // save integer register gp + sd s0,CxXIntS0(sp) // save integer registers s0 - s7 + sd s1,CxXIntS1(sp) // + sd s2,CxXIntS2(sp) // + sd s3,CxXIntS3(sp) // + sd s4,CxXIntS4(sp) // + sd s5,CxXIntS5(sp) // + sd s6,CxXIntS6(sp) // + sd s7,CxXIntS7(sp) // + sdc1 f20,CxFltF20(sp) // store floating registers f20 - f31 + sdc1 f22,CxFltF22(sp) // + sdc1 f24,CxFltF24(sp) // + sdc1 f26,CxFltF26(sp) // + sdc1 f28,CxFltF28(sp) // + sdc1 f30,CxFltF30(sp) // + move s8,sp // set frame pointer + .set at + .set reorder + + PROLOGUE_END + +//++ +// +// 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 context 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. +// +// Arguments: +// +// a0 - Supplies the normal context parameter that was specified when the +// APC was initialized. +// +// a1 - Supplies the first argument that was provied by the executive when +// the APC was queued. +// +// a2 - Supplies the second argument that was provided by the executive +// when the APC was queued. +// +// a3 - Supplies that address of the function that is to be called. +// +// sp - Supplies a pointer to a context frame. +// +// s8 - Supplies the same value as sp and is used as a frame pointer. +// +// Return Value: +// +// None. +// +//-- + + ALTERNATE_ENTRY(KiUserApcDispatcher) + + jal a3 // call specified APC routine + move a0,s8 // set address of context frame + li a1,1 // set test alert argument true + jal ZwContinue // execute system service to continue + +// +// 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 their is not return from raise +// status. +// + + move s0,v0 // save status value +10: move a0,s0 // set status value + jal RtlRaiseStatus // raise exception + b 10b // loop on return + + .end 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 thought 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 (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: +// +// ExceptionContinueSearch is returned as the function value. +//-- + + .struct 0 + .space 4 * 4 // argument save area +HdRa: .space 4 // saved return address + .space 3 * 4 // +HandlerFrameLength: // length of handler frame + + NESTED_ENTRY(KiUserApcHandler, HandlerFrameLength, zero) + + subu sp,sp,HandlerFrameLength // allocate stack frame + sw ra,HdRa(sp) // save return address + + PROLOGUE_END + + lw t0,ErExceptionFlags(a0) // get exception flags + and t0,t0,EXCEPTION_UNWIND // check if unwind in progress + beq zero,t0,10f // if eq, no unwind in progress + jal ZwTestAlert // test for alert pending +10: li v0,ExceptionContinueSearch // set disposition value + lw ra,HdRa(sp) // restore return address + addu sp,sp,HandlerFrameLength // deallocate stack frame + j ra // return + + .end KiUserApcHandler + + SBTTL("User Callback Dispatcher") +//++ +// +// The following code is never executed. Its purpose is to support unwinding +// through the call to the APC dispatcher. +// +//-- + +// EXCEPTION_HANDLER(KiUserCallbackHandler) + + NESTED_ENTRY(KiUserCallbackDispatch, ContextFrameLength, zero); + + .set noreorder + .set noat + sd sp,CkSp(sp) // save stack pointer + sd ra,CkRa(sp) // save return address + .set at + .set reorder + + PROLOGUE_END + +//++ +// +// 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) + + lw a0,CkBuffer(sp) // get input buffer address + lw a1,CkLength(sp) // get input buffer length + lw t0,CkApiNumber(sp) // get API number + li t1,UsPcr // get user PCR page address + lw t1,PcTeb(t1) // get address of TEB + lw t2,TePeb(t1) // get address of PEB + lw t3,PeKernelCallbackTable(t2) // get address of callback table + sll t0,t0,2 // compute address of table entry + addu t3,t3,t0 // + lw t3,0(t3) // get address of callback routine + jal t3 // call specified function + +// +// If a return from the callback function occurs, then the output buffer +// address and length are returned as NULL. +// + + move a0,zero // set zero buffer address + move a1,zero // set zero buffer lenfth + move a2,v0 // set completion status + jal ZwCallbackReturn // 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 their is not return from raise +// status. +// + +10: move a0,v0 // set status value + jal RtlRaiseStatus // raise exception + b 10b // loop on return + + .end 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 (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: +// +// ExceptionContinueSearch is returned as the function value. +//-- + + NESTED_ENTRY(KiUserCallbackHandler, HandlerFrameLength, zero) + + subu sp,sp,HandlerFrameLength // allocate stack frame + sw ra,HdRa(sp) // save return address + + PROLOGUE_END + + lw t0,ErExceptionFlags(a0) // get exception flags + and t0,t0,EXCEPTION_UNWIND // check if unwind in progress + bne zero,t0,10f // if ne, unwind in progress + li v0,ExceptionContinueSearch // set disposition value + addu sp,sp,HandlerFrameLength // deallocate stack frame + j ra // return + +// +// 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. +// + +10: lw a2,ErExceptionCode(a0) // get exception code + move a0,zero // set zero buffer address + move a1,zero // set zero buffer lenfth + jal ZwCallbackReturn // 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. +// + +20: move a0,v0 // set status value + jal RtlRaiseStatus // raise exception + b 20b // loop on return + + .end KiUserCallbackHandler + + SBTTL("User Exception Dispatcher") +//++ +// +// The following code is never executed. Its purpose is to support unwinding +// through the call to the exception dispatcher. +// +//-- + + NESTED_ENTRY(KiUserExceptionDispatch, ExceptionDispatcherFrame, zero); + + .set noreorder + .set noat + sd sp,CxXIntSp(sp) // save stack pointer + sd ra,CxXIntRa(sp) // save return address + sw ra,CxFir(sp) // save return address + sd s8,CxXIntS8(sp) // save integer register s8 + sd gp,CxXIntGp(sp) // save integer register gp + sd s0,CxXIntS0(sp) // save integer registers s0 - s7 + sd s1,CxXIntS1(sp) // + sd s2,CxXIntS2(sp) // + sd s3,CxXIntS3(sp) // + sd s4,CxXIntS4(sp) // + sd s5,CxXIntS5(sp) // + sd s6,CxXIntS6(sp) // + sd s7,CxXIntS7(sp) // + sdc1 f20,CxFltF20(sp) // store floating registers f20 - f31 + sdc1 f22,CxFltF22(sp) // + sdc1 f24,CxFltF24(sp) // + sdc1 f26,CxFltF26(sp) // + sdc1 f28,CxFltF28(sp) // + sdc1 f30,CxFltF30(sp) // + move s8,sp // set frame pointer + .set at + .set reorder + + PROLOGUE_END + +//++ +// +// 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: +// +// s0 - Supplies a pointer to an exception record. +// +// s1 - Supplies a pointer to a context frame. +// +// s8 - Supplies the same value as sp and is used as a frame pointer. +// +// Return Value: +// +// None. +// +//-- + + ALTERNATE_ENTRY(KiUserExceptionDispatcher) + + move a0,s0 // set address of exception record + move a1,s1 // set address of context record + jal 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. +// + + beq zero,v0,10f // if eq, perform last chance processing + +// +// Continue execution. +// + + move a0,s1 // set address of context frame + li a1,0 // set test alert argument false + jal ZwContinue // execute system service to continue + b 20f // join common code + +// +// Last chance processing. +// + +10: move a0,s0 // set address of exception record + move a1,s1 // set address of context frame + move a2,zero // set first chance FALSE + jal ZwRaiseException // perform last chance processing + +// +// 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. +// + +20: move s1,v0 // save status value +30: subu sp,sp,ExceptionRecordLength + (4 * 4) // allocate exception record + addu a0,sp,4 * 4 // compute address of actual record + sw s1,ErExceptionCode(a0) // set exception code + li t0,EXCEPTION_NONCONTINUABLE // set noncontinuable flag + sw t0,ErExceptionFlags(a0) // + sw s0,ErExceptionRecord(a0) // set associated exception record + sw zero,ErNumberParameters(a0) // set number of parameters + jal RtlRaiseException // raise exception + b 20b // loop of error + + .end KiUserExceptionDispatch +//++ +// +// NTSTATUS +// KiRaiseUserExceptionDispatcher ( +// IN NTSTATUS ExceptionCode +// ) +// +// Routine Description: +// +// This routine is entered on return from kernel mode to raise a user +// mode exception. +// +// 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 Fir address of the trap frame. Thus when +// the kernel returns from the trap, the following code is executed directly. +// +// Arguments: +// +// v0 - Supplies the status code to be raised. +// +// Return Value: +// +// ExceptionCode +// +//-- + + .struct 0 + .space 4 * 4 // argument save area +RaiseRa:.space 4 // saved return address +RaiseV0:.space 4 // saved S0 +RaiseEr:.space ExceptionRecordLength // exception record for RtlRaiseException +RaiseFrameLength: // length of handler frame + + NESTED_ENTRY(KiRaiseUserExceptionDispatcher, RaiseFrameLength, zero) + + subu sp,sp,RaiseFrameLength // allocate stack frame + sw ra,RaiseRa(sp) // save return address + + PROLOGUE_END + + sw v0,RaiseV0(sp) // save function return status + sw v0,ErExceptionCode + RaiseEr(sp) // set exception code + sw zero,ErExceptionFlags + RaiseEr(sp) // set exception flags + sw zero,ErExceptionRecord + RaiseEr(sp) // clear exception record + sw ra,ErExceptionAddress + RaiseEr(sp) // set exception address + sw zero,ErNumberParameters+RaiseEr(sp) // set number of parameters + addu a0,sp,RaiseEr // compute exception record address + jal RtlRaiseException // attempt to raise the exception + lw v0,RaiseV0(sp) // restore function status + lw ra,RaiseRa(sp) // restore return address + addu sp,sp,RaiseFrameLength // deallocate stack frame + j ra // return + + .end KiRaiseUserExceptionDispatch |