title  "User Mode Dispatcher Code"
;++
;
; Copyright (c) 1989  Microsoft Corporation
;
; Module Name:
;
;    userdisp.asm
;
; Abstract:
;
;    The module contains procedures to do user mode dispatching
;    ("trampolining") of user apcs and user exceptions.
;
; Author:
;
;    Bryan M Willman (bryanwi) 31-Aug-90
;
; Environment:
;
;    User mode.
;
; Revision History:
;
;--
.386p
        .xlist
include ks386.inc
include callconv.inc            ; calling convention macros
        .list

ifndef WX86_i386
        EXTRNP  _ZwCallbackReturn,3
endif

        EXTRNP  _ZwContinue,2
        EXTRNP  _RtlDispatchException,2
        EXTRNP  _RtlRaiseStatus,1
        EXTRNP  _ZwRaiseException,3
        EXTRNP  _RtlRaiseException,1
;
; Exception record size definition.
;

ExceptionRecordSize = (ErNumberParameters + 4 + 3) AND 0fffffffcH ;

        page ,132
_TEXT   SEGMENT DWORD PUBLIC 'CODE'
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

ifndef WX86_i386
        page
        subttl  "User APC Dispatcher"
;++
;
; VOID
; KiUserApcDispatcher (
;    IN PKNORMAL_ROUTINE NormalRoutine,
;    IN PVOID NormalContext,
;    IN PVOID SystemArgument1,
;    IN PVOID SystemArgument2,
;    IN CONTEXT ContinueContext
;    )
;
; 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:
;
;    NormalRoutine - Supplies that address of the function that is to be called.
;
;    NormalContext] - Supplies the normal context parameter that was specified
;       when the APC was initialized.
;
;    SystemArgument1 - Supplies the first argument that was provied by the
;       executive when the APC was queued.
;
;    SystemArgument2 - Supplies the second argument that was provided by
;       the executive when the APC was queued.
;
;    ContinueContext - Context record to pass to Continue call.
;
;
; Return Value:
;
;    None.
;
;--
cPublicProc _KiUserApcDispatcher ,5

        lea     edi, [esp+16]           ; (edi)->context frame
        pop     eax                     ; (eax)->specified function
        call    eax                     ; call the specified function

; 1 - set alert argument true
; ebp - addr of context frame
; execute system service to continue
        stdCall   _ZwContinue, <edi, 1>

stdENDP _KiUserApcDispatcher


        page
        subttl  "User Callback Dispatcher"
;++
;
; 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.
;
; Arguments:
;
;    ApiNumber - Supplies the API number of the callback function that is
;        executed.
;
;    InputBuffer - Supplies a pointer to the input buffer.
;
;    InputLength - Supplies the input buffer length.
;
; Return Value:
;
;    This function returns to kernel mode.
;
;--
cPublicProc _KiUserCallbackDispatcher, 3
.FPO (0, 0, 0, 0, 0, 0)

        add     esp,4                   ; skip over return address
        pop     edx                     ; get address of callback function

                                        ; get peb pointer from teb
        mov     eax,fs:[PcTeb]
        mov     eax,[eax].TebPeb
        mov     eax,[eax].PebKernelCallbackTable    ; get address of callback table

        call    [eax+edx*4]             ; 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
ifdef BUILD_WOW6432
        stdCall _ZwCallbackReturn, <ecx, ecx, eax>
else
        xor     edx,edx                 ; clear output buffer length
        int     02bH                    ; return from callback
endif
        int     3                       ; break if return occurs

stdENDP _KiUserCallbackDispatcher

endif  ;; ndef WX86_i386

        page
        subttl  "User Exception Dispatcher"
;++
;
; 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.
;
;    NOTE:  This procedure is not called, but rather dispatched to.
;           It depends on there not being a return address on the stack
;           (assumption w.r.t. argument offsets.)
;
; Arguments:
;
;    ExceptionRecord (esp+0) - Supplies a pointer to an exception record.
;
;    ContextRecord (esp+4) - Supplies a pointer to a context frame.
;
; Return Value:
;
;    None.
;
;--

cPublicProc _KiUserExceptionDispatcher      ,2
.FPO (0, 2, 0, 0, 0, 0)

        mov     ecx, [esp+4]            ; (ecx)->context record
        mov     ebx, [esp]              ; (ebx)->exception record

; attempt to dispatch the exception
        stdCall   _RtlDispatchException, <ebx, ecx>

;
; 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 statusn is FALSE, then the exception was not handled
; and ZwRaiseException is called to perform last chance exception processing.
;

        or      al,al
        je      short kued10

;
; Continue execution.
;
        pop     ebx                     ; (ebx)->exception record
        pop     ecx                     ; (ecx)->context record

; continue execution
        stdCall   _ZwContinue, <ecx, 0>
        jmp     short kued20            ; join common code

;
; Last chance processing.
;
;   (esp+0) = ExceptionRecord
;   (esp+4) = ContextRecord
;

kued10: pop     ebx                     ; (ebx)->exception record
        pop     ecx                     ; (ecx)->context record

; ecx - context record
; ebx - exception record
; perform last chance processiong
        stdCall   _ZwRaiseException, <ebx, ecx, 0>

;
; Common code for nonsuccessful completion of the continue or raiseexception
; services. 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.
;

.FPO(0, 0, 0, 0, 0, 0)

kued20: add     esp, -ExceptionRecordSize ; allocate stack space
        mov     [esp]+ErExceptionCode, eax ; set exception code
        mov     dword ptr [esp]+ErExceptionFlags, EXCEPTION_NONCONTINUABLE
        mov     [esp]+ErExceptionRecord,ebx ; set associated exception record
        mov     dword ptr [esp]+ErNumberParameters, 0
                                        ; set number of parameters
; esp - addr of exception record
        stdCall   _RtlRaiseException, <esp>
; never return
        stdRET    _KiUserExceptionDispatcher

stdENDP _KiUserExceptionDispatcher

        page
        subttl  "Raise User Exception Dispatcher"
ifndef WX86_i386
;++
;
; NTSTATUS
; KiUserExceptionDispatcher (
;    IN PVOID ReturnAddress
;    IN NTSTATUS ExceptionCode
;    )
;
; Routine Description:
;
;    This routine is entered on return from kernel mode to raise a user
;    mode exception.
;
;    NOTE:  This procedure is not called, but rather dispatched to.
;
;    The exception code to be raised is passed in the TEB.
;
; Arguments:
;
;    ExceptionCode (TEB->ExceptionCode) - Supplies the exception code to be raised
;
; Return Value:
;
;    The exception code that was raised.
;
;--

cPublicProc _KiRaiseUserExceptionDispatcher

        push    ebp                     ; make the debugger happy
        mov     ebp, esp
        sub     esp, ExceptionRecordLength      ; allocate exception record
        mov     [esp].ErExceptionAddress, eax   ; set exception address
        mov     eax,fs:[PcTeb]                  ; get exception code to be raised
        mov     eax,[eax].TbExceptionCode       ;
        mov     [esp].ErExceptionCode, eax      ; store exception code
        mov     [esp].ErExceptionFlags, 0       ; set exception flags
        mov     [esp].ErExceptionRecord, 0      ; set exception record
        mov     [esp].ErNumberParameters, 0     ; set number of parameters
; raise the exception
        stdCall   _RtlRaiseException, <esp>
        mov     eax, [esp].ErExceptionCode
        mov     esp,ebp
        pop     ebp                     ; restore return code
        ret

stdENDP _KiRaiseUserExceptionDispatcher
endif  ;; ndef WX86_i386


_TEXT   ENDS

        END