ReactOS 0.4.15-dev-7961-gdcf9eb0
virtual.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
#include <mm/ARM3/miarm.h>
Include dependency graph for virtual.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define MODULE_INVOLVED_IN_ARM3
 
#define MI_MAPPED_COPY_PAGES   14
 
#define MI_POOL_COPY_BYTES   512
 
#define MI_MAX_TRANSFER_SIZE   64 * 1024
 

Functions

NTSTATUS NTAPI MiProtectVirtualMemory (IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection OPTIONAL)
 
VOID NTAPI MiFlushTbAndCapture (IN PMMVAD FoundVad, IN PMMPTE PointerPte, IN ULONG ProtectionMask, IN PMMPFN Pfn1, IN BOOLEAN CaptureDirtyBit)
 
ULONG NTAPI MiCalculatePageCommitment (IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
 
ULONG NTAPI MiMakeSystemAddressValid (IN PVOID PageTableVirtualAddress, IN PEPROCESS CurrentProcess)
 
ULONG NTAPI MiMakeSystemAddressValidPfn (IN PVOID VirtualAddress, IN KIRQL OldIrql)
 
PFN_COUNT NTAPI MiDeleteSystemPageableVm (IN PMMPTE PointerPte, IN PFN_NUMBER PageCount, IN ULONG Flags, OUT PPFN_NUMBER ValidPages)
 
VOID NTAPI MiDeletePte (IN PMMPTE PointerPte, IN PVOID VirtualAddress, IN PEPROCESS CurrentProcess, IN PMMPTE PrototypePte)
 
VOID NTAPI MiDeleteVirtualAddresses (IN ULONG_PTR Va, IN ULONG_PTR EndingAddress, IN PMMVAD Vad)
 
LONG MiGetExceptionInfo (IN PEXCEPTION_POINTERS ExceptionInfo, OUT PBOOLEAN HaveBadAddress, OUT PULONG_PTR BadAddress)
 
NTSTATUS NTAPI MiDoMappedCopy (IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
 
NTSTATUS NTAPI MiDoPoolCopy (IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
 
NTSTATUS NTAPI MmCopyVirtualMemory (IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
 
NTSTATUS NTAPI MmFlushVirtualMemory (IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, OUT PIO_STATUS_BLOCK IoStatusBlock)
 
ULONG NTAPI MiGetPageProtection (IN PMMPTE PointerPte)
 
ULONG NTAPI MiQueryAddressState (IN PVOID Va, IN PMMVAD Vad, IN PEPROCESS TargetProcess, OUT PULONG ReturnedProtect, OUT PVOID *NextVa)
 
NTSTATUS NTAPI MiQueryMemoryBasicInformation (IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
 
BOOLEAN NTAPI MiIsEntireRangeCommitted (IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
 
NTSTATUS NTAPI MiRosProtectVirtualMemory (IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection OPTIONAL)
 
VOID NTAPI MiMakePdeExistAndMakeValid (IN PMMPDE PointerPde, IN PEPROCESS TargetProcess, IN KIRQL OldIrql)
 
VOID NTAPI MiProcessValidPteList (IN PMMPTE *ValidPteList, IN ULONG Count)
 
ULONG NTAPI MiDecommitPages (IN PVOID StartingAddress, IN PMMPTE EndingPte, IN PEPROCESS Process, IN PMMVAD Vad)
 
PVOID NTAPI MmGetVirtualForPhysical (IN PHYSICAL_ADDRESS PhysicalAddress)
 
PVOID NTAPI MmSecureVirtualMemory (IN PVOID Address, IN SIZE_T Length, IN ULONG Mode)
 
VOID NTAPI MmUnsecureVirtualMemory (IN PVOID SecureMem)
 
NTSTATUS NTAPI NtReadVirtualMemory (IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN SIZE_T NumberOfBytesToRead, OUT PSIZE_T NumberOfBytesRead OPTIONAL)
 
NTSTATUS NTAPI NtWriteVirtualMemory (IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite, OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
 
NTSTATUS NTAPI NtFlushInstructionCache (_In_ HANDLE ProcessHandle, _In_opt_ PVOID BaseAddress, _In_ SIZE_T FlushSize)
 
NTSTATUS NTAPI NtProtectVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *UnsafeBaseAddress, IN OUT SIZE_T *UnsafeNumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG UnsafeOldAccessProtection)
 
FORCEINLINE BOOLEAN MI_IS_LOCKED_VA (PMMPFN Pfn1, ULONG LockType)
 
FORCEINLINE VOID MI_LOCK_VA (PMMPFN Pfn1, ULONG LockType)
 
FORCEINLINE VOID MI_UNLOCK_VA (PMMPFN Pfn1, ULONG LockType)
 
static NTSTATUS MiCheckVadsForLockOperation (_Inout_ PVOID *BaseAddress, _Inout_ PSIZE_T RegionSize, _Inout_ PVOID *EndAddress)
 
static NTSTATUS MiLockVirtualMemory (IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
 
NTSTATUS NTAPI NtLockVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToLock, IN ULONG MapType)
 
static NTSTATUS MiUnlockVirtualMemory (IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
 
NTSTATUS NTAPI NtUnlockVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToUnlock, IN ULONG MapType)
 
NTSTATUS NTAPI NtFlushVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToFlush, OUT PIO_STATUS_BLOCK IoStatusBlock)
 
NTSTATUS NTAPI NtGetWriteWatch (IN HANDLE ProcessHandle, IN ULONG Flags, IN PVOID BaseAddress, IN SIZE_T RegionSize, IN PVOID *UserAddressArray, OUT PULONG_PTR EntriesInUserAddressArray, OUT PULONG Granularity)
 
NTSTATUS NTAPI NtResetWriteWatch (IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN SIZE_T RegionSize)
 
NTSTATUS NTAPI NtQueryVirtualMemory (IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN MEMORY_INFORMATION_CLASS MemoryInformationClass, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
 
NTSTATUS NTAPI NtAllocateVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *UBaseAddress, IN ULONG_PTR ZeroBits, IN OUT PSIZE_T URegionSize, IN ULONG AllocationType, IN ULONG Protect)
 
NTSTATUS NTAPI NtFreeVirtualMemory (IN HANDLE ProcessHandle, IN PVOID *UBaseAddress, IN PSIZE_T URegionSize, IN ULONG FreeType)
 
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress (PVOID Address)
 

Macro Definition Documentation

◆ MI_MAPPED_COPY_PAGES

#define MI_MAPPED_COPY_PAGES   14

Definition at line 18 of file virtual.c.

◆ MI_MAX_TRANSFER_SIZE

#define MI_MAX_TRANSFER_SIZE   64 * 1024

Definition at line 20 of file virtual.c.

◆ MI_POOL_COPY_BYTES

#define MI_POOL_COPY_BYTES   512

Definition at line 19 of file virtual.c.

◆ MODULE_INVOLVED_IN_ARM3

#define MODULE_INVOLVED_IN_ARM3

Definition at line 15 of file virtual.c.

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file virtual.c.

Function Documentation

◆ MI_IS_LOCKED_VA()

FORCEINLINE BOOLEAN MI_IS_LOCKED_VA ( PMMPFN  Pfn1,
ULONG  LockType 
)

Definition at line 3277 of file virtual.c.

3280{
3281 // HACK until we have proper WSLIST support
3282 PMMWSLE Wsle = &Pfn1->Wsle;
3283
3284 if ((LockType & MAP_PROCESS) && (Wsle->u1.e1.LockedInWs))
3285 return TRUE;
3286 if ((LockType & MAP_SYSTEM) && (Wsle->u1.e1.LockedInMemory))
3287 return TRUE;
3288
3289 return FALSE;
3290}
_In_ WDFREQUEST _In_ MEDIA_LOCK_TYPE LockType
Definition: cdrom.h:1335
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define MAP_PROCESS
Definition: mmtypes.h:67
#define MAP_SYSTEM
Definition: mmtypes.h:68
MMWSLE Wsle
Definition: mm.h:434
ULONG_PTR LockedInMemory
Definition: mmtypes.h:829
ULONG_PTR LockedInWs
Definition: mmtypes.h:828
union _MMWSLE::@2621 u1
MMWSLENTRY e1
Definition: mmtypes.h:858

Referenced by MiLockVirtualMemory(), and MiUnlockVirtualMemory().

◆ MI_LOCK_VA()

FORCEINLINE VOID MI_LOCK_VA ( PMMPFN  Pfn1,
ULONG  LockType 
)

Definition at line 3294 of file virtual.c.

3297{
3298 // HACK until we have proper WSLIST support
3299 PMMWSLE Wsle = &Pfn1->Wsle;
3300
3301 if (!Wsle->u1.e1.LockedInWs &&
3302 !Wsle->u1.e1.LockedInMemory)
3303 {
3305 }
3306
3307 if (LockType & MAP_PROCESS)
3308 Wsle->u1.e1.LockedInWs = 1;
3309 if (LockType & MAP_SYSTEM)
3310 Wsle->u1.e1.LockedInMemory = 1;
3311}
FORCEINLINE VOID MiReferenceProbedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1687

Referenced by MiLockVirtualMemory().

◆ MI_UNLOCK_VA()

FORCEINLINE VOID MI_UNLOCK_VA ( PMMPFN  Pfn1,
ULONG  LockType 
)

Definition at line 3315 of file virtual.c.

3318{
3319 // HACK until we have proper WSLIST support
3320 PMMWSLE Wsle = &Pfn1->Wsle;
3321
3322 if (LockType & MAP_PROCESS)
3323 Wsle->u1.e1.LockedInWs = 0;
3324 if (LockType & MAP_SYSTEM)
3325 Wsle->u1.e1.LockedInMemory = 0;
3326
3327 if (!Wsle->u1.e1.LockedInWs &&
3328 !Wsle->u1.e1.LockedInMemory)
3329 {
3331 }
3332}
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1615

Referenced by MiUnlockVirtualMemory().

◆ MiCalculatePageCommitment()

ULONG NTAPI MiCalculatePageCommitment ( IN ULONG_PTR  StartingAddress,
IN ULONG_PTR  EndingAddress,
IN PMMVAD  Vad,
IN PEPROCESS  Process 
)

Definition at line 42 of file virtual.c.

46{
47 PMMPTE PointerPte, LastPte;
48 PMMPDE PointerPde;
49 BOOLEAN OnPdeBoundary = TRUE;
50#if _MI_PAGING_LEVELS >= 3
51 PMMPPE PointerPpe;
52 BOOLEAN OnPpeBoundary = TRUE;
53#if _MI_PAGING_LEVELS == 4
54 PMMPXE PointerPxe;
55 BOOLEAN OnPxeBoundary = TRUE;
56#endif
57#endif
58
59 /* Make sure this all makes sense */
60 ASSERT(PsGetCurrentThread()->OwnsProcessWorkingSetExclusive || PsGetCurrentThread()->OwnsProcessWorkingSetShared);
61 ASSERT(EndingAddress >= StartingAddress);
62 PointerPte = MiAddressToPte(StartingAddress);
63 LastPte = MiAddressToPte(EndingAddress);
64
65 /*
66 * In case this is a committed VAD, assume the whole range is committed
67 * and count the individually decommitted pages.
68 * In case it is not, assume the range is not committed and count the individually committed pages.
69 */
70 ULONG_PTR CommittedPages = Vad->u.VadFlags.MemCommit ? BYTES_TO_PAGES(EndingAddress - StartingAddress) : 0;
71
72 while (PointerPte <= LastPte)
73 {
74#if _MI_PAGING_LEVELS == 4
75 /* Check if PXE was ever paged in. */
76 if (OnPxeBoundary)
77 {
78 PointerPxe = MiPteToPxe(PointerPte);
79
80 /* Check that this loop is sane */
81 ASSERT(OnPpeBoundary);
82 ASSERT(OnPdeBoundary);
83
84 if (PointerPxe->u.Long == 0)
85 {
86 PointerPxe++;
87 PointerPte = MiPxeToPte(PointerPde);
88 continue;
89 }
90
91 if (PointerPxe->u.Hard.Valid == 0)
93 }
94 ASSERT(PointerPxe->u.Hard.Valid == 1);
95#endif
96
97#if _MI_PAGING_LEVELS >= 3
98 /* Now PPE */
99 if (OnPpeBoundary)
100 {
101 PointerPpe = MiPteToPpe(PointerPte);
102
103 /* Sanity again */
104 ASSERT(OnPdeBoundary);
105
106 if (PointerPpe->u.Long == 0)
107 {
108 PointerPpe++;
109 PointerPte = MiPpeToPte(PointerPpe);
110#if _MI_PAGING_LEVELS == 4
111 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
112#endif
113 continue;
114 }
115
116 if (PointerPpe->u.Hard.Valid == 0)
118 }
119 ASSERT(PointerPpe->u.Hard.Valid == 1);
120#endif
121
122 /* Last level is the PDE */
123 if (OnPdeBoundary)
124 {
125 PointerPde = MiPteToPde(PointerPte);
126 if (PointerPde->u.Long == 0)
127 {
128 PointerPde++;
129 PointerPte = MiPdeToPte(PointerPde);
130#if _MI_PAGING_LEVELS >= 3
131 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
132#if _MI_PAGING_LEVELS == 4
133 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
134#endif
135#endif
136 continue;
137 }
138
139 if (PointerPde->u.Hard.Valid == 0)
141 }
142 ASSERT(PointerPde->u.Hard.Valid == 1);
143
144 /* Is this PTE demand zero? */
145 if (PointerPte->u.Long != 0)
146 {
147 /* It isn't -- is it a decommited, invalid, or faulted PTE? */
148 if ((PointerPte->u.Hard.Valid == 0) &&
149 (PointerPte->u.Soft.Protection == MM_DECOMMIT) &&
150 ((PointerPte->u.Soft.Prototype == 0) ||
151 (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
152 {
153 /* It is, so remove it from the count of committed pages if we have to */
154 if (Vad->u.VadFlags.MemCommit)
155 CommittedPages--;
156 }
157 else if (!Vad->u.VadFlags.MemCommit)
158 {
159 /* It is a valid, non-decommited, non-paged out PTE. Count it in. */
160 CommittedPages++;
161 }
162 }
163
164 /* Move to the next PTE */
165 PointerPte++;
166 /* Manage page tables */
167 OnPdeBoundary = MiIsPteOnPdeBoundary(PointerPte);
168#if _MI_PAGING_LEVELS >= 3
169 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
170#if _MI_PAGING_LEVELS == 4
171 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
172#endif
173#endif
174 }
175
176 /* Make sure we didn't mess this up */
177 ASSERT(CommittedPages <= BYTES_TO_PAGES(EndingAddress - StartingAddress));
178 return CommittedPages;
179}
unsigned char BOOLEAN
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
#define MM_DECOMMIT
Definition: miarm.h:64
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:241
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define ASSERT(a)
Definition: mode.c:44
FORCEINLINE PMMPPE MiPteToPpe(PMMPTE PointerPte)
Definition: mm.h:276
FORCEINLINE PMMPTE MiPxeToPte(PMMPXE PointerPxe)
Definition: mm.h:260
#define MiIsPteOnPpeBoundary(PointerPte)
Definition: mm.h:308
FORCEINLINE PMMPTE MiPpeToPte(PMMPPE PointerPpe)
Definition: mm.h:252
#define MiIsPteOnPdeBoundary(PointerPte)
Definition: mm.h:306
#define MiIsPteOnPxeBoundary(PointerPte)
Definition: mm.h:310
FORCEINLINE PMMPXE MiPteToPxe(PMMPTE PointerPte)
Definition: mm.h:284
#define MiPteToPde(_Pte)
Definition: mm.h:121
#define MiPdeToPte(_Pde)
Definition: mm.h:120
ULONG NTAPI MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress, IN PEPROCESS CurrentProcess)
Definition: virtual.c:183
ULONG64 Valid
Definition: mmtypes.h:150
ULONG64 Protection
Definition: mmtypes.h:88
ULONG64 Prototype
Definition: mmtypes.h:89
ULONG64 PageFileHigh
Definition: mmtypes.h:93
union _MMPTE::@2330 u
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
ULONG_PTR Long
Definition: mmtypes.h:215
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define BYTES_TO_PAGES(Size)

Referenced by NtFreeVirtualMemory().

◆ MiCheckVadsForLockOperation()

static NTSTATUS MiCheckVadsForLockOperation ( _Inout_ PVOID BaseAddress,
_Inout_ PSIZE_T  RegionSize,
_Inout_ PVOID EndAddress 
)
static

FIXME: this might be a memory area for a section view...

Definition at line 3336 of file virtual.c.

3341{
3342 PMMVAD Vad;
3343 PVOID CurrentVa;
3344
3345 /* Get the base address and align the start address */
3346 *EndAddress = (PUCHAR)*BaseAddress + *RegionSize;
3347 *EndAddress = ALIGN_UP_POINTER_BY(*EndAddress, PAGE_SIZE);
3349
3350 /* First loop and check all VADs */
3351 CurrentVa = *BaseAddress;
3352 while (CurrentVa < *EndAddress)
3353 {
3354 /* Get VAD */
3355 Vad = MiLocateAddress(CurrentVa);
3356 if (Vad == NULL)
3357 {
3360 }
3361
3362 /* Check VAD type */
3363 if ((Vad->u.VadFlags.VadType != VadNone) &&
3364 (Vad->u.VadFlags.VadType != VadImageMap) &&
3365 (Vad->u.VadFlags.VadType != VadWriteWatch))
3366 {
3367 *EndAddress = CurrentVa;
3368 *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3370 }
3371
3372 CurrentVa = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
3373 }
3374
3375 *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3376 return STATUS_SUCCESS;
3377}
#define NULL
Definition: types.h:112
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
Definition: vadnode.c:116
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
__kernel_entry _Inout_ _Inout_ PSIZE_T RegionSize
Definition: mmfuncs.h:172
@ VadWriteWatch
Definition: mmtypes.h:208
@ VadImageMap
Definition: mmtypes.h:206
@ VadNone
Definition: mmtypes.h:204
#define STATUS_INCOMPATIBLE_FILE_MAP
Definition: ntstatus.h:313
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
#define STATUS_SUCCESS
Definition: shellext.h:65
ULONG_PTR VadType
Definition: mmtypes.h:694
ULONG_PTR EndingVpn
Definition: mmtypes.h:730
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:734
union _MMVAD::@2611 u
void * PVOID
Definition: typedefs.h:50
unsigned char * PUCHAR
Definition: typedefs.h:53
#define ALIGN_UP_POINTER_BY(ptr, align)
Definition: umtypes.h:85
#define ALIGN_DOWN_POINTER_BY(ptr, align)
Definition: umtypes.h:82

Referenced by MiLockVirtualMemory(), and MiUnlockVirtualMemory().

◆ MiDecommitPages()

ULONG NTAPI MiDecommitPages ( IN PVOID  StartingAddress,
IN PMMPTE  EndingPte,
IN PEPROCESS  Process,
IN PMMVAD  Vad 
)

Definition at line 2627 of file virtual.c.

2631{
2632 PMMPTE PointerPte, CommitPte = NULL;
2633 PMMPDE PointerPde;
2634 ULONG CommitReduction = 0;
2635 PMMPTE ValidPteList[256];
2636 ULONG PteCount = 0;
2637 PMMPFN Pfn1;
2638 MMPTE PteContents;
2639 PETHREAD CurrentThread = PsGetCurrentThread();
2640
2641 //
2642 // Get the PTE and PTE for the address, and lock the working set
2643 // If this was a VAD for a MEM_COMMIT allocation, also figure out where the
2644 // commited range ends so that we can do the right accounting.
2645 //
2646 PointerPde = MiAddressToPde(StartingAddress);
2647 PointerPte = MiAddressToPte(StartingAddress);
2648 if (Vad->u.VadFlags.MemCommit) CommitPte = MiAddressToPte(Vad->EndingVpn << PAGE_SHIFT);
2649 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
2650
2651 //
2652 // Make the PDE valid, and now loop through each page's worth of data
2653 //
2655 while (PointerPte <= EndingPte)
2656 {
2657 //
2658 // Check if we've crossed a PDE boundary
2659 //
2660 if (MiIsPteOnPdeBoundary(PointerPte))
2661 {
2662 //
2663 // Get the new PDE and flush the valid PTEs we had built up until
2664 // now. This helps reduce the amount of TLB flushing we have to do.
2665 // Note that Windows does a much better job using timestamps and
2666 // such, and does not flush the entire TLB all the time, but right
2667 // now we have bigger problems to worry about than TLB flushing.
2668 //
2669 PointerPde = MiAddressToPde(StartingAddress);
2670 if (PteCount)
2671 {
2672 MiProcessValidPteList(ValidPteList, PteCount);
2673 PteCount = 0;
2674 }
2675
2676 //
2677 // Make this PDE valid
2678 //
2680 }
2681
2682 //
2683 // Read this PTE. It might be active or still demand-zero.
2684 //
2685 PteContents = *PointerPte;
2686 if (PteContents.u.Long)
2687 {
2688 //
2689 // The PTE is active. It might be valid and in a working set, or
2690 // it might be a prototype PTE or paged out or even in transition.
2691 //
2692 if (PointerPte->u.Long == MmDecommittedPte.u.Long)
2693 {
2694 //
2695 // It's already decommited, so there's nothing for us to do here
2696 //
2697 CommitReduction++;
2698 }
2699 else
2700 {
2701 //
2702 // Remove it from the counters, and check if it was valid or not
2703 //
2704 //Process->NumberOfPrivatePages--;
2705 if (PteContents.u.Hard.Valid)
2706 {
2707 //
2708 // It's valid. At this point make sure that it is not a ROS
2709 // PFN. Also, we don't support ProtoPTEs in this code path.
2710 //
2711 Pfn1 = MiGetPfnEntry(PteContents.u.Hard.PageFrameNumber);
2712 ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
2713 ASSERT(Pfn1->u3.e1.PrototypePte == FALSE);
2714
2715 //
2716 // Flush any pending PTEs that we had not yet flushed, if our
2717 // list has gotten too big, then add this PTE to the flush list.
2718 //
2719 if (PteCount == 256)
2720 {
2721 MiProcessValidPteList(ValidPteList, PteCount);
2722 PteCount = 0;
2723 }
2724 ValidPteList[PteCount++] = PointerPte;
2725 }
2726 else
2727 {
2728 //
2729 // We do not support any of these other scenarios at the moment
2730 //
2731 ASSERT(PteContents.u.Soft.Prototype == 0);
2732 ASSERT(PteContents.u.Soft.Transition == 0);
2733 ASSERT(PteContents.u.Soft.PageFileHigh == 0);
2734
2735 //
2736 // So the only other possibility is that it is still a demand
2737 // zero PTE, in which case we undo the accounting we did
2738 // earlier and simply make the page decommitted.
2739 //
2740 //Process->NumberOfPrivatePages++;
2742 }
2743 }
2744 }
2745 else
2746 {
2747 //
2748 // This used to be a zero PTE and it no longer is, so we must add a
2749 // reference to the pagetable.
2750 //
2751 MiIncrementPageTableReferences(StartingAddress);
2752
2753 //
2754 // Next, we account for decommitted PTEs and make the PTE as such
2755 //
2756 if (PointerPte > CommitPte) CommitReduction++;
2758 }
2759
2760 //
2761 // Move to the next PTE and the next address
2762 //
2763 PointerPte++;
2764 StartingAddress = (PVOID)((ULONG_PTR)StartingAddress + PAGE_SIZE);
2765 }
2766
2767 //
2768 // Flush any dangling PTEs from the loop in the last page table, and then
2769 // release the working set and return the commit reduction accounting.
2770 //
2771 if (PteCount) MiProcessValidPteList(ValidPteList, PteCount);
2773 return CommitReduction;
2774}
#define MI_IS_ROS_PFN(x)
Definition: miarm.h:1103
FORCEINLINE VOID MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1239
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:992
FORCEINLINE USHORT MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2481
FORCEINLINE VOID MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1169
#define MiAddressToPde(x)
Definition: mmx86.c:20
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:1047
#define MM_NOIRQL
Definition: mm.h:70
VOID NTAPI MiProcessValidPteList(IN PMMPTE *ValidPteList, IN ULONG Count)
Definition: virtual.c:2575
VOID NTAPI MiMakePdeExistAndMakeValid(IN PMMPDE PointerPde, IN PEPROCESS TargetProcess, IN KIRQL OldIrql)
Definition: virtual.c:2481
MMPTE MmDecommittedPte
Definition: init.c:44
USHORT PrototypePte
Definition: mm.h:363
Definition: mm.h:374
union _MMPFN::@1795 u3
MMPFNENTRY e1
Definition: mm.h:397
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
ULONG64 Transition
Definition: mmtypes.h:90
uint32_t ULONG
Definition: typedefs.h:59

Referenced by NtFreeVirtualMemory().

◆ MiDeletePte()

VOID NTAPI MiDeletePte ( IN PMMPTE  PointerPte,
IN PVOID  VirtualAddress,
IN PEPROCESS  CurrentProcess,
IN PMMPTE  PrototypePte 
)

Definition at line 369 of file virtual.c.

373{
374 PMMPFN Pfn1;
376 PFN_NUMBER PageFrameIndex;
377 PMMPDE PointerPde;
378
379 /* PFN lock must be held */
381
382 /* WorkingSet must be exclusively locked */
384
385 /* This must be current process. */
386 ASSERT(CurrentProcess == PsGetCurrentProcess());
387
388 /* Capture the PTE */
389 TempPte = *PointerPte;
390
391 /* See if the PTE is valid */
392 if (TempPte.u.Hard.Valid == 0)
393 {
394 /* Prototype and paged out PTEs not supported yet */
395 ASSERT(TempPte.u.Soft.Prototype == 0);
396 ASSERT((TempPte.u.Soft.PageFileHigh == 0) || (TempPte.u.Soft.Transition == 1));
397
398 if (TempPte.u.Soft.Transition)
399 {
400 /* Get the PFN entry */
401 PageFrameIndex = PFN_FROM_PTE(&TempPte);
402 Pfn1 = MiGetPfnEntry(PageFrameIndex);
403
404 DPRINT("Pte %p is transitional!\n", PointerPte);
405
406 /* Make sure the saved PTE address is valid */
407 ASSERT((PMMPTE)((ULONG_PTR)Pfn1->PteAddress & ~0x1) == PointerPte);
408
409 /* Destroy the PTE */
410 MI_ERASE_PTE(PointerPte);
411
412 /* Drop the reference on the page table. */
414
415 /* In case of shared page, the prototype PTE must be in transition, not the process one */
416 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
417
418 /* Delete the PFN */
419 MI_SET_PFN_DELETED(Pfn1);
420
421 /* It must be either free (refcount == 0) or being written (refcount == 1) */
422 ASSERT(Pfn1->u3.e2.ReferenceCount == Pfn1->u3.e1.WriteInProgress);
423
424 /* See if we must free it ourselves, or if it will be freed once I/O is over */
425 if (Pfn1->u3.e2.ReferenceCount == 0)
426 {
427 /* And it should be in standby or modified list */
429
430 /* Unlink it and set its reference count to one */
432 Pfn1->u3.e2.ReferenceCount++;
433
434 /* This will put it back in free list and clean properly up */
435 MiDecrementReferenceCount(Pfn1, PageFrameIndex);
436 }
437 return;
438 }
439 }
440
441 /* Get the PFN entry */
442 PageFrameIndex = PFN_FROM_PTE(&TempPte);
443 Pfn1 = MiGetPfnEntry(PageFrameIndex);
444
445 /* Check if this is a valid, prototype PTE */
446 if (Pfn1->u3.e1.PrototypePte == 1)
447 {
448 /* Get the PDE and make sure it's faulted in */
449 PointerPde = MiPteToPde(PointerPte);
450 if (PointerPde->u.Hard.Valid == 0)
451 {
452#if (_MI_PAGING_LEVELS == 2)
453 /* Could be paged pool access from a new process -- synchronize the page directories */
455 {
456#endif
457 /* The PDE must be valid at this point */
458 KeBugCheckEx(MEMORY_MANAGEMENT,
459 0x61940,
460 (ULONG_PTR)PointerPte,
461 PointerPte->u.Long,
463 }
464#if (_MI_PAGING_LEVELS == 2)
465 }
466#endif
467 /* Drop the share count on the page table */
468 PointerPde = MiPteToPde(PointerPte);
470 PointerPde->u.Hard.PageFrameNumber);
471
472 /* Drop the share count */
473 MiDecrementShareCount(Pfn1, PageFrameIndex);
474
475 /* Either a fork, or this is the shared user data page */
476 if ((PointerPte <= MiHighestUserPte) && (PrototypePte != Pfn1->PteAddress))
477 {
478 /* If it's not the shared user page, then crash, since there's no fork() yet */
481 {
482 /* Must be some sort of memory corruption */
483 KeBugCheckEx(MEMORY_MANAGEMENT,
484 0x400,
485 (ULONG_PTR)PointerPte,
487 (ULONG_PTR)Pfn1->PteAddress);
488 }
489 }
490
491 /* Erase it */
492 MI_ERASE_PTE(PointerPte);
493 }
494 else
495 {
496 /* Make sure the saved PTE address is valid */
497 if ((PMMPTE)((ULONG_PTR)Pfn1->PteAddress & ~0x1) != PointerPte)
498 {
499 /* The PFN entry is illegal, or invalid */
500 KeBugCheckEx(MEMORY_MANAGEMENT,
501 0x401,
502 (ULONG_PTR)PointerPte,
503 PointerPte->u.Long,
504 (ULONG_PTR)Pfn1->PteAddress);
505 }
506
507 /* Erase the PTE */
508 MI_ERASE_PTE(PointerPte);
509
510 /* There should only be 1 shared reference count */
511 ASSERT(Pfn1->u2.ShareCount == 1);
512
513 /* Drop the reference on the page table. */
515
516 /* Mark the PFN for deletion and dereference what should be the last ref */
517 MI_SET_PFN_DELETED(Pfn1);
518 MiDecrementShareCount(Pfn1, PageFrameIndex);
519
520 /* We should eventually do this */
521 //CurrentProcess->NumberOfPrivatePages--;
522 }
523
524 /* Flush the TLB */
526}
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:76
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define USER_SHARED_DATA
Definition: pstypes.h:51
PMMPTE MiHighestUserPte
Definition: mminit.c:233
FORCEINLINE BOOLEAN MM_ANY_WS_LOCK_HELD_EXCLUSIVE(_In_ PETHREAD Thread)
Definition: miarm.h:1065
#define MI_SET_PFN_DELETED(x)
Definition: miarm.h:194
FORCEINLINE VOID MI_ERASE_PTE(IN PMMPTE PointerPte)
Definition: miarm.h:1006
VOID NTAPI MiDecrementShareCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1141
VOID NTAPI MiUnlinkPageFromList(IN PMMPFN Pfn)
Definition: pfnlist.c:265
NTSTATUS FASTCALL MiCheckPdeForPagedPool(IN PVOID Address)
Definition: pagfault.c:479
VOID NTAPI MiDecrementReferenceCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1236
@ ModifiedPageList
Definition: mmtypes.h:156
@ StandbyPageList
Definition: mmtypes.h:155
#define PFN_FROM_PTE(v)
Definition: mm.h:92
VOID NTAPI KeFlushCurrentTb(VOID)
Definition: cpu.c:526
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:1043
MMPTE PrototypePte
Definition: init.c:40
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
PVOID MmHighestUserAddress
Definition: rtlcompat.c:29
ULONG PFN_NUMBER
Definition: ke.h:9
#define DPRINT
Definition: sndvol32.h:71
USHORT PageLocation
Definition: mm.h:365
USHORT WriteInProgress
Definition: mm.h:362
union _MMPFN::@1794 u2
struct _MMPFN::@1795::@1801 e2
PMMPTE PteAddress
Definition: mm.h:386
ULONG_PTR ShareCount
Definition: mm.h:390
union _MMPFN::@1798 u4
ULONG_PTR PteFrame
Definition: mm.h:418
_Must_inspect_result_ _In_ WDFDMATRANSACTION _In_ PFN_WDF_PROGRAM_DMA _In_ WDF_DMA_DIRECTION _In_ PMDL _In_ PVOID VirtualAddress
#define PAGE_ALIGN(Va)
#define PsGetCurrentProcess
Definition: psfuncs.h:17

Referenced by MiDeletePde(), MiDeleteVirtualAddresses(), MiResolveProtoPteFault(), and MmArmAccessFault().

◆ MiDeleteSystemPageableVm()

PFN_COUNT NTAPI MiDeleteSystemPageableVm ( IN PMMPTE  PointerPte,
IN PFN_NUMBER  PageCount,
IN ULONG  Flags,
OUT PPFN_NUMBER  ValidPages 
)

Definition at line 275 of file virtual.c.

279{
280 PFN_COUNT ActualPages = 0;
281 PETHREAD CurrentThread = PsGetCurrentThread();
282 PMMPFN Pfn1, Pfn2;
283 PFN_NUMBER PageFrameIndex, PageTableIndex;
286
287 /* Lock the system working set */
288 MiLockWorkingSet(CurrentThread, &MmSystemCacheWs);
289
290 /* Loop all pages */
291 while (PageCount)
292 {
293 /* Make sure there's some data about the page */
294 if (PointerPte->u.Long)
295 {
296 /* Normally this is one possibility -- freeing a valid page */
297 if (PointerPte->u.Hard.Valid)
298 {
299 /* Get the page PFN */
300 PageFrameIndex = PFN_FROM_PTE(PointerPte);
301 Pfn1 = MiGetPfnEntry(PageFrameIndex);
302
303 /* Should not have any working set data yet */
304 ASSERT(Pfn1->u1.WsIndex == 0);
305
306 /* Actual valid, legitimate, pages */
307 if (ValidPages) (*ValidPages)++;
308
309 /* Get the page table entry */
310 PageTableIndex = Pfn1->u4.PteFrame;
311 Pfn2 = MiGetPfnEntry(PageTableIndex);
312
313 /* Lock the PFN database */
314 OldIrql = MiAcquirePfnLock();
315
316 /* Delete it the page */
317 MI_SET_PFN_DELETED(Pfn1);
318 MiDecrementShareCount(Pfn1, PageFrameIndex);
319
320 /* Decrement the page table too */
321 MiDecrementShareCount(Pfn2, PageTableIndex);
322
323 /* Release the PFN database */
324 MiReleasePfnLock(OldIrql);
325
326 /* Destroy the PTE */
327 MI_ERASE_PTE(PointerPte);
328 }
329 else
330 {
331 /* As always, only handle current ARM3 scenarios */
332 ASSERT(PointerPte->u.Soft.Prototype == 0);
333 ASSERT(PointerPte->u.Soft.Transition == 0);
334
335 /*
336 * The only other ARM3 possibility is a demand zero page, which would
337 * mean freeing some of the paged pool pages that haven't even been
338 * touched yet, as part of a larger allocation.
339 *
340 * Right now, we shouldn't expect any page file information in the PTE
341 */
342 ASSERT(PointerPte->u.Soft.PageFileHigh == 0);
343
344 /* Destroy the PTE */
345 MI_ERASE_PTE(PointerPte);
346 }
347
348 /* Actual legitimate pages */
349 ActualPages++;
350 }
351
352 /* Keep going */
353 PointerPte++;
354 PageCount--;
355 }
356
357 /* Release the working set */
358 MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs);
359
360 /* Flush the entire TLB */
362
363 /* Done */
364 return ActualPages;
365}
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
FORCEINLINE VOID MiLockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1265
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1351
VOID NTAPI KeFlushEntireTb(IN BOOLEAN Invalid, IN BOOLEAN AllProcessors)
Definition: cpu.c:652
MMSUPPORT MmSystemCacheWs
Definition: init.c:55
ULONG WsIndex
Definition: mm.h:378
union _MMPFN::@1793 u1
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
ULONG PFN_COUNT
Definition: mmtypes.h:102

Referenced by MiFreeInitializationCode(), MiFreePoolPages(), MmFreeDriverInitialization(), and MmFreeSpecialPool().

◆ MiDeleteVirtualAddresses()

VOID NTAPI MiDeleteVirtualAddresses ( IN ULONG_PTR  Va,
IN ULONG_PTR  EndingAddress,
IN PMMVAD  Vad 
)

Definition at line 530 of file virtual.c.

533{
534 PMMPTE PointerPte, PrototypePte, LastPrototypePte;
535 PMMPDE PointerPde;
536#if (_MI_PAGING_LEVELS >= 3)
537 PMMPPE PointerPpe;
538#endif
539#if (_MI_PAGING_LEVELS >= 4)
540 PMMPPE PointerPxe;
541#endif
543 PEPROCESS CurrentProcess;
545 BOOLEAN AddressGap = FALSE;
546 PSUBSECTION Subsection;
547
548 /* Get out if this is a fake VAD, RosMm will free the marea pages */
549 if ((Vad) && (Vad->u.VadFlags.Spare == 1)) return;
550
551 /* Get the current process */
552 CurrentProcess = PsGetCurrentProcess();
553
554 /* Check if this is a section VAD or a VM VAD */
555 if (!(Vad) || (Vad->u.VadFlags.PrivateMemory) || !(Vad->FirstPrototypePte))
556 {
557 /* Don't worry about prototypes */
558 PrototypePte = LastPrototypePte = NULL;
559 }
560 else
561 {
562 /* Get the prototype PTE */
563 PrototypePte = Vad->FirstPrototypePte;
564 LastPrototypePte = Vad->FirstPrototypePte + 1;
565 }
566
567 /* In all cases, we don't support fork() yet */
568 ASSERT(CurrentProcess->CloneRoot == NULL);
569
570 /* Loop the PTE for each VA (EndingAddress is inclusive!) */
571 while (Va <= EndingAddress)
572 {
573#if (_MI_PAGING_LEVELS >= 4)
574 /* Get the PXE and check if it's valid */
575 PointerPxe = MiAddressToPxe((PVOID)Va);
576 if (!PointerPxe->u.Hard.Valid)
577 {
578 /* Check for unmapped range and skip it */
579 if (!PointerPxe->u.Long)
580 {
581 /* There are gaps in the address space */
582 AddressGap = TRUE;
583
584 /* Update Va and continue looping */
585 Va = (ULONG_PTR)MiPxeToAddress(PointerPxe + 1);
586 continue;
587 }
588
589 /* Make the PXE valid */
590 MiMakeSystemAddressValid(MiPteToAddress(PointerPxe), CurrentProcess);
591 }
592#endif
593#if (_MI_PAGING_LEVELS >= 3)
594 /* Get the PPE and check if it's valid */
595 PointerPpe = MiAddressToPpe((PVOID)Va);
596 if (!PointerPpe->u.Hard.Valid)
597 {
598 /* Check for unmapped range and skip it */
599 if (!PointerPpe->u.Long)
600 {
601 /* There are gaps in the address space */
602 AddressGap = TRUE;
603
604 /* Update Va and continue looping */
605 Va = (ULONG_PTR)MiPpeToAddress(PointerPpe + 1);
606 continue;
607 }
608
609 /* Make the PPE valid */
610 MiMakeSystemAddressValid(MiPteToAddress(PointerPpe), CurrentProcess);
611 }
612#endif
613 /* Skip invalid PDEs */
614 PointerPde = MiAddressToPde((PVOID)Va);
615 if (!PointerPde->u.Long)
616 {
617 /* There are gaps in the address space */
618 AddressGap = TRUE;
619
620 /* Check if all the PDEs are invalid, so there's nothing to free */
621 Va = (ULONG_PTR)MiPdeToAddress(PointerPde + 1);
622 continue;
623 }
624
625 /* Now check if the PDE is mapped in */
626 if (!PointerPde->u.Hard.Valid)
627 {
628 /* It isn't, so map it in */
629 PointerPte = MiPteToAddress(PointerPde);
630 MiMakeSystemAddressValid(PointerPte, CurrentProcess);
631 }
632
633 /* Now we should have a valid PDE, mapped in, and still have some VA */
634 ASSERT(PointerPde->u.Hard.Valid == 1);
635 ASSERT(Va <= EndingAddress);
636
637 /* Check if this is a section VAD with gaps in it */
638 if ((AddressGap) && (LastPrototypePte))
639 {
640 /* We need to skip to the next correct prototype PTE */
642
643 /* And we need the subsection to skip to the next last prototype PTE */
644 Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
645 if (Subsection)
646 {
647 /* Found it! */
648 LastPrototypePte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
649 }
650 else
651 {
652 /* No more subsections, we are done with prototype PTEs */
654 }
655 }
656
657 /* Lock the PFN Database while we delete the PTEs */
658 OldIrql = MiAcquirePfnLock();
659 PointerPte = MiAddressToPte(Va);
660 do
661 {
662 /* Making sure the PDE is still valid */
663 ASSERT(PointerPde->u.Hard.Valid == 1);
664
665 /* Capture the PDE and make sure it exists */
666 TempPte = *PointerPte;
667 if (TempPte.u.Long)
668 {
669 /* Check if the PTE is actually mapped in */
671 {
672 /* Are we dealing with section VAD? */
673 if ((LastPrototypePte) && (PrototypePte > LastPrototypePte))
674 {
675 /* We need to skip to the next correct prototype PTE */
677
678 /* And we need the subsection to skip to the next last prototype PTE */
679 Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
680 if (Subsection)
681 {
682 /* Found it! */
683 LastPrototypePte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
684 }
685 else
686 {
687 /* No more subsections, we are done with prototype PTEs */
689 }
690 }
691
692 /* Check for prototype PTE */
693 if ((TempPte.u.Hard.Valid == 0) &&
694 (TempPte.u.Soft.Prototype == 1))
695 {
696 /* Just nuke it */
697 MI_ERASE_PTE(PointerPte);
698 }
699 else
700 {
701 /* Delete the PTE proper */
702 MiDeletePte(PointerPte,
703 (PVOID)Va,
704 CurrentProcess,
706 }
707 }
708 else
709 {
710 /* The PTE was never mapped, just nuke it here */
711 MI_ERASE_PTE(PointerPte);
712 }
713
715 {
716 ASSERT(PointerPde->u.Long != 0);
717
718 /* Delete the PDE proper */
719 MiDeletePde(PointerPde, CurrentProcess);
720
721 /* Continue with the next PDE */
722 Va = (ULONG_PTR)MiPdeToAddress(PointerPde + 1);
723
724 /* Use this to detect address gaps */
725 PointerPte++;
726
727 PrototypePte++;
728 break;
729 }
730 }
731
732 /* Update the address and PTE for it */
733 Va += PAGE_SIZE;
734 PointerPte++;
735 PrototypePte++;
736 } while ((Va & (PDE_MAPPED_VA - 1)) && (Va <= EndingAddress));
737
738 /* Release the lock */
739 MiReleasePfnLock(OldIrql);
740
741 if (Va > EndingAddress) return;
742
743 /* Check if we exited the loop regularly */
744 AddressGap = (PointerPte != MiAddressToPte(Va));
745 }
746}
#define ULONG_PTR
Definition: config.h:101
FORCEINLINE PMMPTE MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad, IN ULONG_PTR Vpn)
Definition: miarm.h:1557
FORCEINLINE VOID MiDeletePde(_In_ PMMPDE PointerPde, _In_ PEPROCESS CurrentProcess)
Definition: miarm.h:2541
FORCEINLINE USHORT MiDecrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2507
PSUBSECTION NTAPI MiLocateSubsection(IN PMMVAD Vad, IN ULONG_PTR Vpn)
Definition: section.c:556
FORCEINLINE PVOID MiPpeToAddress(PMMPTE PointerPpe)
Definition: mm.h:226
FORCEINLINE PMMPTE MiAddressToPpe(PVOID Address)
Definition: mm.h:161
FORCEINLINE PMMPTE MiAddressToPxe(PVOID Address)
Definition: mm.h:171
FORCEINLINE BOOLEAN MI_IS_MAPPED_PTE(PMMPTE PointerPte)
Definition: mm.h:356
#define PDE_MAPPED_VA
Definition: mm.h:39
FORCEINLINE PVOID MiPxeToAddress(PMMPTE PointerPxe)
Definition: mm.h:235
#define MiPdeToAddress(_Pde)
Definition: mm.h:117
#define MiPteToAddress(_Pte)
Definition: mm.h:116
VOID NTAPI MiDeletePte(IN PMMPTE PointerPte, IN PVOID VirtualAddress, IN PEPROCESS CurrentProcess, IN PMMPTE PrototypePte)
Definition: virtual.c:369
PVOID CloneRoot
Definition: pstypes.h:1299
ULONG PtesInSubsection
Definition: mmtypes.h:583
PMMPTE SubsectionBase
Definition: mmtypes.h:581

Referenced by MiRemoveMappedView(), MmCleanProcessAddressSpace(), MmDeleteTeb(), and NtFreeVirtualMemory().

◆ MiDoMappedCopy()

NTSTATUS NTAPI MiDoMappedCopy ( IN PEPROCESS  SourceProcess,
IN PVOID  SourceAddress,
IN PEPROCESS  TargetProcess,
OUT PVOID  TargetAddress,
IN SIZE_T  BufferSize,
IN KPROCESSOR_MODE  PreviousMode,
OUT PSIZE_T  ReturnSize 
)

Definition at line 794 of file virtual.c.

801{
802 PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
803 PMDL Mdl = (PMDL)MdlBuffer;
804 SIZE_T TotalSize, CurrentSize, RemainingSize;
805 volatile BOOLEAN FailedInProbe = FALSE;
806 volatile BOOLEAN PagesLocked = FALSE;
807 PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
808 volatile PVOID MdlAddress = NULL;
810 BOOLEAN HaveBadAddress;
811 ULONG_PTR BadAddress;
813 PAGED_CODE();
814
815 //
816 // Calculate the maximum amount of data to move
817 //
818 TotalSize = MI_MAPPED_COPY_PAGES * PAGE_SIZE;
819 if (BufferSize <= TotalSize) TotalSize = BufferSize;
820 CurrentSize = TotalSize;
821 RemainingSize = BufferSize;
822
823 //
824 // Loop as long as there is still data
825 //
826 while (RemainingSize > 0)
827 {
828 //
829 // Check if this transfer will finish everything off
830 //
831 if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
832
833 //
834 // Attach to the source address space
835 //
836 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
837
838 //
839 // Check state for this pass
840 //
841 ASSERT(MdlAddress == NULL);
842 ASSERT(PagesLocked == FALSE);
843 ASSERT(FailedInProbe == FALSE);
844
845 //
846 // Protect user-mode copy
847 //
849 {
850 //
851 // If this is our first time, probe the buffer
852 //
853 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
854 {
855 //
856 // Catch a failure here
857 //
858 FailedInProbe = TRUE;
859
860 //
861 // Do the probe
862 //
864
865 //
866 // Passed
867 //
868 FailedInProbe = FALSE;
869 }
870
871 //
872 // Initialize and probe and lock the MDL
873 //
874 MmInitializeMdl(Mdl, CurrentAddress, CurrentSize);
876 PagesLocked = TRUE;
877 }
879 {
881 }
883
884 /* Detach from source process */
886
887 if (Status != STATUS_SUCCESS)
888 {
889 goto Exit;
890 }
891
892 //
893 // Now map the pages
894 //
897 MmCached,
898 NULL,
899 FALSE,
901 if (!MdlAddress)
902 {
904 goto Exit;
905 }
906
907 //
908 // Grab to the target process
909 //
910 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
911
913 {
914 //
915 // Check if this is our first time through
916 //
917 if ((CurrentTargetAddress == TargetAddress) && (PreviousMode != KernelMode))
918 {
919 //
920 // Catch a failure here
921 //
922 FailedInProbe = TRUE;
923
924 //
925 // Do the probe
926 //
928
929 //
930 // Passed
931 //
932 FailedInProbe = FALSE;
933 }
934
935 //
936 // Now do the actual move
937 //
938 RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
939 }
941 &HaveBadAddress,
942 &BadAddress))
943 {
944 *ReturnSize = BufferSize - RemainingSize;
945 //
946 // Check if we failed during the probe
947 //
948 if (FailedInProbe)
949 {
950 //
951 // Exit
952 //
954 }
955 else
956 {
957 //
958 // Othewise we failed during the move.
959 // Check if we know exactly where we stopped copying
960 //
961 if (HaveBadAddress)
962 {
963 //
964 // Return the exact number of bytes copied
965 //
966 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
967 }
968 //
969 // Return partial copy
970 //
972 }
973 }
974 _SEH2_END;
975
976 /* Detach from target process */
978
979 //
980 // Check for SEH status
981 //
982 if (Status != STATUS_SUCCESS)
983 {
984 goto Exit;
985 }
986
987 //
988 // Unmap and unlock
989 //
990 MmUnmapLockedPages(MdlAddress, Mdl);
991 MdlAddress = NULL;
993 PagesLocked = FALSE;
994
995 //
996 // Update location and size
997 //
998 RemainingSize -= CurrentSize;
999 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
1000 CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
1001 }
1002
1003Exit:
1004 if (MdlAddress != NULL)
1005 MmUnmapLockedPages(MdlAddress, Mdl);
1006 if (PagesLocked)
1008
1009 //
1010 // All bytes read
1011 //
1012 if (Status == STATUS_SUCCESS)
1013 *ReturnSize = BufferSize;
1014 return Status;
1015}
#define PAGED_CODE()
LONG NTSTATUS
Definition: precomp.h:26
#define BufferSize
Definition: mmc.h:75
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
Status
Definition: gdiplustypes.h:25
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:931
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1435
PVOID NTAPI MmMapLockedPagesSpecifyCache(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN MEMORY_CACHING_TYPE CacheType, IN PVOID BaseAddress, IN ULONG BugCheckOnFailure, IN ULONG Priority)
Definition: mdlsup.c:660
VOID NTAPI MmUnmapLockedPages(IN PVOID BaseAddress, IN PMDL Mdl)
Definition: mdlsup.c:837
@ HighPagePriority
Definition: imports.h:57
#define KernelMode
Definition: asm.h:34
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1765
LONG MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo, OUT PBOOLEAN HaveBadAddress, OUT PULONG_PTR BadAddress)
Definition: virtual.c:749
#define MI_MAPPED_COPY_PAGES
Definition: virtual.c:18
#define STATUS_PARTIAL_COPY
Definition: ntstatus.h:193
VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState)
Definition: procobj.c:704
VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
Definition: procobj.c:756
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:158
static void Exit(void)
Definition: sock.c:1330
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
PVOID PMDL
Definition: usb.h:39
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER _Outptr_ PVOID * TargetAddress
Definition: iotypes.h:1037
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS SourceAddress
Definition: iotypes.h:1127
@ IoReadAccess
Definition: ketypes.h:863
KAPC_STATE
Definition: ketypes.h:1409
#define MmInitializeMdl(_MemoryDescriptorList, _BaseVa, _Length)
MDL
Definition: mmtypes.h:117
@ MmCached
Definition: mmtypes.h:130
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
char CHAR
Definition: xmlstorage.h:175

Referenced by MmCopyVirtualMemory().

◆ MiDoPoolCopy()

NTSTATUS NTAPI MiDoPoolCopy ( IN PEPROCESS  SourceProcess,
IN PVOID  SourceAddress,
IN PEPROCESS  TargetProcess,
OUT PVOID  TargetAddress,
IN SIZE_T  BufferSize,
IN KPROCESSOR_MODE  PreviousMode,
OUT PSIZE_T  ReturnSize 
)

Definition at line 1019 of file virtual.c.

1026{
1027 UCHAR StackBuffer[MI_POOL_COPY_BYTES];
1028 SIZE_T TotalSize, CurrentSize, RemainingSize;
1029 volatile BOOLEAN FailedInProbe = FALSE, HavePoolAddress = FALSE;
1030 PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
1031 PVOID PoolAddress;
1033 BOOLEAN HaveBadAddress;
1034 ULONG_PTR BadAddress;
1036 PAGED_CODE();
1037
1038 DPRINT("Copying %Iu bytes from process %p (address %p) to process %p (Address %p)\n",
1039 BufferSize, SourceProcess, SourceAddress, TargetProcess, TargetAddress);
1040
1041 //
1042 // Calculate the maximum amount of data to move
1043 //
1044 TotalSize = MI_MAX_TRANSFER_SIZE;
1045 if (BufferSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
1046 CurrentSize = TotalSize;
1047 RemainingSize = BufferSize;
1048
1049 //
1050 // Check if we can use the stack
1051 //
1053 {
1054 //
1055 // Use it
1056 //
1057 PoolAddress = (PVOID)StackBuffer;
1058 }
1059 else
1060 {
1061 //
1062 // Allocate pool
1063 //
1064 PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, 'VmRw');
1065 if (!PoolAddress) ASSERT(FALSE);
1066 HavePoolAddress = TRUE;
1067 }
1068
1069 //
1070 // Loop as long as there is still data
1071 //
1072 while (RemainingSize > 0)
1073 {
1074 //
1075 // Check if this transfer will finish everything off
1076 //
1077 if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
1078
1079 //
1080 // Attach to the source address space
1081 //
1082 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
1083
1084 /* Check that state is sane */
1085 ASSERT(FailedInProbe == FALSE);
1087
1088 //
1089 // Protect user-mode copy
1090 //
1091 _SEH2_TRY
1092 {
1093 //
1094 // If this is our first time, probe the buffer
1095 //
1096 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
1097 {
1098 //
1099 // Catch a failure here
1100 //
1101 FailedInProbe = TRUE;
1102
1103 //
1104 // Do the probe
1105 //
1107
1108 //
1109 // Passed
1110 //
1111 FailedInProbe = FALSE;
1112 }
1113
1114 //
1115 // Do the copy
1116 //
1117 RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
1118 }
1120 &HaveBadAddress,
1121 &BadAddress))
1122 {
1123 *ReturnSize = BufferSize - RemainingSize;
1124
1125 //
1126 // Check if we failed during the probe
1127 //
1128 if (FailedInProbe)
1129 {
1130 //
1131 // Exit
1132 //
1134 }
1135 else
1136 {
1137 //
1138 // We failed during the move.
1139 // Check if we know exactly where we stopped copying
1140 //
1141 if (HaveBadAddress)
1142 {
1143 //
1144 // Return the exact number of bytes copied
1145 //
1146 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
1147 }
1148 //
1149 // Return partial copy
1150 //
1152 }
1153 }
1154 _SEH2_END
1155
1156 /* Let go of the source */
1158
1159 if (Status != STATUS_SUCCESS)
1160 {
1161 goto Exit;
1162 }
1163
1164 /* Grab the target process */
1165 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
1166
1167 _SEH2_TRY
1168 {
1169 //
1170 // Check if this is our first time through
1171 //
1172 if ((CurrentTargetAddress == TargetAddress) && (PreviousMode != KernelMode))
1173 {
1174 //
1175 // Catch a failure here
1176 //
1177 FailedInProbe = TRUE;
1178
1179 //
1180 // Do the probe
1181 //
1183
1184 //
1185 // Passed
1186 //
1187 FailedInProbe = FALSE;
1188 }
1189
1190 //
1191 // Now do the actual move
1192 //
1193 RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
1194 }
1196 &HaveBadAddress,
1197 &BadAddress))
1198 {
1199 *ReturnSize = BufferSize - RemainingSize;
1200 //
1201 // Check if we failed during the probe
1202 //
1203 if (FailedInProbe)
1204 {
1205 //
1206 // Exit
1207 //
1209 }
1210 else
1211 {
1212 //
1213 // Otherwise we failed during the move.
1214 // Check if we know exactly where we stopped copying
1215 //
1216 if (HaveBadAddress)
1217 {
1218 //
1219 // Return the exact number of bytes copied
1220 //
1221 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
1222 }
1223 //
1224 // Return partial copy
1225 //
1227 }
1228 }
1229 _SEH2_END;
1230
1231 //
1232 // Detach from target
1233 //
1235
1236 //
1237 // Check for SEH status
1238 //
1239 if (Status != STATUS_SUCCESS)
1240 {
1241 goto Exit;
1242 }
1243
1244 //
1245 // Update location and size
1246 //
1247 RemainingSize -= CurrentSize;
1248 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
1249 CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress +
1250 CurrentSize);
1251 }
1252
1253Exit:
1254 //
1255 // Check if we had allocated pool
1256 //
1257 if (HavePoolAddress)
1258 ExFreePoolWithTag(PoolAddress, 'VmRw');
1259
1260 //
1261 // All bytes read
1262 //
1263 if (Status == STATUS_SUCCESS)
1264 *ReturnSize = BufferSize;
1265 return Status;
1266}
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define NonPagedPool
Definition: env_spec_w32.h:307
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define MI_MAX_TRANSFER_SIZE
Definition: virtual.c:20
#define MI_POOL_COPY_BYTES
Definition: virtual.c:19
unsigned char UCHAR
Definition: xmlstorage.h:181

Referenced by MmCopyVirtualMemory().

◆ MiFlushTbAndCapture()

VOID NTAPI MiFlushTbAndCapture ( IN PMMVAD  FoundVad,
IN PMMPTE  PointerPte,
IN ULONG  ProtectionMask,
IN PMMPFN  Pfn1,
IN BOOLEAN  CaptureDirtyBit 
)

Definition at line 2015 of file section.c.

2020{
2021 MMPTE TempPte, PreviousPte;
2022 KIRQL OldIrql;
2023 BOOLEAN RebuildPte = FALSE;
2024
2025 //
2026 // User for sanity checking later on
2027 //
2028 PreviousPte = *PointerPte;
2029
2030 //
2031 // Build the PTE and acquire the PFN lock
2032 //
2034 PointerPte,
2035 ProtectionMask,
2036 PreviousPte.u.Hard.PageFrameNumber);
2037 OldIrql = MiAcquirePfnLock();
2038
2039 //
2040 // We don't support I/O mappings in this path yet
2041 //
2042 ASSERT(Pfn1 != NULL);
2043 ASSERT(Pfn1->u3.e1.CacheAttribute != MiWriteCombined);
2044
2045 //
2046 // Make sure new protection mask doesn't get in conflict and fix it if it does
2047 //
2048 if (Pfn1->u3.e1.CacheAttribute == MiCached)
2049 {
2050 //
2051 // This is a cached PFN
2052 //
2053 if (ProtectionMask & (MM_NOCACHE | MM_NOACCESS))
2054 {
2055 RebuildPte = TRUE;
2056 ProtectionMask &= ~(MM_NOCACHE | MM_NOACCESS);
2057 }
2058 }
2059 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
2060 {
2061 //
2062 // This is a non-cached PFN
2063 //
2064 if ((ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) != MM_NOCACHE)
2065 {
2066 RebuildPte = TRUE;
2067 ProtectionMask &= ~MM_NOACCESS;
2068 ProtectionMask |= MM_NOCACHE;
2069 }
2070 }
2071
2072 if (RebuildPte)
2073 {
2075 PointerPte,
2076 ProtectionMask,
2077 PreviousPte.u.Hard.PageFrameNumber);
2078 }
2079
2080 //
2081 // Write the new PTE, making sure we are only changing the bits
2082 //
2083 MI_UPDATE_VALID_PTE(PointerPte, TempPte);
2084
2085 //
2086 // Flush the TLB
2087 //
2088 ASSERT(PreviousPte.u.Hard.Valid == 1);
2090 ASSERT(PreviousPte.u.Hard.Valid == 1);
2091
2092 //
2093 // Windows updates the relevant PFN1 information, we currently don't.
2094 //
2095 if (UpdateDirty && PreviousPte.u.Hard.Dirty)
2096 {
2097 if (!Pfn1->u3.e1.Modified)
2098 {
2099 DPRINT1("FIXME: Mark PFN as dirty\n");
2100 }
2101 }
2102
2103 //
2104 // Not supported in ARM3
2105 //
2106 ASSERT(FoundVad->u.VadFlags.VadType != VadWriteWatch);
2107
2108 //
2109 // Release the PFN lock, we are done
2110 //
2111 MiReleasePfnLock(OldIrql);
2112}
#define DPRINT1
Definition: precomp.h:8
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:827
#define MM_NOCACHE
Definition: miarm.h:56
@ MiWriteCombined
Definition: miarm.h:412
@ MiCached
Definition: miarm.h:411
@ MiNonCached
Definition: miarm.h:410
#define MM_NOACCESS
Definition: miarm.h:65
FORCEINLINE VOID MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:977
ULONG64 Dirty
Definition: mmtypes.h:164

Referenced by MiProtectVirtualMemory(), and MiSetProtectionOnSection().

◆ MiGetExceptionInfo()

LONG MiGetExceptionInfo ( IN PEXCEPTION_POINTERS  ExceptionInfo,
OUT PBOOLEAN  HaveBadAddress,
OUT PULONG_PTR  BadAddress 
)

Definition at line 749 of file virtual.c.

752{
753 PEXCEPTION_RECORD ExceptionRecord;
754 PAGED_CODE();
755
756 //
757 // Assume default
758 //
759 *HaveBadAddress = FALSE;
760
761 //
762 // Get the exception record
763 //
764 ExceptionRecord = ExceptionInfo->ExceptionRecord;
765
766 //
767 // Look at the exception code
768 //
769 if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
770 (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
771 (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
772 {
773 //
774 // We can tell the address if we have more than one parameter
775 //
776 if (ExceptionRecord->NumberParameters > 1)
777 {
778 //
779 // Return the address
780 //
781 *HaveBadAddress = TRUE;
782 *BadAddress = ExceptionRecord->ExceptionInformation[1];
783 }
784 }
785
786 //
787 // Continue executing the next handler
788 //
790}
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:243
#define STATUS_GUARD_PAGE_VIOLATION
Definition: ntstatus.h:182
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:210
DWORD ExceptionCode
Definition: compat.h:208
DWORD NumberParameters
Definition: compat.h:212
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]
Definition: compat.h:213

Referenced by MiDoMappedCopy(), and MiDoPoolCopy().

◆ MiGetPageProtection()

ULONG NTAPI MiGetPageProtection ( IN PMMPTE  PointerPte)

Definition at line 1355 of file virtual.c.

1356{
1357 MMPTE TempPte;
1358 PMMPFN Pfn;
1359 PEPROCESS CurrentProcess;
1360 PETHREAD CurrentThread;
1361 BOOLEAN WsSafe, WsShared;
1362 ULONG Protect;
1363 KIRQL OldIrql;
1364 PAGED_CODE();
1365
1366 /* Copy this PTE's contents */
1367 TempPte = *PointerPte;
1368
1369 /* Assure it's not totally zero */
1370 ASSERT(TempPte.u.Long);
1371
1372 /* Check for a special prototype format */
1373 if ((TempPte.u.Soft.Valid == 0) &&
1374 (TempPte.u.Soft.Prototype == 1))
1375 {
1376 /* Check if the prototype PTE is not yet pointing to a PTE */
1377 if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
1378 {
1379 /* The prototype PTE contains the protection */
1380 return MmProtectToValue[TempPte.u.Soft.Protection];
1381 }
1382
1383 /* Get a pointer to the underlying shared PTE */
1384 PointerPte = MiProtoPteToPte(&TempPte);
1385
1386 /* Since the PTE we want to read can be paged out at any time, we need
1387 to release the working set lock first, so that it can be paged in */
1388 CurrentThread = PsGetCurrentThread();
1389 CurrentProcess = PsGetCurrentProcess();
1390 MiUnlockProcessWorkingSetForFault(CurrentProcess,
1391 CurrentThread,
1392 &WsSafe,
1393 &WsShared);
1394
1395 /* Now read the PTE value */
1396 TempPte = *PointerPte;
1397
1398 /* Check if that one is invalid */
1399 if (!TempPte.u.Hard.Valid)
1400 {
1401 /* We get the protection directly from this PTE */
1402 Protect = MmProtectToValue[TempPte.u.Soft.Protection];
1403 }
1404 else
1405 {
1406 /* The PTE is valid, so we might need to get the protection from
1407 the PFN. Lock the PFN database */
1408 OldIrql = MiAcquirePfnLock();
1409
1410 /* Check if the PDE is still valid */
1411 if (MiAddressToPte(PointerPte)->u.Hard.Valid == 0)
1412 {
1413 /* It's not, make it valid */
1415 }
1416
1417 /* Now it's safe to read the PTE value again */
1418 TempPte = *PointerPte;
1419 ASSERT(TempPte.u.Long != 0);
1420
1421 /* Check again if the PTE is invalid */
1422 if (!TempPte.u.Hard.Valid)
1423 {
1424 /* The PTE is not valid, so we can use it's protection field */
1425 Protect = MmProtectToValue[TempPte.u.Soft.Protection];
1426 }
1427 else
1428 {
1429 /* The PTE is valid, so we can find the protection in the
1430 OriginalPte field of the PFN */
1433 }
1434
1435 /* Release the PFN database */
1436 MiReleasePfnLock(OldIrql);
1437 }
1438
1439 /* Lock the working set again */
1440 MiLockProcessWorkingSetForFault(CurrentProcess,
1441 CurrentThread,
1442 WsSafe,
1443 WsShared);
1444
1445 return Protect;
1446 }
1447
1448 /* In the easy case of transition or demand zero PTE just return its protection */
1449 if (!TempPte.u.Hard.Valid) return MmProtectToValue[TempPte.u.Soft.Protection];
1450
1451 /* If we get here, the PTE is valid, so look up the page in PFN database */
1453 if (!Pfn->u3.e1.PrototypePte)
1454 {
1455 /* Return protection of the original pte */
1456 ASSERT(Pfn->u4.AweAllocation == 0);
1458 }
1459
1460 /* This is software PTE */
1461 DPRINT("Prototype PTE: %lx %p\n", TempPte.u.Hard.PageFrameNumber, Pfn);
1462 DPRINT("VA: %p\n", MiPteToAddress(&TempPte));
1463 DPRINT("Mask: %lx\n", TempPte.u.Soft.Protection);
1464 DPRINT("Mask2: %lx\n", Pfn->OriginalPte.u.Soft.Protection);
1465 return MmProtectToValue[TempPte.u.Soft.Protection];
1466}
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
FORCEINLINE VOID MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, OUT PBOOLEAN Safe, OUT PBOOLEAN Shared)
Definition: miarm.h:1468
FORCEINLINE VOID MiLockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, IN BOOLEAN Safe, IN BOOLEAN Shared)
Definition: miarm.h:1501
FORCEINLINE PMMPFN MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
Definition: miarm.h:1574
#define MiProtoPteToPte(x)
Definition: mm.h:316
ULONG NTAPI MiMakeSystemAddressValidPfn(IN PVOID VirtualAddress, IN KIRQL OldIrql)
Definition: virtual.c:235
const ULONG MmProtectToValue[32]
Definition: page.c:71
ULONG PageFrameNumber
Definition: mmtypes.h:109
MMPTE OriginalPte
Definition: mm.h:407
ULONG_PTR AweAllocation
Definition: mm.h:421
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T _In_ SECTION_INHERIT _In_ ULONG _In_ ULONG Protect
Definition: zwfuncs.h:221

Referenced by MiProtectVirtualMemory(), MiQueryAddressState(), MiSetProtectionOnSection(), and NtAllocateVirtualMemory().

◆ MiIsEntireRangeCommitted()

BOOLEAN NTAPI MiIsEntireRangeCommitted ( IN ULONG_PTR  StartingAddress,
IN ULONG_PTR  EndingAddress,
IN PMMVAD  Vad,
IN PEPROCESS  Process 
)

Definition at line 2002 of file virtual.c.

2006{
2007 PMMPTE PointerPte, LastPte;
2008 PMMPDE PointerPde;
2009 BOOLEAN OnPdeBoundary = TRUE;
2010#if _MI_PAGING_LEVELS >= 3
2011 PMMPPE PointerPpe;
2012 BOOLEAN OnPpeBoundary = TRUE;
2013#if _MI_PAGING_LEVELS == 4
2014 PMMPXE PointerPxe;
2015 BOOLEAN OnPxeBoundary = TRUE;
2016#endif
2017#endif
2018
2019 PAGED_CODE();
2020
2021 /* Check that we hols the right locks */
2022 ASSERT(PsGetCurrentThread()->OwnsProcessWorkingSetExclusive || PsGetCurrentThread()->OwnsProcessWorkingSetShared);
2023
2024 /* Get the PTE addresses */
2025 PointerPte = MiAddressToPte(StartingAddress);
2026 LastPte = MiAddressToPte(EndingAddress);
2027
2028 /* Loop all the PTEs */
2029 while (PointerPte <= LastPte)
2030 {
2031#if _MI_PAGING_LEVELS == 4
2032 /* Check for new PXE boundary */
2033 if (OnPxeBoundary)
2034 {
2035 PointerPxe = MiPteToPxe(PointerPte);
2036
2037 /* Check that this loop is sane */
2038 ASSERT(OnPpeBoundary);
2039 ASSERT(OnPdeBoundary);
2040
2041 if (PointerPxe->u.Long != 0)
2042 {
2043 /* Make it valid if needed */
2044 if (PointerPxe->u.Hard.Valid == 0)
2046 }
2047 else
2048 {
2049 /* Is the entire VAD committed? If not, fail */
2050 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2051
2052 PointerPxe++;
2053 PointerPte = MiPxeToPte(PointerPte);
2054 continue;
2055 }
2056 }
2057#endif
2058
2059#if _MI_PAGING_LEVELS >= 3
2060 /* Check for new PPE boundary */
2061 if (OnPpeBoundary)
2062 {
2063 PointerPpe = MiPteToPpe(PointerPte);
2064
2065 /* Check that this loop is sane */
2066 ASSERT(OnPdeBoundary);
2067
2068 if (PointerPpe->u.Long != 0)
2069 {
2070 /* Make it valid if needed */
2071 if (PointerPpe->u.Hard.Valid == 0)
2073 }
2074 else
2075 {
2076 /* Is the entire VAD committed? If not, fail */
2077 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2078
2079 PointerPpe++;
2080 PointerPte = MiPpeToPte(PointerPpe);
2081#if _MI_PAGING_LEVELS == 4
2082 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2083#endif
2084 continue;
2085 }
2086 }
2087#endif
2088 /* Check if we've hit a new PDE boundary */
2089 if (OnPdeBoundary)
2090 {
2091 /* Is this PDE demand zero? */
2092 PointerPde = MiPteToPde(PointerPte);
2093 if (PointerPde->u.Long != 0)
2094 {
2095 /* It isn't -- is it valid? */
2096 if (PointerPde->u.Hard.Valid == 0)
2097 {
2098 /* Nope, fault it in */
2099 MiMakeSystemAddressValid(PointerPte, Process);
2100 }
2101 }
2102 else
2103 {
2104 /* Is the entire VAD committed? If not, fail */
2105 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2106
2107 /* The PTE was already valid, so move to the next one */
2108 PointerPde++;
2109 PointerPte = MiPdeToPte(PointerPde);
2110#if _MI_PAGING_LEVELS >= 3
2111 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
2112#if _MI_PAGING_LEVELS == 4
2113 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2114#endif
2115#endif
2116
2117 /* New loop iteration with our new, on-boundary PTE. */
2118 continue;
2119 }
2120 }
2121
2122 /* Is the PTE demand zero? */
2123 if (PointerPte->u.Long == 0)
2124 {
2125 /* Is the entire VAD committed? If not, fail */
2126 if (!Vad->u.VadFlags.MemCommit) return FALSE;
2127 }
2128 else
2129 {
2130 /* It isn't -- is it a decommited, invalid, or faulted PTE? */
2131 if ((PointerPte->u.Soft.Protection == MM_DECOMMIT) &&
2132 (PointerPte->u.Hard.Valid == 0) &&
2133 ((PointerPte->u.Soft.Prototype == 0) ||
2134 (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
2135 {
2136 /* Then part of the range is decommitted, so fail */
2137 return FALSE;
2138 }
2139 }
2140
2141 /* Move to the next PTE */
2142 PointerPte++;
2143 OnPdeBoundary = MiIsPteOnPdeBoundary(PointerPte);
2144#if _MI_PAGING_LEVELS >= 3
2145 OnPpeBoundary = MiIsPteOnPpeBoundary(PointerPte);
2146#if _MI_PAGING_LEVELS == 4
2147 OnPxeBoundary = MiIsPteOnPxeBoundary(PointerPte);
2148#endif
2149#endif
2150 }
2151
2152 /* All PTEs seem valid, and no VAD checks failed, the range is okay */
2153 return TRUE;
2154}

Referenced by MiProtectVirtualMemory().

◆ MiLockVirtualMemory()

static NTSTATUS MiLockVirtualMemory ( IN OUT PVOID BaseAddress,
IN OUT PSIZE_T  RegionSize,
IN ULONG  MapType 
)
static

Definition at line 3381 of file virtual.c.

3385{
3386 PEPROCESS CurrentProcess;
3388 PVOID CurrentVa, EndAddress;
3389 PMMPTE PointerPte, LastPte;
3390 PMMPDE PointerPde;
3391#if (_MI_PAGING_LEVELS >= 3)
3392 PMMPDE PointerPpe;
3393#endif
3394#if (_MI_PAGING_LEVELS == 4)
3395 PMMPDE PointerPxe;
3396#endif
3397 PMMPFN Pfn1;
3398 NTSTATUS Status, TempStatus;
3399
3400 /* Lock the address space */
3403
3404 /* Make sure we still have an address space */
3405 CurrentProcess = PsGetCurrentProcess();
3406 if (CurrentProcess->VmDeleted)
3407 {
3409 goto Cleanup;
3410 }
3411
3412 /* Check the VADs in the requested range */
3414 if (!NT_SUCCESS(Status))
3415 {
3416 goto Cleanup;
3417 }
3418
3419 /* Enter SEH for probing */
3420 _SEH2_TRY
3421 {
3422 /* Loop all pages and probe them */
3423 CurrentVa = *BaseAddress;
3424 while (CurrentVa < EndAddress)
3425 {
3426 (void)(*(volatile CHAR*)CurrentVa);
3427 CurrentVa = (PUCHAR)CurrentVa + PAGE_SIZE;
3428 }
3429 }
3431 {
3433 goto Cleanup;
3434 }
3435 _SEH2_END;
3436
3437 /* All pages were accessible, since we hold the address space lock, nothing
3438 can be de-committed. Assume success for now. */
3440
3441 /* Get the PTE and PDE */
3442 PointerPte = MiAddressToPte(*BaseAddress);
3443 PointerPde = MiAddressToPde(*BaseAddress);
3444#if (_MI_PAGING_LEVELS >= 3)
3445 PointerPpe = MiAddressToPpe(*BaseAddress);
3446#endif
3447#if (_MI_PAGING_LEVELS == 4)
3448 PointerPxe = MiAddressToPxe(*BaseAddress);
3449#endif
3450
3451 /* Get the last PTE */
3452 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3453
3454 /* Lock the process working set */
3456
3457 /* Loop the pages */
3458 do
3459 {
3460 /* Check for a page that is not accessible */
3461 while (
3462#if (_MI_PAGING_LEVELS == 4)
3463 (PointerPxe->u.Hard.Valid == 0) ||
3464#endif
3465#if (_MI_PAGING_LEVELS >= 3)
3466 (PointerPpe->u.Hard.Valid == 0) ||
3467#endif
3468 (PointerPde->u.Hard.Valid == 0) ||
3469 (PointerPte->u.Hard.Valid == 0))
3470 {
3471 /* Release process working set */
3473
3474 /* Access the page */
3475 CurrentVa = MiPteToAddress(PointerPte);
3476
3477 //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked
3478 TempStatus = MmAccessFault(TRUE, CurrentVa, KernelMode, (PVOID)(ULONG_PTR)0xBADBADA3BADBADA3ULL);
3479 if (!NT_SUCCESS(TempStatus))
3480 {
3481 // This should only happen, when remote backing storage is not accessible
3482 ASSERT(FALSE);
3483 Status = TempStatus;
3484 goto Cleanup;
3485 }
3486
3487 /* Lock the process working set */
3489 }
3490
3491 /* Get the PFN */
3492 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3493 ASSERT(Pfn1 != NULL);
3494
3495 /* Check the previous lock status */
3496 if (MI_IS_LOCKED_VA(Pfn1, MapType))
3497 {
3499 }
3500
3501 /* Lock it */
3502 MI_LOCK_VA(Pfn1, MapType);
3503
3504 /* Go to the next PTE */
3505 PointerPte++;
3506
3507 /* Check if we're on a PDE boundary */
3508 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3509#if (_MI_PAGING_LEVELS >= 3)
3510 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3511#endif
3512#if (_MI_PAGING_LEVELS == 4)
3513 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3514#endif
3515 } while (PointerPte <= LastPte);
3516
3517 /* Release process working set */
3519
3520Cleanup:
3521 /* Unlock address space */
3523
3524 return Status;
3525}
static const WCHAR Cleanup[]
Definition: register.c:80
if(dx< 0)
Definition: linetemp.h:194
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1194
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1124
#define _MI_PAGING_LEVELS
Definition: mm.h:6
FORCEINLINE PMMSUPPORT MmGetCurrentAddressSpace(VOID)
Definition: mm.h:1719
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1691
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1704
NTSTATUS NTAPI MmAccessFault(IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
Definition: mmfault.c:209
FORCEINLINE VOID MI_LOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3294
static NTSTATUS MiCheckVadsForLockOperation(_Inout_ PVOID *BaseAddress, _Inout_ PSIZE_T RegionSize, _Inout_ PVOID *EndAddress)
Definition: virtual.c:3336
FORCEINLINE BOOLEAN MI_IS_LOCKED_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3277
#define STATUS_WAS_LOCKED
Definition: ntstatus.h:139
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
ULONG VmDeleted
Definition: pstypes.h:1398
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2274

Referenced by NtLockVirtualMemory(), and RunTest().

◆ MiMakePdeExistAndMakeValid()

VOID NTAPI MiMakePdeExistAndMakeValid ( IN PMMPDE  PointerPde,
IN PEPROCESS  TargetProcess,
IN KIRQL  OldIrql 
)

Definition at line 2481 of file virtual.c.

2484{
2485 PMMPTE PointerPte;
2486#if _MI_PAGING_LEVELS >= 3
2487 PMMPPE PointerPpe = MiPdeToPpe(PointerPde);
2488#if _MI_PAGING_LEVELS == 4
2489 PMMPXE PointerPxe = MiPdeToPxe(PointerPde);
2490#endif
2491#endif
2492
2493 //
2494 // Sanity checks. The latter is because we only use this function with the
2495 // PFN lock not held, so it may go away in the future.
2496 //
2499
2500 //
2501 // If everything is already valid, there is nothing to do.
2502 //
2503 if (
2504#if _MI_PAGING_LEVELS == 4
2505 (PointerPxe->u.Hard.Valid) &&
2506#endif
2507#if _MI_PAGING_LEVELS >= 3
2508 (PointerPpe->u.Hard.Valid) &&
2509#endif
2510 (PointerPde->u.Hard.Valid))
2511 {
2512 return;
2513 }
2514
2515 //
2516 // At least something is invalid, so begin by getting the PTE for the PDE itself
2517 // and then lookup each additional level. We must do it in this precise order
2518 // because the pagfault.c code (as well as in Windows) depends that the next
2519 // level up (higher) must be valid when faulting a lower level
2520 //
2521 PointerPte = MiPteToAddress(PointerPde);
2522 do
2523 {
2524 //
2525 // Make sure APCs continued to be disabled
2526 //
2528
2529#if _MI_PAGING_LEVELS == 4
2530 //
2531 // First, make the PXE valid if needed
2532 //
2533 if (!PointerPxe->u.Hard.Valid)
2534 {
2535 MiMakeSystemAddressValid(PointerPpe, TargetProcess);
2536 ASSERT(PointerPxe->u.Hard.Valid == 1);
2537 }
2538#endif
2539
2540#if _MI_PAGING_LEVELS >= 3
2541 //
2542 // Next, the PPE
2543 //
2544 if (!PointerPpe->u.Hard.Valid)
2545 {
2546 MiMakeSystemAddressValid(PointerPde, TargetProcess);
2547 ASSERT(PointerPpe->u.Hard.Valid == 1);
2548 }
2549#endif
2550
2551 //
2552 // And finally, make the PDE itself valid.
2553 //
2554 MiMakeSystemAddressValid(PointerPte, TargetProcess);
2555
2556 /* Do not increment Page table refcount here for the PDE, this must be managed by caller */
2557
2558 //
2559 // This should've worked the first time so the loop is really just for
2560 // show -- ASSERT that we're actually NOT going to be looping.
2561 //
2562 ASSERT(PointerPde->u.Hard.Valid == 1);
2563 } while (
2564#if _MI_PAGING_LEVELS == 4
2565 !PointerPxe->u.Hard.Valid ||
2566#endif
2567#if _MI_PAGING_LEVELS >= 3
2568 !PointerPpe->u.Hard.Valid ||
2569#endif
2570 !PointerPde->u.Hard.Valid);
2571}
FORCEINLINE PMMPXE MiPdeToPxe(PMMPDE PointerPde)
Definition: mm.h:300
FORCEINLINE PMMPDE MiPdeToPpe(PMMPDE PointerPde)
Definition: mm.h:292
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985

Referenced by _Success_(), MiDecommitPages(), MiMapLockedPagesInUserSpace(), MiProtectVirtualMemory(), MiSetProtectionOnSection(), MmCreatePageFileMapping(), MmCreateVirtualMappingUnsafeEx(), MmDeletePageFileMapping(), MmGetPageFileMapping(), MmGetPageProtect(), MmGetPfnForProcess(), MmIsDisabledPage(), MmIsPagePresent(), MmIsPageSwapEntry(), MmSetDirtyBit(), MmSetPageProtect(), and NtAllocateVirtualMemory().

◆ MiMakeSystemAddressValid()

ULONG NTAPI MiMakeSystemAddressValid ( IN PVOID  PageTableVirtualAddress,
IN PEPROCESS  CurrentProcess 
)

Definition at line 183 of file virtual.c.

185{
187 BOOLEAN WsShared = FALSE, WsSafe = FALSE, LockChange = FALSE;
188 PETHREAD CurrentThread = PsGetCurrentThread();
189
190 /* Must be a non-pool page table, since those are double-mapped already */
191 ASSERT(PageTableVirtualAddress > MM_HIGHEST_USER_ADDRESS);
192 ASSERT((PageTableVirtualAddress < MmPagedPoolStart) ||
193 (PageTableVirtualAddress > MmPagedPoolEnd));
194
195 /* Working set lock or PFN lock should be held */
197
198 /* Check if the page table is valid */
199 while (!MmIsAddressValid(PageTableVirtualAddress))
200 {
201 /* Release the working set lock */
203 CurrentThread,
204 &WsSafe,
205 &WsShared);
206
207 /* Fault it in */
208 Status = MmAccessFault(FALSE, PageTableVirtualAddress, KernelMode, NULL);
209 if (!NT_SUCCESS(Status))
210 {
211 /* This should not fail */
212 KeBugCheckEx(KERNEL_DATA_INPAGE_ERROR,
213 1,
214 Status,
215 (ULONG_PTR)CurrentProcess,
216 (ULONG_PTR)PageTableVirtualAddress);
217 }
218
219 /* Lock the working set again */
220 MiLockProcessWorkingSetForFault(CurrentProcess,
221 CurrentThread,
222 WsSafe,
223 WsShared);
224
225 /* This flag will be useful later when we do better locking */
226 LockChange = TRUE;
227 }
228
229 /* Let caller know what the lock state is */
230 return LockChange;
231}
#define MM_HIGHEST_USER_ADDRESS
Definition: armddk.h:17
PVOID MmPagedPoolStart
Definition: miarm.h:574
BOOLEAN NTAPI MmIsAddressValid(IN PVOID VirtualAddress)
Definition: mmsup.c:174
PVOID MmPagedPoolEnd
Definition: init.c:26

Referenced by MiCalculatePageCommitment(), MiDeleteVirtualAddresses(), MiIsEntireRangeCommitted(), MiIsPageTablePresent(), MiMakePdeExistAndMakeValid(), and MiQueryAddressState().

◆ MiMakeSystemAddressValidPfn()

ULONG NTAPI MiMakeSystemAddressValidPfn ( IN PVOID  VirtualAddress,
IN KIRQL  OldIrql 
)

Definition at line 235 of file virtual.c.

237{
239 BOOLEAN LockChange = FALSE;
240
241 /* Must be e kernel address */
243
244 /* Check if the page is valid */
246 {
247 /* Release the PFN database */
248 MiReleasePfnLock(OldIrql);
249
250 /* Fault it in */
252 if (!NT_SUCCESS(Status))
253 {
254 /* This should not fail */
255 KeBugCheckEx(KERNEL_DATA_INPAGE_ERROR,
256 3,
257 Status,
258 0,
260 }
261
262 /* This flag will be useful later when we do better locking */
263 LockChange = TRUE;
264
265 /* Lock the PFN database */
266 OldIrql = MiAcquirePfnLock();
267 }
268
269 /* Let caller know what the lock state is */
270 return LockChange;
271}

Referenced by MiGetPageProtection(), and MiSegmentDelete().

◆ MiProcessValidPteList()

VOID NTAPI MiProcessValidPteList ( IN PMMPTE ValidPteList,
IN ULONG  Count 
)

Definition at line 2575 of file virtual.c.

2577{
2578 KIRQL OldIrql;
2579 ULONG i;
2580 MMPTE TempPte;
2581 PFN_NUMBER PageFrameIndex;
2582 PMMPFN Pfn1, Pfn2;
2583
2584 //
2585 // Acquire the PFN lock and loop all the PTEs in the list
2586 //
2587 OldIrql = MiAcquirePfnLock();
2588 for (i = 0; i != Count; i++)
2589 {
2590 //
2591 // The PTE must currently be valid
2592 //
2593 TempPte = *ValidPteList[i];
2594 ASSERT(TempPte.u.Hard.Valid == 1);
2595
2596 //
2597 // Get the PFN entry for the page itself, and then for its page table
2598 //
2599 PageFrameIndex = PFN_FROM_PTE(&TempPte);
2600 Pfn1 = MiGetPfnEntry(PageFrameIndex);
2601 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
2602
2603 //
2604 // Decrement the share count on the page table, and then on the page
2605 // itself
2606 //
2607 MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
2608 MI_SET_PFN_DELETED(Pfn1);
2609 MiDecrementShareCount(Pfn1, PageFrameIndex);
2610
2611 //
2612 // Make the page decommitted
2613 //
2614 MI_WRITE_INVALID_PTE(ValidPteList[i], MmDecommittedPte);
2615 }
2616
2617 //
2618 // All the PTEs have been dereferenced and made invalid, flush the TLB now
2619 // and then release the PFN lock
2620 //
2622 MiReleasePfnLock(OldIrql);
2623}
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
int Count
Definition: noreturn.cpp:7

Referenced by MiDecommitPages().

◆ MiProtectVirtualMemory()

NTSTATUS NTAPI MiProtectVirtualMemory ( IN PEPROCESS  Process,
IN OUT PVOID BaseAddress,
IN OUT PSIZE_T  NumberOfBytesToProtect,
IN ULONG  NewAccessProtection,
OUT PULONG OldAccessProtection  OPTIONAL 
)

Definition at line 2198 of file virtual.c.

2203{
2205 PMMVAD Vad;
2207 ULONG_PTR StartingAddress, EndingAddress;
2208 PMMPTE PointerPte, LastPte;
2209 PMMPDE PointerPde;
2210 MMPTE PteContents;
2211 PMMPFN Pfn1;
2212 ULONG ProtectionMask, OldProtect;
2213 BOOLEAN Committed;
2217
2218 /* We must be attached */
2220
2221 /* Calculate base address for the VAD */
2222 StartingAddress = (ULONG_PTR)PAGE_ALIGN((*BaseAddress));
2223 EndingAddress = (((ULONG_PTR)*BaseAddress + *NumberOfBytesToProtect - 1) | (PAGE_SIZE - 1));
2224
2225 /* Calculate the protection mask and make sure it's valid */
2226 ProtectionMask = MiMakeProtectionMask(NewAccessProtection);
2227 if (ProtectionMask == MM_INVALID_PROTECTION)
2228 {
2229 DPRINT1("Invalid protection mask\n");
2231 }
2232
2233 /* Lock the address space and make sure the process isn't already dead */
2236 if (Process->VmDeleted)
2237 {
2238 DPRINT1("Process is dying\n");
2240 goto FailPath;
2241 }
2242
2243 /* Check for ROS specific memory area */
2246 {
2247 /* Evil hack */
2251 NumberOfBytesToProtect,
2252 NewAccessProtection,
2253 OldAccessProtection);
2254 }
2255
2256 /* Get the VAD for this address range, and make sure it exists */
2257 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
2258 EndingAddress >> PAGE_SHIFT,
2259 &Process->VadRoot,
2260 (PMMADDRESS_NODE*)&Vad);
2261 if (Result != TableFoundNode)
2262 {
2263 DPRINT("Could not find a VAD for this allocation\n");
2265 goto FailPath;
2266 }
2267
2268 /* Make sure the address is within this VAD's boundaries */
2269 if ((((ULONG_PTR)StartingAddress >> PAGE_SHIFT) < Vad->StartingVpn) ||
2270 (((ULONG_PTR)EndingAddress >> PAGE_SHIFT) > Vad->EndingVpn))
2271 {
2273 goto FailPath;
2274 }
2275
2276 /* These kinds of VADs are not supported atm */
2277 if ((Vad->u.VadFlags.VadType == VadAwe) ||
2279 (Vad->u.VadFlags.VadType == VadLargePages))
2280 {
2281 DPRINT1("Illegal VAD for attempting to set protection\n");
2283 goto FailPath;
2284 }
2285
2286 /* Check for a VAD whose protection can't be changed */
2287 if (Vad->u.VadFlags.NoChange == 1)
2288 {
2289 DPRINT1("Trying to change protection of a NoChange VAD\n");
2291 goto FailPath;
2292 }
2293
2294 /* Is this section, or private memory? */
2295 if (Vad->u.VadFlags.PrivateMemory == 0)
2296 {
2297 /* Not yet supported */
2299 {
2300 DPRINT1("Illegal VAD for attempting to set protection\n");
2302 goto FailPath;
2303 }
2304
2305 /* Rotate VADs are not yet supported */
2306 if (Vad->u.VadFlags.VadType == VadRotatePhysical)
2307 {
2308 DPRINT1("Illegal VAD for attempting to set protection\n");
2310 goto FailPath;
2311 }
2312
2313 /* Not valid on section files */
2314 if (NewAccessProtection & (PAGE_NOCACHE | PAGE_WRITECOMBINE))
2315 {
2316 /* Fail */
2317 DPRINT1("Invalid protection flags for section\n");
2319 goto FailPath;
2320 }
2321
2322 /* Check if data or page file mapping protection PTE is compatible */
2323 if (!Vad->ControlArea->u.Flags.Image)
2324 {
2325 /* Not yet */
2326 DPRINT1("Fixme: Not checking for valid protection\n");
2327 }
2328
2329 /* This is a section, and this is not yet supported */
2330 DPRINT1("Section protection not yet supported\n");
2331 OldProtect = 0;
2332 }
2333 else
2334 {
2335 /* Private memory, check protection flags */
2336 if ((NewAccessProtection & PAGE_WRITECOPY) ||
2337 (NewAccessProtection & PAGE_EXECUTE_WRITECOPY))
2338 {
2339 DPRINT1("Invalid protection flags for private memory\n");
2341 goto FailPath;
2342 }
2343
2344 /* Lock the working set */
2346
2347 /* Check if all pages in this range are committed */
2348 Committed = MiIsEntireRangeCommitted(StartingAddress,
2349 EndingAddress,
2350 Vad,
2351 Process);
2352 if (!Committed)
2353 {
2354 /* Fail */
2355 DPRINT1("The entire range is not committed\n");
2358 goto FailPath;
2359 }
2360
2361 /* Compute starting and ending PTE and PDE addresses */
2362 PointerPde = MiAddressToPde(StartingAddress);
2363 PointerPte = MiAddressToPte(StartingAddress);
2364 LastPte = MiAddressToPte(EndingAddress);
2365
2366 /* Make this PDE valid */
2368
2369 /* Save protection of the first page */
2370 if (PointerPte->u.Long != 0)
2371 {
2372 /* Capture the page protection and make the PDE valid */
2373 OldProtect = MiGetPageProtection(PointerPte);
2375 }
2376 else
2377 {
2378 /* Grab the old protection from the VAD itself */
2379 OldProtect = MmProtectToValue[Vad->u.VadFlags.Protection];
2380 }
2381
2382 /* Loop all the PTEs now */
2383 while (PointerPte <= LastPte)
2384 {
2385 /* Check if we've crossed a PDE boundary and make the new PDE valid too */
2386 if (MiIsPteOnPdeBoundary(PointerPte))
2387 {
2388 PointerPde = MiPteToPde(PointerPte);
2390 }
2391
2392 /* Capture the PTE and check if it was empty */
2393 PteContents = *PointerPte;
2394 if (PteContents.u.Long == 0)
2395 {
2396 /* This used to be a zero PTE and it no longer is, so we must add a
2397 reference to the pagetable. */
2399 }
2400
2401 /* Check what kind of PTE we are dealing with */
2402 if (PteContents.u.Hard.Valid == 1)
2403 {
2404 /* Get the PFN entry */
2405 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
2406
2407 /* We don't support this yet */
2408 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
2409
2410 /* Check if the page should not be accessible at all */
2411 if ((NewAccessProtection & PAGE_NOACCESS) ||
2412 (NewAccessProtection & PAGE_GUARD))
2413 {
2414 KIRQL OldIrql = MiAcquirePfnLock();
2415
2416 /* Mark the PTE as transition and change its protection */
2417 PteContents.u.Hard.Valid = 0;
2418 PteContents.u.Soft.Transition = 1;
2419 PteContents.u.Trans.Protection = ProtectionMask;
2420 /* Decrease PFN share count and write the PTE */
2421 MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
2422 // FIXME: remove the page from the WS
2423 MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2424#ifdef CONFIG_SMP
2425 // FIXME: Should invalidate entry in every CPU TLB
2427#endif
2429
2430 /* We are done for this PTE */
2431 MiReleasePfnLock(OldIrql);
2432 }
2433 else
2434 {
2435 /* Write the protection mask and write it with a TLB flush */
2436 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
2438 PointerPte,
2439 ProtectionMask,
2440 Pfn1,
2441 TRUE);
2442 }
2443 }
2444 else
2445 {
2446 /* We don't support these cases yet */
2447 ASSERT(PteContents.u.Soft.Prototype == 0);
2448 //ASSERT(PteContents.u.Soft.Transition == 0);
2449
2450 /* The PTE is already demand-zero, just update the protection mask */
2451 PteContents.u.Soft.Protection = ProtectionMask;
2452 MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2453 ASSERT(PointerPte->u.Long != 0);
2454 }
2455
2456 /* Move to the next PTE */
2457 PointerPte++;
2458 }
2459
2460 /* Unlock the working set */
2462 }
2463
2464 /* Unlock the address space */
2466
2467 /* Return parameters and success */
2468 *NumberOfBytesToProtect = EndingAddress - StartingAddress + 1;
2469 *BaseAddress = (PVOID)StartingAddress;
2470 *OldAccessProtection = OldProtect;
2471 return STATUS_SUCCESS;
2472
2473FailPath:
2474 /* Unlock the address space and return the failure code */
2476 return Status;
2477}
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
#define MM_INVALID_PROTECTION
Definition: miarm.h:67
TABLE_SEARCH_RESULT NTAPI MiCheckForConflictingNode(IN ULONG_PTR StartVpn, IN ULONG_PTR EndVpn, IN PMM_AVL_TABLE Table, OUT PMMADDRESS_NODE *NodeOrParent)
Definition: vadnode.c:150
ULONG NTAPI MiMakeProtectionMask(IN ULONG Protect)
Definition: section.c:140
@ VadAwe
Definition: mmtypes.h:207
@ VadLargePageSection
Definition: mmtypes.h:211
@ VadLargePages
Definition: mmtypes.h:209
@ VadRotatePhysical
Definition: mmtypes.h:210
@ VadDevicePhysicalMemory
Definition: mmtypes.h:205
_In_ PMEMORY_AREA MemoryArea
Definition: newmm.h:207
#define PAGE_WRITECOPY
Definition: nt_native.h:1305
#define PAGE_NOCACHE
Definition: nt_native.h:1311
#define PAGE_EXECUTE_WRITECOPY
Definition: nt_native.h:1309
#define PAGE_NOACCESS
Definition: nt_native.h:1302
#define PAGE_GUARD
Definition: nt_native.h:1310
FORCEINLINE VOID KeInvalidateTlbEntry(IN PVOID Address)
Definition: ke.h:264
PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress(PMMSUPPORT AddressSpace, PVOID Address)
Definition: marea.c:60
#define MEMORY_AREA_OWNED_BY_ARM3
Definition: mm.h:97
ULONG NTAPI MiGetPageProtection(IN PMMPTE PointerPte)
Definition: virtual.c:1355
VOID NTAPI MiFlushTbAndCapture(IN PMMVAD FoundVad, IN PMMPTE PointerPte, IN ULONG ProtectionMask, IN PMMPFN Pfn1, IN BOOLEAN CaptureDirtyBit)
Definition: section.c:2015
BOOLEAN NTAPI MiIsEntireRangeCommitted(IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
Definition: virtual.c:2002
NTSTATUS NTAPI MiRosProtectVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection OPTIONAL)
Definition: virtual.c:2158
#define STATUS_INVALID_PARAMETER_4
Definition: ntstatus.h:478
#define STATUS_CONFLICTING_ADDRESSES
Definition: ntstatus.h:261
#define STATUS_INVALID_PAGE_PROTECTION
Definition: ntstatus.h:305
#define STATUS_NOT_COMMITTED
Definition: ntstatus.h:282
union _CONTROL_AREA::@2604 u
MMSECTION_FLAGS Flags
Definition: mmtypes.h:531
ULONG Type
Definition: mm.h:251
ULONG64 Protection
Definition: mmtypes.h:103
MMPTE_TRANSITION Trans
Definition: mmtypes.h:220
ULONG_PTR NoChange
Definition: mmtypes.h:693
ULONG_PTR Protection
Definition: mmtypes.h:696
ULONG_PTR PrivateMemory
Definition: mmtypes.h:698
PCONTROL_AREA ControlArea
Definition: mmtypes.h:736
ULONG_PTR StartingVpn
Definition: mmtypes.h:729
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
#define PAGE_WRITECOMBINE
Definition: mmtypes.h:78
TABLE_SEARCH_RESULT
Definition: rtltypes.h:373

Referenced by CcPreparePinWrite(), CcpUnpinData(), NtAllocateVirtualMemory(), and NtProtectVirtualMemory().

◆ MiQueryAddressState()

ULONG NTAPI MiQueryAddressState ( IN PVOID  Va,
IN PMMVAD  Vad,
IN PEPROCESS  TargetProcess,
OUT PULONG  ReturnedProtect,
OUT PVOID NextVa 
)

Definition at line 1470 of file virtual.c.

1475{
1476
1477 PMMPTE PointerPte, ProtoPte;
1478 PMMPDE PointerPde;
1479#if (_MI_PAGING_LEVELS >= 3)
1480 PMMPPE PointerPpe;
1481#endif
1482#if (_MI_PAGING_LEVELS >= 4)
1483 PMMPXE PointerPxe;
1484#endif
1485 MMPTE TempPte, TempProtoPte;
1486 BOOLEAN DemandZeroPte = TRUE, ValidPte = FALSE;
1488 ASSERT((Vad->StartingVpn <= ((ULONG_PTR)Va >> PAGE_SHIFT)) &&
1489 (Vad->EndingVpn >= ((ULONG_PTR)Va >> PAGE_SHIFT)));
1490
1491 /* Only normal VADs supported */
1492 ASSERT(Vad->u.VadFlags.VadType == VadNone);
1493
1494 /* Get the PDE and PTE for the address */
1495 PointerPde = MiAddressToPde(Va);
1496 PointerPte = MiAddressToPte(Va);
1497#if (_MI_PAGING_LEVELS >= 3)
1498 PointerPpe = MiAddressToPpe(Va);
1499#endif
1500#if (_MI_PAGING_LEVELS >= 4)
1501 PointerPxe = MiAddressToPxe(Va);
1502#endif
1503
1504 /* Return the next range */
1505 *NextVa = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
1506
1507 do
1508 {
1509#if (_MI_PAGING_LEVELS >= 4)
1510 /* Does the PXE exist? */
1511 if (PointerPxe->u.Long == 0)
1512 {
1513 /* It does not, next range starts at the next PXE */
1514 *NextVa = MiPxeToAddress(PointerPxe + 1);
1515 break;
1516 }
1517
1518 /* Is the PXE valid? */
1519 if (PointerPxe->u.Hard.Valid == 0)
1520 {
1521 /* Is isn't, fault it in (make the PPE accessible) */
1522 MiMakeSystemAddressValid(PointerPpe, TargetProcess);
1523 }
1524#endif
1525#if (_MI_PAGING_LEVELS >= 3)
1526 /* Does the PPE exist? */
1527 if (PointerPpe->u.Long == 0)
1528 {
1529 /* It does not, next range starts at the next PPE */
1530 *NextVa = MiPpeToAddress(PointerPpe + 1);
1531 break;
1532 }
1533
1534 /* Is the PPE valid? */
1535 if (PointerPpe->u.Hard.Valid == 0)
1536 {
1537 /* Is isn't, fault it in (make the PDE accessible) */
1538 MiMakeSystemAddressValid(PointerPde, TargetProcess);
1539 }
1540#endif
1541
1542 /* Does the PDE exist? */
1543 if (PointerPde->u.Long == 0)
1544 {
1545 /* It does not, next range starts at the next PDE */
1546 *NextVa = MiPdeToAddress(PointerPde + 1);
1547 break;
1548 }
1549
1550 /* Is the PDE valid? */
1551 if (PointerPde->u.Hard.Valid == 0)
1552 {
1553 /* Is isn't, fault it in (make the PTE accessible) */
1554 MiMakeSystemAddressValid(PointerPte, TargetProcess);
1555 }
1556
1557 /* We have a PTE that we can access now! */
1558 ValidPte = TRUE;
1559
1560 } while (FALSE);
1561
1562 /* Is it safe to try reading the PTE? */
1563 if (ValidPte)
1564 {
1565 /* FIXME: watch out for large pages */
1566 ASSERT(PointerPde->u.Hard.LargePage == FALSE);
1567
1568 /* Capture the PTE */
1569 TempPte = *PointerPte;
1570 if (TempPte.u.Long != 0)
1571 {
1572 /* The PTE is valid, so it's not zeroed out */
1574
1575 /* Is it a decommited, invalid, or faulted PTE? */
1576 if ((TempPte.u.Soft.Protection == MM_DECOMMIT) &&
1577 (TempPte.u.Hard.Valid == 0) &&
1578 ((TempPte.u.Soft.Prototype == 0) ||
1579 (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
1580 {
1581 /* Otherwise our defaults should hold */
1582 ASSERT(Protect == 0);
1584 }
1585 else
1586 {
1587 /* This means it's committed */
1588 State = MEM_COMMIT;
1589
1590 /* We don't support these */
1591 ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
1592 ASSERT(Vad->u.VadFlags.VadType != VadRotatePhysical);
1593 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
1594
1595 /* Get protection state of this page */
1596 Protect = MiGetPageProtection(PointerPte);
1597
1598 /* Check if this is an image-backed VAD */
1599 if ((TempPte.u.Soft.Valid == 0) &&
1600 (TempPte.u.Soft.Prototype == 1) &&
1601 (Vad->u.VadFlags.PrivateMemory == 0) &&
1602 (Vad->ControlArea))
1603 {
1604 DPRINT1("Not supported\n");
1605 ASSERT(FALSE);
1606 }
1607 }
1608 }
1609 }
1610
1611 /* Check if this was a demand-zero PTE, since we need to find the state */
1612 if (DemandZeroPte)
1613 {
1614 /* Not yet handled */
1615 ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
1616 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
1617
1618 /* Check if this is private commited memory, or an section-backed VAD */
1619 if ((Vad->u.VadFlags.PrivateMemory == 0) && (Vad->ControlArea))
1620 {
1621 /* Tell caller about the next range */
1622 *NextVa = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
1623
1624 /* Get the prototype PTE for this VAD */
1625 ProtoPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(Vad,
1626 (ULONG_PTR)Va >> PAGE_SHIFT);
1627 if (ProtoPte)
1628 {
1629 /* We should unlock the working set, but it's not being held! */
1630
1631 /* Is the prototype PTE actually valid (committed)? */
1632 TempProtoPte = *ProtoPte;
1633 if (TempProtoPte.u.Long)
1634 {
1635 /* Unless this is a memory-mapped file, handle it like private VAD */
1636 State = MEM_COMMIT;
1637 ASSERT(Vad->u.VadFlags.VadType != VadImageMap);
1638 Protect = MmProtectToValue[Vad->u.VadFlags.Protection];
1639 }
1640
1641 /* We should re-lock the working set */
1642 }
1643 }
1644 else if (Vad->u.VadFlags.MemCommit)
1645 {
1646 /* This is committed memory */
1647 State = MEM_COMMIT;
1648
1649 /* Convert the protection */
1650 Protect = MmProtectToValue[Vad->u.VadFlags.Protection];
1651 }
1652 }
1653
1654 /* Return the protection code */
1655 *ReturnedProtect = Protect;
1656 return State;
1657}
#define MEM_RESERVE
Definition: nt_native.h:1314
#define MEM_COMMIT
Definition: nt_native.h:1313
MMPTE DemandZeroPte
Definition: init.c:37
ULONG64 LargePage
Definition: mmtypes.h:165

Referenced by MiQueryMemoryBasicInformation().

◆ MiQueryMemoryBasicInformation()

NTSTATUS NTAPI MiQueryMemoryBasicInformation ( IN HANDLE  ProcessHandle,
IN PVOID  BaseAddress,
OUT PVOID  MemoryInformation,
IN SIZE_T  MemoryInformationLength,
OUT PSIZE_T  ReturnLength 
)

Definition at line 1661 of file virtual.c.

1666{
1667 PEPROCESS TargetProcess;
1669 PMMVAD Vad = NULL;
1670 PVOID Address, NextAddress;
1672 ULONG NewProtect, NewState;
1673 ULONG_PTR BaseVpn;
1674 MEMORY_BASIC_INFORMATION MemoryInfo;
1679
1680 /* Check for illegal addresses in user-space, or the shared memory area */
1683 {
1685
1686 /* Make up an info structure describing this range */
1687 MemoryInfo.BaseAddress = Address;
1688 MemoryInfo.AllocationProtect = PAGE_READONLY;
1689 MemoryInfo.Type = MEM_PRIVATE;
1690
1691 /* Special case for shared data */
1693 {
1695 MemoryInfo.State = MEM_COMMIT;
1696 MemoryInfo.Protect = PAGE_READONLY;
1697 MemoryInfo.RegionSize = PAGE_SIZE;
1698 }
1699 else
1700 {
1702 MemoryInfo.State = MEM_RESERVE;
1703 MemoryInfo.Protect = PAGE_NOACCESS;
1705 }
1706
1707 /* Return the data, NtQueryInformation already probed it*/
1708 if (PreviousMode != KernelMode)
1709 {
1710 _SEH2_TRY
1711 {
1712 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1714 }
1716 {
1718 }
1719 _SEH2_END;
1720 }
1721 else
1722 {
1723 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1725 }
1726
1727 return Status;
1728 }
1729
1730 /* Check if this is for a local or remote process */
1732 {
1733 TargetProcess = PsGetCurrentProcess();
1734 }
1735 else
1736 {
1737 /* Reference the target process */
1742 (PVOID*)&TargetProcess,
1743 NULL);
1744 if (!NT_SUCCESS(Status)) return Status;
1745
1746 /* Attach to it now */
1747 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
1748 }
1749
1750 /* Lock the address space and make sure the process isn't already dead */
1751 MmLockAddressSpace(&TargetProcess->Vm);
1752 if (TargetProcess->VmDeleted)
1753 {
1754 /* Unlock the address space of the process */
1755 MmUnlockAddressSpace(&TargetProcess->Vm);
1756
1757 /* Check if we were attached */
1759 {
1760 /* Detach and dereference the process */
1762 ObDereferenceObject(TargetProcess);
1763 }
1764
1765 /* Bail out */
1766 DPRINT1("Process is dying\n");
1768 }
1769
1770 /* Loop the VADs */
1772 if (TargetProcess->VadRoot.NumberGenericTableElements)
1773 {
1774 /* Scan on the right */
1775 Vad = (PMMVAD)TargetProcess->VadRoot.BalancedRoot.RightChild;
1776 BaseVpn = (ULONG_PTR)BaseAddress >> PAGE_SHIFT;
1777 while (Vad)
1778 {
1779 /* Check if this VAD covers the allocation range */
1780 if ((BaseVpn >= Vad->StartingVpn) &&
1781 (BaseVpn <= Vad->EndingVpn))
1782 {
1783 /* We're done */
1784 Found = TRUE;
1785 break;
1786 }
1787
1788 /* Check if this VAD is too high */
1789 if (BaseVpn < Vad->StartingVpn)
1790 {
1791 /* Stop if there is no left child */
1792 if (!Vad->LeftChild) break;
1793
1794 /* Search on the left next */
1795 Vad = Vad->LeftChild;
1796 }
1797 else
1798 {
1799 /* Then this VAD is too low, keep searching on the right */
1800 ASSERT(BaseVpn > Vad->EndingVpn);
1801
1802 /* Stop if there is no right child */
1803 if (!Vad->RightChild) break;
1804
1805 /* Search on the right next */
1806 Vad = Vad->RightChild;
1807 }
1808 }
1809 }
1810
1811 /* Was a VAD found? */
1812 if (!Found)
1813 {
1815
1816 /* Calculate region size */
1817 if (Vad)
1818 {
1819 if (Vad->StartingVpn >= BaseVpn)
1820 {
1821 /* Region size is the free space till the start of that VAD */
1822 MemoryInfo.RegionSize = (ULONG_PTR)(Vad->StartingVpn << PAGE_SHIFT) - (ULONG_PTR)Address;
1823 }
1824 else
1825 {
1826 /* Get the next VAD */
1828 if (Vad)
1829 {
1830 /* Region size is the free space till the start of that VAD */
1831 MemoryInfo.RegionSize = (ULONG_PTR)(Vad->StartingVpn << PAGE_SHIFT) - (ULONG_PTR)Address;
1832 }
1833 else
1834 {
1835 /* Maximum possible region size with that base address */
1837 }
1838 }
1839 }
1840 else
1841 {
1842 /* Maximum possible region size with that base address */
1844 }
1845
1846 /* Unlock the address space of the process */
1847 MmUnlockAddressSpace(&TargetProcess->Vm);
1848
1849 /* Check if we were attached */
1851 {
1852 /* Detach and dereference the process */
1854 ObDereferenceObject(TargetProcess);
1855 }
1856
1857 /* Build the rest of the initial information block */
1858 MemoryInfo.BaseAddress = Address;
1859 MemoryInfo.AllocationBase = NULL;
1860 MemoryInfo.AllocationProtect = 0;
1861 MemoryInfo.State = MEM_FREE;
1862 MemoryInfo.Protect = PAGE_NOACCESS;
1863 MemoryInfo.Type = 0;
1864
1865 /* Return the data, NtQueryInformation already probed it*/
1866 if (PreviousMode != KernelMode)
1867 {
1868 _SEH2_TRY
1869 {
1870 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1872 }
1874 {
1876 }
1877 _SEH2_END;
1878 }
1879 else
1880 {
1881 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1883 }
1884
1885 return Status;
1886 }
1887
1888 /* Set the correct memory type based on what kind of VAD this is */
1889 if ((Vad->u.VadFlags.PrivateMemory) ||
1891 {
1892 MemoryInfo.Type = MEM_PRIVATE;
1893 }
1894 else if (Vad->u.VadFlags.VadType == VadImageMap)
1895 {
1896 MemoryInfo.Type = MEM_IMAGE;
1897 }
1898 else
1899 {
1900 MemoryInfo.Type = MEM_MAPPED;
1901 }
1902
1903 /* Find the memory area the specified address belongs to */
1906
1907 /* Determine information dependent on the memory area type */
1909 {
1911 if (!NT_SUCCESS(Status))
1912 {
1913 DPRINT1("MmQuerySectionView failed. MemoryArea=%p (%p-%p), BaseAddress=%p\n",
1916 }
1917 }
1918 else
1919 {
1920 /* Build the initial information block */
1922 MemoryInfo.BaseAddress = Address;
1923 MemoryInfo.AllocationBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
1925 MemoryInfo.Type = MEM_PRIVATE;
1926
1927 /* Acquire the working set lock (shared is enough) */
1929
1930 /* Find the largest chunk of memory which has the same state and protection mask */
1931 MemoryInfo.State = MiQueryAddressState(Address,
1932 Vad,
1933 TargetProcess,
1934 &MemoryInfo.Protect,
1935 &NextAddress);
1936 Address = NextAddress;
1937 while (((ULONG_PTR)Address >> PAGE_SHIFT) <= Vad->EndingVpn)
1938 {
1939 /* Keep going unless the state or protection mask changed */
1940 NewState = MiQueryAddressState(Address, Vad, TargetProcess, &NewProtect, &NextAddress);
1941 if ((NewState != MemoryInfo.State) || (NewProtect != MemoryInfo.Protect)) break;
1942 Address = NextAddress;
1943 }
1944
1945 /* Release the working set lock */
1947
1948 /* Check if we went outside of the VAD */
1949 if (((ULONG_PTR)Address >> PAGE_SHIFT) > Vad->EndingVpn)
1950 {
1951 /* Set the end of the VAD as the end address */
1952 Address = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
1953 }
1954
1955 /* Now that we know the last VA address, calculate the region size */
1956 MemoryInfo.RegionSize = ((ULONG_PTR)Address - (ULONG_PTR)MemoryInfo.BaseAddress);
1957 }
1958
1959 /* Unlock the address space of the process */
1960 MmUnlockAddressSpace(&TargetProcess->Vm);
1961
1962 /* Check if we were attached */
1964 {
1965 /* Detach and dereference the process */
1967 ObDereferenceObject(TargetProcess);
1968 }
1969
1970 /* Return the data, NtQueryInformation already probed it */
1971 if (PreviousMode != KernelMode)
1972 {
1973 _SEH2_TRY
1974 {
1975 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1977 }
1979 {
1981 }
1982 _SEH2_END;
1983 }
1984 else
1985 {
1986 *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1988 }
1989
1990 /* All went well */
1991 DPRINT("Base: %p AllocBase: %p AllocProtect: %lx Protect: %lx "
1992 "State: %lx Type: %lx Size: %lx\n",
1993 MemoryInfo.BaseAddress, MemoryInfo.AllocationBase,
1994 MemoryInfo.AllocationProtect, MemoryInfo.Protect,
1995 MemoryInfo.State, MemoryInfo.Type, MemoryInfo.RegionSize);
1996
1997 return Status;
1998}
return Found
Definition: dirsup.c:1270
#define PAGE_READONLY
Definition: compat.h:138
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:43
#define ExGetPreviousMode
Definition: ex.h:140
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:166
FORCEINLINE VOID MiLockProcessWorkingSetShared(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1146
FORCEINLINE VOID MiUnlockProcessWorkingSetShared(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1215
PMMADDRESS_NODE NTAPI MiGetNextNode(IN PMMADDRESS_NODE Node)
Definition: vadnode.c:549
#define PCHAR
Definition: match.c:90
#define MM_SHARED_USER_DATA_VA
Definition: mmtypes.h:48
_In_ HANDLE ProcessHandle
Definition: mmfuncs.h:403
struct _MEMORY_BASIC_INFORMATION * PMEMORY_BASIC_INFORMATION
#define MEM_IMAGE
Definition: mmtypes.h:89
struct _MMVAD * PMMVAD
struct _MEMORY_BASIC_INFORMATION MEMORY_BASIC_INFORMATION
#define MEM_FREE
Definition: nt_native.h:1317
#define MEM_PRIVATE
Definition: nt_native.h:1318
#define NtCurrentProcess()
Definition: nt_native.h:1657
#define MEM_MAPPED
Definition: nt_native.h:1319
#define MM_HIGHEST_VAD_ADDRESS
Definition: mm.h:46
NTSTATUS NTAPI MmQuerySectionView(PMEMORY_AREA MemoryArea, PVOID Address, PMEMORY_BASIC_INFORMATION Info, PSIZE_T ResultLength)
Definition: section.c:2099
#define MA_GetEndingAddress(_MemoryArea)
Definition: mm.h:245
#define MA_GetStartingAddress(_MemoryArea)
Definition: mm.h:244
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:93
ULONG NTAPI MiQueryAddressState(IN PVOID Va, IN PMMVAD Vad, IN PEPROCESS TargetProcess, OUT PULONG ReturnedProtect, OUT PVOID *NextVa)
Definition: virtual.c:1470
POBJECT_TYPE PsProcessType
Definition: process.c:20
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
static WCHAR Address[46]
Definition: ping.c:68
MM_AVL_TABLE VadRoot
Definition: pstypes.h:1453
KPROCESS Pcb
Definition: pstypes.h:1262
MMSUPPORT Vm
Definition: pstypes.h:1356
struct _MMADDRESS_NODE * RightChild
Definition: mmtypes.h:652
struct _MMVAD * RightChild
Definition: mmtypes.h:728
struct _MMVAD * LeftChild
Definition: mmtypes.h:727
ULONG_PTR NumberGenericTableElements
Definition: mmtypes.h:668
MMADDRESS_NODE BalancedRoot
Definition: mmtypes.h:662
char * PCHAR
Definition: typedefs.h:51
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3776
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_Must_inspect_result_ _In_ ULONG NewProtect
Definition: mmfuncs.h:682
#define ObDereferenceObject
Definition: obfuncs.h:203

Referenced by NtQueryVirtualMemory().

◆ MiRosProtectVirtualMemory()

NTSTATUS NTAPI MiRosProtectVirtualMemory ( IN PEPROCESS  Process,
IN OUT PVOID BaseAddress,
IN OUT PSIZE_T  NumberOfBytesToProtect,
IN ULONG  NewAccessProtection,
OUT PULONG OldAccessProtection  OPTIONAL 
)

Definition at line 2158 of file virtual.c.

2163{
2166 ULONG OldAccessProtection_;
2168
2169 *NumberOfBytesToProtect = PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - PAGE_ROUND_DOWN(*BaseAddress);
2171
2172 AddressSpace = &Process->Vm;
2176 {
2178 return STATUS_UNSUCCESSFUL;
2179 }
2180
2181 if (OldAccessProtection == NULL) OldAccessProtection = &OldAccessProtection_;
2182
2185 MemoryArea,
2186 *BaseAddress,
2187 *NumberOfBytesToProtect,
2188 NewAccessProtection,
2189 OldAccessProtection);
2190
2192
2193 return Status;
2194}
#define PAGE_ROUND_UP(x)
Definition: mmtypes.h:38
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
NTSTATUS NTAPI MmProtectSectionView(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PVOID BaseAddress, SIZE_T Length, ULONG Protect, PULONG OldProtect)
Definition: section.c:2063
BOOLEAN DeleteInProgress
Definition: mm.h:253
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132

Referenced by MiProtectVirtualMemory().

◆ MiUnlockVirtualMemory()

static NTSTATUS MiUnlockVirtualMemory ( IN OUT PVOID BaseAddress,
IN OUT PSIZE_T  RegionSize,
IN ULONG  MapType 
)
static

Definition at line 3700 of file virtual.c.

3704{
3705 PEPROCESS CurrentProcess;
3707 PVOID EndAddress;
3708 PMMPTE PointerPte, LastPte;
3709 PMMPDE PointerPde;
3710#if (_MI_PAGING_LEVELS >= 3)
3711 PMMPDE PointerPpe;
3712#endif
3713#if (_MI_PAGING_LEVELS == 4)
3714 PMMPDE PointerPxe;
3715#endif
3716 PMMPFN Pfn1;
3718
3719 /* Lock the address space */
3722
3723 /* Make sure we still have an address space */
3724 CurrentProcess = PsGetCurrentProcess();
3725 if (CurrentProcess->VmDeleted)
3726 {
3728 goto Cleanup;
3729 }
3730
3731 /* Check the VADs in the requested range */
3733
3734 /* Note: only bail out, if we hit an area without a VAD. If we hit an
3735 incompatible VAD we continue, like Windows does */
3737 {
3739 goto Cleanup;
3740 }
3741
3742 /* Get the PTE and PDE */
3743 PointerPte = MiAddressToPte(*BaseAddress);
3744 PointerPde = MiAddressToPde(*BaseAddress);
3745#if (_MI_PAGING_LEVELS >= 3)
3746 PointerPpe = MiAddressToPpe(*BaseAddress);
3747#endif
3748#if (_MI_PAGING_LEVELS == 4)
3749 PointerPxe = MiAddressToPxe(*BaseAddress);
3750#endif
3751
3752 /* Get the last PTE */
3753 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3754
3755 /* Lock the process working set */
3757
3758 /* Loop the pages */
3759 do
3760 {
3761 /* Check for a page that is not present */
3762 if (
3763#if (_MI_PAGING_LEVELS == 4)
3764 (PointerPxe->u.Hard.Valid == 0) ||
3765#endif
3766#if (_MI_PAGING_LEVELS >= 3)
3767 (PointerPpe->u.Hard.Valid == 0) ||
3768#endif
3769 (PointerPde->u.Hard.Valid == 0) ||
3770 (PointerPte->u.Hard.Valid == 0))
3771 {
3772 /* Remember it, but keep going */
3774 }
3775 else
3776 {
3777 /* Get the PFN */
3778 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3779 ASSERT(Pfn1 != NULL);
3780
3781 /* Check if all of the requested locks are present */
3782 if (((MapType & MAP_SYSTEM) && !MI_IS_LOCKED_VA(Pfn1, MAP_SYSTEM)) ||
3783 ((MapType & MAP_PROCESS) && !MI_IS_LOCKED_VA(Pfn1, MAP_PROCESS)))
3784 {
3785 /* Remember it, but keep going */
3787
3788 /* Check if no lock is present */
3790 {
3791 DPRINT1("FIXME: Should remove the page from WS\n");
3792 }
3793 }
3794 }
3795
3796 /* Go to the next PTE */
3797 PointerPte++;
3798
3799 /* Check if we're on a PDE boundary */
3800 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3801#if (_MI_PAGING_LEVELS >= 3)
3802 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3803#endif
3804#if (_MI_PAGING_LEVELS == 4)
3805 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3806#endif
3807 } while (PointerPte <= LastPte);
3808
3809 /* Check if we hit a page that was not locked */
3811 {
3812 goto CleanupWithWsLock;
3813 }
3814
3815 /* All pages in the region were locked, so unlock them all */
3816
3817 /* Get the PTE and PDE */
3818 PointerPte = MiAddressToPte(*BaseAddress);
3819 PointerPde = MiAddressToPde(*BaseAddress);
3820#if (_MI_PAGING_LEVELS >= 3)
3821 PointerPpe = MiAddressToPpe(*BaseAddress);
3822#endif
3823#if (_MI_PAGING_LEVELS == 4)
3824 PointerPxe = MiAddressToPxe(*BaseAddress);
3825#endif
3826
3827 /* Loop the pages */
3828 do
3829 {
3830 /* Unlock it */
3831 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3832 MI_UNLOCK_VA(Pfn1, MapType);
3833
3834 /* Go to the next PTE */
3835 PointerPte++;
3836
3837 /* Check if we're on a PDE boundary */
3838 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3839#if (_MI_PAGING_LEVELS >= 3)
3840 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3841#endif
3842#if (_MI_PAGING_LEVELS == 4)
3843 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3844#endif
3845 } while (PointerPte <= LastPte);
3846
3847 /* Everything is done */
3849
3850CleanupWithWsLock:
3851
3852 /* Release process working set */
3854
3855Cleanup:
3856 /* Unlock address space */
3858
3859 return Status;
3860}
FORCEINLINE VOID MI_UNLOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3315
#define STATUS_NOT_LOCKED
Definition: ntstatus.h:279

Referenced by NtUnlockVirtualMemory().

◆ MmCopyVirtualMemory()

NTSTATUS NTAPI MmCopyVirtualMemory ( IN PEPROCESS  SourceProcess,
IN PVOID  SourceAddress,
IN PEPROCESS  TargetProcess,
OUT PVOID  TargetAddress,
IN SIZE_T  BufferSize,
IN KPROCESSOR_MODE  PreviousMode,
OUT PSIZE_T  ReturnSize 
)

Definition at line 1270 of file virtual.c.

1277{
1279 PEPROCESS Process = SourceProcess;
1280
1281 //
1282 // Don't accept zero-sized buffers
1283 //
1284 if (!BufferSize) return STATUS_SUCCESS;
1285
1286 //
1287 // If we are copying from ourselves, lock the target instead
1288 //
1289 if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess;
1290
1291 //
1292 // Acquire rundown protection
1293 //
1294 if (!ExAcquireRundownProtection(&Process->RundownProtect))
1295 {
1296 //
1297 // Fail
1298 //
1300 }
1301
1302 //
1303 // See if we should use the pool copy
1304 //
1306 {
1307 //
1308 // Use MDL-copy
1309 //
1310 Status = MiDoMappedCopy(SourceProcess,
1312 TargetProcess,
1314 BufferSize,
1316 ReturnSize);
1317 }
1318 else
1319 {
1320 //
1321 // Do pool copy
1322 //
1323 Status = MiDoPoolCopy(SourceProcess,
1325 TargetProcess,
1327 BufferSize,
1329 ReturnSize);
1330 }
1331
1332 //
1333 // Release the lock
1334 //
1335 ExReleaseRundownProtection(&Process->RundownProtect);
1336 return Status;
1337}
#define ExReleaseRundownProtection
Definition: ex.h:136
#define ExAcquireRundownProtection
Definition: ex.h:135
NTSTATUS NTAPI MiDoPoolCopy(IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
Definition: virtual.c:1019
NTSTATUS NTAPI MiDoMappedCopy(IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
Definition: virtual.c:794

Referenced by LpcpCopyRequestData(), NtReadVirtualMemory(), and NtWriteVirtualMemory().

◆ MmFlushVirtualMemory()

NTSTATUS NTAPI MmFlushVirtualMemory ( IN PEPROCESS  Process,
IN OUT PVOID BaseAddress,
IN OUT PSIZE_T  RegionSize,
OUT PIO_STATUS_BLOCK  IoStatusBlock 
)

Definition at line 1341 of file virtual.c.

1345{
1346 PAGED_CODE();
1347
1349
1351}
#define UNIMPLEMENTED
Definition: debug.h:115
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239

Referenced by NtFlushVirtualMemory().

◆ MmGetPhysicalAddress()

PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress ( PVOID  Address)

Definition at line 5736 of file virtual.c.

5737{
5739 MMPDE TempPde;
5740 MMPTE TempPte;
5741
5742 /* Check if the PXE/PPE/PDE is valid */
5743 if (
5744#if (_MI_PAGING_LEVELS == 4)
5745 (MiAddressToPxe(Address)->u.Hard.Valid) &&
5746#endif
5747#if (_MI_PAGING_LEVELS >= 3)
5748 (MiAddressToPpe(Address)->u.Hard.Valid) &&
5749#endif
5750 (MiAddressToPde(Address)->u.Hard.Valid))
5751 {
5752 /* Check for large pages */
5754 if (TempPde.u.Hard.LargePage)
5755 {
5756 /* Physical address is base page + large page offset */
5759 return PhysicalAddress;
5760 }
5761
5762 /* Check if the PTE is valid */
5764 if (TempPte.u.Hard.Valid)
5765 {
5766 /* Physical address is base page + page offset */
5769 return PhysicalAddress;
5770 }
5771 }
5772
5774 DPRINT1("MM:MmGetPhysicalAddressFailed base address was %p\n", Address);
5776 return PhysicalAddress;
5777}
HARDWARE_PDE_ARMV6 TempPde
Definition: winldr.c:78
#define KeRosDumpStackFrames(Frames, Count)
Definition: gdidebug.h:11
unsigned __int64 ULONG64
Definition: imports.h:198
#define PTE_PER_PAGE
Definition: mm.h:20
ULONG PageFrameNumber
Definition: mmtypes.h:74
LONGLONG QuadPart
Definition: typedefs.h:114
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS PhysicalAddress
Definition: iotypes.h:1098

◆ MmGetVirtualForPhysical()

PVOID NTAPI MmGetVirtualForPhysical ( IN PHYSICAL_ADDRESS  PhysicalAddress)

Definition at line 2783 of file virtual.c.

2784{
2786 return 0;
2787}

◆ MmSecureVirtualMemory()

PVOID NTAPI MmSecureVirtualMemory ( IN PVOID  Address,
IN SIZE_T  Length,
IN ULONG  Mode 
)

Definition at line 2794 of file virtual.c.

2797{
2798 static ULONG Warn; if (!Warn++) UNIMPLEMENTED;
2799 return Address;
2800}
@ Warn
Definition: video.h:589

Referenced by EngSecureMem(), and EngSecureMemForRead().

◆ MmUnsecureVirtualMemory()

VOID NTAPI MmUnsecureVirtualMemory ( IN PVOID  SecureMem)

Definition at line 2807 of file virtual.c.

2808{
2809 static ULONG Warn; if (!Warn++) UNIMPLEMENTED;
2810}

Referenced by EngUnsecureMem().

◆ NtAllocateVirtualMemory()

NTSTATUS NTAPI NtAllocateVirtualMemory ( IN HANDLE  ProcessHandle,
IN OUT PVOID UBaseAddress,
IN ULONG_PTR  ZeroBits,
IN OUT PSIZE_T  URegionSize,
IN ULONG  AllocationType,
IN ULONG  Protect 
)
Todo:
HACK: pretend success

Definition at line 4492 of file virtual.c.

4498{
4501 PMMVAD Vad = NULL, FoundVad;
4504 PVOID PBaseAddress;
4505 ULONG_PTR PRegionSize, StartingAddress, EndingAddress;
4506 ULONG_PTR HighestAddress = (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
4507 PEPROCESS CurrentProcess = PsGetCurrentProcess();
4509 PETHREAD CurrentThread = PsGetCurrentThread();
4511 ULONG ProtectionMask, QuotaCharge = 0, QuotaFree = 0;
4512 BOOLEAN Attached = FALSE, ChangeProtection = FALSE, QuotaCharged = FALSE;
4513 MMPTE TempPte;
4514 PMMPTE PointerPte, LastPte;
4515 PMMPDE PointerPde;
4517 PAGED_CODE();
4518
4519 /* Check for valid Zero bits */
4521 {
4522 DPRINT1("Too many zero bits\n");
4524 }
4525
4526 /* Check for valid Allocation Types */
4529 {
4530 DPRINT1("Invalid Allocation Type\n");
4532 }
4533
4534 /* Check for at least one of these Allocation Types to be set */
4536 {
4537 DPRINT1("No memory allocation base type\n");
4539 }
4540
4541 /* MEM_RESET is an exclusive flag, make sure that is valid too */
4543 {
4544 DPRINT1("Invalid use of MEM_RESET\n");
4546 }
4547
4548 /* Check if large pages are being used */
4550 {
4551 /* Large page allocations MUST be committed */
4552 if (!(AllocationType & MEM_COMMIT))
4553 {
4554 DPRINT1("Must supply MEM_COMMIT with MEM_LARGE_PAGES\n");
4556 }
4557
4558 /* These flags are not allowed with large page allocations */
4560 {
4561 DPRINT1("Using illegal flags with MEM_LARGE_PAGES\n");
4563 }
4564 }
4565
4566 /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
4568 {
4569 DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
4571 }
4572
4573 /* Check for valid MEM_PHYSICAL usage */
4575 {
4576 /* MEM_PHYSICAL can only be used if MEM_RESERVE is also used */
4577 if (!(AllocationType & MEM_RESERVE))
4578 {
4579 DPRINT1("MEM_PHYSICAL used without MEM_RESERVE\n");
4581 }
4582
4583 /* Only these flags are allowed with MEM_PHYSIAL */
4585 {
4586 DPRINT1("Using illegal flags with MEM_PHYSICAL\n");
4588 }
4589
4590 /* Then make sure PAGE_READWRITE is used */
4591 if (Protect != PAGE_READWRITE)
4592 {
4593 DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
4595 }
4596 }
4597
4598 /* Calculate the protection mask and make sure it's valid */
4599 ProtectionMask = MiMakeProtectionMask(Protect);
4600 if (ProtectionMask == MM_INVALID_PROTECTION)
4601 {
4602 DPRINT1("Invalid protection mask\n");
4604 }
4605
4606 /* Enter SEH */
4607 _SEH2_TRY
4608 {
4609 /* Check for user-mode parameters */
4610 if (PreviousMode != KernelMode)
4611 {
4612 /* Make sure they are writable */
4613 ProbeForWritePointer(UBaseAddress);
4614 ProbeForWriteSize_t(URegionSize);
4615 }
4616
4617 /* Capture their values */
4618 PBaseAddress = *UBaseAddress;
4619 PRegionSize = *URegionSize;
4620 }
4622 {
4623 /* Return the exception code */
4625 }
4626 _SEH2_END;
4627
4628 /* Make sure the allocation isn't past the VAD area */
4629 if (PBaseAddress > MM_HIGHEST_VAD_ADDRESS)
4630 {
4631 DPRINT1("Virtual allocation base above User Space\n");
4633 }
4634
4635 /* Make sure the allocation wouldn't overflow past the VAD area */
4636 if ((((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) - (ULONG_PTR)PBaseAddress) < PRegionSize)
4637 {
4638 DPRINT1("Region size would overflow into kernel-memory\n");
4640 }
4641
4642 /* Make sure there's a size specified */
4643 if (!PRegionSize)
4644 {
4645 DPRINT1("Region size is invalid (zero)\n");
4647 }
4648
4649 //
4650 // If this is for the current process, just use PsGetCurrentProcess
4651 //
4653 {
4654 Process = CurrentProcess;
4655 }
4656 else
4657 {
4658 //
4659 // Otherwise, reference the process with VM rights and attach to it if
4660 // this isn't the current process. We must attach because we'll be touching
4661 // PTEs and PDEs that belong to user-mode memory, and also touching the
4662 // Working Set which is stored in Hyperspace.
4663 //
4668 (PVOID*)&Process,
4669 NULL);
4670 if (!NT_SUCCESS(Status)) return Status;
4671 if (CurrentProcess != Process)
4672 {
4674 Attached = TRUE;
4675 }
4676 }
4677
4678 DPRINT("NtAllocateVirtualMemory: Process 0x%p, Address 0x%p, Zerobits %lu , RegionSize 0x%x, Allocation type 0x%x, Protect 0x%x.\n",
4679 Process, PBaseAddress, ZeroBits, PRegionSize, AllocationType, Protect);
4680
4681 //
4682 // Check for large page allocations and make sure that the required privilege
4683 // is being held, before attempting to handle them.
4684 //
4687 {
4688 /* Fail without it */
4689 DPRINT1("Privilege not held for MEM_LARGE_PAGES\n");
4691 goto FailPathNoLock;
4692 }
4693
4694 //
4695 // Fail on the things we don't yet support
4696 //
4698 {
4699 DPRINT1("MEM_LARGE_PAGES not supported\n");
4701 goto FailPathNoLock;
4702 }
4704 {
4705 DPRINT1("MEM_PHYSICAL not supported\n");
4707 goto FailPathNoLock;
4708 }
4710 {
4711 DPRINT1("MEM_WRITE_WATCH not supported\n");
4713 goto FailPathNoLock;
4714 }
4715
4716 //
4717 // Check if the caller is reserving memory, or committing memory and letting
4718 // us pick the base address
4719 //
4720 if (!(PBaseAddress) || (AllocationType & MEM_RESERVE))
4721 {
4722 //
4723 // Do not allow COPY_ON_WRITE through this API
4724 //
4726 {
4727 DPRINT1("Copy on write not allowed through this path\n");
4729 goto FailPathNoLock;
4730 }
4731
4732 //
4733 // Does the caller have an address in mind, or is this a blind commit?
4734 //
4735 if (!PBaseAddress)
4736 {
4737 //
4738 // This is a blind commit, all we need is the region size
4739 //
4740 PRegionSize = ROUND_TO_PAGES(PRegionSize);
4741 EndingAddress = 0;
4742 StartingAddress = 0;
4743
4744 //
4745 // Check if ZeroBits were specified
4746 //
4747 if (ZeroBits != 0)
4748 {
4749 //
4750 // Calculate the highest address and check if it's valid
4751 //
4752 HighestAddress = MAXULONG_PTR >> ZeroBits;
4753 if (HighestAddress > (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS)
4754 {
4756 goto FailPathNoLock;
4757 }
4758 }
4759 }
4760 else
4761 {
4762 //
4763 // This is a reservation, so compute the starting address on the
4764 // expected 64KB granularity, and see where the ending address will
4765 // fall based on the aligned address and the passed in region size
4766 //
4767 EndingAddress = ((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1);
4768 PRegionSize = EndingAddress + 1 - ROUND_DOWN((ULONG_PTR)PBaseAddress, _64K);
4769 StartingAddress = (ULONG_PTR)PBaseAddress;
4770 }
4771
4772 // Charge quotas for the VAD
4774 if (!NT_SUCCESS(Status))
4775 {
4776 DPRINT1("Quota exceeded.\n");
4777 goto FailPathNoLock;
4778 }
4779
4781
4782 //
4783 // Allocate and initialize the VAD
4784 //
4785 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'SdaV');
4786 if (Vad == NULL)
4787 {
4788 DPRINT1("Failed to allocate a VAD!\n");
4790 goto FailPathNoLock;
4791 }
4792
4793 RtlZeroMemory(Vad, sizeof(MMVAD_LONG));
4795 Vad->u.VadFlags.Protection = ProtectionMask;
4796 Vad->u.VadFlags.PrivateMemory = 1;
4797 Vad->ControlArea = NULL; // For Memory-Area hack
4798
4799 //
4800 // Insert the VAD
4801 //
4802 Status = MiInsertVadEx(Vad,
4803 &StartingAddress,
4804 PRegionSize,
4805 HighestAddress,
4808 if (!NT_SUCCESS(Status))
4809 {
4810 DPRINT1("Failed to insert the VAD!\n");
4811 ExFreePoolWithTag(Vad, 'SdaV');
4812 goto FailPathNoLock;
4813 }
4814
4815 //
4816 // Detach and dereference the target process if
4817 // it was different from the current process
4818 //
4821
4822 //
4823 // Use SEH to write back the base address and the region size. In the case
4824 // of an exception, we do not return back the exception code, as the memory
4825 // *has* been allocated. The caller would now have to call VirtualQuery
4826 // or do some other similar trick to actually find out where its memory
4827 // allocation ended up
4828 //
4829 _SEH2_TRY
4830 {
4831 *URegionSize = PRegionSize;
4832 *UBaseAddress = (PVOID)StartingAddress;
4833 }
4835 {
4836 //
4837 // Ignore exception!
4838 //
4839 }
4840 _SEH2_END;
4841 DPRINT("Reserved %x bytes at %p.\n", PRegionSize, StartingAddress);
4842 return STATUS_SUCCESS;
4843 }
4844
4845 //
4846 // This is a MEM_COMMIT on top of an existing address which must have been
4847 // MEM_RESERVED already. Compute the start and ending base addresses based
4848 // on the user input, and then compute the actual region size once all the
4849 // alignments have been done.
4850 //
4851 EndingAddress = (((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1));
4852 StartingAddress = (ULONG_PTR)PAGE_ALIGN(PBaseAddress);
4853 PRegionSize = EndingAddress - StartingAddress + 1;
4854
4855 //
4856 // Lock the address space and make sure the process isn't already dead
4857 //
4860 if (Process->VmDeleted)
4861 {
4862 DPRINT1("Process is dying\n");
4864 goto FailPath;
4865 }
4866
4867 //
4868 // Get the VAD for this address range, and make sure it exists
4869 //
4870 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
4871 EndingAddress >> PAGE_SHIFT,
4872 &Process->VadRoot,
4873 (PMMADDRESS_NODE*)&FoundVad);
4874 if (Result != TableFoundNode)
4875 {
4876 DPRINT1("Could not find a VAD for this allocation\n");
4878 goto FailPath;
4879 }
4880
4882 {
4884 DPRINT("MEM_RESET not supported\n");
4886 goto FailPath;
4887 }
4888
4889 //
4890 // These kinds of VADs are illegal for this Windows function when trying to
4891 // commit an existing range
4892 //
4893 if ((FoundVad->u.VadFlags.VadType == VadAwe) ||
4894 (FoundVad->u.VadFlags.VadType == VadDevicePhysicalMemory) ||
4895 (FoundVad->u.VadFlags.VadType == VadLargePages))
4896 {
4897 DPRINT1("Illegal VAD for attempting a MEM_COMMIT\n");
4899 goto FailPath;
4900 }
4901
4902 //
4903 // Make sure that this address range actually fits within the VAD for it
4904 //
4905 if (((StartingAddress >> PAGE_SHIFT) < FoundVad->StartingVpn) ||
4906 ((EndingAddress >> PAGE_SHIFT) > FoundVad->EndingVpn))
4907 {
4908 DPRINT1("Address range does not fit into the VAD\n");
4910 goto FailPath;
4911 }
4912
4913 //
4914 // Make sure this is an ARM3 section
4915 //
4919 {
4920 DPRINT1("Illegal commit of non-ARM3 section!\n");
4922 goto FailPath;
4923 }
4924
4925 // Is this a previously reserved section being committed? If so, enter the
4926 // special section path
4927 //
4928 if (FoundVad->u.VadFlags.PrivateMemory == FALSE)
4929 {
4930 //
4931 // You cannot commit large page sections through this API
4932 //
4933 if (FoundVad->u.VadFlags.VadType == VadLargePageSection)
4934 {
4935 DPRINT1("Large page sections cannot be VirtualAlloc'd\n");
4937 goto FailPath;
4938 }
4939
4940 //
4941 // You can only use caching flags on a rotate VAD
4942 //
4944 (FoundVad->u.VadFlags.VadType != VadRotatePhysical))
4945 {
4946 DPRINT1("Cannot use caching flags with anything but rotate VADs\n");
4948 goto FailPath;
4949 }
4950
4951 //
4952 // We should make sure that the section's permissions aren't being
4953 // messed with
4954 //
4955 if (FoundVad->u.VadFlags.NoChange)
4956 {
4957 //
4958 // Make sure it's okay to touch it
4959 // Note: The Windows 2003 kernel has a bug here, passing the
4960 // unaligned base address together with the aligned size,
4961 // potentially covering a region larger than the actual allocation.
4962 // Might be exposed through NtGdiCreateDIBSection w/ section handle
4963 // For now we keep this behavior.
4964 // TODO: analyze possible implications, create test case
4965 //
4966 Status = MiCheckSecuredVad(FoundVad,
4967 PBaseAddress,
4968 PRegionSize,
4969 ProtectionMask);
4970 if (!NT_SUCCESS(Status))
4971 {
4972 DPRINT1("Secured VAD being messed around with\n");
4973 goto FailPath;
4974 }
4975 }
4976
4977 //
4978 // ARM3 does not support file-backed sections, only shared memory
4979 //
4980 ASSERT(FoundVad->ControlArea->FilePointer == NULL);
4981
4982 //
4983 // Rotate VADs cannot be guard pages or inaccessible, nor copy on write
4984 //
4985 if ((FoundVad->u.VadFlags.VadType == VadRotatePhysical) &&
4987 {
4988 DPRINT1("Invalid page protection for rotate VAD\n");
4990 goto FailPath;
4991 }
4992
4993 //
4994 // Compute PTE addresses and the quota charge, then grab the commit lock
4995 //
4996 PointerPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(FoundVad, StartingAddress >> PAGE_SHIFT);
4997 LastPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(FoundVad, EndingAddress >> PAGE_SHIFT);
4998 QuotaCharge = (ULONG)(LastPte - PointerPte + 1);
5000
5001 //
5002 // Get the segment template PTE and start looping each page
5003 //
5004 TempPte = FoundVad->ControlArea->Segment->SegmentPteTemplate;
5005 ASSERT(TempPte.u.Long != 0);
5006 while (PointerPte <= LastPte)
5007 {
5008 //
5009 // For each non-already-committed page, write the invalid template PTE
5010 //
5011 if (PointerPte->u.Long == 0)
5012 {
5013 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
5014 }
5015 else
5016 {
5017 QuotaFree++;
5018 }
5019 PointerPte++;
5020 }
5021
5022 //
5023 // Now do the commit accounting and release the lock
5024 //
5025 ASSERT(QuotaCharge >= QuotaFree);
5026 QuotaCharge -= QuotaFree;
5027 FoundVad->ControlArea->Segment->NumberOfCommittedPages += QuotaCharge;
5029
5030 //
5031 // We are done with committing the section pages
5032 //
5034 goto FailPath;
5035 }
5036
5037 //
5038 // This is a specific ReactOS check because we only use normal VADs
5039 //
5040 ASSERT(FoundVad->u.VadFlags.VadType == VadNone);
5041
5042 //
5043 // While this is an actual Windows check
5044 //
5045 ASSERT(FoundVad->u.VadFlags.VadType != VadRotatePhysical);
5046
5047 //
5048 // Throw out attempts to use copy-on-write through this API path
5049 //
5051 {
5052 DPRINT1("Write copy attempted when not allowed\n");
5054 goto FailPath;
5055 }
5056
5057 //
5058 // Initialize a demand-zero PTE
5059 //
5060 TempPte.u.Long = 0;
5061 TempPte.u.Soft.Protection = ProtectionMask;
5062 ASSERT(TempPte.u.Long != 0);
5063
5064 //
5065 // Get the PTE, PDE and the last PTE for this address range
5066 //
5067 PointerPde = MiAddressToPde(StartingAddress);
5068 PointerPte = MiAddressToPte(StartingAddress);
5069 LastPte = MiAddressToPte(EndingAddress);
5070
5071 //
5072 // Update the commit charge in the VAD as well as in the process, and check
5073 // if this commit charge was now higher than the last recorded peak, in which
5074 // case we also update the peak
5075 //
5076 FoundVad->u.VadFlags.CommitCharge += (1 + LastPte - PointerPte);
5077 Process->CommitCharge += (1 + LastPte - PointerPte);
5078 if (Process->CommitCharge > Process->CommitChargePeak)
5079 {
5080 Process->CommitChargePeak = Process->CommitCharge;
5081 }
5082
5083 //
5084 // Lock the working set while we play with user pages and page tables
5085 //
5086 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5087
5088 //
5089 // Make the current page table valid, and then loop each page within it
5090 //
5092 while (PointerPte <= LastPte)
5093 {
5094 //
5095 // Have we crossed into a new page table?
5096 //
5097 if (MiIsPteOnPdeBoundary(PointerPte))
5098 {
5099 //
5100 // Get the PDE and now make it valid too
5101 //
5102 PointerPde = MiPteToPde(PointerPte);
5104 }
5105
5106 //
5107 // Is this a zero PTE as expected?
5108 //
5109 if (PointerPte->u.Long == 0)
5110 {
5111 //
5112 // First increment the count of pages in the page table for this
5113 // process
5114 //
5116
5117 //
5118 // And now write the invalid demand-zero PTE as requested
5119 //
5120 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
5121 }
5122 else if (PointerPte->u.Long == MmDecommittedPte.u.Long)
5123 {
5124 //
5125 // If the PTE was already decommitted, there is nothing else to do
5126 // but to write the new demand-zero PTE
5127 //
5128 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
5129 }
5130 else if (!(ChangeProtection) && (Protect != MiGetPageProtection(PointerPte)))
5131 {
5132 //
5133 // We don't handle these scenarios yet
5134 //
5135 if (PointerPte->u.Soft.Valid == 0)
5136 {
5137 ASSERT(PointerPte->u.Soft.Prototype == 0);
5138 ASSERT((PointerPte->u.Soft.PageFileHigh == 0) || (PointerPte->u.Soft.Transition == 1));
5139 }
5140
5141 //
5142 // There's a change in protection, remember this for later, but do
5143 // not yet handle it.
5144 //
5145 ChangeProtection = TRUE;
5146 }
5147
5148 //
5149 // Move to the next PTE
5150 //
5151 PointerPte++;
5152 }
5153
5154 //
5155 // Release the working set lock, unlock the address space, and detach from
5156 // the target process if it was not the current process. Also dereference the
5157 // target process if this wasn't the case.
5158 //
5161FailPath:
5163
5164 if (!NT_SUCCESS(Status))
5165 {
5166 if (Vad != NULL)
5167 {
5168 ExFreePoolWithTag(Vad, 'SdaV');
5169 }
5170 }
5171
5172 //
5173 // Check if we need to update the protection
5174 //
5175 if (ChangeProtection)
5176 {
5177 PVOID ProtectBaseAddress = (PVOID)StartingAddress;
5178 SIZE_T ProtectSize = PRegionSize;
5179 ULONG OldProtection;
5180
5181 //
5182 // Change the protection of the region
5183 //
5185 &ProtectBaseAddress,
5186 &ProtectSize,
5187 Protect,
5188 &OldProtection);
5189 }
5190
5191FailPathNoLock:
5194
5195 //
5196 // Only write back results on success
5197 //
5198 if (NT_SUCCESS(Status))
5199 {
5200 //
5201 // Use SEH to write back the base address and the region size. In the case
5202 // of an exception, we strangely do return back the exception code, even
5203 // though the memory *has* been allocated. This mimics Windows behavior and
5204 // there is not much we can do about it.
5205 //
5206 _SEH2_TRY
5207 {
5208 *URegionSize = PRegionSize;
5209 *UBaseAddress = (PVOID)StartingAddress;
5210 }
5212 {
5214 }
5215 _SEH2_END;
5216 }
5217 else if (QuotaCharged)
5218 {
5220 }
5221
5222 return Status;
5223}
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
#define MAXULONG_PTR
Definition: basetsd.h:103
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
VOID FASTCALL KeReleaseGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:75
VOID FASTCALL KeAcquireGuardedMutexUnsafe(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:64
#define PROCESS_VM_OPERATION
Definition: pstypes.h:160
#define _64K
Definition: miarm.h:23
NTSTATUS NTAPI MiInsertVadEx(_Inout_ PMMVAD Vad, _In_ ULONG_PTR *BaseAddress, _In_ SIZE_T ViewSize, _In_ ULONG_PTR HighestAddress, _In_ ULONG_PTR Alignment, _In_ ULONG AllocationType)
Definition: vadnode.c:282
KGUARDED_MUTEX MmSectionCommitMutex
Definition: section.c:108
NTSTATUS NTAPI MiCheckSecuredVad(IN PMMVAD Vad, IN PVOID Base, IN SIZE_T Size, IN ULONG ProtectionMask)
Definition: vadnode.c:903
#define KeGetPreviousMode()
Definition: ketypes.h:1115
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR ZeroBits
Definition: mmfuncs.h:405
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T _In_ SECTION_INHERIT _In_ ULONG AllocationType
Definition: mmfuncs.h:410
#define MEM_PHYSICAL
Definition: mmtypes.h:87
#define MEM_WRITE_WATCH
Definition: mmtypes.h:86
#define MEM_TOP_DOWN
Definition: nt_native.h:1321
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define MEM_RESET
Definition: nt_native.h:1320
#define MEM_LARGE_PAGES
Definition: nt_native.h:1322
#define MI_MAX_ZERO_BITS
Definition: mm.h:83
#define MM_VIRTMEM_GRANULARITY
Definition: mm.h:102
const LUID SeLockMemoryPrivilege
Definition: priv.c:23
NTSTATUS NTAPI MiProtectVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection OPTIONAL)
Definition: virtual.c:2198
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
#define STATUS_ALREADY_COMMITTED
Definition: ntstatus.h:270
#define STATUS_INVALID_PARAMETER_2
Definition: ntstatus.h:476
#define STATUS_INVALID_PARAMETER_6
Definition: ntstatus.h:480
#define STATUS_INVALID_PARAMETER_3
Definition: ntstatus.h:477
#define STATUS_INVALID_PARAMETER_5
Definition: ntstatus.h:479
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
NTSTATUS NTAPI PsChargeProcessNonPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Charges the non paged pool quota of a given process.
Definition: quota.c:811
VOID NTAPI PsReturnProcessNonPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Returns the non paged quota pool that the process was taking up.
Definition: quota.c:938
#define ProbeForWritePointer(Ptr)
Definition: probe.h:42
#define ProbeForWriteSize_t(Ptr)
Definition: probe.h:45
ULONG64 Valid
Definition: mmtypes.h:86
ULONG_PTR MemCommit
Definition: mmtypes.h:695
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
static BOOL Attached
Definition: vidbios.c:3905
_Out_ PBOOLEAN QuotaCharged
Definition: exfuncs.h:1153
#define ROUND_TO_PAGES(Size)

Referenced by Allocate(), AllocateGuarded(), AllocateReadOnly(), BaseCreateStack(), BaseCreateVDMEnvironment(), BasePushProcessParameters(), CheckAdjacentVADs(), CheckAlignment(), CheckSize(), CheckSomeDefaultAddresses(), CopyLoop(), CreateProcessInternalW(), LsapAllocateClientBuffer(), LsapEnumLogonSessions(), LsapGetLogonSessionData(), MakeReadOnly(), MemInitialize(), PsaiMalloc(), RtlCreateEnvironment(), RtlCreateQueryDebugBuffer(), RtlpDebugBufferCommit(), RtlSetEnvironmentVariable(), START_TEST(), Test_ImageSection(), Test_ImageSection2(), Test_NtFreeVirtualMemory(), Test_PageFileSection(), TestFreeNoAccess(), TestReadWrite(), TH32CreateSnapshot(), VDDAllocMem(), VDDDeInstallMemoryHook(), and VirtualAllocEx().

◆ NtFlushInstructionCache()

NTSTATUS NTAPI NtFlushInstructionCache ( _In_ HANDLE  ProcessHandle,
_In_opt_ PVOID  BaseAddress,
_In_ SIZE_T  FlushSize 
)

Definition at line 3044 of file virtual.c.

3047{
3051 PAGED_CODE();
3052
3053 /* Is a base address given? */
3054 if (BaseAddress != NULL)
3055 {
3056 /* If the requested size is 0, there is nothing to do */
3057 if (FlushSize == 0)
3058 {
3059 return STATUS_SUCCESS;
3060 }
3061
3062 /* Is this a user mode call? */
3064 {
3065 /* Make sure the base address is in user space */
3067 {
3068 DPRINT1("Invalid BaseAddress 0x%p\n", BaseAddress);
3070 }
3071 }
3072 }
3073
3074 /* Is another process requested? */
3076 {
3077 /* Reference the process */
3082 (PVOID*)&Process,
3083 NULL);
3084 if (!NT_SUCCESS(Status))
3085 {
3086 DPRINT1("Failed to reference the process %p\n", ProcessHandle);
3087 return Status;
3088 }
3089
3090 /* Attach to the process */
3092 }
3093
3094 /* Forward to Ke */
3095 KeSweepICache(BaseAddress, FlushSize);
3096
3097 /* Check if we attached */
3099 {
3100 /* Detach from the process and dereference it */
3103 }
3104
3105 /* All done, return to caller */
3106 return STATUS_SUCCESS;
3107}
#define PROCESS_VM_WRITE
Definition: pstypes.h:162
FORCEINLINE VOID KeSweepICache(IN PVOID BaseAddress, IN SIZE_T FlushSize)
Definition: ke.h:280

Referenced by FixupDll(), FlushInstructionCache(), and WriteProcessMemory().

◆ NtFlushVirtualMemory()

NTSTATUS NTAPI NtFlushVirtualMemory ( IN HANDLE  ProcessHandle,
IN OUT PVOID BaseAddress,
IN OUT PSIZE_T  NumberOfBytesToFlush,
OUT PIO_STATUS_BLOCK  IoStatusBlock 
)

Definition at line 4035 of file virtual.c.

4039{
4043 PVOID CapturedBaseAddress;
4044 SIZE_T CapturedBytesToFlush;
4045 IO_STATUS_BLOCK LocalStatusBlock;
4046 PAGED_CODE();
4047
4048 //
4049 // Check if we came from user mode
4050 //
4051 if (PreviousMode != KernelMode)
4052 {
4053 //
4054 // Enter SEH for probing
4055 //
4056 _SEH2_TRY
4057 {
4058 //
4059 // Validate all outputs
4060 //
4062 ProbeForWriteSize_t(NumberOfBytesToFlush);
4064
4065 //
4066 // Capture them
4067 //
4068 CapturedBaseAddress = *BaseAddress;
4069 CapturedBytesToFlush = *NumberOfBytesToFlush;
4070 }
4072 {
4073 //
4074 // Get exception code
4075 //
4077 }
4078 _SEH2_END;
4079 }
4080 else
4081 {
4082 //
4083 // Capture directly
4084 //
4085 CapturedBaseAddress = *BaseAddress;
4086 CapturedBytesToFlush = *NumberOfBytesToFlush;
4087 }
4088
4089 //
4090 // Catch illegal base address
4091 //
4092 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
4093
4094 //
4095 // Catch illegal region size
4096 //
4097 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToFlush)
4098 {
4099 //
4100 // Fail
4101 //
4103 }
4104
4105 //
4106 // Get a reference to the process
4107 //
4112 (PVOID*)(&Process),
4113 NULL);
4114 if (!NT_SUCCESS(Status)) return Status;
4115
4116 //
4117 // Do it
4118 //
4120 &CapturedBaseAddress,
4121 &CapturedBytesToFlush,
4122 &LocalStatusBlock);
4123
4124 //
4125 // Release reference
4126 //
4128
4129 //
4130 // Enter SEH to return data
4131 //
4132 _SEH2_TRY
4133 {
4134 //
4135 // Return data to user
4136 //
4137 *BaseAddress = PAGE_ALIGN(CapturedBaseAddress);
4138 *NumberOfBytesToFlush = 0;
4139 *IoStatusBlock = LocalStatusBlock;
4140 }
4142 {
4143 }
4144 _SEH2_END;
4145
4146 //
4147 // Return status
4148 //
4149 return Status;
4150}
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
ULONG MmUserProbeAddress
Definition: init.c:50
NTSTATUS NTAPI MmFlushVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, OUT PIO_STATUS_BLOCK IoStatusBlock)
Definition: virtual.c:1341
#define ProbeForWriteIoStatusBlock(Ptr)
Definition: probe.h:52

Referenced by FlushViewOfFile(), and Test_ImageSection().

◆ NtFreeVirtualMemory()

NTSTATUS NTAPI NtFreeVirtualMemory ( IN HANDLE  ProcessHandle,
IN PVOID UBaseAddress,
IN PSIZE_T  URegionSize,
IN ULONG  FreeType 
)

Definition at line 5230 of file virtual.c.

5234{
5236 SIZE_T PRegionSize;
5237 PVOID PBaseAddress;
5238 LONG_PTR AlreadyDecommitted, CommitReduction = 0;
5239 LONG_PTR FirstCommit;
5240 ULONG_PTR StartingAddress, EndingAddress;
5241 PMMVAD Vad;
5242 PMMVAD NewVad;
5246 PETHREAD CurrentThread = PsGetCurrentThread();
5247 PEPROCESS CurrentProcess = PsGetCurrentProcess();
5251 PAGED_CODE();
5252
5253 //
5254 // Only two flags are supported, exclusively.
5255 //
5257 {
5258 DPRINT1("Invalid FreeType (0x%08lx)\n", FreeType);
5260 }
5261
5262 //
5263 // Enter SEH for probe and capture. On failure, return back to the caller
5264 // with an exception violation.
5265 //
5266 _SEH2_TRY
5267 {
5268 //
5269 // Check for user-mode parameters and make sure that they are writeable
5270 //
5271 if (PreviousMode != KernelMode)
5272 {
5273 ProbeForWritePointer(UBaseAddress);
5274 ProbeForWriteUlong(URegionSize);
5275 }
5276
5277 //
5278 // Capture the current values
5279 //
5280 PBaseAddress = *UBaseAddress;
5281 PRegionSize = *URegionSize;
5282 }
5284 {
5286 }
5287 _SEH2_END;
5288
5289 //
5290 // Make sure the allocation isn't past the user area
5291 //
5292 if (PBaseAddress >= MM_HIGHEST_USER_ADDRESS)
5293 {
5294 DPRINT1("Virtual free base above User Space\n");
5296 }
5297
5298 //
5299 // Make sure the allocation wouldn't overflow past the user area
5300 //
5301 if (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)PBaseAddress) < PRegionSize)
5302 {
5303 DPRINT1("Region size would overflow into kernel-memory\n");
5305 }
5306
5307 //
5308 // If this is for the current process, just use PsGetCurrentProcess
5309 //
5311 {
5312 Process = CurrentProcess;
5313 }
5314 else
5315 {
5316 //
5317 // Otherwise, reference the process with VM rights and attach to it if
5318 // this isn't the current process. We must attach because we'll be touching
5319 // PTEs and PDEs that belong to user-mode memory, and also touching the
5320 // Working Set which is stored in Hyperspace.
5321 //
5326 (PVOID*)&Process,
5327 NULL);
5328 if (!NT_SUCCESS(Status)) return Status;
5329 if (CurrentProcess != Process)
5330 {
5332 Attached = TRUE;
5333 }
5334 }
5335
5336 DPRINT("NtFreeVirtualMemory: Process 0x%p, Address 0x%p, Size 0x%Ix, FreeType 0x%08lx\n",
5337 Process, PBaseAddress, PRegionSize, FreeType);
5338
5339 //
5340 // Lock the address space
5341 //
5344
5345 //
5346 // If the address space is being deleted, fail the de-allocation since it's
5347 // too late to do anything about it
5348 //
5349 if (Process->VmDeleted)
5350 {
5351 DPRINT1("Process is dead\n");
5353 goto FailPath;
5354 }
5355
5356 //
5357 // Compute start and end addresses, and locate the VAD
5358 //
5359 StartingAddress = (ULONG_PTR)PAGE_ALIGN(PBaseAddress);
5360 EndingAddress = ((ULONG_PTR)PBaseAddress + PRegionSize - 1) | (PAGE_SIZE - 1);
5361 Vad = MiLocateAddress((PVOID)StartingAddress);
5362 if (!Vad)
5363 {
5364 DPRINT1("Unable to find VAD for address 0x%p\n", StartingAddress);
5366 goto FailPath;
5367 }
5368
5369 //
5370 // If the range exceeds the VAD's ending VPN, fail this request
5371 //
5372 if (Vad->EndingVpn < (EndingAddress >> PAGE_SHIFT))
5373 {
5374 DPRINT1("Address 0x%p is beyond the VAD\n", EndingAddress);
5376 goto FailPath;
5377 }
5378
5379 //
5380 // Only private memory (except rotate VADs) can be freed through here */
5381 //
5382 if ((!(Vad->u.VadFlags.PrivateMemory) &&
5383 (Vad->u.VadFlags.VadType != VadRotatePhysical)) ||
5385 {
5386 DPRINT("Attempt to free section memory\n");
5388 goto FailPath;
5389 }
5390
5391 //
5392 // ARM3 does not yet handle protected VM
5393 //
5394 ASSERT(Vad->u.VadFlags.NoChange == 0);
5395
5396 //
5397 // Finally, make sure there is a ReactOS Mm MEMORY_AREA for this allocation
5398 // and that is is an ARM3 memory area, and not a section view, as we currently
5399 // don't support freeing those though this interface.
5400 //
5404
5405 //
5406 // Now we can try the operation. First check if this is a RELEASE or a DECOMMIT
5407 //
5408 if (FreeType & MEM_RELEASE)
5409 {
5410 //
5411 // ARM3 only supports this VAD in this path
5412 //
5413 ASSERT(Vad->u.VadFlags.VadType == VadNone);
5414
5415 //
5416 // Is the caller trying to remove the whole VAD, or remove only a portion
5417 // of it? If no region size is specified, then the assumption is that the
5418 // whole VAD is to be destroyed
5419 //
5420 if (!PRegionSize)
5421 {
5422 //
5423 // The caller must specify the base address identically to the range
5424 // that is stored in the VAD.
5425 //
5426 if (((ULONG_PTR)PBaseAddress >> PAGE_SHIFT) != Vad->StartingVpn)
5427 {
5428 DPRINT1("Address 0x%p does not match the VAD\n", PBaseAddress);
5430 goto FailPath;
5431 }
5432
5433 //
5434 // Now compute the actual start/end addresses based on the VAD
5435 //
5436 StartingAddress = Vad->StartingVpn << PAGE_SHIFT;
5437 EndingAddress = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
5438
5439 //
5440 // Finally lock the working set and remove the VAD from the VAD tree
5441 //
5442 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5443 ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
5444 MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
5446 }
5447 else
5448 {
5449 //
5450 // This means the caller wants to release a specific region within
5451 // the range. We have to find out which range this is -- the following
5452 // possibilities exist plus their union (CASE D):
5453 //
5454 // STARTING ADDRESS ENDING ADDRESS
5455 // [<========][========================================][=========>]
5456 // CASE A CASE B CASE C
5457 //
5458 //
5459 // First, check for case A or D
5460 //
5461 if ((StartingAddress >> PAGE_SHIFT) == Vad->StartingVpn)
5462 {
5463 //
5464 // Check for case D
5465 //
5466 if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn)
5467 {
5468 //
5469 // Case D (freeing the entire region)
5470 //
5471 // This is the easiest one to handle -- it is identical to
5472 // the code path above when the caller sets a zero region size
5473 // and the whole VAD is destroyed
5474 //
5475 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5476 ASSERT(Process->VadRoot.NumberGenericTableElements >= 1);
5477 MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot);
5479 }
5480 else
5481 {
5482 //
5483 // Case A (freeing a part at the beginning)
5484 //
5485 // This case is pretty easy too -- we compute a bunch of
5486 // pages to decommit, and then push the VAD's starting address
5487 // a bit further down, then decrement the commit charge
5488 //
5489 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5490 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5491 EndingAddress,
5492 Vad,
5493 Process);
5494 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5495 // For ReactOS: shrink the corresponding memory area
5498 Vad->StartingVpn = (EndingAddress + 1) >> PAGE_SHIFT;
5500
5501 //
5502 // After analyzing the VAD, set it to NULL so that we don't
5503 // free it in the exit path
5504 //
5505 Vad = NULL;
5506 }
5507 }
5508 else
5509 {
5510 //
5511 // This is case B or case C. First check for case C
5512 //
5513 if ((EndingAddress >> PAGE_SHIFT) == Vad->EndingVpn)
5514 {
5515 //
5516 // Case C (freeing a part at the end)
5517 //
5518 // This is pretty easy and similar to case A. We compute the
5519 // amount of pages to decommit, update the VAD's commit charge
5520 // and then change the ending address of the VAD to be a bit
5521 // smaller.
5522 //
5523 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5524 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5525 EndingAddress,
5526 Vad,
5527 Process);
5528 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5529 // For ReactOS: shrink the corresponding memory area
5532 Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT;
5534 }
5535 else
5536 {
5537 //
5538 // Case B (freeing a part in the middle)
5539 //
5540 // This is the hardest one. Because we are removing a chunk
5541 // of memory from the very middle of the VAD, we must actually
5542 // split the VAD into two new VADs and compute the commit
5543 // charges for each of them, and reinsert new charges.
5544 //
5545 NewVad = ExAllocatePoolZero(NonPagedPool, sizeof(MMVAD_LONG), 'SdaV');
5546 if (NewVad == NULL)
5547 {
5548 DPRINT1("Failed to allocate a VAD!\n");
5550 goto FailPath;
5551 }
5552
5553 // Charge quota for the new VAD
5555
5556 if (!NT_SUCCESS(Status))
5557 {
5558 DPRINT1("Ran out of process quota whilst creating new VAD!\n");
5559 ExFreePoolWithTag(NewVad, 'SdaV');
5561 goto FailPath;
5562 }
5563
5564 //
5565 // This new VAD describes the second chunk, so we keep the end
5566 // address of the original and adjust the start to point past
5567 // the released region.
5568 // The commit charge will be calculated below.
5569 //
5570 NewVad->StartingVpn = (EndingAddress + 1) >> PAGE_SHIFT;
5571 NewVad->EndingVpn = Vad->EndingVpn;
5572 NewVad->u.LongFlags = Vad->u.LongFlags;
5573 NewVad->u.VadFlags.CommitCharge = 0;
5574 ASSERT(NewVad->EndingVpn >= NewVad->StartingVpn);
5575
5576 //
5577 // Get the commit charge for the released region
5578 //
5579 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
5580 CommitReduction = MiCalculatePageCommitment(StartingAddress,
5581 EndingAddress,
5582 Vad,
5583 Process);
5584
5585 //
5586 // Adjust the end of the original VAD (first chunk).
5587 // For ReactOS: shrink the corresponding memory area
5588 //
5591 Vad->EndingVpn = (StartingAddress - 1) >> PAGE_SHIFT;
5593
5594 //
5595 // Now the addresses for both VADs are consistent,
5596 // so insert the new one.
5597 // ReactOS: This will take care of creating a second MEMORY_AREA.
5598 //
5599 MiInsertVad(NewVad, &Process->VadRoot);
5600
5601 //
5602 // Calculate the commit charge for the first split.
5603 // The second chunk's size is the original size, minus the
5604 // released region's size, minus this first chunk.
5605 //
5606 FirstCommit = MiCalculatePageCommitment(Vad->StartingVpn << PAGE_SHIFT,
5607 StartingAddress - 1,
5608 Vad,
5609 Process);
5610 NewVad->u.VadFlags.CommitCharge = Vad->u.VadFlags.CommitCharge - CommitReduction - FirstCommit;
5611 Vad->u.VadFlags.CommitCharge = FirstCommit;
5612 }
5613
5614 //
5615 // After analyzing the VAD, set it to NULL so that we don't
5616 // free it in the exit path
5617 //
5618 Vad = NULL;
5619 }
5620 }
5621
5622 //
5623 // Now we have a range of pages to dereference, so call the right API
5624 // to do that and then release the working set, since we're done messing
5625 // around with process pages.
5626 //
5627 MiDeleteVirtualAddresses(StartingAddress, EndingAddress, NULL);
5630
5631FinalPath:
5632 //
5633 // Update the process counters
5634 //
5635 PRegionSize = EndingAddress - StartingAddress + 1;
5636 Process->CommitCharge -= CommitReduction;
5637 if (FreeType & MEM_RELEASE) Process->VirtualSize -= PRegionSize;
5638
5639 //
5640 // Unlock the address space and free the VAD in failure cases. Next,
5641 // detach from the target process so we can write the region size and the
5642 // base address to the correct source process, and dereference the target
5643 // process.
5644 //
5646 if (Vad) ExFreePool(Vad);
5649
5650 //
5651 // Use SEH to safely return the region size and the base address of the
5652 // deallocation. If we get an access violation, don't return a failure code
5653 // as the deallocation *has* happened. The caller will just have to figure
5654 // out another way to find out where it is (such as VirtualQuery).
5655 //
5656 _SEH2_TRY
5657 {
5658 *URegionSize = PRegionSize;
5659 *UBaseAddress = (PVOID)StartingAddress;
5660 }
5662 {
5663 }
5664 _SEH2_END;
5665 return Status;
5666 }
5667
5668 //
5669 // This is the decommit path. You cannot decommit from the following VADs in
5670 // Windows, so fail the vall
5671 //
5672 if ((Vad->u.VadFlags.VadType == VadAwe) ||
5673 (Vad->u.VadFlags.VadType == VadLargePages) ||
5675 {
5676 DPRINT1("Trying to decommit from invalid VAD\n");
5678 goto FailPath;
5679 }
5680
5681 //
5682 // If the caller did not specify a region size, first make sure that this
5683 // region is actually committed. If it is, then compute the ending address
5684 // based on the VAD.
5685 //
5686 if (!PRegionSize)
5687 {
5688 if (((ULONG_PTR)PBaseAddress >> PAGE_SHIFT) != Vad->StartingVpn)
5689 {
5690 DPRINT1("Decomitting non-committed memory\n");
5692 goto FailPath;
5693 }
5694 EndingAddress = (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1);
5695 }
5696
5697 //
5698 // Decommit the PTEs for the range plus the actual backing pages for the
5699 // range, then reduce that amount from the commit charge in the VAD
5700 //
5701 AlreadyDecommitted = MiDecommitPages((PVOID)StartingAddress,
5702 MiAddressToPte(EndingAddress),
5703 Process,
5704 Vad);
5705 CommitReduction = MiAddressToPte(EndingAddress) -
5706 MiAddressToPte(StartingAddress) +
5707 1 -
5708 AlreadyDecommitted;
5709
5710 ASSERT(CommitReduction >= 0);
5711 ASSERT(Vad->u.VadFlags.CommitCharge >= CommitReduction);
5712 Vad->u.VadFlags.CommitCharge -= CommitReduction;
5713
5714 //
5715 // We are done, go to the exit path without freeing the VAD as it remains
5716 // valid since we have not released the allocation.
5717 //
5718 Vad = NULL;
5720 goto FinalPath;
5721
5722 //
5723 // In the failure path, we detach and dereference the target process, and
5724 // return whatever failure code was sent.
5725 //
5726FailPath:
5730 return Status;
5731}
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
VOID NTAPI MiRemoveNode(IN PMMADDRESS_NODE Node, IN PMM_AVL_TABLE Table)
Definition: vadnode.c:440
VOID NTAPI MiInsertVad(_Inout_ PMMVAD Vad, _Inout_ PMM_AVL_TABLE VadRoot)
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
__kernel_entry _Inout_ _Inout_ PSIZE_T _In_ ULONG FreeType
Definition: mmfuncs.h:174
#define MEM_DECOMMIT
Definition: nt_native.h:1315
#define MEM_RELEASE
Definition: nt_native.h:1316
VOID NTAPI MiDeleteVirtualAddresses(IN ULONG_PTR Va, IN ULONG_PTR EndingAddress, IN PMMVAD Vad)
Definition: virtual.c:530
ULONG NTAPI MiCalculatePageCommitment(IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
Definition: virtual.c:42
ULONG NTAPI MiDecommitPages(IN PVOID StartingAddress, IN PMMPTE EndingPte, IN PEPROCESS Process, IN PMMVAD Vad)
Definition: virtual.c:2627
#define STATUS_QUOTA_EXCEEDED
Definition: ntstatus.h:304
#define STATUS_UNABLE_TO_DELETE_SECTION
Definition: ntstatus.h:264
#define STATUS_UNABLE_TO_FREE_VM
Definition: ntstatus.h:263
#define STATUS_MEMORY_NOT_ALLOCATED
Definition: ntstatus.h:396
#define STATUS_FREE_VM_NOT_AT_BASE
Definition: ntstatus.h:395
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
MMVAD VadNode
Definition: mm.h:249
ULONG_PTR CommitCharge
Definition: mmtypes.h:691
ULONG_PTR LongFlags
Definition: mmtypes.h:733

Referenced by Allocate(), AllocateGuarded(), BaseCreateStack(), BaseCreateVDMEnvironment(), BaseDestroyVDMEnvironment(), BaseFreeThreadStack(), CheckAdjacentVADs(), CheckAlignment(), CheckSize(), CheckSomeDefaultAddresses(), CopyLoop(), CreateProcessInternalW(), DeleteFiber(), Free(), FreeGuarded(), FreeReadOnly(), LsapFreeClientBuffer(), MakeReadOnly(), MemCleanup(), PsaiFree(), RtlDestroyEnvironment(), RtlDestroyHandleTable(), RtlDestroyQueryDebugBuffer(), RtlFreeUserThreadStack(), RtlSetEnvironmentVariable(), START_TEST(), Test_NtFreeVirtualMemory(), Test_NtFreeVirtualMemory_Parameters(), Test_PageFileSection(), TestFreeNoAccess(), TestReadWrite(), TH32CreateSnapshot(), TH32FreeAllocatedResources(), VDDFreeMem(), VDDInstallMemoryHook(), and VirtualFreeEx().

◆ NtGetWriteWatch()

NTSTATUS NTAPI NtGetWriteWatch ( IN HANDLE  ProcessHandle,
IN ULONG  Flags,
IN PVOID  BaseAddress,
IN SIZE_T  RegionSize,
IN PVOID UserAddressArray,
OUT PULONG_PTR  EntriesInUserAddressArray,
OUT PULONG  Granularity 
)

Definition at line 4157 of file virtual.c.

4164{
4167 PVOID EndAddress;
4169 ULONG_PTR CapturedEntryCount;
4170 PAGED_CODE();
4171
4172 //
4173 // Check if we came from user mode
4174 //
4175 if (PreviousMode != KernelMode)
4176 {
4177 //
4178 // Enter SEH for probing
4179 //
4180 _SEH2_TRY
4181 {
4182 //
4183 // Catch illegal base address
4184 //
4186
4187 //
4188 // Catch illegal region size
4189 //
4191 {
4192 //
4193 // Fail
4194 //
4196 }
4197
4198 //
4199 // Validate all data
4200 //
4201 ProbeForWriteSize_t(EntriesInUserAddressArray);
4202 ProbeForWriteUlong(Granularity);
4203
4204 //
4205 // Capture them
4206 //
4207 CapturedEntryCount = *EntriesInUserAddressArray;
4208
4209 //
4210 // Must have a count
4211 //
4212 if (CapturedEntryCount == 0) _SEH2_YIELD(return STATUS_INVALID_PARAMETER_5);
4213
4214 //
4215 // Can't be larger than the maximum
4216 //
4217 if (CapturedEntryCount > (MAXULONG_PTR / sizeof(ULONG_PTR)))
4218 {
4219 //
4220 // Fail
4221 //
4223 }
4224
4225 //
4226 // Probe the actual array
4227 //
4228 ProbeForWrite(UserAddressArray,
4229 CapturedEntryCount * sizeof(PVOID),
4230 sizeof(PVOID));
4231 }
4233 {
4234 //
4235 // Get exception code
4236 //
4238 }
4239 _SEH2_END;
4240 }
4241 else
4242 {
4243 //
4244 // Capture directly
4245 //
4246 CapturedEntryCount = *EntriesInUserAddressArray;
4247 ASSERT(CapturedEntryCount != 0);
4248 }
4249
4250 //
4251 // Check if this is a local request
4252 //
4254 {
4255 //
4256 // No need to reference the process
4257 //
4259 }
4260 else
4261 {
4262 //
4263 // Reference the target
4264 //
4269 (PVOID *)&Process,
4270 NULL);
4271 if (!NT_SUCCESS(Status)) return Status;
4272 }
4273
4274 //
4275 // Compute the last address and validate it
4276 //
4277 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
4278 if (BaseAddress > EndAddress)
4279 {
4280 //
4281 // Fail
4282 //
4285 }
4286
4287 //
4288 // Oops :(
4289 //
4291
4292 //
4293 // Dereference if needed
4294 //
4296
4297 //
4298 // Enter SEH to return data
4299 //
4300 _SEH2_TRY
4301 {
4302 //
4303 // Return data to user
4304 //
4305 *EntriesInUserAddressArray = 0;
4306 *Granularity = PAGE_SIZE;
4307 }
4309 {
4310 //
4311 // Get exception code
4312 //
4314 }
4315 _SEH2_END;
4316
4317 //
4318 // Return success
4319 //
4320 return STATUS_SUCCESS;
4321}

Referenced by GetWriteWatch().

◆ NtLockVirtualMemory()

NTSTATUS NTAPI NtLockVirtualMemory ( IN HANDLE  ProcessHandle,
IN OUT PVOID BaseAddress,
IN OUT PSIZE_T  NumberOfBytesToLock,
IN ULONG  MapType 
)

Definition at line 3529 of file virtual.c.

3533{
3535 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3540 PVOID CapturedBaseAddress;
3541 SIZE_T CapturedBytesToLock;
3542 PAGED_CODE();
3543
3544 //
3545 // Validate flags
3546 //
3547 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
3548 {
3549 //
3550 // Invalid set of flags
3551 //
3553 }
3554
3555 //
3556 // At least one flag must be specified
3557 //
3558 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
3559 {
3560 //
3561 // No flag given
3562 //
3564 }
3565
3566 //
3567 // Enter SEH for probing
3568 //
3569 _SEH2_TRY
3570 {
3571 //
3572 // Validate output data
3573 //
3575 ProbeForWriteSize_t(NumberOfBytesToLock);
3576
3577 //
3578 // Capture it
3579 //
3580 CapturedBaseAddress = *BaseAddress;
3581 CapturedBytesToLock = *NumberOfBytesToLock;
3582 }
3584 {
3585 //
3586 // Get exception code
3587 //
3589 }
3590 _SEH2_END;
3591
3592 //
3593 // Catch illegal base address
3594 //
3595 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
3596
3597 //
3598 // Catch illegal region size
3599 //
3600 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToLock)
3601 {
3602 //
3603 // Fail
3604 //
3606 }
3607
3608 //
3609 // 0 is also illegal
3610 //
3611 if (!CapturedBytesToLock) return STATUS_INVALID_PARAMETER;
3612
3613 //
3614 // Get a reference to the process
3615 //
3620 (PVOID*)(&Process),
3621 NULL);
3622 if (!NT_SUCCESS(Status)) return Status;
3623
3624 //
3625 // Check if this is is system-mapped
3626 //
3627 if (MapType & MAP_SYSTEM)
3628 {
3629 //
3630 // Check for required privilege
3631 //
3633 {
3634 //
3635 // Fail: Don't have it
3636 //
3639 }
3640 }
3641
3642 //
3643 // Check if we should attach
3644 //
3645 if (CurrentProcess != Process)
3646 {
3647 //
3648 // Do it
3649 //
3651 Attached = TRUE;
3652 }
3653
3654 //
3655 // Call the internal function
3656 //
3657 Status = MiLockVirtualMemory(&CapturedBaseAddress,
3658 &CapturedBytesToLock,
3659 MapType);
3660
3661 //
3662 // Detach if needed
3663 //
3665
3666 //
3667 // Release reference
3668 //
3670
3671 //
3672 // Enter SEH to return data
3673 //
3674 _SEH2_TRY
3675 {
3676 //
3677 // Return data to user
3678 //
3679 *BaseAddress = CapturedBaseAddress;
3680 *NumberOfBytesToLock = CapturedBytesToLock;
3681 }
3683 {
3684 //
3685 // Get exception code
3686 //
3688 }
3689 _SEH2_END;
3690
3691 //
3692 // Return status
3693 //
3694 return Status;
3695}
static NTSTATUS MiLockVirtualMemory(IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
Definition: virtual.c:3381

Referenced by VirtualLock().

◆ NtProtectVirtualMemory()

NTSTATUS NTAPI NtProtectVirtualMemory ( IN HANDLE  ProcessHandle,
IN OUT PVOID UnsafeBaseAddress,
IN OUT SIZE_T UnsafeNumberOfBytesToProtect,
IN ULONG  NewAccessProtection,
OUT PULONG  UnsafeOldAccessProtection 
)

Definition at line 3111 of file virtual.c.

3116{
3118 ULONG OldAccessProtection;
3119 ULONG Protection;
3120 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3122 SIZE_T NumberOfBytesToProtect = 0;
3127 PAGED_CODE();
3128
3129 //
3130 // Check for valid protection flags
3131 //
3132 Protection = NewAccessProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
3133 if (Protection != PAGE_NOACCESS &&
3134 Protection != PAGE_READONLY &&
3135 Protection != PAGE_READWRITE &&
3136 Protection != PAGE_WRITECOPY &&
3137 Protection != PAGE_EXECUTE &&
3138 Protection != PAGE_EXECUTE_READ &&
3139 Protection != PAGE_EXECUTE_READWRITE &&
3140 Protection != PAGE_EXECUTE_WRITECOPY)
3141 {
3142 //
3143 // Fail
3144 //
3146 }
3147
3148 //
3149 // Check if we came from user mode
3150 //
3151 if (PreviousMode != KernelMode)
3152 {
3153 //
3154 // Enter SEH for probing
3155 //
3156 _SEH2_TRY
3157 {
3158 //
3159 // Validate all outputs
3160 //
3161 ProbeForWritePointer(UnsafeBaseAddress);
3162 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);
3163 ProbeForWriteUlong(UnsafeOldAccessProtection);
3164
3165 //
3166 // Capture them
3167 //
3168 BaseAddress = *UnsafeBaseAddress;
3169 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
3170 }
3172 {
3173 //
3174 // Get exception code
3175 //
3177 }
3178 _SEH2_END;
3179 }
3180 else
3181 {
3182 //
3183 // Capture directly
3184 //
3185 BaseAddress = *UnsafeBaseAddress;
3186 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
3187 }
3188
3189 //
3190 // Catch illegal base address
3191 //
3193
3194 //
3195 // Catch illegal region size
3196 //
3197 if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect)
3198 {
3199 //
3200 // Fail
3201 //
3203 }
3204
3205 //
3206 // 0 is also illegal
3207 //
3208 if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3;
3209
3210 //
3211 // Get a reference to the process
3212 //
3217 (PVOID*)(&Process),
3218 NULL);
3219 if (!NT_SUCCESS(Status)) return Status;
3220
3221 //
3222 // Check if we should attach
3223 //
3224 if (CurrentProcess != Process)
3225 {
3226 //
3227 // Do it
3228 //
3230 Attached = TRUE;
3231 }
3232
3233 //
3234 // Do the actual work
3235 //
3237 &BaseAddress,
3238 &NumberOfBytesToProtect,
3239 NewAccessProtection,
3240 &OldAccessProtection);
3241
3242 //
3243 // Detach if needed
3244 //
3246
3247 //
3248 // Release reference
3249 //
3251
3252 //
3253 // Enter SEH to return data
3254 //
3255 _SEH2_TRY
3256 {
3257 //
3258 // Return data to user
3259 //
3260 *UnsafeOldAccessProtection = OldAccessProtection;
3261 *UnsafeBaseAddress = BaseAddress;
3262 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
3263 }
3265 {
3266 }
3267 _SEH2_END;
3268
3269 //
3270 // Return status
3271 //
3272 return Status;
3273}
#define PAGE_EXECUTE_READ
Definition: nt_native.h:1307
#define PAGE_EXECUTE
Definition: nt_native.h:1306
#define PAGE_EXECUTE_READWRITE
Definition: nt_native.h:1308

Referenced by AVrfpSnapDllImports(), BaseCreateStack(), BasepCheckForReadOnlyResource(), LdrpSnapIAT(), SeiPatchNewImport(), Test_PageFileSection(), TestFreeNoAccess(), TestReadWrite(), VirtualProtectEx(), Write(), and WriteProcessMemory().

◆ NtQueryVirtualMemory()

NTSTATUS NTAPI NtQueryVirtualMemory ( IN HANDLE  ProcessHandle,
IN PVOID  BaseAddress,
IN MEMORY_INFORMATION_CLASS  MemoryInformationClass,
OUT PVOID  MemoryInformation,
IN SIZE_T  MemoryInformationLength,
OUT PSIZE_T  ReturnLength 
)

Definition at line 4409 of file virtual.c.

4415{
4418
4419 DPRINT("Querying class %d about address: %p\n", MemoryInformationClass, BaseAddress);
4420
4421 /* Bail out if the address is invalid */
4423
4424 /* Probe return buffer */
4426 if (PreviousMode != KernelMode)
4427 {
4428 _SEH2_TRY
4429 {
4430 ProbeForWrite(MemoryInformation,
4431 MemoryInformationLength,
4432 sizeof(ULONG_PTR));
4433
4435 }
4437 {
4439 }
4440 _SEH2_END;
4441
4442 if (!NT_SUCCESS(Status))
4443 {
4444 return Status;
4445 }
4446 }
4447
4448 switch(MemoryInformationClass)
4449 {
4451 /* Validate the size information of the class */
4452 if (MemoryInformationLength < sizeof(MEMORY_BASIC_INFORMATION))
4453 {
4454 /* The size is invalid */
4456 }
4459 MemoryInformation,
4460 MemoryInformationLength,
4461 ReturnLength);
4462 break;
4463
4464 case MemorySectionName:
4465 /* Validate the size information of the class */
4466 if (MemoryInformationLength < sizeof(MEMORY_SECTION_NAME))
4467 {
4468 /* The size is invalid */
4470 }
4473 MemoryInformation,
4474 MemoryInformationLength,
4475 ReturnLength);
4476 break;
4479 default:
4480 DPRINT1("Unhandled memory information class %d\n", MemoryInformationClass);
4481 break;
4482 }
4483
4484 return Status;
4485}
NTSTATUS NTAPI MiQueryMemorySectionName(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: section.c:1948
@ MemoryBasicInformation
Definition: mmtypes.h:183
@ MemorySectionName
Definition: mmtypes.h:185
@ MemoryWorkingSetList
Definition: mmtypes.h:184
@ MemoryBasicVlmInformation
Definition: mmtypes.h:186
NTSTATUS NTAPI MiQueryMemoryBasicInformation(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: virtual.c:1661
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133

Referenced by BasepCheckForReadOnlyResource(), CheckAdjacentVADs(), GetMappedFileNameW(), infinite_recursive(), InitFunctionPtrs(), LdrpInit(), QueryWorkingSet(), QueryWorkingSetEx(), RtlCreateEnvironment(), RtlSetEnvironmentVariable(), START_TEST(), and VirtualQueryEx().

◆ NtReadVirtualMemory()

NTSTATUS NTAPI NtReadVirtualMemory ( IN HANDLE  ProcessHandle,
IN PVOID  BaseAddress,
OUT PVOID  Buffer,
IN SIZE_T  NumberOfBytesToRead,
OUT PSIZE_T NumberOfBytesRead  OPTIONAL 
)

Definition at line 2816 of file virtual.c.

2821{
2825 SIZE_T BytesRead = 0;
2826 PAGED_CODE();
2827
2828 //
2829 // Check if we came from user mode
2830 //
2831 if (PreviousMode != KernelMode)
2832 {
2833 //
2834 // Validate the read addresses
2835 //
2836 if ((((ULONG_PTR)BaseAddress + NumberOfBytesToRead) < (ULONG_PTR)BaseAddress) ||
2837 (((ULONG_PTR)Buffer + NumberOfBytesToRead) < (ULONG_PTR)Buffer) ||
2838 (((ULONG_PTR)BaseAddress + NumberOfBytesToRead) > MmUserProbeAddress) ||
2839 (((ULONG_PTR)Buffer + NumberOfBytesToRead) > MmUserProbeAddress))
2840 {
2841 //
2842 // Don't allow to write into kernel space
2843 //
2845 }
2846
2847 //
2848 // Enter SEH for probe
2849 //
2850 _SEH2_TRY
2851 {
2852 //
2853 // Probe the output value
2854 //
2855 if (NumberOfBytesRead) ProbeForWriteSize_t(NumberOfBytesRead);
2856 }
2858 {
2859 //
2860 // Get exception code
2861 //
2863 }
2864 _SEH2_END;
2865 }
2866
2867 //
2868 // Don't do zero-byte transfers
2869 //
2870 if (NumberOfBytesToRead)
2871 {
2872 //
2873 // Reference the process
2874 //
2879 (PVOID*)(&Process),
2880 NULL);
2881 if (NT_SUCCESS(Status))
2882 {
2883 //
2884 // Do the copy
2885 //
2889 Buffer,
2890 NumberOfBytesToRead,
2892 &BytesRead);
2893
2894 //
2895 // Dereference the process
2896 //
2898 }
2899 }
2900
2901 //
2902 // Check if the caller sent this parameter
2903 //
2904 if (NumberOfBytesRead)
2905 {
2906 //
2907 // Enter SEH to guard write
2908 //
2909 _SEH2_TRY
2910 {
2911 //
2912 // Return the number of bytes read
2913 //
2914 *NumberOfBytesRead = BytesRead;
2915 }
2917 {
2918 }
2919 _SEH2_END;
2920 }
2921
2922 //
2923 // Return status
2924 //
2925 return Status;
2926}
Definition: bufpool.h:45
#define PROCESS_VM_READ
Definition: pstypes.h:161
NTSTATUS NTAPI MmCopyVirtualMemory(IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
Definition: virtual.c:1270
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870

Referenced by CON_API(), ConSrvConnect(), CreateProcessInternalW(), FixupDll(), InitFunctionPtrs(), LsapCallAuthenticationPackage(), LsapCopyFromClientBuffer(), LsapCopyLocalGroups(), LsapLogonUser(), PsaEnumerateProcessModules(), ReadProcessMemory(), RtlFreeUserThreadStack(), RtlpQueryRemoteProcessModules(), RtlReadOutOfProcessMemoryStream(), UserpCaptureStringParameters(), and UserpGetClientFileName().

◆ NtResetWriteWatch()

NTSTATUS NTAPI NtResetWriteWatch ( IN HANDLE  ProcessHandle,
IN PVOID  BaseAddress,
IN SIZE_T  RegionSize 
)

Definition at line 4328 of file virtual.c.

4331{
4332 PVOID EndAddress;
4337
4338 //
4339 // Catch illegal base address
4340 //
4342
4343 //
4344 // Catch illegal region size
4345 //
4347 {
4348 //
4349 // Fail
4350 //
4352 }
4353
4354 //
4355 // Check if this is a local request
4356 //
4358 {
4359 //
4360 // No need to reference the process
4361 //
4363 }
4364 else
4365 {
4366 //
4367 // Reference the target
4368 //
4373 (PVOID *)&Process,
4374 NULL);
4375 if (!NT_SUCCESS(Status)) return Status;
4376 }
4377
4378 //
4379 // Compute the last address and validate it
4380 //
4381 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
4382 if (BaseAddress > EndAddress)
4383 {
4384 //
4385 // Fail
4386 //
4389 }
4390
4391 //
4392 // Oops :(
4393 //
4395
4396 //
4397 // Dereference if needed
4398 //
4400
4401 //
4402 // Return success
4403 //
4404 return STATUS_SUCCESS;
4405}
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693

Referenced by ResetWriteWatch().

◆ NtUnlockVirtualMemory()

NTSTATUS NTAPI NtUnlockVirtualMemory ( IN HANDLE  ProcessHandle,
IN OUT PVOID BaseAddress,
IN OUT PSIZE_T  NumberOfBytesToUnlock,
IN ULONG  MapType 
)

Definition at line 3865 of file virtual.c.

3869{
3871 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3876 PVOID CapturedBaseAddress;
3877 SIZE_T CapturedBytesToUnlock;
3878 PAGED_CODE();
3879
3880 //
3881 // Validate flags
3882 //
3883 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
3884 {
3885 //
3886 // Invalid set of flags
3887 //
3889 }
3890
3891 //
3892 // At least one flag must be specified
3893 //
3894 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
3895 {
3896 //
3897 // No flag given
3898 //
3900 }
3901
3902 //
3903 // Enter SEH for probing
3904 //
3905 _SEH2_TRY
3906 {
3907 //
3908 // Validate output data
3909 //
3911 ProbeForWriteSize_t(NumberOfBytesToUnlock);
3912
3913 //
3914 // Capture it
3915 //
3916 CapturedBaseAddress = *BaseAddress;
3917 CapturedBytesToUnlock = *NumberOfBytesToUnlock;
3918 }
3920 {
3921 //
3922 // Get exception code
3923 //
3925 }
3926 _SEH2_END;
3927
3928 //
3929 // Catch illegal base address
3930 //
3931 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
3932
3933 //
3934 // Catch illegal region size
3935 //
3936 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToUnlock)
3937 {
3938 //
3939 // Fail
3940 //
3942 }
3943
3944 //
3945 // 0 is also illegal
3946 //
3947 if (!CapturedBytesToUnlock) return STATUS_INVALID_PARAMETER;
3948
3949 //
3950 // Get a reference to the process
3951 //
3956 (PVOID*)(&Process),
3957 NULL);
3958 if (!NT_SUCCESS(Status)) return Status;
3959
3960 //
3961 // Check if this is is system-mapped
3962 //
3963 if (MapType & MAP_SYSTEM)
3964 {
3965 //
3966 // Check for required privilege
3967 //
3969 {
3970 //
3971 // Fail: Don't have it
3972 //
3975 }
3976 }
3977
3978 //
3979 // Check if we should attach
3980 //
3981 if (CurrentProcess != Process)
3982 {
3983 //
3984 // Do it
3985 //
3987 Attached = TRUE;
3988 }
3989
3990 //
3991 // Call the internal function
3992 //
3993 Status = MiUnlockVirtualMemory(&CapturedBaseAddress,
3994 &CapturedBytesToUnlock,
3995 MapType);
3996
3997 //
3998 // Detach if needed
3999 //
4001
4002 //
4003 // Release reference
4004 //
4006
4007 //
4008 // Enter SEH to return data
4009 //
4010 _SEH2_TRY
4011 {
4012 //
4013 // Return data to user
4014 //
4015 *BaseAddress = CapturedBaseAddress;
4016 *NumberOfBytesToUnlock = CapturedBytesToUnlock;
4017 }
4019 {
4020 //
4021 // Get exception code
4022 //
4024 }
4025 _SEH2_END;
4026
4027 //
4028 // Return status
4029 //
4030 return STATUS_SUCCESS;
4031}
static NTSTATUS MiUnlockVirtualMemory(IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
Definition: virtual.c:3700

Referenced by VirtualUnlock().

◆ NtWriteVirtualMemory()

NTSTATUS NTAPI NtWriteVirtualMemory ( IN HANDLE  ProcessHandle,
IN PVOID  BaseAddress,
IN PVOID  Buffer,
IN SIZE_T  NumberOfBytesToWrite,
OUT PSIZE_T NumberOfBytesWritten  OPTIONAL 
)

Definition at line 2930 of file virtual.c.

2935{
2939 SIZE_T BytesWritten = 0;
2940 PAGED_CODE();
2941
2942 //
2943 // Check if we came from user mode
2944 //
2945 if (PreviousMode != KernelMode)
2946 {
2947 //
2948 // Validate the read addresses
2949 //
2950 if ((((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) < (ULONG_PTR)BaseAddress) ||
2951 (((ULONG_PTR)Buffer + NumberOfBytesToWrite) < (ULONG_PTR)Buffer) ||
2952 (((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) > MmUserProbeAddress) ||
2953 (((ULONG_PTR)Buffer + NumberOfBytesToWrite) > MmUserProbeAddress))
2954 {
2955 //
2956 // Don't allow to write into kernel space
2957 //
2959 }
2960
2961 //
2962 // Enter SEH for probe
2963 //
2964 _SEH2_TRY
2965 {
2966 //
2967 // Probe the output value
2968 //
2969 if (NumberOfBytesWritten) ProbeForWriteSize_t(NumberOfBytesWritten);
2970 }
2972 {
2973 //
2974 // Get exception code
2975 //
2977 }
2978 _SEH2_END;
2979 }
2980
2981 //
2982 // Don't do zero-byte transfers
2983 //
2984 if (NumberOfBytesToWrite)
2985 {
2986 //
2987 // Reference the process
2988 //
2993 (PVOID*)&Process,
2994 NULL);
2995 if (NT_SUCCESS(Status))
2996 {
2997 //
2998 // Do the copy
2999 //
3001 Buffer,
3002 Process,
3004 NumberOfBytesToWrite,
3006 &BytesWritten);
3007
3008 //
3009 // Dereference the process
3010 //
3012 }
3013 }
3014
3015 //
3016 // Check if the caller sent this parameter
3017 //
3018 if (NumberOfBytesWritten)
3019 {
3020 //
3021 // Enter SEH to guard write
3022 //
3023 _SEH2_TRY
3024 {
3025 //
3026 // Return the number of bytes written
3027 //
3028 *NumberOfBytesWritten = BytesWritten;
3029 }
3031 {
3032 }
3033 _SEH2_END;
3034 }
3035
3036 //
3037 // Return status
3038 //
3039 return Status;
3040}
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960

Referenced by BasePushProcessParameters(), LsapCopyToClientBuffer(), LsapEnumLogonSessions(), LsapGetLogonSessionData(), StuffStdHandle(), Write(), and WriteProcessMemory().