From e4007ae73a74e53d08b1f46c672bc006f82ca057 Mon Sep 17 00:00:00 2001 From: Stefan Ginsberg Date: Tue, 1 Sep 2015 23:45:48 +0000 Subject: [PATCH] - Implement super-simple KeSweepICache that always flushes the entire instruction cache. Use it in KD64 after modifying memory to make sure CPU gets the correct code to execute, and in NtFlushInstructionCache. May improve breakpoints somewhat. - Move NtFlushInstructionCache from sysinfo.c to virtual.c where it fits better. Likewise, move it from kefuncs to mmfuncs in NDK, and fix function arguments (ULONG -> SIZE_T). - Re-enable TRAP_DEBUG, adding back critical checks in the trap code. Checks can be improved but it is better than potentially silently messing up system state. - Move remaining RtlPrefetchMemoryNonTemporal code into kernel. Stubbed for non-x86. - By Hermes suggestion, override ASSERT to NT_ASSERT only for MSVC builds as that is where the main benefit is. svn path=/trunk/; revision=68907 --- reactos/dll/win32/kernel32/client/proc.c | 4 +- reactos/include/ndk/kefuncs.h | 9 -- reactos/include/ndk/mmfuncs.h | 9 ++ reactos/lib/rtl/mem.c | 15 ---- reactos/lib/rtl/powerpc/rtlmem.s | 3 - reactos/ntoskrnl/ex/sysinfo.c | 86 +------------------ reactos/ntoskrnl/include/internal/amd64/ke.h | 13 +++ reactos/ntoskrnl/include/internal/arm/ke.h | 13 +++ reactos/ntoskrnl/include/internal/i386/ke.h | 13 +++ .../ntoskrnl/include/internal/i386/trap_x.h | 6 +- .../ntoskrnl/include/internal/powerpc/ke.h | 13 +++ reactos/ntoskrnl/include/ntoskrnl.h | 2 + reactos/ntoskrnl/kd64/kdapi.c | 5 ++ reactos/ntoskrnl/ke/i386/traphdlr.c | 2 +- reactos/ntoskrnl/mm/ARM3/virtual.c | 67 +++++++++++++++ reactos/ntoskrnl/rtl/misc.c | 17 ++++ 16 files changed, 160 insertions(+), 117 deletions(-) diff --git a/reactos/dll/win32/kernel32/client/proc.c b/reactos/dll/win32/kernel32/client/proc.c index 809457c78b9..0f57b7bbffb 100644 --- a/reactos/dll/win32/kernel32/client/proc.c +++ b/reactos/dll/win32/kernel32/client/proc.c @@ -1507,12 +1507,12 @@ BOOL WINAPI FlushInstructionCache(IN HANDLE hProcess, IN LPCVOID lpBaseAddress, - IN SIZE_T dwSize) + IN SIZE_T nSize) { NTSTATUS Status; /* Call the native function */ - Status = NtFlushInstructionCache(hProcess, (PVOID)lpBaseAddress, dwSize); + Status = NtFlushInstructionCache(hProcess, (PVOID)lpBaseAddress, nSize); if (!NT_SUCCESS(Status)) { /* Handle failure case */ diff --git a/reactos/include/ndk/kefuncs.h b/reactos/include/ndk/kefuncs.h index a1e379fdc7f..bf8463ef13d 100644 --- a/reactos/include/ndk/kefuncs.h +++ b/reactos/include/ndk/kefuncs.h @@ -398,15 +398,6 @@ NtDelayExecution( _In_ LARGE_INTEGER *Interval ); -NTSYSCALLAPI -NTSTATUS -NTAPI -NtFlushInstructionCache( - _In_ HANDLE ProcessHandle, - _In_ PVOID BaseAddress, - _In_ ULONG NumberOfBytesToFlush -); - ULONG NTAPI NtGetCurrentProcessorNumber( diff --git a/reactos/include/ndk/mmfuncs.h b/reactos/include/ndk/mmfuncs.h index 0d3782fba9e..9872ecb9770 100644 --- a/reactos/include/ndk/mmfuncs.h +++ b/reactos/include/ndk/mmfuncs.h @@ -134,6 +134,15 @@ NtExtendSection( _In_ PLARGE_INTEGER NewMaximumSize ); +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushInstructionCache( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_ SIZE_T NumberOfBytesToFlush +); + NTSYSCALLAPI NTSTATUS NTAPI diff --git a/reactos/lib/rtl/mem.c b/reactos/lib/rtl/mem.c index 0704f521ab2..6927f543f3e 100644 --- a/reactos/lib/rtl/mem.c +++ b/reactos/lib/rtl/mem.c @@ -146,21 +146,6 @@ RtlMoveMemory(PVOID Destination, memmove(Destination, Source, Length); } - -/* -* @implemented -*/ -VOID -FASTCALL -RtlPrefetchMemoryNonTemporal(IN PVOID Source, - IN SIZE_T Length) -{ - /* By nature of prefetch, this is non-portable. */ - (void)Source; - (void)Length; -} - - #undef RtlZeroMemory /* * @implemented diff --git a/reactos/lib/rtl/powerpc/rtlmem.s b/reactos/lib/rtl/powerpc/rtlmem.s index 12c98c60aa3..8d08ed0424e 100644 --- a/reactos/lib/rtl/powerpc/rtlmem.s +++ b/reactos/lib/rtl/powerpc/rtlmem.s @@ -100,6 +100,3 @@ RtlZeroMemory: mr 5,4 xor 4,4,4 b memset - -RtlPrefetchMemoryNonTemporal: - blr diff --git a/reactos/ntoskrnl/ex/sysinfo.c b/reactos/ntoskrnl/ex/sysinfo.c index 3f5bf6f2663..570bf91f545 100644 --- a/reactos/ntoskrnl/ex/sysinfo.c +++ b/reactos/ntoskrnl/ex/sysinfo.c @@ -2533,99 +2533,19 @@ NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass, return Status; } -NTSTATUS -NTAPI -NtFlushInstructionCache( - _In_ HANDLE ProcessHandle, - _In_opt_ PVOID BaseAddress, - _In_ ULONG FlushSize) -{ - KAPC_STATE ApcState; - PKPROCESS Process; - NTSTATUS Status; - PAGED_CODE(); - - /* Is a base address given? */ - if (BaseAddress != NULL) - { - /* If the requested size is 0, there is nothing to do */ - if (FlushSize == 0) - { - return STATUS_SUCCESS; - } - - /* Is this a user mode call? */ - if (KeGetPreviousMode() != KernelMode) - { - /* Make sure the base address is in user space */ - if (BaseAddress > MmHighestUserAddress) - { - DPRINT1("Invalid BaseAddress 0x%p\n", BaseAddress); - return STATUS_ACCESS_VIOLATION; - } - } - } - - /* Is another process requested? */ - if (ProcessHandle != NtCurrentProcess()) - { - /* Reference the process */ - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_WRITE, - PsProcessType, - KeGetPreviousMode(), - (PVOID*)&Process, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to reference the process %p\n", ProcessHandle); - return Status; - } - - /* Attach to the process */ - KeStackAttachProcess(Process, &ApcState); - } - - /* FIXME: don't flush everything if a range is requested */ -#if defined(_M_IX86) || defined(_M_AMD64) - __wbinvd(); -#elif defined(_M_PPC) - __asm__ __volatile__("tlbsync"); -#elif defined(_M_MIPS) - DPRINT1("NtFlushInstructionCache() is not implemented\n"); - DbgBreakPoint(); -#elif defined(_M_ARM) - _MoveToCoprocessor(0, CP15_ICIALLU); -#else -#error Unknown architecture -#endif - - /* Check if we attached */ - if (ProcessHandle != NtCurrentProcess()) - { - /* Detach from the process */ - KeUnstackDetachProcess(&ApcState); - ObDereferenceObject(Process); - } - - return STATUS_SUCCESS; -} - ULONG NTAPI NtGetCurrentProcessorNumber(VOID) { - /* Just return the CPU */ + /* Just use Ke */ return KeGetCurrentProcessorNumber(); } -/* - * @implemented - */ #undef ExGetPreviousMode KPROCESSOR_MODE NTAPI -ExGetPreviousMode (VOID) +ExGetPreviousMode(VOID) { + /* Just use Ke */ return KeGetPreviousMode(); } diff --git a/reactos/ntoskrnl/include/internal/amd64/ke.h b/reactos/ntoskrnl/include/internal/amd64/ke.h index 1701fe60fb2..c5af042be7b 100644 --- a/reactos/ntoskrnl/include/internal/amd64/ke.h +++ b/reactos/ntoskrnl/include/internal/amd64/ke.h @@ -188,6 +188,19 @@ KeFlushProcessTb(VOID) __writecr3(__readcr3()); } +FORCEINLINE +VOID +KeSweepICache(IN PVOID BaseAddress, + IN SIZE_T FlushSize) +{ + // + // Always sweep the whole cache + // + UNREFERENCED_PARAMETER(BaseAddress); + UNREFERENCED_PARAMETER(FlushSize); + __wbinvd(); +} + FORCEINLINE VOID KiRundownThread(IN PKTHREAD Thread) diff --git a/reactos/ntoskrnl/include/internal/arm/ke.h b/reactos/ntoskrnl/include/internal/arm/ke.h index 32ac28d84df..2d39c580b15 100644 --- a/reactos/ntoskrnl/include/internal/arm/ke.h +++ b/reactos/ntoskrnl/include/internal/arm/ke.h @@ -116,6 +116,19 @@ KeFlushProcessTb(VOID) KeArmFlushTlb(); } +FORCEINLINE +VOID +KeSweepICache(IN PVOID BaseAddress, + IN SIZE_T FlushSize) +{ + // + // Always sweep the whole cache + // + UNREFERENCED_PARAMETER(BaseAddress); + UNREFERENCED_PARAMETER(FlushSize); + _MoveToCoprocessor(0, CP15_ICIALLU); +} + FORCEINLINE VOID KiRundownThread(IN PKTHREAD Thread) diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index 4dbdb2d5891..7c9cce3ffcc 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -266,6 +266,19 @@ KeFlushProcessTb(VOID) __writecr3(__readcr3()); } +FORCEINLINE +VOID +KeSweepICache(IN PVOID BaseAddress, + IN SIZE_T FlushSize) +{ + // + // Always sweep the whole cache + // + UNREFERENCED_PARAMETER(BaseAddress); + UNREFERENCED_PARAMETER(FlushSize); + __wbinvd(); +} + FORCEINLINE PRKTHREAD KeGetCurrentThread(VOID) diff --git a/reactos/ntoskrnl/include/internal/i386/trap_x.h b/reactos/ntoskrnl/include/internal/i386/trap_x.h index 99e7cba3262..444696fee7a 100644 --- a/reactos/ntoskrnl/include/internal/i386/trap_x.h +++ b/reactos/ntoskrnl/include/internal/i386/trap_x.h @@ -8,8 +8,6 @@ #pragma once -#define TRAP_DEBUG 0 - #define UNREACHABLE __assume(0) #if _MSC_VER @@ -72,9 +70,9 @@ KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame) DbgPrint("V86Gs: %x\n", TrapFrame->V86Gs); } -#if TRAP_DEBUG -VOID +#if DBG FORCEINLINE +VOID KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame) { /* Set the debug information */ diff --git a/reactos/ntoskrnl/include/internal/powerpc/ke.h b/reactos/ntoskrnl/include/internal/powerpc/ke.h index 4edfbf4ce94..87c72a2d505 100644 --- a/reactos/ntoskrnl/include/internal/powerpc/ke.h +++ b/reactos/ntoskrnl/include/internal/powerpc/ke.h @@ -89,6 +89,19 @@ KeFlushProcessTb(VOID) __asm__("sync\n\tisync\n\t"); } +FORCEINLINE +VOID +KeSweepICache(IN PVOID BaseAddress, + IN SIZE_T FlushSize) +{ + // + // Always sweep the whole cache + // + UNREFERENCED_PARAMETER(BaseAddress); + UNREFERENCED_PARAMETER(FlushSize); + __asm__ __volatile__("tlbsync"); +} + FORCEINLINE PRKTHREAD KeGetCurrentThread(VOID) diff --git a/reactos/ntoskrnl/include/ntoskrnl.h b/reactos/ntoskrnl/include/ntoskrnl.h index 1b51ebc3697..5e5c9b49bcd 100644 --- a/reactos/ntoskrnl/include/ntoskrnl.h +++ b/reactos/ntoskrnl/include/ntoskrnl.h @@ -98,8 +98,10 @@ extern UCHAR _KeNumberProcessors; // // NT_ASSERT Best Assert // +#if defined(_MSC_VER) #undef ASSERT #define ASSERT NT_ASSERT +#endif /* Internal Headers */ #include "internal/ntoskrnl.h" diff --git a/reactos/ntoskrnl/kd64/kdapi.c b/reactos/ntoskrnl/kd64/kdapi.c index 1c427922f7a..5f14240694c 100644 --- a/reactos/ntoskrnl/kd64/kdapi.c +++ b/reactos/ntoskrnl/kd64/kdapi.c @@ -84,6 +84,11 @@ KdpCopyMemoryChunks(IN ULONG64 Address, RemainingLength = RemainingLength - CopyChunk; } + /* + * We may have modified executable code, flush the instruction cache + */ + KeSweepICache((PVOID)Address, TotalSize); + /* * Return the size we managed to copy * and return success if we could copy the whole range diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index 908a35ef2ab..d3b041e2f1c 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -56,7 +56,7 @@ PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler; PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL; PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL; #endif -#if TRAP_DEBUG +#if DBG BOOLEAN StopChecking = FALSE; #endif diff --git a/reactos/ntoskrnl/mm/ARM3/virtual.c b/reactos/ntoskrnl/mm/ARM3/virtual.c index ee9446515f5..95c157184a8 100644 --- a/reactos/ntoskrnl/mm/ARM3/virtual.c +++ b/reactos/ntoskrnl/mm/ARM3/virtual.c @@ -2914,6 +2914,73 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle, return Status; } +NTSTATUS +NTAPI +NtFlushInstructionCache(_In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_ SIZE_T FlushSize) +{ + KAPC_STATE ApcState; + PKPROCESS Process; + NTSTATUS Status; + PAGED_CODE(); + + /* Is a base address given? */ + if (BaseAddress != NULL) + { + /* If the requested size is 0, there is nothing to do */ + if (FlushSize == 0) + { + return STATUS_SUCCESS; + } + + /* Is this a user mode call? */ + if (ExGetPreviousMode() != KernelMode) + { + /* Make sure the base address is in user space */ + if (BaseAddress > MmHighestUserAddress) + { + DPRINT1("Invalid BaseAddress 0x%p\n", BaseAddress); + return STATUS_ACCESS_VIOLATION; + } + } + } + + /* Is another process requested? */ + if (ProcessHandle != NtCurrentProcess()) + { + /* Reference the process */ + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_VM_WRITE, + PsProcessType, + ExGetPreviousMode(), + (PVOID*)&Process, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to reference the process %p\n", ProcessHandle); + return Status; + } + + /* Attach to the process */ + KeStackAttachProcess(Process, &ApcState); + } + + /* Forward to Ke */ + KeSweepICache(BaseAddress, FlushSize); + + /* Check if we attached */ + if (ProcessHandle != NtCurrentProcess()) + { + /* Detach from the process and dereference it */ + KeUnstackDetachProcess(&ApcState); + ObDereferenceObject(Process); + } + + /* All done, return to caller */ + return STATUS_SUCCESS; +} + NTSTATUS NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, diff --git a/reactos/ntoskrnl/rtl/misc.c b/reactos/ntoskrnl/rtl/misc.c index 1b885498aa0..5d0861d9f11 100644 --- a/reactos/ntoskrnl/rtl/misc.c +++ b/reactos/ntoskrnl/rtl/misc.c @@ -62,4 +62,21 @@ RtlGetVersion(IN OUT PRTL_OSVERSIONINFOW lpVersionInformation) return STATUS_SUCCESS; } +#if !defined(_M_IX86) +// +// Stub for architectures which don't have this implemented +// +VOID +FASTCALL +RtlPrefetchMemoryNonTemporal(IN PVOID Source, + IN SIZE_T Length) +{ + // + // Do nothing + // + UNREFERENCED_PARAMETER(Source); + UNREFERENCED_PARAMETER(Length); +} +#endif + /* EOF */