From d136b969cf4d39cf3e59740b1e5ac68af4df966c Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Thu, 24 Apr 2008 21:26:01 +0000 Subject: [PATCH] - Rewrite NtRead/WriteVirtualMemory around MiCopyVirtualMemory, and use MmMapLockedPagesSpecifyCache to do the bulk of the work, instead of the MDL hacks that were previously used. - Reformat and cleanup the entire file, deprecate NtVirtualLock/Unlock which didn't really work (and aren't really required for any apps for now) - Major perf optimizations to NtRead/VirtualMemory: Use pool memory transfer when more efficient than MDL, and use local stack buffer when size permits. - This patch provides up to 109% improvement (more than twice as fast) in certain virtual memory operations. - Thanks to Alex for researching this issue, and providing the internal information on the various optimizations and behaviors the NT implementation uses. svn path=/trunk/; revision=33133 --- reactos/ntoskrnl/ex/exintrin.c | 101 +++ reactos/ntoskrnl/mm/virtual.c | 1543 ++++++++++++++++---------------- 2 files changed, 886 insertions(+), 758 deletions(-) diff --git a/reactos/ntoskrnl/ex/exintrin.c b/reactos/ntoskrnl/ex/exintrin.c index b7081790021..e9604a9ff34 100644 --- a/reactos/ntoskrnl/ex/exintrin.c +++ b/reactos/ntoskrnl/ex/exintrin.c @@ -25,6 +25,9 @@ /* FUNCTIONS ******************************************************************/ +/* + * @implemented + */ LONG FASTCALL InterlockedIncrement(IN LONG volatile *Addend) @@ -35,6 +38,9 @@ InterlockedIncrement(IN LONG volatile *Addend) return _InterlockedIncrement(Addend); } +/* + * @implemented + */ LONG FASTCALL InterlockedDecrement(IN LONG volatile *Addend) @@ -45,6 +51,9 @@ InterlockedDecrement(IN LONG volatile *Addend) return _InterlockedDecrement(Addend); } +/* + * @implemented + */ LONG FASTCALL InterlockedCompareExchange(IN OUT LONG volatile *Destination, @@ -57,6 +66,9 @@ InterlockedCompareExchange(IN OUT LONG volatile *Destination, return _InterlockedCompareExchange(Destination, Exchange, Comperand); } +/* + * @implemented + */ LONG FASTCALL InterlockedExchange(IN OUT LONG volatile *Destination, @@ -68,6 +80,9 @@ InterlockedExchange(IN OUT LONG volatile *Destination, return _InterlockedExchange(Destination, Value); } +/* + * @implemented + */ LONG FASTCALL InterlockedExchangeAdd(IN OUT LONG volatile *Addend, @@ -78,3 +93,89 @@ InterlockedExchangeAdd(IN OUT LONG volatile *Addend, // return _InterlockedExchangeAdd(Addend, Increment); } + +/* + * @implemented + */ +VOID +NTAPI +ProbeForRead(IN CONST VOID *Address, + IN ULONG Length, + IN ULONG Alignment) +{ + PAGED_CODE(); + + /* Only probe if we have a valid length */ + if (Length != 0) + { + /* Sanity check */ + ASSERT((Alignment == 1) || + (Alignment == 2) || + (Alignment == 4) || + (Alignment == 8) || + (Alignment == 16)); + + /* Check for correct alignment */ + if (((ULONG_PTR)Address & (Alignment - 1)) != 0) + { + /* Incorrect alignment */ + ExRaiseDatatypeMisalignment(); + } + else if (((ULONG_PTR)Address + Length) < (ULONG_PTR)Address || + ((ULONG_PTR)Address + Length) > (ULONG_PTR)MmUserProbeAddress) + { + /* Attempt a read */ + *(volatile CHAR* const)MmUserProbeAddress = 0; + } + } +} + +/* + * @implemented + */ +VOID +NTAPI +ProbeForWrite(IN PVOID Address, + IN ULONG Length, + IN ULONG Alignment) +{ + ULONG_PTR Last, Current = (ULONG_PTR)Address; + PAGED_CODE(); + + /* Only probe if we have a valid length */ + if (Length != 0) + { + /* Sanity check */ + ASSERT((Alignment == 1) || + (Alignment == 2) || + (Alignment == 4) || + (Alignment == 8) || + (Alignment == 16)); + + /* Check the alignment */ + if ((Current & (Alignment - 1)) != 0) + { + /* Incorrect alignment */ + ExRaiseDatatypeMisalignment(); + } + + /* Get the end address */ + Last = Current + Length - 1; + if ((Last < Current) || (Last >= (ULONG_PTR)MmUserProbeAddress)) + { + /* Raise an access violation */ + ExRaiseAccessViolation(); + } + + /* Round down to the last page */ + Last = PAGE_ROUND_DOWN(Last) + PAGE_SIZE; + do + { + /* Attempt a write */ + *(volatile CHAR*)Current = *(volatile CHAR*)Current; + + /* Go to the next address */ + Current = PAGE_ROUND_DOWN(Current) + PAGE_SIZE; + } while (Current != Last); + } +} diff --git a/reactos/ntoskrnl/mm/virtual.c b/reactos/ntoskrnl/mm/virtual.c index 5f5cf18bad6..e5323a35a15 100644 --- a/reactos/ntoskrnl/mm/virtual.c +++ b/reactos/ntoskrnl/mm/virtual.c @@ -7,107 +7,412 @@ * PROGRAMMERS: David Welch */ -/* INCLUDE *****************************************************************/ +/* INCLUDE ********************************************************************/ #include - #define NDEBUG -#include +#include -/* FUNCTIONS *****************************************************************/ +#define MI_MAPPED_COPY_PAGES 16 +#define MI_POOL_COPY_BYTES 512 +#define MI_MAX_TRANSFER_SIZE 64 * 1024 +#define TAG_VM TAG('V', 'm', 'R', 'w') -NTSTATUS STDCALL -NtFlushVirtualMemory(IN HANDLE ProcessHandle, - IN OUT PVOID *BaseAddress, - IN OUT PSIZE_T NumberOfBytesToFlush, - OUT PIO_STATUS_BLOCK IoStatusBlock) -/* - * FUNCTION: Flushes virtual memory to file - * ARGUMENTS: - * ProcessHandle = Points to the process that allocated the virtual - * memory - * BaseAddress = Points to the memory address - * NumberOfBytesToFlush = Limits the range to flush, - * NumberOfBytesFlushed = Actual number of bytes flushed - * RETURNS: Status - */ +/* PRIVATE FUNCTIONS **********************************************************/ + +_SEH_DEFINE_LOCALS(MiGetExceptionInfo) { - /* This should be implemented once we support network filesystems */ - DPRINT("NtFlushVirtualMemory is UNIMPLEMENTED\n"); - return(STATUS_SUCCESS); -} + volatile BOOLEAN HaveBadAddress; + volatile ULONG_PTR BadAddress; +}; - -NTSTATUS STDCALL -MiLockVirtualMemory(HANDLE ProcessHandle, - PVOID BaseAddress, - ULONG NumberOfBytesToLock, - PULONG NumberOfBytesLocked, - PObReferenceObjectByHandle pObReferenceObjectByHandle, - PMmCreateMdl pMmCreateMdl, - PObDereferenceObject pObDereferenceObject, - PMmProbeAndLockPages pMmProbeAndLockPages, - PExFreePool pExFreePool) +_SEH_FILTER(MiGetExceptionInfo) { - PEPROCESS Process; - NTSTATUS Status; - PMDL Mdl; - - Status = pObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_WRITE, - NULL, - UserMode, - (PVOID*)(&Process), - NULL); - if (!NT_SUCCESS(Status)) - return(Status); - - Mdl = pMmCreateMdl(NULL, - BaseAddress, - NumberOfBytesToLock); - if (Mdl == NULL) + _SEH_ACCESS_LOCALS(MiGetExceptionInfo); + EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers(); + PEXCEPTION_RECORD ExceptionRecord; + PAGED_CODE(); + + /* Assume default */ + _SEH_VAR(HaveBadAddress) = FALSE; + + /* Get the exception record */ + ExceptionRecord = ExceptionInfo->ExceptionRecord; + + /* Look at the exception code */ + if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) || + (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) || + (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR)) { - pObDereferenceObject(Process); - return(STATUS_NO_MEMORY); + /* We can tell the address if we have more than one parameter */ + if (ExceptionRecord->NumberParameters > 1) + { + /* Return the address */ + _SEH_VAR(HaveBadAddress) = TRUE; + _SEH_VAR(BadAddress) = ExceptionRecord->ExceptionInformation[1]; + } } - - pMmProbeAndLockPages(Mdl, - UserMode, - IoWriteAccess); - - pExFreePool(Mdl); - - pObDereferenceObject(Process); - - *NumberOfBytesLocked = NumberOfBytesToLock; - return(STATUS_SUCCESS); + + /* Continue executing the next handler */ + return EXCEPTION_EXECUTE_HANDLER; } - -NTSTATUS STDCALL -NtLockVirtualMemory(HANDLE ProcessHandle, - PVOID BaseAddress, - ULONG NumberOfBytesToLock, - PULONG NumberOfBytesLocked) +NTSTATUS +NTAPI +MiDoMappedCopy(IN PEPROCESS SourceProcess, + IN PVOID SourceAddress, + IN PEPROCESS TargetProcess, + OUT PVOID TargetAddress, + IN ULONG BufferSize, + IN KPROCESSOR_MODE PreviousMode, + OUT PULONG ReturnSize) { - DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, " - "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n", - ProcessHandle, - BaseAddress, - NumberOfBytesToLock, - NumberOfBytesLocked); - - return MiLockVirtualMemory(ProcessHandle, - BaseAddress, - NumberOfBytesToLock, - NumberOfBytesLocked, - ObReferenceObjectByHandle, - MmCreateMdl, - (PVOID)ObfDereferenceObject, - MmProbeAndLockPages, - ExFreePool); + PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + (MI_MAPPED_COPY_PAGES >> PAGE_SHIFT) + 1]; + PMDL Mdl = (PMDL)MdlBuffer; + ULONG TotalSize, CurrentSize, RemainingSize; + BOOLEAN FailedInProbe = FALSE, FailedInMapping = FALSE, FailedInMoving; + BOOLEAN PagesLocked; + PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress; + PVOID MdlAddress; + KAPC_STATE ApcState; + _SEH_DECLARE_LOCALS(MiGetExceptionInfo); + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); + + /* Calculate the maximum amount of data to move */ + TotalSize = MI_MAPPED_COPY_PAGES - 2; + if (TotalSize <= (MI_MAPPED_COPY_PAGES - 2)) TotalSize = BufferSize; + CurrentSize = BufferSize; + RemainingSize = TotalSize; + + /* Loop as long as there is still data */ + while (RemainingSize > 0) + { + /* Check if this transfer will finish everything off */ + if (RemainingSize < CurrentSize) CurrentSize = RemainingSize; + + /* Attach to the source address space */ + KeStackAttachProcess(&SourceProcess->Pcb, &ApcState); + + /* Reset state for this pass */ + MdlAddress = NULL; + PagesLocked = FALSE; + FailedInMoving = FALSE; + ASSERT(FailedInProbe == FALSE); + + /* Protect user-mode copy */ + _SEH_TRY + { + /* If this is our first time, probe the buffer */ + if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode)) + { + /* Catch a failure here */ + FailedInProbe = TRUE; + + /* Do the probe */ + ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR)); + + /* Passed */ + FailedInProbe = FALSE; + } + + /* Initialize and probe and lock the MDL */ + MmInitializeMdl (Mdl, CurrentAddress, CurrentSize); + MmProbeAndLockPages (Mdl, PreviousMode, IoReadAccess); + PagesLocked = TRUE; + + /* Now map the pages */ + MdlAddress = MmMapLockedPagesSpecifyCache(Mdl, + KernelMode, + MmCached, + NULL, + FALSE, + HighPagePriority); + if (!MdlAddress) + { + /* Use our SEH handler to pick this up */ + FailedInMapping = TRUE; + ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); + } + + /* Now let go of the source and grab to the target process */ + KeUnstackDetachProcess(&ApcState); + KeStackAttachProcess(&TargetProcess->Pcb, &ApcState); + + /* Check if this is our first time through */ + if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode)) + { + /* Catch a failure here */ + FailedInProbe = TRUE; + + /* Do the probe */ + ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR)); + + /* Passed */ + FailedInProbe = FALSE; + } + + /* Now do the actual move */ + FailedInMoving = TRUE; + RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize); + } + _SEH_EXCEPT(MiGetExceptionInfo) + { + /* Detach from whoever we may be attached to */ + KeUnstackDetachProcess(&ApcState); + + /* Check if we had mapped the pages */ + if (MdlAddress) MmUnmapLockedPages(MdlAddress, Mdl); + + /* Check if we had locked the pages */ + if (PagesLocked) MmUnlockPages(Mdl); + + /* Check if we failed during the probe or mapping */ + if ((FailedInProbe) || (FailedInMapping)) + { + /* Exit */ + Status = _SEH_GetExceptionCode(); + _SEH_YIELD(); + } + + /* Otherwise, we failed probably during the move */ + *ReturnSize = BufferSize - RemainingSize; + if (FailedInMoving) + { + /* Check if we know exactly where we stopped copying */ + if (_SEH_VAR(HaveBadAddress)) + { + /* Return the exact number of bytes copied */ + *ReturnSize = _SEH_VAR(BadAddress) - (ULONG_PTR)SourceAddress; + } + } + + /* Return partial copy */ + Status = STATUS_PARTIAL_COPY; + } + _SEH_END; + + /* Check for SEH status */ + if (Status != STATUS_SUCCESS) return Status; + + /* Detach from target */ + KeUnstackDetachProcess(&ApcState); + + /* Unmap and unlock */ + MmUnmapLockedPages(MdlAddress, Mdl); + MmUnlockPages(Mdl); + + /* Update location and size */ + RemainingSize -= CurrentSize; + CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize); + CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize); + } + + /* All bytes read */ + *ReturnSize = BufferSize; + return STATUS_SUCCESS; } +NTSTATUS +NTAPI +MiDoPoolCopy(IN PEPROCESS SourceProcess, + IN PVOID SourceAddress, + IN PEPROCESS TargetProcess, + OUT PVOID TargetAddress, + IN ULONG BufferSize, + IN KPROCESSOR_MODE PreviousMode, + OUT PULONG ReturnSize) +{ + UCHAR StackBuffer[MI_POOL_COPY_BYTES]; + ULONG TotalSize, CurrentSize, RemainingSize; + BOOLEAN FailedInProbe = FALSE, FailedInMoving, HavePoolAddress = FALSE; + PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress; + PVOID PoolAddress; + KAPC_STATE ApcState; + _SEH_DECLARE_LOCALS(MiGetExceptionInfo); + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); + + /* Calculate the maximum amount of data to move */ + TotalSize = MI_MAX_TRANSFER_SIZE; + if (TotalSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize; + CurrentSize = BufferSize; + RemainingSize = TotalSize; + + /* Check if we can use the stack */ + if (BufferSize <= MI_POOL_COPY_BYTES) + { + /* Use it */ + PoolAddress = (PVOID)StackBuffer; + } + else + { + /* Allocate pool */ + PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, TAG_VM); + if (!PoolAddress) ASSERT(FALSE); + HavePoolAddress = TRUE; + } + + /* Loop as long as there is still data */ + while (RemainingSize > 0) + { + /* Check if this transfer will finish everything off */ + if (RemainingSize < CurrentSize) CurrentSize = RemainingSize; + + /* Attach to the source address space */ + KeStackAttachProcess(&SourceProcess->Pcb, &ApcState); + + /* Reset state for this pass */ + FailedInMoving = FALSE; + ASSERT(FailedInProbe == FALSE); + + /* Protect user-mode copy */ + _SEH_TRY + { + /* If this is our first time, probe the buffer */ + if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode)) + { + /* Catch a failure here */ + FailedInProbe = TRUE; + + /* Do the probe */ + ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR)); + + /* Passed */ + FailedInProbe = FALSE; + } + + /* Do the copy */ + RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize); + + /* Now let go of the source and grab to the target process */ + KeUnstackDetachProcess(&ApcState); + KeStackAttachProcess(&TargetProcess->Pcb, &ApcState); + + /* Check if this is our first time through */ + if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode)) + { + /* Catch a failure here */ + FailedInProbe = TRUE; + + /* Do the probe */ + ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR)); + + /* Passed */ + FailedInProbe = FALSE; + } + + /* Now do the actual move */ + FailedInMoving = TRUE; + RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize); + } + _SEH_EXCEPT(MiGetExceptionInfo) + { + /* Detach from whoever we may be attached to */ + KeUnstackDetachProcess(&ApcState); + + /* Check if we had allocated pool */ + if (HavePoolAddress) ExFreePool(PoolAddress); + + /* Check if we failed during the probe */ + if (FailedInProbe) + { + /* Exit */ + Status = _SEH_GetExceptionCode(); + _SEH_YIELD(); + } + + /* Otherwise, we failed probably during the move */ + *ReturnSize = BufferSize - RemainingSize; + if (FailedInMoving) + { + /* Check if we know exactly where we stopped copying */ + if (_SEH_VAR(HaveBadAddress)) + { + /* Return the exact number of bytes copied */ + *ReturnSize = _SEH_VAR(BadAddress) - (ULONG_PTR)SourceAddress; + } + } + + /* Return partial copy */ + Status = STATUS_PARTIAL_COPY; + } + _SEH_END; + + /* Check for SEH status */ + if (Status != STATUS_SUCCESS) return Status; + + /* Detach from target */ + KeUnstackDetachProcess(&ApcState); + + /* Update location and size */ + RemainingSize -= CurrentSize; + CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize); + CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize); + } + + /* Check if we had allocated pool */ + if (HavePoolAddress) ExFreePool(PoolAddress); + + /* All bytes read */ + *ReturnSize = BufferSize; + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +MmCopyVirtualMemory(IN PEPROCESS SourceProcess, + IN PVOID SourceAddress, + IN PEPROCESS TargetProcess, + OUT PVOID TargetAddress, + IN ULONG BufferSize, + IN KPROCESSOR_MODE PreviousMode, + OUT PULONG ReturnSize) +{ + NTSTATUS Status; + PEPROCESS Process = SourceProcess; + + /* Don't accept zero-sized buffers */ + if (!BufferSize) return STATUS_SUCCESS; + + /* If we are copying from ourselves, lock the target instead */ + if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess; + + /* Acquire rundown protection */ + if (!ExAcquireRundownProtection(&Process->RundownProtect)) + { + /* Fail */ + return STATUS_PROCESS_IS_TERMINATING; + } + + /* See if we should use the pool copy */ + if (BufferSize > MI_POOL_COPY_BYTES) + { + /* Use MDL-copy */ + Status = MiDoMappedCopy(SourceProcess, + SourceAddress, + TargetProcess, + TargetAddress, + BufferSize, + PreviousMode, + ReturnSize); + } + else + { + /* Do pool copy */ + Status = MiDoPoolCopy(SourceProcess, + SourceAddress, + TargetProcess, + TargetAddress, + BufferSize, + PreviousMode, + ReturnSize); + } + + /* Release the lock */ + ExReleaseRundownProtection(&Process->RundownProtect); + return Status; +} NTSTATUS FASTCALL MiQueryVirtualMemory(IN HANDLE ProcessHandle, @@ -276,11 +581,370 @@ MiQueryVirtualMemory(IN HANDLE ProcessHandle, return Status; } -/* (tMk 2004.II.4) - * FUNCTION: - * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c) - * +NTSTATUS STDCALL +MiProtectVirtualMemory(IN PEPROCESS Process, + IN OUT PVOID *BaseAddress, + IN OUT PULONG NumberOfBytesToProtect, + IN ULONG NewAccessProtection, + OUT PULONG OldAccessProtection OPTIONAL) +{ + PMEMORY_AREA MemoryArea; + PMADDRESS_SPACE AddressSpace; + ULONG OldAccessProtection_; + NTSTATUS Status; + + *NumberOfBytesToProtect = + PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - + PAGE_ROUND_DOWN(*BaseAddress); + *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress); + + AddressSpace = (PMADDRESS_SPACE)&(Process)->VadRoot; + + MmLockAddressSpace(AddressSpace); + MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress); + if (MemoryArea == NULL) + { + MmUnlockAddressSpace(AddressSpace); + return STATUS_UNSUCCESSFUL; + } + + if (OldAccessProtection == NULL) + OldAccessProtection = &OldAccessProtection_; + + if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY) + { + Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress, + *NumberOfBytesToProtect, NewAccessProtection, + OldAccessProtection); + } + else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) + { + Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress, + *NumberOfBytesToProtect, + NewAccessProtection, + OldAccessProtection); + } + else + { + /* FIXME: Should we return failure or success in this case? */ + Status = STATUS_CONFLICTING_ADDRESSES; + } + + MmUnlockAddressSpace(AddressSpace); + + return Status; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/* + * @unimplemented */ +PVOID +NTAPI +MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress) +{ + UNIMPLEMENTED; + return 0; +} + +/* + * @unimplemented + */ +PVOID +NTAPI +MmSecureVirtualMemory(IN PVOID Address, + IN SIZE_T Length, + IN ULONG Mode) +{ + UNIMPLEMENTED; + return NULL; +} + +/* + * @unimplemented + */ +VOID +NTAPI +MmUnsecureVirtualMemory(IN PVOID SecureMem) +{ + UNIMPLEMENTED; +} + +/* SYSTEM CALLS ***************************************************************/ + +NTSTATUS +NTAPI +NtReadVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + OUT PVOID Buffer, + IN ULONG NumberOfBytesToRead, + OUT PULONG NumberOfBytesRead OPTIONAL) +{ + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + PEPROCESS Process; + NTSTATUS Status = STATUS_SUCCESS; + ULONG BytesRead = 0; + PAGED_CODE(); + + /* Check if we came from user mode */ + if (PreviousMode != KernelMode) + { + /* Validate the read addresses */ + if ((((ULONG_PTR)BaseAddress + NumberOfBytesToRead) < (ULONG_PTR)BaseAddress) || + (((ULONG_PTR)Buffer + NumberOfBytesToRead) < (ULONG_PTR)Buffer) || + (((ULONG_PTR)BaseAddress + NumberOfBytesToRead) > MmUserProbeAddress) || + (((ULONG_PTR)Buffer + NumberOfBytesToRead) > MmUserProbeAddress)) + { + /* Don't allow to write into kernel space */ + return STATUS_ACCESS_VIOLATION; + } + + /* Enter SEH for probe */ + _SEH_TRY + { + /* Probe the output value */ + if (NumberOfBytesRead) ProbeForWriteUlong(NumberOfBytesRead); + } + _SEH_HANDLE + { + /* Get exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Return if we failed */ + if (!NT_SUCCESS(Status)) return Status; + } + + /* Reference the process */ + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_VM_READ, + PsProcessType, + PreviousMode, + (PVOID*)(&Process), + NULL); + if (NT_SUCCESS(Status)) + { + /* Do the copy */ + Status = MmCopyVirtualMemory(Process, + BaseAddress, + PsGetCurrentProcess(), + Buffer, + NumberOfBytesToRead, + PreviousMode, + &BytesRead); + + /* Derefernece the process */ + ObDereferenceObject(Process); + } + + /* Check if the caller sent this parameter */ + if (NumberOfBytesRead) + { + /* Enter SEH to guard write */ + _SEH_TRY + { + /* Return the number of bytes read */ + *NumberOfBytesRead = BytesRead; + } + _SEH_HANDLE + { + /* Handle exception */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +NtWriteVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, + OUT PULONG NumberOfBytesWritten OPTIONAL) +{ + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + PEPROCESS Process; + NTSTATUS Status = STATUS_SUCCESS; + ULONG BytesWritten = 0; + PAGED_CODE(); + + /* Check if we came from user mode */ + if (PreviousMode != KernelMode) + { + /* Validate the read addresses */ + if ((((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) < (ULONG_PTR)BaseAddress) || + (((ULONG_PTR)Buffer + NumberOfBytesToWrite) < (ULONG_PTR)Buffer) || + (((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) > MmUserProbeAddress) || + (((ULONG_PTR)Buffer + NumberOfBytesToWrite) > MmUserProbeAddress)) + { + /* Don't allow to write into kernel space */ + return STATUS_ACCESS_VIOLATION; + } + + /* Enter SEH for probe */ + _SEH_TRY + { + /* Probe the output value */ + if (NumberOfBytesWritten) ProbeForWriteUlong(NumberOfBytesWritten); + } + _SEH_HANDLE + { + /* Get exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Return if we failed */ + if (!NT_SUCCESS(Status)) return Status; + } + + /* Reference the process */ + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_VM_WRITE, + PsProcessType, + PreviousMode, + (PVOID*)&Process, + NULL); + if (NT_SUCCESS(Status)) + { + /* Do the copy */ + Status = MmCopyVirtualMemory(PsGetCurrentProcess(), + Buffer, + Process, + BaseAddress, + NumberOfBytesToWrite, + PreviousMode, + &BytesWritten); + + /* Derefernece the process */ + ObDereferenceObject(Process); + } + + /* Check if the caller sent this parameter */ + if (NumberOfBytesWritten) + { + /* Enter SEH to guard write */ + _SEH_TRY + { + /* Return the number of bytes read */ + *NumberOfBytesWritten = BytesWritten; + } + _SEH_HANDLE + { + /* Handle exception */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +NtProtectVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID *UnsafeBaseAddress, + IN OUT ULONG *UnsafeNumberOfBytesToProtect, + IN ULONG NewAccessProtection, + OUT PULONG UnsafeOldAccessProtection) +{ + PEPROCESS Process; + ULONG OldAccessProtection; + PVOID BaseAddress = NULL; + ULONG NumberOfBytesToProtect = 0; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; + + /* Check if we came from user mode */ + if (PreviousMode != KernelMode) + { + /* Enter SEH for probing */ + _SEH_TRY + { + /* Validate all outputs */ + ProbeForWritePointer(UnsafeBaseAddress); + ProbeForWriteUlong(UnsafeNumberOfBytesToProtect); + ProbeForWriteUlong(UnsafeOldAccessProtection); + + /* Capture them */ + BaseAddress = *UnsafeBaseAddress; + NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect; + } + _SEH_HANDLE + { + /* Get exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Return on exception */ + if (!NT_SUCCESS(Status)) return Status; + } + else + { + /* Capture directly */ + BaseAddress = *UnsafeBaseAddress; + NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect; + } + + /* Catch illegal base address */ + if (BaseAddress > (PVOID)MmUserProbeAddress) return STATUS_INVALID_PARAMETER_2; + + /* Catch illegal region size */ + if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect) + { + /* Fail */ + return STATUS_INVALID_PARAMETER_3; + } + + /* 0 is also illegal */ + if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3; + + /* Get a reference to the process */ + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_VM_OPERATION, + PsProcessType, + PreviousMode, + (PVOID*)(&Process), + NULL); + if (!NT_SUCCESS(Status)) return Status; + + /* Do the actual work */ + Status = MiProtectVirtualMemory(Process, + &BaseAddress, + &NumberOfBytesToProtect, + NewAccessProtection, + &OldAccessProtection); + + /* Release reference */ + ObDereferenceObject(Process); + + /* Enter SEH to return data */ + _SEH_TRY + { + /* Return data to user */ + *UnsafeOldAccessProtection = OldAccessProtection; + *UnsafeBaseAddress = BaseAddress; + *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect; + } + _SEH_HANDLE + { + /* Catch exception */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Return status */ + return Status; +} + NTSTATUS STDCALL NtQueryVirtualMemory(IN HANDLE ProcessHandle, IN PVOID Address, @@ -297,15 +961,15 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle, MEMORY_BASIC_INFORMATION BasicInfo; } VirtualMemoryInfo; - + DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, " "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, " "Length %lu ResultLength %x)\n",ProcessHandle,Address, VirtualMemoryInformationClass,VirtualMemoryInformation, Length,ResultLength); - + PreviousMode = ExGetPreviousMode(); - + if (PreviousMode != KernelMode && UnsafeResultLength != NULL) { _SEH_TRY @@ -317,26 +981,26 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle, Status = _SEH_GetExceptionCode(); } _SEH_END; - + if (!NT_SUCCESS(Status)) { return Status; } } - + if (Address >= MmSystemRangeStart) { DPRINT1("Invalid parameter\n"); return STATUS_INVALID_PARAMETER; } - + Status = MiQueryVirtualMemory(ProcessHandle, Address, VirtualMemoryInformationClass, &VirtualMemoryInfo, Length, &ResultLength ); - + if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) @@ -371,687 +1035,50 @@ NtQueryVirtualMemory(IN HANDLE ProcessHandle, &VirtualMemoryInfo, ResultLength); } - + if (UnsafeResultLength != NULL) { *UnsafeResultLength = ResultLength; } } } - - return(Status); -} - - -NTSTATUS STDCALL -MiProtectVirtualMemory(IN PEPROCESS Process, - IN OUT PVOID *BaseAddress, - IN OUT PULONG NumberOfBytesToProtect, - IN ULONG NewAccessProtection, - OUT PULONG OldAccessProtection OPTIONAL) -{ - PMEMORY_AREA MemoryArea; - PMADDRESS_SPACE AddressSpace; - ULONG OldAccessProtection_; - NTSTATUS Status; - - *NumberOfBytesToProtect = - PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - - PAGE_ROUND_DOWN(*BaseAddress); - *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress); - - AddressSpace = (PMADDRESS_SPACE)&(Process)->VadRoot; - - MmLockAddressSpace(AddressSpace); - MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress); - if (MemoryArea == NULL) - { - MmUnlockAddressSpace(AddressSpace); - return STATUS_UNSUCCESSFUL; - } - - if (OldAccessProtection == NULL) - OldAccessProtection = &OldAccessProtection_; - - if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY) - { - Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress, - *NumberOfBytesToProtect, NewAccessProtection, - OldAccessProtection); - } - else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) - { - Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress, - *NumberOfBytesToProtect, - NewAccessProtection, - OldAccessProtection); - } - else - { - /* FIXME: Should we return failure or success in this case? */ - Status = STATUS_CONFLICTING_ADDRESSES; - } - - MmUnlockAddressSpace(AddressSpace); - - return Status; -} - - -/* (tMk 2004.II.5) - * FUNCTION: - * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c) - * - */ -NTSTATUS STDCALL -NtProtectVirtualMemory(IN HANDLE ProcessHandle, - IN OUT PVOID *UnsafeBaseAddress, - IN OUT ULONG *UnsafeNumberOfBytesToProtect, - IN ULONG NewAccessProtection, - OUT PULONG UnsafeOldAccessProtection) -{ - PEPROCESS Process; - ULONG OldAccessProtection; - PVOID BaseAddress = NULL; - ULONG NumberOfBytesToProtect = 0; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - PreviousMode = ExGetPreviousMode(); - - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForWritePointer(UnsafeBaseAddress); - ProbeForWriteUlong(UnsafeNumberOfBytesToProtect); - ProbeForWriteUlong(UnsafeOldAccessProtection); - - BaseAddress = *UnsafeBaseAddress; - NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (!NT_SUCCESS(Status)) - { - return Status; - } - } - else - { - BaseAddress = *UnsafeBaseAddress; - NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect; - } - - if ((ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 < (ULONG_PTR)BaseAddress || - (ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 >= MmUserProbeAddress) - { - /* Don't allow to change the protection of a kernel mode address */ - return STATUS_INVALID_PARAMETER_2; - } - - /* (tMk 2004.II.5) in Microsoft SDK I read: - * 'if this parameter is NULL or does not point to a valid variable, the function fails' - */ - if(UnsafeOldAccessProtection == NULL) - { - return(STATUS_INVALID_PARAMETER); - } - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_OPERATION, - PsProcessType, - UserMode, - (PVOID*)(&Process), - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtProtectVirtualMemory() = %x\n",Status); - return(Status); - } - - Status = MiProtectVirtualMemory(Process, - &BaseAddress, - &NumberOfBytesToProtect, - NewAccessProtection, - &OldAccessProtection); - - ObDereferenceObject(Process); - - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - *UnsafeOldAccessProtection = OldAccessProtection; - *UnsafeBaseAddress = BaseAddress; - *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - else - { - *UnsafeOldAccessProtection = OldAccessProtection; - *UnsafeBaseAddress = BaseAddress; - *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect; - } - + return(Status); } - -/* (tMk 2004.II.05) - * FUNCTION: - * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c) - * - * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED. - */ -NTSTATUS STDCALL -NtReadVirtualMemory(IN HANDLE ProcessHandle, +NTSTATUS +NTAPI +NtLockVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, - OUT PVOID Buffer, - IN ULONG NumberOfBytesToRead, - OUT PULONG NumberOfBytesRead OPTIONAL) -{ - PMDL Mdl; - PVOID SystemAddress; - KPROCESSOR_MODE PreviousMode; - PEPROCESS Process, CurrentProcess; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, " - "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress, - Buffer,NumberOfBytesToRead); - - if ((ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 < (ULONG_PTR)BaseAddress || - (ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 >= MmUserProbeAddress) - { - /* Don't allow to read from kernel space */ - return STATUS_ACCESS_VIOLATION; - } - - PreviousMode = ExGetPreviousMode(); - - if (PreviousMode != KernelMode) - { - if ((ULONG_PTR)Buffer + NumberOfBytesToRead - 1 < (ULONG_PTR)Buffer || - (ULONG_PTR)Buffer + NumberOfBytesToRead - 1 >= MmUserProbeAddress) - { - /* Don't allow to write into kernel space */ - return STATUS_ACCESS_VIOLATION; - } - } - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_READ, - NULL, - PreviousMode, - (PVOID*)(&Process), - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - CurrentProcess = PsGetCurrentProcess(); - - if(PreviousMode != KernelMode) - { - _SEH_TRY - { - if(NumberOfBytesRead != NULL) - { - ProbeForWriteUlong(NumberOfBytesRead); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - - if (Process == CurrentProcess) - { - _SEH_TRY - { - RtlCopyMemory(Buffer, BaseAddress, NumberOfBytesToRead); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - else - { - Mdl = MmCreateMdl(NULL, - Buffer, - NumberOfBytesToRead); - if(Mdl == NULL) - { - ObDereferenceObject(Process); - return(STATUS_NO_MEMORY); - } - - _SEH_TRY - { - MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(NT_SUCCESS(Status)) - { - KeAttachProcess(&Process->Pcb); - - SystemAddress = MmGetSystemAddressForMdl(Mdl); - - Status = STATUS_SUCCESS; - _SEH_TRY - { - Status = STATUS_PARTIAL_COPY; - RtlCopyMemory(SystemAddress, BaseAddress, NumberOfBytesToRead); - Status = STATUS_SUCCESS; - } - _SEH_HANDLE - { - if(Status != STATUS_PARTIAL_COPY) - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - KeDetachProcess(); - - if (Mdl->MappedSystemVa != NULL) - { - MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); - } - MmUnlockPages(Mdl); - } - ExFreePool(Mdl); - } - - ObDereferenceObject(Process); - - if ((NT_SUCCESS(Status) || Status == STATUS_PARTIAL_COPY) && - NumberOfBytesRead != NULL) - { - _SEH_TRY - { - *NumberOfBytesRead = NumberOfBytesToRead; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - - return(Status); -} - -/* (tMk 2004.II.05) - * FUNCTION: THIS function doesn't make a sense... - * Called from VirtualUnlock (lib\kernel32\mem\virtual.c) - */ -NTSTATUS STDCALL -NtUnlockVirtualMemory(HANDLE ProcessHandle, - PVOID BaseAddress, - ULONG NumberOfBytesToUnlock, - PULONG NumberOfBytesUnlocked OPTIONAL) -{ - // AG [08-20-03] : I have *no* idea if this is correct, I just used the - // other functions as a template and made a few intelligent guesses... - - NTSTATUS Status; - PMDL Mdl; - PEPROCESS Process; - - DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, " - "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress, - NumberOfBytesToUnlock, NumberOfBytesUnlocked); - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_WRITE, - NULL, - UserMode, - (PVOID*)(&Process), - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - Mdl = MmCreateMdl(NULL, - BaseAddress, - NumberOfBytesToUnlock); - if(Mdl == NULL) - { - ObDereferenceObject(Process); - return(STATUS_NO_MEMORY); - } - - ObDereferenceObject(Process); - - if (Mdl->MappedSystemVa != NULL) - { - MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); - } - MmUnlockPages(Mdl); - ExFreePool(Mdl); - - *NumberOfBytesUnlocked = NumberOfBytesToUnlock; - - return(STATUS_SUCCESS); -} - - -/* (tMk 2004.II.05) - * FUNCTION: - * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c) - * - * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED. - */ -NTSTATUS STDCALL -NtWriteVirtualMemory(IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - IN PVOID Buffer, - IN ULONG NumberOfBytesToWrite, - OUT PULONG NumberOfBytesWritten OPTIONAL) -{ - PMDL Mdl; - PVOID SystemAddress; - PEPROCESS Process; - KPROCESSOR_MODE PreviousMode; - NTSTATUS CopyStatus, Status = STATUS_SUCCESS; - - DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, " - "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress, - Buffer,NumberOfBytesToWrite); - - if ((ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 < (ULONG_PTR)BaseAddress || - (ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 >= MmUserProbeAddress) - { - /* Don't allow to write into kernel space */ - return STATUS_ACCESS_VIOLATION; - } - - PreviousMode = ExGetPreviousMode(); - - if (PreviousMode != KernelMode) - { - if ((ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 < (ULONG_PTR)Buffer || - (ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 >= MmUserProbeAddress) - { - /* Don't allow to read from kernel space */ - return STATUS_ACCESS_VIOLATION; - } - if (NumberOfBytesWritten != NULL) - { - _SEH_TRY - { - ProbeForWriteUlong(NumberOfBytesWritten); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (!NT_SUCCESS(Status)) - { - return Status; - } - } - } - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_WRITE, - NULL, - UserMode, - (PVOID*)(&Process), - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - CopyStatus = STATUS_SUCCESS; - - /* Write memory */ - if (Process == PsGetCurrentProcess()) - { - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - memcpy(BaseAddress, Buffer, NumberOfBytesToWrite); - } - _SEH_HANDLE - { - CopyStatus = _SEH_GetExceptionCode(); - } - _SEH_END; - } - else - { - memcpy(BaseAddress, Buffer, NumberOfBytesToWrite); - } - } - else - { - /* Create MDL describing the source buffer. */ - Mdl = MmCreateMdl(NULL, - Buffer, - NumberOfBytesToWrite); - if (Mdl == NULL) - { - ObDereferenceObject(Process); - return(STATUS_NO_MEMORY); - } - _SEH_TRY - { - /* Map the MDL. */ - MmProbeAndLockPages(Mdl, UserMode, IoReadAccess); - } - _SEH_HANDLE - { - CopyStatus = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (NT_SUCCESS(CopyStatus)) - { - /* Copy memory from the mapped MDL into the target buffer. */ - KeAttachProcess(&Process->Pcb); - - SystemAddress = MmGetSystemAddressForMdl(Mdl); - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite); - } - _SEH_HANDLE - { - CopyStatus = _SEH_GetExceptionCode(); - } - _SEH_END; - } - else - { - memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite); - } - - KeDetachProcess(); - } - - /* Free the MDL. */ - if (Mdl->MappedSystemVa != NULL) - { - MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); - } - MmUnlockPages(Mdl); - ExFreePool(Mdl); - } - ObDereferenceObject(Process); - - if (NT_SUCCESS(CopyStatus) && NumberOfBytesWritten != NULL) - { - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - *NumberOfBytesWritten = NumberOfBytesToWrite; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - else - { - *NumberOfBytesWritten = NumberOfBytesToWrite; - } - } - - return(NT_SUCCESS(CopyStatus) ? Status : CopyStatus); -} - -/* - * @unimplemented - */ - -PVOID -STDCALL -MmGetVirtualForPhysical( - IN PHYSICAL_ADDRESS PhysicalAddress - ) + IN ULONG NumberOfBytesToLock, + OUT PULONG NumberOfBytesLocked OPTIONAL) { UNIMPLEMENTED; - return 0; + if (NumberOfBytesLocked) *NumberOfBytesLocked = 0; + return STATUS_SUCCESS; } -/* FUNCTION: - * Called from EngSecureMem (subsys\win32k\eng\mem.c) - * @unimplemented - */ -PVOID STDCALL -MmSecureVirtualMemory(PVOID Address, - SIZE_T Length, - ULONG Mode) +NTSTATUS +NTAPI +NtUnlockVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN ULONG NumberOfBytesToUnlock, + OUT PULONG NumberOfBytesUnlocked OPTIONAL) { - /* Only works for user space */ - if (((ULONG_PTR)Address >= (ULONG_PTR)Address + Length) || - ((ULONG_PTR)MmHighestUserAddress < (ULONG_PTR)Address + Length)) - { - return NULL; - } - UNIMPLEMENTED; - - return 0; + if (NumberOfBytesUnlocked) *NumberOfBytesUnlocked = 0; + return STATUS_SUCCESS; } - -/* FUNCTION: - * Called from EngUnsecureMem (subsys\win32k\eng\mem.c) - * @unimplemented - */ -VOID STDCALL -MmUnsecureVirtualMemory(PVOID SecureMem) +NTSTATUS +NTAPI +NtFlushVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN OUT PSIZE_T NumberOfBytesToFlush, + OUT PIO_STATUS_BLOCK IoStatusBlock) { - if (NULL == SecureMem) - { - return; - } - UNIMPLEMENTED; -} - - -/* - * @implemented - */ -VOID STDCALL -ProbeForRead(IN CONST VOID *Address, - IN ULONG Length, - IN ULONG Alignment) -{ - if (Length != 0) - { - ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8); - - if (((ULONG_PTR)Address & (Alignment - 1)) != 0) - { - ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT); - } - else if ((ULONG_PTR)Address + Length - 1 < (ULONG_PTR)Address || - (ULONG_PTR)Address + Length - 1 >= (ULONG_PTR)MmUserProbeAddress) - { - ExRaiseStatus (STATUS_ACCESS_VIOLATION); - } - } -} - - -/* - * @implemented - */ -VOID STDCALL -ProbeForWrite(IN PVOID Address, - IN ULONG Length, - IN ULONG Alignment) -{ - volatile CHAR *Current; - PCHAR Last; - - if (Length != 0) - { - ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8); - - if (((ULONG_PTR)Address & (Alignment - 1)) != 0) - { - ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT); - } - - Last = (PCHAR)((ULONG_PTR)Address + Length - 1); - if ((ULONG_PTR)Last < (ULONG_PTR)Address || - (ULONG_PTR)Last >= (ULONG_PTR)MmUserProbeAddress) - { - ExRaiseStatus (STATUS_ACCESS_VIOLATION); - } - - /* Check for accessible pages, do *not* touch any memory outside of the - range!*/ - Current = (volatile CHAR*)Address; - Last = (PCHAR)(PAGE_ROUND_DOWN(Last)); - do - { - *Current = *Current; - Current = (volatile CHAR*)(PAGE_ROUND_DOWN(Current) + PAGE_SIZE); - } while (Current <= Last); - } + return STATUS_SUCCESS; } /* EOF */