;++ ; ; 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