[NTOS:KE:X64][NTDLL:X64] Implement x64 version of user callback code

This commit is contained in:
Timo Kreuzer 2018-02-05 01:26:11 +01:00
parent 52d1bb5ec9
commit fdc1261fb7
9 changed files with 465 additions and 193 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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 */

View file

@ -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

View file

@ -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;

View file

@ -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:

View file

@ -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);
}

View 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

View file

@ -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