From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/rtl/alpha/trampoln.s | 524 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 524 insertions(+) create mode 100644 private/ntos/rtl/alpha/trampoln.s (limited to 'private/ntos/rtl/alpha/trampoln.s') diff --git a/private/ntos/rtl/alpha/trampoln.s b/private/ntos/rtl/alpha/trampoln.s new file mode 100644 index 000000000..b37d471e7 --- /dev/null +++ b/private/ntos/rtl/alpha/trampoln.s @@ -0,0 +1,524 @@ +// TITLE("Trampoline Code For User Mode APC and Exception Dispatching") +//++ +// +// Copyright (c) 1990 Microsoft Corporation +// Copyright (c) 1992 Digital Equipment 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: +// +// Thomas Van Baak (tvb) 11-May-1992 +// +// Adapted for Alpha AXP. +// +//-- + +#include "ksalpha.h" + +// +// Define length of exception dispatcher stack frame. +// + +#define ExceptionDispatcherFrameLength (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. +// +//-- + +// +// N.B. This function specifies its own private exception handler. +// + EXCEPTION_HANDLER(KiUserApcHandler) + + NESTED_ENTRY(KiUserApcDispatch, ContextFrameLength, zero); + + .set noreorder + .set noat + stq sp, CxIntSp(sp) // save stack pointer + stq ra, CxIntRa(sp) // save return address + stq ra, CxFir(sp) // set continuation address + stq fp, CxIntFp(sp) // save integer register fp + stq gp, CxIntGp(sp) // save integer register gp + + stq s0, CxIntS0(sp) // save integer registers s0 - s5 + stq s1, CxIntS1(sp) // + stq s2, CxIntS2(sp) // + stq s3, CxIntS3(sp) // + stq s4, CxIntS4(sp) // + stq s5, CxIntS5(sp) // + + stt f2, CxFltF2(sp) // save floating registers f2 - f9 + stt f3, CxFltF3(sp) // + stt f4, CxFltF4(sp) // + stt f5, CxFltF5(sp) // + stt f6, CxFltF6(sp) // + stt f7, CxFltF7(sp) // + stt f8, CxFltF8(sp) // + stt f9, CxFltF9(sp) // + + mov sp, fp // 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 provided 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 the address of the function that is to be called. +// +// N.B. Register sp supplies a pointer to a context frame. +// +// N.B. Register fp supplies the same value as sp and is used as a frame +// pointer. +// +// Return Value: +// +// None. +// +//-- + +// +// 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. +// + ALTERNATE_ENTRY(KiUserApcDispatcher) + + jsr ra, (a3) // call specified APC routine + + mov fp, a0 // set address of context frame + ldil a1, TRUE // set test alert argument true + bsr ra, ZwContinue // execute system service to continue + mov v0, s0 // save status value + +// +// 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. +// + +10: mov s0, a0 // set status value + bsr ra, RtlRaiseStatus // raise exception + br zero, 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, or 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 (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 +HdRa: .space 8 // saved return address + .space 1 * 8 // required for 16-byte stack alignment +HandlerFrameLength: // length of handler frame + + NESTED_ENTRY(KiUserApcHandler, HandlerFrameLength, zero) + + lda sp, -HandlerFrameLength(sp) // allocate stack frame + stq ra, HdRa(sp) // save return address + + PROLOGUE_END + +// +// The following code is equivalent to: +// +// EXCEPTION_DISPOSITION +// KiUserApcHandler(IN PEXCEPTION_RECORD ExceptionRecord) +// { +// if (IS_UNWINDING(ExceptionRecord->ExceptionFlags)) { +// NtTestAlert(); +// } +// return ExceptionContinueSearch +// } +// + + ldl t0, ErExceptionFlags(a0) // get exception flags + and t0, EXCEPTION_UNWIND, t0 // check if unwind in progress + beq t0, 10f // if eq, no unwind in progress + + bsr ra, ZwTestAlert // test for alert pending + +10: ldil v0, ExceptionContinueSearch // set disposition value + ldq ra, HdRa(sp) // restore return address + lda sp, HandlerFrameLength(sp) // deallocate stack frame + ret zero, (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 exception dispatcher. +// +//-- + + NESTED_ENTRY(KiUserCallbackDispatch, ContextFrameLength, zero); +.set noreorder + stq sp, CkSp(sp) + stq ra, CkRa(sp) +.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 + 16) - Supplies a value of zero for alignment. +// +// (sp + 24) - Supplies the API number of the callback function that is +// executed. +// +// (sp + 32) - Supplies a pointer to the input buffer. +// +// (sp + 40) - Supplies the input buffer length. +// +// Return Value: +// +// This function returns to kernel mode. +// +//-- + + ALTERNATE_ENTRY(KiUserCallbackDispatcher) + + ldl a0, CkBuffer(sp) // get input buffer address + ldl a1, CkLength(sp) // get input buffer length + ldl t0, CkApiNumber(sp) // get API number + GET_THREAD_ENVIRONMENT_BLOCK // get TEB in v0 + ldl t5, TePeb(v0) // get PEB in t5 + ldl t2, PeKernelCallbackTable(t5) // get address of callback table + s4addl t0, t2, t3 // get address of callback + ldl t4, 0(t3) // get callback pointer + jsr ra, (t4) // call specified function + +// +// If a return from the callback function occurs, then the output buffer +// address and length are returned as NULL. +// + + bis zero,zero,a0 // set zero buffer address + bis zero,zero,a1 // set zero buffer length + bis v0, zero, a2 // set completion status + bsr ra, 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. +// + + bis v0, zero, s0 // save status value +10: bis s0, zero, a0 // set status value + bsr ra, RtlRaiseStatus // raise exception + br zero, 10b // loop on return + + .end KiUserCallbackDispatch + + SBTTL("User Exception Dispatcher") +//++ +// +// The following code is never executed. Its purpose is to support unwinding +// through the call to the exception dispatcher. +// +// When reverse executed, this prologue will restore all integer registers, +// rather than just the non-volatile registers. This is necessary for proper +// unwinding through the call to the exception dispatcher when non-standard +// calls have been used in frames at or above the exception frame. Non-leaf +// functions using a non-standard call are allowed to save the return address +// register in another integer register instead of on the stack. +// +//-- + + NESTED_ENTRY(KiUserExceptionDispatch, ExceptionDispatcherFrameLength, zero); + + .set noreorder + .set noat + stq sp, CxIntSp(sp) // save stack pointer + stq ra, CxIntRa(sp) // save return address + stq ra, CxFir(sp) // set continuation address + + stq v0, CxIntV0(sp) // save integer register v0 + stq t0, CxIntT0(sp) // save integer registers t0 - t6 + stq t1, CxIntT1(sp) // + stq t2, CxIntT2(sp) // + stq t3, CxIntT3(sp) // + stq t4, CxIntT4(sp) // + stq t5, CxIntT5(sp) // + stq t6, CxIntT6(sp) // + stq t7, CxIntT7(sp) // + + stq s0, CxIntS0(sp) // save integer registers s0 - s5 + stq s1, CxIntS1(sp) // + stq s2, CxIntS2(sp) // + stq s3, CxIntS3(sp) // + stq s4, CxIntS4(sp) // + stq s5, CxIntS5(sp) // + stq fp, CxIntFp(sp) // save integer register fp + + stq a0, CxIntA0(sp) // save integer registers a0 - a5 + stq a1, CxIntA1(sp) // + stq a2, CxIntA2(sp) // + stq a3, CxIntA3(sp) // + stq a4, CxIntA4(sp) // + stq a5, CxIntA5(sp) // + + stq t8, CxIntT8(sp) // save integer registers t8 - t11 + stq t9, CxIntT9(sp) // + stq t10, CxIntT10(sp) // + stq t11, CxIntT11(sp) // + + stq t12, CxIntT12(sp) // save integer register t12 + stq AT, CxIntAt(sp) // save integer register AT + stq gp, CxIntGp(sp) // save integer register gp + + stt f2, CxFltF2(sp) // save floating registers f2 - f9 + stt f3, CxFltF3(sp) // + stt f4, CxFltF4(sp) // + stt f5, CxFltF5(sp) // + stt f6, CxFltF6(sp) // + stt f7, CxFltF7(sp) // + stt f8, CxFltF8(sp) // + stt f9, CxFltF9(sp) // + + mov sp, fp // 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. Otherwise last chance processing is performed. +// +// Arguments: +// +// s0 - Supplies a pointer to an exception record. +// +// s1 - Supplies a pointer to a context frame. +// +// fp - Supplies the same value as sp and is used as a frame pointer. +// +// Return Value: +// +// None. +// +//-- + +// +// 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. +// + + ALTERNATE_ENTRY(KiUserExceptionDispatcher) + + mov s0, a0 // set address of exception record + mov s1, a1 // set address of context frame + bsr ra, 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 v0, 10f // if eq [false], perform last chance processing + +// +// Continue execution. +// + + mov s1, a0 // set address of context frame + ldil a1, FALSE // set test alert argument false + bsr ra, ZwContinue // execute system service to continue + br zero, 20f // join common code + +// +// Last chance processing. +// + +10: mov s0, a0 // set address of exception record + mov s1, a1 // set address of context frame + ldil a2, FALSE // set first chance argument false + bsr ra, ZwRaiseException // perform last chance processing + +// +// Common code for unsuccessful completion of the continue or last chance +// service. Use the return status (which is now in v0) as the exception code, +// set noncontinuable exception and attempt to raise another exception. Note +// the stack grows and eventually this loop will end. +// + +20: lda sp, -ExceptionRecordLength(sp) // allocate exception record + mov sp, a0 // get address of actual record + stl v0, ErExceptionCode(a0) // set exception code + ldil t0, EXCEPTION_NONCONTINUABLE // set noncontinuable flag + stl t0, ErExceptionFlags(a0) // store exception flags + stl s0, ErExceptionRecord(a0) // set associated exception record + stl zero, ErNumberParameters(a0) // set number of parameters + bsr ra, RtlRaiseException // raise exception + br zero, 20b // loop on 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. +// +// Arguments: +// +// v0 - 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 Fir address of the trap frame. Thus when +// the kernel returns from the trap, the following code is executed directly. +// + + .struct 0 +RaiseRa: .space 8 // saved return address +RaiseV0: .space 8 // saved S0 +RaiseExr: .space ExceptionRecordLength // exception record for RtlRaiseException +RaiseFrameLength: // length of handler frame + + NESTED_ENTRY(KiRaiseUserExceptionDispatcher, RaiseFrameLength, zero) + lda sp, -RaiseFrameLength(sp) // allocate stack frame + stq ra, RaiseRa(sp) // save return address + PROLOGUE_END + + stq v0, RaiseV0(sp) // save function return status + stl v0, ErExceptionCode+RaiseExr(sp) // set exception code + stl zero, ErExceptionFlags+RaiseExr(sp) // set exception flags + stl zero, ErExceptionRecord+RaiseExr(sp) // set exception record + stl ra, ErExceptionAddress+RaiseExr(sp) // set exception address + stl zero, ErNumberParameters+RaiseExr(sp) + + lda a0, RaiseExr(sp) // set argument to RtlRaiseException + bsr ra, RtlRaiseException // attempt to raise the exception + + ldq v0, RaiseV0(sp) // return status + + ldq ra, RaiseRa(sp) // restore ra + lda sp, RaiseFrameLength(sp) // deallocate stack frame + ret zero, (ra) // return + + .end KiRaiseUserExceptionDispatch -- cgit v1.2.3