Index: ntoskrnl/include/internal/ke.h =================================================================== --- ntoskrnl/include/internal/ke.h (revision 60601) +++ ntoskrnl/include/internal/ke.h (working copy) @@ -1050,7 +1050,15 @@ IN PULONG OutputLength ); +DECLSPEC_NORETURN VOID +FASTCALL +KiCallbackReturn( + IN PVOID Stack, + IN NTSTATUS Status +); + +VOID NTAPI KiInitMachineDependent(VOID); Index: ntoskrnl/ke/i386/usercall.c =================================================================== --- ntoskrnl/ke/i386/usercall.c (revision 60701) +++ ntoskrnl/ke/i386/usercall.c (working copy) @@ -351,5 +351,140 @@ KiServiceExit(CallbackTrapFrame, 0); } +/*++ + * @name NtCallbackReturn + * + * The NtCallbackReturn routine returns to kernel mode after a user-mode + * callback was done through KeUserModeCallback. It uses the callback frame + * which was setup in order to return the information, restores the stack, + * and resumes execution where it was left off. + * + * @param Result + * Pointer to a caller-allocated buffer where the return data + * from the user-mode function is located. + * + * @param ResultLength + * Size of the Output Buffer described above. + * + * @param CallbackStatus + * Status code of the callback operation. + * + * @return Status code of the callback operation. + * + * @remark This call MUST be paired with KeUserModeCallback. + * + *--*/ +NTSTATUS +NTAPI +NtCallbackReturn( + _In_ PVOID Result, + _In_ ULONG ResultLength, + _In_ NTSTATUS CallbackStatus) +{ + PKTHREAD CurrentThread; + PKCALLOUT_FRAME CalloutFrame; + PKTRAP_FRAME CallbackTrapFrame, TrapFrame; + PFX_SAVE_AREA FxSaveArea, CbFxSaveArea; + ULONG Size; + PKPCR Pcr; + PKTSS Tss; + /* Get the current thread and make sure we have a callback stack */ + CurrentThread = KeGetCurrentThread(); + CalloutFrame = CurrentThread->CallbackStack; + if (CalloutFrame == NULL) + { + return STATUS_NO_CALLBACK_ACTIVE; + } + + /* Get the trap frame */ + CallbackTrapFrame = CurrentThread->TrapFrame; + + /* Restore the exception list */ + Pcr = KeGetPcr(); + Pcr->NtTib.ExceptionList = CallbackTrapFrame->ExceptionList; + + /* Store the results in the callback stack */ + *((PVOID*)CalloutFrame->Result) = Result; + *((ULONG*)CalloutFrame->ResultLength) = ResultLength; + + /* Disable interrupts for NPX save and stack switch */ + _disable(); + + /* Set desination and origin NPX Frames */ + CbFxSaveArea = (PVOID)((ULONG)CurrentThread->InitialStack - sizeof(FX_SAVE_AREA)); + FxSaveArea = (PVOID)(CalloutFrame->InitialStack - sizeof(FX_SAVE_AREA)); + + /* Now copy back NPX State */ + FxSaveArea->U.FnArea.ControlWord = CbFxSaveArea->U.FnArea.ControlWord; + FxSaveArea->U.FnArea.StatusWord = CbFxSaveArea->U.FnArea.StatusWord; + FxSaveArea->U.FnArea.TagWord = CbFxSaveArea->U.FnArea.TagWord; + FxSaveArea->U.FnArea.DataSelector = CbFxSaveArea->U.FnArea.DataSelector; + FxSaveArea->Cr0NpxState = CbFxSaveArea->Cr0NpxState; + + /* Get the previous trap frame */ + TrapFrame = (PKTRAP_FRAME)CalloutFrame->TrapFrame; + + /* Check if we failed in user mode */ + if (CallbackStatus == STATUS_CALLBACK_POP_STACK) + { + /* Check if we came from v86 mode */ + if (CallbackTrapFrame->EFlags & EFLAGS_V86_MASK) + { + Size = sizeof(KTRAP_FRAME) - FIELD_OFFSET(KTRAP_FRAME, SegFs); + } + else + { + Size = FIELD_OFFSET(KTRAP_FRAME, V86Es) - FIELD_OFFSET(KTRAP_FRAME, SegFs); + } + + /* Copy back part of the trap frame */ + RtlCopyMemory(&TrapFrame->SegFs, &CallbackTrapFrame->SegFs, Size); + } + + /* Clear DR7 */ + TrapFrame->Dr7 = 0; + + /* Check if debugging was active */ + if (CurrentThread->Header.DebugActive & 0xFF) + { + /* Copy debug registers data from it */ + TrapFrame->Dr0 = CallbackTrapFrame->Dr0; + TrapFrame->Dr1 = CallbackTrapFrame->Dr1; + TrapFrame->Dr2 = CallbackTrapFrame->Dr2; + TrapFrame->Dr3 = CallbackTrapFrame->Dr3; + TrapFrame->Dr6 = CallbackTrapFrame->Dr6; + TrapFrame->Dr7 = CallbackTrapFrame->Dr7; + } + + /* Get TSS */ + Tss = Pcr->TSS; + + /* Check for V86 mode */ + if (TrapFrame->EFlags & EFLAGS_V86_MASK) + { + /* Set new stack address in TSS (full trap frame) */ + Tss->Esp0 = (ULONG_PTR)(TrapFrame + 1); + } + else + { + /* Set new stack address in TSS (non-V86 trap frame) */ + Tss->Esp0 = (ULONG_PTR)&TrapFrame->V86Es; + } + + /* Get the initial stack and restore it */ + CurrentThread->InitialStack = (PVOID)CalloutFrame->InitialStack; + + /* Restore the trap frame and the previous callback stack */ + CurrentThread->TrapFrame = TrapFrame; + CurrentThread->CallbackStack = (PVOID)CalloutFrame->CallbackStack; + + /* Bring interrupts back */ + _enable(); + + /* Now switch back to the old stack */ + KiCallbackReturn(&CalloutFrame->Edi, CallbackStatus); +} + + /* EOF */ Index: ntoskrnl/ke/i386/usercall_asm.S =================================================================== --- ntoskrnl/ke/i386/usercall_asm.S (revision 60601) +++ ntoskrnl/ke/i386/usercall_asm.S (working copy) @@ -76,185 +76,23 @@ ret 8 -/*++ - * @name NtCallbackReturn - * - * The NtCallbackReturn routine returns to kernel mode after a user-mode - * callback was done through KeUserModeCallback. It uses the callback frame - * which was setup in order to return the information, restores the stack, - * and resumes execution where it was left off. - * - * @param Result - * Pointer to a caller-allocated buffer where the return data - * from the user-mode function is located. - * - * @param ResultLength - * Size of the Output Buffer described above. - * - * @param CallbackStatus - * Status code of the callback operation. - * - * @return Status code of the callback operation. - * - * @remark This call MUST be paired with KeUserModeCallback. - * - *--*/ -PUBLIC _NtCallbackReturn@12 -_NtCallbackReturn@12: - /* Get the current thread and make sure we have a callback stack */ - mov eax, fs:[KPCR_CURRENT_THREAD] - mov ecx, [eax+KTHREAD_CALLBACK_STACK] - test ecx, ecx - jz NoStack +PUBLIC @KiCallbackReturn@8 +@KiCallbackReturn@8: - /* Get the trap frame */ - mov ebx, [eax+KTHREAD_TRAP_FRAME] + /* Restore the stack */ + mov esp, ecx - /* Restore the exception list */ - mov edx, [ebx+KTRAP_FRAME_EXCEPTION_LIST] - mov fs:[KPCR_EXCEPTION_LIST], edx - - /* Get the result, the result length and the status */ - mov edi, [esp+4] - mov esi, [esp+8] - mov ebp, [esp+12] - - /* Store the results in the callback stack */ - mov ebx, [ecx+CBSTACK_RESULT] - mov [ebx], edi - mov ebx, [ecx+CBSTACK_RESULT_LENGTH] - mov [ebx], esi - - /* Get the previous stack */ - mov ebx, [ecx] - - /* Disable interrupts for NPX save and stack switch */ - cli - - /* Get the initial stack and restore it */ - mov esi, [eax+KTHREAD_INITIAL_STACK] - mov [eax+KTHREAD_INITIAL_STACK], ebx - - /* Set desination and origin NPX Frames */ - sub esi, NPX_FRAME_LENGTH - sub ebx, NPX_FRAME_LENGTH - - /* Copy NPX Data */ - mov edx, [esi+FP_CONTROL_WORD] - mov [ebx+FP_CONTROL_WORD], edx - mov edx, [esi+FP_STATUS_WORD] - mov [ebx+FP_STATUS_WORD], edx - mov edx, [esi+FP_TAG_WORD] - mov [ebx+FP_TAG_WORD], edx - mov edx, [esi+FP_DATA_SELECTOR] - mov [ebx+FP_DATA_SELECTOR], edx - mov edx, [esi+FN_CR0_NPX_STATE] - mov [ebx+FN_CR0_NPX_STATE], edx - - /* Check if we failed in user mode */ - cmp ebp, STATUS_CALLBACK_POP_STACK - mov edi, [ecx+CBSTACK_TRAP_FRAME] - jz UserFault - -CheckDebug: - - /* Clear DR7 */ - and dword ptr [edi+KTRAP_FRAME_DR7], 0 - - /* Check if debugging was active */ - test byte ptr [eax+KTHREAD_DEBUG_ACTIVE], HEX(0FF) - jnz RestoreDebug - -RestoreStack: - - /* Get TSS */ - mov edx, fs:[KPCR_TSS] - - /* Restore stack pointer */ - lea esp, [ecx+CBSTACK_CALLBACK_STACK] - - /* Check if we were in V86 mode */ - test dword ptr [edi+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - jnz V86Ret - sub ebx, 16 - -V86Ret: - /* Restore the ESP in TSS */ - mov [edx+KTSS_ESP0], ebx - - /* Restore the trap frame */ - mov [eax+KTHREAD_TRAP_FRAME], edi - - /* Bring interrupts back */ - sti - - /* Restore the callback stack*/ - pop [eax+KTHREAD_CALLBACK_STACK] - /* Set status and return */ - mov eax, ebp + mov eax, edx pop edi pop esi pop ebx pop ebp - pop edx /* Clean stack and jump back */ - add esp, 8 - jmp edx + ret 8 -UserFault: - /* Set size to copy */ - mov ecx, (KTRAP_FRAME_V86_ES - KTRAP_FRAME_FS) / 4 - - /* Check if this was V86 mode */ - mov esi, [eax+KTHREAD_TRAP_FRAME] - test dword ptr [esi+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK - - /* Save EDI and load destination */ - mov edx, edi - lea edi, [edi+KTRAP_FRAME_FS] - jz NotV86 - add ecx, 16 / 4 - -NotV86: - /* Set source and copy */ - lea esi, [esi+KTRAP_FRAME_FS] - rep movsd - - /* Restore ECX and ECX */ - mov ecx, [eax+KTHREAD_CALLBACK_STACK] - mov edi, edx - jmp CheckDebug - -RestoreDebug: - /* Get a pointer to thread's trap frame */ - mov esi, [eax+KTHREAD_TRAP_FRAME] - - /* Copy debug registers data from it */ - mov edx, [esi+KTRAP_FRAME_DR0] - mov [edi+KTRAP_FRAME_DR0], edx - mov edx, [esi+KTRAP_FRAME_DR1] - mov [edi+KTRAP_FRAME_DR1], edx - mov edx, [esi+KTRAP_FRAME_DR2] - mov [edi+KTRAP_FRAME_DR2], edx - mov edx, [esi+KTRAP_FRAME_DR3] - mov [edi+KTRAP_FRAME_DR3], edx - mov edx, [esi+KTRAP_FRAME_DR6] - mov [edi+KTRAP_FRAME_DR6], edx - mov edx, [esi+KTRAP_FRAME_DR7] - mov [edi+KTRAP_FRAME_DR7], edx - - /* Jump back */ - jmp RestoreStack - -NoStack: - - /* Return failure */ - mov eax, STATUS_NO_CALLBACK_ACTIVE - ret 12 - /*++ * @name KeSwitchKernelStack *