diff --git a/dll/ntdll/dispatch/amd64/dispatch.S b/dll/ntdll/dispatch/amd64/dispatch.S index f433c5fb22e..6d132df7755 100644 --- a/dll/ntdll/dispatch/amd64/dispatch.S +++ b/dll/ntdll/dispatch/amd64/dispatch.S @@ -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 diff --git a/dll/ntdll/dispatch/amd64/stubs.c b/dll/ntdll/dispatch/amd64/stubs.c deleted file mode 100644 index b5af8f7ba2e..00000000000 --- a/dll/ntdll/dispatch/amd64/stubs.c +++ /dev/null @@ -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 -#define NDEBUG -#include - -/* 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; -} diff --git a/ntoskrnl/include/internal/amd64/ke.h b/ntoskrnl/include/internal/amd64/ke.h index 21a2c66a4f2..fa0408b921e 100644 --- a/ntoskrnl/include/internal/amd64/ke.h +++ b/ntoskrnl/include/internal/amd64/ke.h @@ -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 */ diff --git a/ntoskrnl/ke/amd64/ctxswitch.S b/ntoskrnl/ke/amd64/ctxswitch.S index b91f314ced9..a8346021e89 100644 --- a/ntoskrnl/ke/amd64/ctxswitch.S +++ b/ntoskrnl/ke/amd64/ctxswitch.S @@ -9,7 +9,6 @@ /* INCLUDES ******************************************************************/ -#include #include 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 diff --git a/ntoskrnl/ke/amd64/stubs.c b/ntoskrnl/ke/amd64/stubs.c index 185d68988de..c99a0efcfac 100644 --- a/ntoskrnl/ke/amd64/stubs.c +++ b/ntoskrnl/ke/amd64/stubs.c @@ -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; - diff --git a/ntoskrnl/ke/amd64/trap.S b/ntoskrnl/ke/amd64/trap.S index d361acb1fb1..7dbe7a291f4 100644 --- a/ntoskrnl/ke/amd64/trap.S +++ b/ntoskrnl/ke/amd64/trap.S @@ -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: diff --git a/ntoskrnl/ke/amd64/usercall.c b/ntoskrnl/ke/amd64/usercall.c index 38517cb58fc..42976d340ef 100644 --- a/ntoskrnl/ke/amd64/usercall.c +++ b/ntoskrnl/ke/amd64/usercall.c @@ -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); +} + diff --git a/ntoskrnl/ke/amd64/usercall_asm.S b/ntoskrnl/ke/amd64/usercall_asm.S new file mode 100644 index 00000000000..2d894161fed --- /dev/null +++ b/ntoskrnl/ke/amd64/usercall_asm.S @@ -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 + +; +; NTSTATUS +; KiUserModeCallout ( +; _Inout_ PKCALLOUT_FRAME CalloutFrame); +; +EXTERN KiUserModeCallout:PROC + +.code64 + +; +; NTSTATUS +; KiCallUserMode ( +; _In_ PVOID *OutputBuffer@, +; _In_ PULONG OutputLength@); +; +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 diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake index c69c284cdf2..6b2a127c2fd 100644 --- a/ntoskrnl/ntos.cmake +++ b/ntoskrnl/ntos.cmake @@ -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