[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / ke / i386 / usercall.c
index 91bd672..8876da0 100644 (file)
@@ -351,5 +351,140 @@ KiUserModeCallout(PKCALLOUT_FRAME CalloutFrame)
     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 */