;++
;
; NTSTATUS
; NtCallbackReturn (
; IN PVOID OutputBuffer OPTIONAL,
; IN ULONG OutputLength,
; IN NTSTATUS Status
; )
;
; Routine Description:
;
; This function returns from a user mode callout to the kernel mode
; caller of the user mode callback function.
;
; N.B. This service uses a nonstandard calling sequence.
;
; Arguments:
;
; OutputBuffer (ecx) - Supplies an optional pointer to an output buffer.
;
; OutputLength (edx) - Supplies the length of the output buffer.
;
; Status (esp + 4) - Supplies the status value returned to the caller of
; the callback function.
;
; Return Value:
;
; If the callback return cannot be executed, then an error status is
; returned. Otherwise, the specified callback status is returned to
; the caller of the callback function.
;
; N.B. This function returns to the function that called out to user
; mode is a callout is currently active.
;
;--
align 16
PUBLIC _KiCallbackReturn
_KiCallbackReturn proc
push fs ; save segment register
push ecx ; save buffer address and return status
push eax ;
mov ecx,KGDT_R0_PCR ; set PCR segment number
mov fs,cx ;
mov eax,PCR[PcPrcbData + PbCurrentThread] ; get current thread address
mov ecx,[eax].ThCallbackStack ; get callback stack address
or ecx,ecx ; check if callback active
jz _KiCbExit ; if z, no callback active
mov edi,[esp] + 4 ; set output buffer address
mov esi,edx ; set output buffer length
mov ebp,[esp] + 0 ; set return status
;
; N.B. The following code is entered with:
;
; eax - The address of the current thread.
; ecx - The callback stack address.
; edi - The output buffer address.
; esi - The output buffer length.
; ebp - The callback service status.
;
; Restore the trap frame and callback stack addresses,
; store the output buffer address and length, and set the service status.
;
cld ; clear the direction flag
mov ebx,[ecx].CuOutBf ; get address to store output buffer
mov [ebx],edi ; store output buffer address
mov ebx,[ecx].CuOutLn ; get address to store output length
mov [ebx],esi ; store output buffer length
mov esi,PCR[PcInitialStack] ; get source NPX save area address
mov ebx,[ecx] ; get previous initial stack address
mov [eax].ThInitialStack,ebx ; restore initial stack address
sub ebx,NPX_FRAME_LENGTH ; compute destination NPX save area
; All we want to do is to copy ControlWord, StatusWord and TagWord from
; the source NPX save area. So we always copy first 3 dwords, irrespective
; of the fact whether the save was done using fxsave or fnsave.
mov edx,[esi].FpControlWord ; copy NPX state to previous frame
mov [ebx].FpControlWord,edx ;
mov edx,[esi].FpStatusWord ;
mov [ebx].FpStatusWord,edx ;
mov edx,[esi].FpTagWord ;
mov [ebx].FpTagWord,edx ;
mov edx,[esi].FpCr0NpxState ;
mov [ebx].FpCr0NpxState,edx ;
mov edx,PCR[PcTss] ; get address of task switch segment
mov PCR[PcInitialStack],ebx ; restore stack check base address
sub ebx,TsV86Gs - TsHardwareSegSs ; bias for missing V86 fields
mov [edx].TssEsp0,ebx ; restore kernel entry stack address
mov esp,ecx ; trim stack back to callback frame
add esp,4 ;
sti ; enable interrupts
pop [eax].ThTrapFrame ; restore current trap frame address
pop [eax].ThCallbackStack ; restore callback stack address
mov eax,ebp ; set callback service status
;
; Restore nonvolatile registers, clean call parameters from stack, and
; return to callback caller.
;
pop edi ; restore nonvolatile registers
pop esi ;
pop ebx ;
pop ebp ;
pop edx ; save return address
add esp,8 ; remove parameters from stack
jmp edx ; return to callback caller
;
; Restore segment register, set systerm service status, and return.
;
_KiCbExit: ;
add esp, 2 * 4 ; remove saved registers from stack
pop fs ; restore segment register
mov eax,STATUS_NO_CALLBACK_ACTIVE ; set service status
iretd ;
_KiCallbackReturn endp