mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[NTOS:KE:X64][NTDLL:X64] Implement x64 version of user callback code
This commit is contained in:
parent
52d1bb5ec9
commit
fdc1261fb7
9 changed files with 465 additions and 193 deletions
|
@ -14,6 +14,8 @@
|
|||
|
||||
EXTERN NtContinue:PROC
|
||||
EXTERN LdrpInit:PROC
|
||||
EXTERN ZwCallbackReturn:PROC
|
||||
EXTERN RtlRaiseStatus:PROC
|
||||
|
||||
.code
|
||||
|
||||
|
@ -59,8 +61,49 @@ PUBLIC KiRaiseUserExceptionDispatcher
|
|||
|
||||
PUBLIC KiUserCallbackDispatcher
|
||||
.PROC KiUserCallbackDispatcher
|
||||
.endprolog
|
||||
int 3
|
||||
|
||||
; The stack is set up with a UCALLOUT_FRAME
|
||||
; The frame ends with a MACHINE_FRAME.
|
||||
.PUSHFRAME
|
||||
|
||||
; This is for the Home space, Buffer, Length and ApiNumber
|
||||
.ALLOCSTACK 6 * 8
|
||||
.ENDPROLOG
|
||||
|
||||
#if DBG
|
||||
; We enter the function with a fully setup stack, so it must be aligned!
|
||||
test rsp, 15
|
||||
jz AlignmentOk
|
||||
int HEX(2C)
|
||||
AlignmentOk:
|
||||
#endif
|
||||
|
||||
; Get the parameters from the callout frame
|
||||
mov rcx, [rsp + CkBuffer]
|
||||
mov edx, [rsp + CkLength]
|
||||
mov r8d, [rsp + CkApiNumber]
|
||||
|
||||
; Get the callback table
|
||||
mov rax, gs:[TePeb]
|
||||
mov r9, [rax + PeKernelCallbackTable]
|
||||
|
||||
; Call the routine
|
||||
call qword ptr [r9 + r8 * 8]
|
||||
|
||||
; Return from callback
|
||||
xor ecx, ecx
|
||||
xor edx, edx
|
||||
mov r8d, eax
|
||||
call ZwCallbackReturn
|
||||
|
||||
; Save callback return value
|
||||
mov esi, eax
|
||||
|
||||
; Raise status
|
||||
StatusRaise:
|
||||
mov ecx, esi
|
||||
call RtlRaiseStatus
|
||||
jmp StatusRaise
|
||||
|
||||
.ENDP
|
||||
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS NT Library
|
||||
* FILE: dll/ntdll/dispatch/amd64/stubs.c
|
||||
* PURPOSE: AMD64 stubs
|
||||
* PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntdll.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
LdrInitializeThunk(ULONG Unknown1, // FIXME: Parameters!
|
||||
ULONG Unknown2,
|
||||
ULONG Unknown3,
|
||||
ULONG Unknown4)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
KiUserApcDispatcher(IN PVOID NormalRoutine,
|
||||
IN PVOID NormalContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KiRaiseUserExceptionDispatcher(VOID)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KiUserCallbackDispatcher(VOID)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KiUserExceptionDispatcher(VOID)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return;
|
||||
}
|
|
@ -383,6 +383,13 @@ HalAllocateAdapterChannel(
|
|||
IN ULONG NumberOfMapRegisters,
|
||||
IN PDRIVER_CONTROL ExecutionRoutine);
|
||||
|
||||
FORCEINLINE
|
||||
PULONG_PTR
|
||||
KiGetUserModeStackAddress(void)
|
||||
{
|
||||
return &PsGetCurrentThread()->Tcb.TrapFrame->Rsp;
|
||||
}
|
||||
|
||||
#endif /* __NTOSKRNL_INCLUDE_INTERNAL_AMD64_KE_H */
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <asm.inc>
|
||||
#include <ksamd64.inc>
|
||||
|
||||
EXTERN KiSwapContextResume:PROC
|
||||
|
@ -202,66 +201,17 @@ PUBLIC KiSwapContextInternal
|
|||
PUBLIC KiSwapContext
|
||||
.PROC KiSwapContext
|
||||
|
||||
/* Allocate a KEXCEPTION_FRAME on the stack (+8 for proper alignment) */
|
||||
sub rsp, KEXCEPTION_FRAME_LENGTH + 8
|
||||
.allocstack KEXCEPTION_FRAME_LENGTH + 8
|
||||
|
||||
/* save non-volatiles in KEXCEPTION_FRAME */
|
||||
mov [rsp + KEXCEPTION_FRAME_Rbp], rbp
|
||||
.savereg rbp, KEXCEPTION_FRAME_Rbp
|
||||
mov [rsp + KEXCEPTION_FRAME_Rbx], rbx
|
||||
.savereg rbx, KEXCEPTION_FRAME_Rbx
|
||||
mov [rsp + KEXCEPTION_FRAME_Rdi], rdi
|
||||
.savereg rdi, KEXCEPTION_FRAME_Rdi
|
||||
mov [rsp + KEXCEPTION_FRAME_Rsi], rsi
|
||||
.savereg rsi, KEXCEPTION_FRAME_Rsi
|
||||
mov [rsp + KEXCEPTION_FRAME_R12], r12
|
||||
.savereg r12, KEXCEPTION_FRAME_R12
|
||||
mov [rsp + KEXCEPTION_FRAME_R13], r13
|
||||
.savereg r13, KEXCEPTION_FRAME_R13
|
||||
mov [rsp + KEXCEPTION_FRAME_R14], r14
|
||||
.savereg r14, KEXCEPTION_FRAME_R14
|
||||
mov [rsp + KEXCEPTION_FRAME_R15], r15
|
||||
.savereg r15, KEXCEPTION_FRAME_R15
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm6], xmm6
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm7], xmm7
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm8], xmm8
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm9], xmm9
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm10], xmm10
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm11], xmm11
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm12], xmm12
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm13], xmm13
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm14], xmm14
|
||||
movdqa [rsp + KEXCEPTION_FRAME_Xmm15], xmm15
|
||||
// KEXCEPTION_FRAME_MxCsr
|
||||
.endprolog
|
||||
/* Generate a KEXCEPTION_FRAME on the stack */
|
||||
GENERATE_EXCEPTION_FRAME
|
||||
|
||||
/* Do the swap with the registers correctly setup */
|
||||
mov rcx, gs:[PcCurrentThread] /* Pointer to the new thread */
|
||||
call KiSwapContextInternal
|
||||
|
||||
/* restore non-volatile registers */
|
||||
mov rbp, [rsp + KEXCEPTION_FRAME_Rbp]
|
||||
mov rbx, [rsp + KEXCEPTION_FRAME_Rbx]
|
||||
mov rdi, [rsp + KEXCEPTION_FRAME_Rdi]
|
||||
mov rsi, [rsp + KEXCEPTION_FRAME_Rsi]
|
||||
mov r12, [rsp + KEXCEPTION_FRAME_R12]
|
||||
mov r13, [rsp + KEXCEPTION_FRAME_R13]
|
||||
mov r14, [rsp + KEXCEPTION_FRAME_R14]
|
||||
mov r15, [rsp + KEXCEPTION_FRAME_R15]
|
||||
movdqa xmm6, [rsp + KEXCEPTION_FRAME_Xmm6]
|
||||
movdqa xmm7, [rsp + KEXCEPTION_FRAME_Xmm7]
|
||||
movdqa xmm8, [rsp + KEXCEPTION_FRAME_Xmm8]
|
||||
movdqa xmm9, [rsp + KEXCEPTION_FRAME_Xmm9]
|
||||
movdqa xmm10, [rsp + KEXCEPTION_FRAME_Xmm10]
|
||||
movdqa xmm11, [rsp + KEXCEPTION_FRAME_Xmm11]
|
||||
movdqa xmm12, [rsp + KEXCEPTION_FRAME_Xmm12]
|
||||
movdqa xmm13, [rsp + KEXCEPTION_FRAME_Xmm13]
|
||||
movdqa xmm14, [rsp + KEXCEPTION_FRAME_Xmm14]
|
||||
movdqa xmm15, [rsp + KEXCEPTION_FRAME_Xmm15]
|
||||
/* Restore the registers from the KEXCEPTION_FRAME */
|
||||
RESTORE_EXCEPTION_STATE
|
||||
|
||||
/* Clean stack and return */
|
||||
add rsp, KEXCEPTION_FRAME_LENGTH + 8
|
||||
/* Return */
|
||||
ret
|
||||
.ENDP
|
||||
|
||||
|
|
|
@ -167,20 +167,6 @@ KiSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
|
|||
return OldStackBase;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
KeUserModeCallback(IN ULONG RoutineIndex,
|
||||
IN PVOID Argument,
|
||||
IN ULONG ArgumentLength,
|
||||
OUT PVOID *Result,
|
||||
OUT PULONG ResultLength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
__debugbreak();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiIdleLoop(VOID)
|
||||
|
@ -426,17 +412,6 @@ KiSystemService(IN PKTHREAD Thread,
|
|||
__debugbreak();
|
||||
}
|
||||
|
||||
NTSYSAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtCallbackReturn
|
||||
( IN PVOID Result OPTIONAL, IN ULONG ResultLength, IN NTSTATUS Status )
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
__debugbreak();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtSetLdtEntries
|
||||
|
@ -456,18 +431,4 @@ NtVdmControl(IN ULONG ControlCode,
|
|||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
KiCallUserMode(
|
||||
IN PVOID *OutputBuffer,
|
||||
IN PULONG OutputLength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
__debugbreak();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
ULONG ProcessCount;
|
||||
BOOLEAN CcPfEnablePrefetcher;
|
||||
|
||||
|
||||
|
|
|
@ -787,6 +787,15 @@ PUBLIC KiSystemCallEntry64
|
|||
mov r9, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9]
|
||||
call rax
|
||||
|
||||
.ENDP
|
||||
|
||||
PUBLIC KiSystemServiceExit
|
||||
.PROC KiSystemServiceExit
|
||||
|
||||
/* Old stack pointer is in rcx, lie and say we saved it in rbp */
|
||||
.setframe rbp, 0
|
||||
.endprolog
|
||||
|
||||
#if DBG
|
||||
/* Restore rbp */
|
||||
mov rbp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rbp]
|
||||
|
@ -822,6 +831,38 @@ IntsEnabled:
|
|||
.ENDP
|
||||
|
||||
|
||||
/*!
|
||||
* VOID
|
||||
* DECLSPEC_NORETURN
|
||||
* KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status));
|
||||
*/
|
||||
PUBLIC KiServiceExit
|
||||
.PROC KiServiceExit
|
||||
.endprolog
|
||||
|
||||
lea rsp, [rcx - MAX_SYSCALL_PARAM_SIZE]
|
||||
jmp KiSystemServiceExit
|
||||
|
||||
.ENDP
|
||||
|
||||
|
||||
/*!
|
||||
* VOID
|
||||
* DECLSPEC_NORETURN
|
||||
* KiServiceExit2(IN PKTRAP_FRAME TrapFrame);
|
||||
*/
|
||||
PUBLIC KiServiceExit2
|
||||
.PROC KiServiceExit2
|
||||
.ENDPROLOG
|
||||
|
||||
mov rbp, rcx
|
||||
mov rsp, rcx
|
||||
|
||||
/* Return */
|
||||
ExitTrap TF_SAVE_ALL
|
||||
.ENDP
|
||||
|
||||
|
||||
PUBLIC KiSystemCallEntry32
|
||||
KiSystemCallEntry32:
|
||||
swapgs
|
||||
|
@ -962,35 +1003,6 @@ ENDFUNC
|
|||
KiExitToUserApc:
|
||||
int 3
|
||||
|
||||
/*!
|
||||
* VOID
|
||||
* DECLSPEC_NORETURN
|
||||
* KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status));
|
||||
*/
|
||||
PUBLIC KiServiceExit
|
||||
KiServiceExit:
|
||||
mov [rcx + KTRAP_FRAME_Rax], rdx
|
||||
mov rbp, rcx
|
||||
mov rsp, rcx
|
||||
|
||||
/* Return */
|
||||
//ExitTrap TF_SAVE_ALL
|
||||
|
||||
/*!
|
||||
* VOID
|
||||
* DECLSPEC_NORETURN
|
||||
* KiServiceExit2(IN PKTRAP_FRAME TrapFrame);
|
||||
*/
|
||||
PUBLIC KiServiceExit2
|
||||
.PROC KiServiceExit2
|
||||
.ENDPROLOG
|
||||
|
||||
mov rbp, rcx
|
||||
mov rsp, rcx
|
||||
|
||||
/* Return */
|
||||
ExitTrap TF_SAVE_ALL
|
||||
.ENDP
|
||||
|
||||
PUBLIC KiInitializeSegments
|
||||
KiInitializeSegments:
|
||||
|
|
|
@ -106,3 +106,293 @@ KiInitializeUserApc(
|
|||
TrapFrame->EFlags &= EFLAGS_USER_SANITIZE;
|
||||
TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stack layout for KiUserModeCallout:
|
||||
* ----------------------------------
|
||||
* KCALLOUT_FRAME.ResultLength <= 2nd Parameter to KiCallUserMode
|
||||
* KCALLOUT_FRAME.Result <= 1st Parameter to KiCallUserMode
|
||||
* KCALLOUT_FRAME.ReturnAddress <= Return address of KiCallUserMode
|
||||
* KCALLOUT_FRAME.Ebp \
|
||||
* KCALLOUT_FRAME.Ebx | = non-volatile registers, pushed
|
||||
* KCALLOUT_FRAME.Esi | by KiCallUserMode
|
||||
* KCALLOUT_FRAME.Edi /
|
||||
* KCALLOUT_FRAME.CallbackStack
|
||||
* KCALLOUT_FRAME.TrapFrame
|
||||
* KCALLOUT_FRAME.InitialStack <= CalloutFrame points here
|
||||
* ----------------------------------
|
||||
* ~~ optional alignment ~~
|
||||
* ----------------------------------
|
||||
* FX_SAVE_AREA
|
||||
* ----------------------------------
|
||||
* KTRAP_FRAME
|
||||
* ----------------------------------
|
||||
* ~~ begin of stack frame for KiUserModeCallout ~~
|
||||
*
|
||||
*/
|
||||
NTSTATUS
|
||||
FASTCALL
|
||||
KiUserModeCallout(
|
||||
_Out_ PKCALLOUT_FRAME CalloutFrame)
|
||||
{
|
||||
PKTHREAD CurrentThread;
|
||||
PKTRAP_FRAME TrapFrame;
|
||||
KTRAP_FRAME CallbackTrapFrame;
|
||||
PKIPCR Pcr;
|
||||
ULONG_PTR InitialStack;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Get the current thread */
|
||||
CurrentThread = KeGetCurrentThread();
|
||||
|
||||
/* Check if we are at pasive level */
|
||||
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
/* Check if we are attached or APCs are disabled */
|
||||
ASSERT((CurrentThread->ApcStateIndex == OriginalApcEnvironment) &&
|
||||
(CurrentThread->CombinedApcDisable == 0));
|
||||
|
||||
/* Align stack on a 16-byte boundary */
|
||||
InitialStack = (ULONG_PTR)ALIGN_DOWN_POINTER_BY(CalloutFrame, 16);
|
||||
|
||||
/* Check if we have enough space on the stack */
|
||||
if ((InitialStack - KERNEL_STACK_SIZE) < CurrentThread->StackLimit)
|
||||
{
|
||||
/* We don't, we'll have to grow our stack */
|
||||
Status = MmGrowKernelStack((PVOID)InitialStack);
|
||||
|
||||
/* Quit if we failed */
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
/* Save the current callback stack and initial stack */
|
||||
CalloutFrame->CallbackStack = (ULONG_PTR)CurrentThread->CallbackStack;
|
||||
CalloutFrame->InitialStack = (ULONG_PTR)CurrentThread->InitialStack;
|
||||
|
||||
/* Get and save the trap frame */
|
||||
TrapFrame = CurrentThread->TrapFrame;
|
||||
CalloutFrame->TrapFrame = (ULONG_PTR)TrapFrame;
|
||||
|
||||
/* Set the new callback stack */
|
||||
CurrentThread->CallbackStack = CalloutFrame;
|
||||
|
||||
/* Disable interrupts so we can fill the NPX State */
|
||||
_disable();
|
||||
|
||||
/* Set the stack address */
|
||||
CurrentThread->InitialStack = (PVOID)InitialStack;
|
||||
|
||||
/* Copy the trap frame to the new location */
|
||||
CallbackTrapFrame = *TrapFrame;
|
||||
|
||||
/* Get PCR */
|
||||
Pcr = (PKIPCR)KeGetPcr();
|
||||
|
||||
/* Set user-mode dispatcher address as EIP */
|
||||
Pcr->TssBase->Rsp0 = InitialStack;
|
||||
Pcr->Prcb.RspBase = InitialStack;
|
||||
CallbackTrapFrame.Rip = (ULONG_PTR)KeUserCallbackDispatcher;
|
||||
|
||||
/* Bring interrupts back */
|
||||
_enable();
|
||||
|
||||
/* Exit to user-mode */
|
||||
KiServiceExit(&CallbackTrapFrame, 0);
|
||||
}
|
||||
|
||||
VOID
|
||||
KiSetupUserCalloutFrame(
|
||||
_Out_ PUCALLOUT_FRAME UserCalloutFrame,
|
||||
_In_ PKTRAP_FRAME TrapFrame,
|
||||
_In_ ULONG ApiNumber,
|
||||
_In_ PVOID Buffer,
|
||||
_In_ ULONG BufferLength)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
CalloutFrame->Reserved = 0;
|
||||
CalloutFrame->ApiNumber = ApiNumber;
|
||||
CalloutFrame->Buffer = (ULONG_PTR)NewStack;
|
||||
CalloutFrame->Length = ArgumentLength;
|
||||
#elif defined(_M_AMD64)
|
||||
UserCalloutFrame->Buffer = (PVOID)(UserCalloutFrame + 1);
|
||||
UserCalloutFrame->Length = BufferLength;
|
||||
UserCalloutFrame->ApiNumber = ApiNumber;
|
||||
UserCalloutFrame->MachineFrame.Rip = TrapFrame->Rip;
|
||||
UserCalloutFrame->MachineFrame.Rsp = TrapFrame->Rsp;
|
||||
#else
|
||||
#error "KiSetupUserCalloutFrame not implemented!"
|
||||
#endif
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
KeUserModeCallback(
|
||||
IN ULONG RoutineIndex,
|
||||
IN PVOID Argument,
|
||||
IN ULONG ArgumentLength,
|
||||
OUT PVOID *Result,
|
||||
OUT PULONG ResultLength)
|
||||
{
|
||||
ULONG_PTR OldStack;
|
||||
PUCHAR UserArguments;
|
||||
PUCALLOUT_FRAME CalloutFrame;
|
||||
PULONG_PTR UserStackPointer;
|
||||
NTSTATUS CallbackStatus;
|
||||
#ifdef _M_IX86
|
||||
PEXCEPTION_REGISTRATION_RECORD ExceptionList;
|
||||
#endif // _M_IX86
|
||||
PTEB Teb;
|
||||
ULONG GdiBatchCount = 0;
|
||||
ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
|
||||
ASSERT(KeGetPreviousMode() == UserMode);
|
||||
|
||||
/* Get the current user-mode stack */
|
||||
UserStackPointer = KiGetUserModeStackAddress();
|
||||
OldStack = *UserStackPointer;
|
||||
|
||||
/* Enter a SEH Block */
|
||||
_SEH2_TRY
|
||||
{
|
||||
/* Calculate and align the stack size */
|
||||
UserArguments = (PUCHAR)ALIGN_DOWN_POINTER_BY(OldStack - ArgumentLength, sizeof(PVOID));
|
||||
|
||||
/* The callout frame is below the arguments */
|
||||
CalloutFrame = ((PUCALLOUT_FRAME)UserArguments) - 1;
|
||||
|
||||
/* Make sure it's all writable */
|
||||
ProbeForWrite(CalloutFrame,
|
||||
sizeof(PUCALLOUT_FRAME) + ArgumentLength,
|
||||
sizeof(PVOID));
|
||||
|
||||
/* Copy the buffer into the stack */
|
||||
RtlCopyMemory(UserArguments, Argument, ArgumentLength);
|
||||
|
||||
/* Write the arguments */
|
||||
KiSetupUserCalloutFrame(CalloutFrame,
|
||||
KeGetCurrentThread()->TrapFrame,
|
||||
RoutineIndex,
|
||||
UserArguments,
|
||||
ArgumentLength);
|
||||
|
||||
/* Save the exception list */
|
||||
Teb = KeGetCurrentThread()->Teb;
|
||||
#ifdef _M_IX86
|
||||
ExceptionList = Teb->NtTib.ExceptionList;
|
||||
#endif // _M_IX86
|
||||
|
||||
/* Jump to user mode */
|
||||
*UserStackPointer = (ULONG_PTR)CalloutFrame;
|
||||
CallbackStatus = KiCallUserMode(Result, ResultLength);
|
||||
if (CallbackStatus != STATUS_CALLBACK_POP_STACK)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
/* Only restore the exception list if we didn't crash in ring 3 */
|
||||
Teb->NtTib.ExceptionList = ExceptionList;
|
||||
#endif // _M_IX86
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, pop the stack */
|
||||
OldStack = *UserStackPointer;
|
||||
}
|
||||
|
||||
/* Read the GDI Batch count */
|
||||
GdiBatchCount = Teb->GdiBatchCount;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
/* Get the SEH exception */
|
||||
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
/* Check if we have GDI Batch operations */
|
||||
if (GdiBatchCount)
|
||||
{
|
||||
*UserStackPointer -= 256;
|
||||
KeGdiFlushUserBatch();
|
||||
}
|
||||
|
||||
/* Restore stack and return */
|
||||
*UserStackPointer = OldStack;
|
||||
#ifdef _M_AMD64 // could probably move the update to TrapFrame->Rsp from the C handler to the asm code
|
||||
__writegsqword(FIELD_OFFSET(KIPCR, UserRsp), OldStack);
|
||||
#endif
|
||||
return CallbackStatus;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtCallbackReturn(
|
||||
_In_ PVOID Result,
|
||||
_In_ ULONG ResultLength,
|
||||
_In_ NTSTATUS CallbackStatus)
|
||||
{
|
||||
PKTHREAD CurrentThread;
|
||||
PKCALLOUT_FRAME CalloutFrame;
|
||||
PKTRAP_FRAME CallbackTrapFrame, TrapFrame;
|
||||
PKIPCR Pcr;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Store the results in the callback stack */
|
||||
*((PVOID*)CalloutFrame->OutputBuffer) = Result;
|
||||
*((ULONG*)CalloutFrame->OutputLength) = ResultLength;
|
||||
|
||||
/* Get the trap frame */
|
||||
CallbackTrapFrame = CurrentThread->TrapFrame;
|
||||
|
||||
/* Disable interrupts for NPX save and stack switch */
|
||||
_disable();
|
||||
|
||||
/* Restore the exception list */
|
||||
Pcr = (PKIPCR)KeGetPcr();
|
||||
|
||||
/* Get the previous trap frame */
|
||||
TrapFrame = (PKTRAP_FRAME)CalloutFrame->TrapFrame;
|
||||
|
||||
/* Check if we failed in user mode */
|
||||
if (CallbackStatus == STATUS_CALLBACK_POP_STACK)
|
||||
{
|
||||
*TrapFrame = *CallbackTrapFrame;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Switch the stack back to the previous value */
|
||||
Pcr->TssBase->Rsp0 = CalloutFrame->InitialStack;
|
||||
Pcr->Prcb.RspBase = CalloutFrame->InitialStack;
|
||||
|
||||
/* 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, CallbackStatus);
|
||||
}
|
||||
|
||||
|
|
75
ntoskrnl/ke/amd64/usercall_asm.S
Normal file
75
ntoskrnl/ke/amd64/usercall_asm.S
Normal file
|
@ -0,0 +1,75 @@
|
|||
;++
|
||||
; PROJECT: ReactOS Kernel
|
||||
; LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
; PURPOSE: ReactOS AMD64 user mode callback helper
|
||||
; COPYRIGHT: Timo Kreuzer (timo.kreuzer@reactos.org)
|
||||
;--
|
||||
|
||||
#include <ksamd64.inc>
|
||||
|
||||
;
|
||||
; NTSTATUS
|
||||
; KiUserModeCallout (
|
||||
; _Inout_ PKCALLOUT_FRAME CalloutFrame);
|
||||
;
|
||||
EXTERN KiUserModeCallout:PROC
|
||||
|
||||
.code64
|
||||
|
||||
;
|
||||
; NTSTATUS
|
||||
; KiCallUserMode (
|
||||
; _In_ PVOID *OutputBuffer@<rcx>,
|
||||
; _In_ PULONG OutputLength@<rdx>);
|
||||
;
|
||||
PUBLIC KiCallUserMode
|
||||
.PROC KiCallUserMode
|
||||
|
||||
; Generate a KEXCEPTION_FRAME on the stack
|
||||
; This is identical to a KCALLOUT_FRAME
|
||||
GENERATE_EXCEPTION_FRAME
|
||||
|
||||
; Save OutputBuffer and OutputLength
|
||||
mov [rsp + ExOutputBuffer], rcx
|
||||
mov [rsp + ExOutputLength], rdx
|
||||
|
||||
; Call the C function
|
||||
mov rcx, rsp
|
||||
call KiUserModeCallout
|
||||
|
||||
; Restore the registers from the KEXCEPTION_FRAME
|
||||
RESTORE_EXCEPTION_STATE
|
||||
|
||||
; Return
|
||||
ret
|
||||
|
||||
.ENDP
|
||||
|
||||
;
|
||||
; DECLSPEC_NORETURN
|
||||
; VOID
|
||||
; KiCallbackReturn (
|
||||
; _In_ PVOID Stack,
|
||||
; _In_ NTSTATUS Status);
|
||||
;
|
||||
PUBLIC KiCallbackReturn
|
||||
.PROC KiCallbackReturn
|
||||
|
||||
.ENDPROLOG
|
||||
|
||||
; Restore the stack
|
||||
mov rsp, rcx
|
||||
|
||||
; Set return status
|
||||
mov eax, edx
|
||||
|
||||
; Restore the registers from the KEXCEPTION_FRAME
|
||||
RESTORE_EXCEPTION_STATE
|
||||
|
||||
; Return
|
||||
ret
|
||||
|
||||
.ENDP
|
||||
|
||||
|
||||
END
|
|
@ -314,7 +314,8 @@ elseif(ARCH STREQUAL "amd64")
|
|||
list(APPEND ASM_SOURCE
|
||||
${REACTOS_SOURCE_DIR}/ntoskrnl/ke/amd64/boot.S
|
||||
${REACTOS_SOURCE_DIR}/ntoskrnl/ke/amd64/ctxswitch.S
|
||||
${REACTOS_SOURCE_DIR}/ntoskrnl/ke/amd64/trap.S)
|
||||
${REACTOS_SOURCE_DIR}/ntoskrnl/ke/amd64/trap.S
|
||||
${REACTOS_SOURCE_DIR}/ntoskrnl/ke/amd64/usercall_asm.S)
|
||||
list(APPEND SOURCE
|
||||
${REACTOS_SOURCE_DIR}/ntoskrnl/config/i386/cmhardwr.c
|
||||
${REACTOS_SOURCE_DIR}/ntoskrnl/ke/amd64/context.c
|
||||
|
|
Loading…
Reference in a new issue