mirror of
https://github.com/reactos/reactos.git
synced 2024-07-01 10:20:03 +00:00
[NTOSKRNL]
Rewrite NtCallbackReturn in C svn path=/trunk/; revision=60709
This commit is contained in:
parent
3440678be4
commit
4385bb351d
|
@ -1050,6 +1050,14 @@ KiCallUserMode(
|
|||
IN PULONG OutputLength
|
||||
);
|
||||
|
||||
DECLSPEC_NORETURN
|
||||
VOID
|
||||
FASTCALL
|
||||
KiCallbackReturn(
|
||||
IN PVOID Stack,
|
||||
IN NTSTATUS Status
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KiInitMachineDependent(VOID);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -76,184 +76,22 @@ _KiCallUserMode@8:
|
|||
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 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]
|
||||
/* Restore the stack */
|
||||
mov esp, ecx
|
||||
|
||||
/* 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
|
||||
|
||||
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
|
||||
/* Clean stack and return */
|
||||
ret 8
|
||||
|
||||
/*++
|
||||
* @name KeSwitchKernelStack
|
||||
|
|
Loading…
Reference in a new issue