windows-nt/Source/XPSP1/NT/base/ntos/rtl/amd64/trampoln.asm
2020-09-26 16:20:57 +08:00

480 lines
16 KiB
NASM

title "User Mode Dispatch Code"
;++
;
; Copyright (c) 2000 Microsoft Corporation
;
; Module Name:
;
; trampoln.asm
;
; Abstract:
;
; This module implements the trampoline code necessary to dispatch user
; mode APCs and exceptions.
;
; Author:
;
; David N. Cutler (davec) 4-Jul-2000
;
; Environment:
;
; User mode.
;
;--
include ksamd64.inc
extern RtlDispatchException:proc
extern RtlRaiseException:proc
extern RtlRaiseStatus:proc
extern RtlRestoreContext:proc
extern Wow64PrepareForException:qword
extern ZwCallbackReturn:proc
extern ZwContinue:proc
extern ZwRaiseException:proc
extern ZwTestAlert:proc
subttl "User APC Exception Handler"
;++
;
; EXCEPTION_DISPOSITION
; KiUserApcHandler (
; IN PEXCEPTION_RECORD ExceptionRecord,
; IN UINT_PTR 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 (rcx) - Supplies a pointer to an exception record.
;
; EstablisherFrame (rdx) - Supplies the frame pointer of the establisher
; of this exception handler.
;
; ContextRecord (r8) - Supplies a pointer to a context record.
;
; DispatcherContext (r9) - Supplies a pointer to the dispatcher context
; record.
;
; Return Value:
;
; Continue search is returned as the function value.
;
;--
UaFrame struct
Fill dq ? ; fill to 8 mod 16
UaFrame ends
NESTED_ENTRY KiUserApcHandler, _TEXT$00
alloc_stack (sizeof UaFrame) ; allocate stack frame
END_PROLOGUE
test dword ptr ErExceptionFlags[rcx], EXCEPTION_UNWIND ; test if unwinding
jz short @f ; if z, unwind not in progress
call ZwTestAlert ; test for alert pending
@@: mov rax, ExceptionContinueSearch ; set continue search disposition
sub rsp, sizeof UaFrame ; deallocate stack frame
ret ; return
NESTED_END KiUserApcHandler, _TEXT$00
subttl "User APC Dispatcher"
;++
;
; The following code is never executed. Its purpose is to support exception
; dispatching and unwinding through the call to the APC dispatcher.
;
;--
altentry KiUserApcDispatcher
NESTED_ENTRY KiUserApcDispatch, _TEXT$00, KiUserApcHandler
.pushframe ; push machine frame
.allocstack CONTEXT_FRAME_LENGTH ; allocate stack frame
.savereg rbx, CxRbx ; save nonvolatile integer registers
.savereg rbp, CxRbp ;
.savereg rsi, CxRsi ;
.savereg rdi, CxRdi ;
.savereg r12, CxR12 ;
.savereg r13, CxR13 ;
.savereg r14, CxR14 ;
.savereg r15, CxR15 ;
.savexmm128 xmm6, CxXmm6 ; save nonvolatile floating register
.savexmm128 xmm7, CxXmm7 ;
.savexmm128 xmm8, CxXmm8 ;
.savexmm128 xmm9, CxXmm9 ;
.savexmm128 xmm10, CxXmm10 ;
.savexmm128 xmm11, CxXmm11 ;
.savexmm128 xmm12, CxXmm12 ;
.savexmm128 xmm13, CxXmm13 ;
.savexmm128 xmm14, CxXmm14 ;
.savexmm128 xmm15, CxXmm15 ;
END_PROLOGUE
;++
;
; 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.
;
; 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 below is stored into the RIP address of the trap frame. Thus
; when the kernel returns from the trap, the following code is executed
; directly.
;
; N.B. The home addresses for called routine register parameters are
; allocated in the context record.
;
; Arguments:
;
; NormalContext (P1Home) - Supplies the normal context parameter that was
; specified when the APC was initialized.
;
; SystemArgument1 (P2Home) - Supplies the first argument that was provided by
; the system when the APC was queued.
;
; SystemArgument2 (P3Home) - Supplies the second argument that was provided by
; the system when the APC was queued.
;
; NormalRoutine (P4Home) - Supplies the address of the function that is to
; be called.
;
; N.B. Register RSP supplies a pointer to a context record.
;
; Return Value:
;
; None.
;
;--
ALTERNATE_ENTRY KiUserApcDispatcher
mov rcx, CxP1Home[rsp] ; get APC parameters
mov rdx, CxP2Home[rsp] ;
mov r8, CxP3Home[rsp] ;
call qword ptr CxP4Home[rsp] ; call APC routine
;
; N.B. The system service to continue execution must be called since test
; alert must also be executed.
;
mov rcx, rsp ; set address of context record
mov dl, TRUE ; set test alert argument
call ZwContinue ; continue execution
;
; Unsuccessful completion after attempting to continue execution. Use the
; return status as the exception code and attempt to raise another exception.
;
mov esi, eax ; save return status
@@: mov ecx, esi ; set status value
call RtlRaiseStatus ; raise status
jmp short @b ; loop forever
NESTED_END KiUserApcDispatch, _TEXT$00
subttl "User Callback Dispatcher"
;++
;
; The following code is never executed. Its purpose is to support exception
; dispatching and unwinding through the call to the exception dispatcher.
;
;--
altentry KiUserCallbackDispatcher
NESTED_ENTRY KiUserCallbackDispatch, _TEXT$00
.pushframe ; push machine frame
.allocstack (CalloutFrameLength - MachineFrameLength) ; allocate stack frame
END_PROLOGUE
;++
;
; VOID
; KiUserCallbackDispatcher (
; IN ULONG ApiNumber,
; IN PVOID InputBuffer,
; IN ULONG INputLength
; )
;
; 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.
;
; 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 below is stored into the RIP address of the trap frame. Thus
; when the kernel returns from the trap, the following code is executed
; directly.
;
; N.B. The home addresses for called routine register parameters are
; allocated in the user callout frame.
;
; Arguments:
;
; N.B. Register RSP supplies a pointer to a user callout record.
;
; Return Value:
;
; This function returns to kernel mode.
;
;--
ALTERNATE_ENTRY KiUserCallbackDispatcher
mov rcx, CkBuffer[rsp] ; set input buffer address
mov edx, CkLength[rsp] ; set input buffer length
mov r8d, CkApiNumber[rsp] ; get API number
mov rax, gs:[TePeb] ; get process environment block address
mov r9, PeKernelCallbackTable[rax] ; get callback table address
call qword ptr [r9][r8 * 8] ; call specified function
;
; If a return from the callback function occurs, then the output buffer
; address and length are returned as NULL.
;
xor ecx, ecx ; clear output buffer address
xor edx, edx ; clear output buffer length
mov r8d, eax ; set completion status
call ZwCallbackReturn ; return to kernel mode
;
; Unsuccessful completion after attempting to return to kernel mode. Use the
; return status as the exception code and attempt to raise another exception.
;
mov esi, eax ; save status value
@@: mov ecx, esi ; set status value
call RtlRaiseStatus ; raise exception
jmp short @b ; loop forever
NESTED_END KiUserCallbackDispatch, _TEXT$00
subttl "User Exception Dispatcher"
;++
;
; The following code is never executed. Its purpose is to support exception
; dispatching and unwinding through the call to the exception dispatcher.
;
;--
ExceptionFramelength equ (ExceptionRecordLength + CONTEXT_FRAME_LENGTH)
altentry KiUserExceptionDispatcher
NESTED_ENTRY KiUserExceptionDispatch, _TEXT$00
.pushframe ;
.allocstack (ExceptionRecordLength + CONTEXT_FRAME_LENGTH) ; allocate stack frame
.savereg rbx, CxRbx ; save nonvolatile integer registers
.savereg rbp, CxRbp ;
.savereg rsi, CxRsi ;
.savereg rdi, CxRdi ;
.savereg r12, CxR12 ;
.savereg r13, CxR13 ;
.savereg r14, CxR14 ;
.savereg r15, CxR15 ;
.savexmm128 xmm6, CxXmm6 ; save nonvolatile floating register
.savexmm128 xmm7, CxXmm7 ;
.savexmm128 xmm8, CxXmm8 ;
.savexmm128 xmm9, CxXmm9 ;
.savexmm128 xmm10, CxXmm10 ;
.savexmm128 xmm11, CxXmm11 ;
.savexmm128 xmm12, CxXmm12 ;
.savexmm128 xmm13, CxXmm13 ;
.savexmm128 xmm14, CxXmm14 ;
.savexmm128 xmm15, CxXmm15 ;
END_PROLOGUE
;++
;
; 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.
;
; 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 below is stored into the RIP address of the trap frame. Thus
; when the kernel returns from the trap, the following code is executed
; directly.
;
; N.B. The home addresses for called routine register parameters are
; allocated in the context record.
;
; Arguments:
;
; ExceptionRecord (rsi) - Supplies a pointer to an exception record.
;
; ContextRecord (rdi) - Supplies a pointer to a context record.
;
; Return Value:
;
; None.
;
;--
ALTERNATE_ENTRY KiUserExceptionDispatcher
;
; If this is a wow64 process, then give wow64 a chance to clean up before
; dispatching the exception.
;
mov rax, Wow64PrepareForException ; get wow64 routine address
test rax, rax ; test if routine specified
jz short Ue05 ; if z, routine not specified
mov rcx, rsi ; set exception record address
mov rdx, rdi ; set context record address
call rax ; call wow64 clean up routine
Ue05: mov rcx, rsi ; set exception record address
mov rdx, rdi ; set context record address
call RtlDispatchException ; dispatch the exception
;
; If the return status is TRUE, then the exception was handled and execution
; should be continued with the continue service in case the context was
; changed. If the return status is FALSE, then the exception was not handled
; and raise exception is called to perform last chance exception processing.
;
test al, al ; test if the exception was handled
jz short Ue10 ; if z, exception was not handled
;
; Restore context and continue execution.
;
mov rcx, rdi ; set context record address
xor edx, edx ; set set exception record address
call RtlRestoreContext ; restore context
jmp short Ue20 ; finish in common code
;
; Last chance processing.
;
Ue10: mov rcx, rsi ; set exception record address
mov rdx, rdi ; set context record address
xor r8b, r8b ; set first change argument falue
call ZwRaiseException ; raise exception
;
; Common code for nonsuccessful completion of the continue or raise exception
; services. Use the return status as the exception code and attempt to raise
; another exception.
;
Ue20: mov esi, eax ; save status value
@@: mov ecx, esi ; set status value
call RtlRaiseStatus ; raise exception
jmp short @b ; loop forever
NESTED_END KiUserExceptionDispatch, _TEXT$00
subttl "Raise User Exception Dispatcher"
;++
;
; NTSTATUS
; KiRaiseUserExceptionDispatcher (
; VOID
; )
;
; 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 normal manner. An exception is
; raised from within the system by placing the address of this
; function in the RIP of the trap frame. This replaces the normal
; return to the system service stub.
;
; Arguments:
;
; None.
;
; Implicit Arguments:
;
; Status (eax) - Supplies the system service status.
;
; Return Value:
;
; The exception code that was raised.
;
;--
RuFrame struct ;
P1Home dq ? ; parameter home address
Xrecord db ExceptionRecordLength dup (?) ; exception record
Status dd ? ; saved exception code
Fill1 dd ? ; fill to 0 mod 8
Fill2 dq ? ; fill to 8 mod 16
RuFrame ends
NESTED_ENTRY KiRaiseUserExceptionDispatcher, _TEXT$00
alloc_stack (sizeof RuFrame) ; allocate stack frame
END_PROLOGUE
mov RuFrame.Status[rsp], eax ; save the service status
mov eax, gs:[TeExceptionCode] ; get exception code
lea rcx, RuFrame.Xrecord[rsp] ; get exception record address
mov ErExceptionCode[rcx], eax ; set exception code
xor eax, eax ; generate zero value
mov ErExceptionFlags[rcx], eax ; zero exception flags
mov ErExceptionRecord[rcx], rax ; zero exception record
mov rdx, sizeof RuFrame[rsp] ; get the real return address
mov ErExceptionAddress[rcx], rdx ; set exception address
mov ErNumberParameters[rcx], eax ; zero number of parameters
call RtlRaiseException ; raise exception
mov eax, RuFrame.Status[rsp] ; get exception code to return
add rsp, sizeof RuFrame ; dealloate stack frame
ret ; return
NESTED_END KiRaiseUserExceptionDispatcher, _TEXT$00
end