ReactOS  0.4.12-dev-75-g00dd17e
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.

Referenced by MiDoMappedCopy().

◆ MI_MAX_TRANSFER_SIZE

#define MI_MAX_TRANSFER_SIZE   64 * 1024

Definition at line 20 of file virtual.c.

Referenced by MiDoPoolCopy().

◆ MI_POOL_COPY_BYTES

#define MI_POOL_COPY_BYTES   512

Definition at line 19 of file virtual.c.

Referenced by MiDoPoolCopy(), and MmCopyVirtualMemory().

◆ 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 3152 of file virtual.c.

Referenced by MiLockVirtualMemory(), and MiUnlockVirtualMemory().

3155 {
3156  // HACK until we have proper WSLIST support
3157  PMMWSLE Wsle = &Pfn1->Wsle;
3158 
3159  if ((LockType & MAP_PROCESS) && (Wsle->u1.e1.LockedInWs))
3160  return TRUE;
3161  if ((LockType & MAP_SYSTEM) && (Wsle->u1.e1.LockedInMemory))
3162  return TRUE;
3163 
3164  return FALSE;
3165 }
#define TRUE
Definition: types.h:120
MMWSLENTRY e1
Definition: mmtypes.h:844
MMWSLE Wsle
Definition: mm.h:364
#define MAP_PROCESS
Definition: mmtypes.h:67
ULONG_PTR LockedInMemory
Definition: mmtypes.h:830
ULONG_PTR LockedInWs
Definition: mmtypes.h:829
#define MAP_SYSTEM
Definition: mmtypes.h:68
union _MMWSLE::@2498 u1

◆ MI_LOCK_VA()

FORCEINLINE VOID MI_LOCK_VA ( PMMPFN  Pfn1,
ULONG  LockType 
)

Definition at line 3169 of file virtual.c.

Referenced by MiLockVirtualMemory().

3172 {
3173  // HACK until we have proper WSLIST support
3174  PMMWSLE Wsle = &Pfn1->Wsle;
3175 
3176  if (!Wsle->u1.e1.LockedInWs &&
3177  !Wsle->u1.e1.LockedInMemory)
3178  {
3180  }
3181 
3182  if (LockType & MAP_PROCESS)
3183  Wsle->u1.e1.LockedInWs = 1;
3184  if (LockType & MAP_SYSTEM)
3185  Wsle->u1.e1.LockedInMemory = 1;
3186 }
MMWSLENTRY e1
Definition: mmtypes.h:844
MMWSLE Wsle
Definition: mm.h:364
#define MAP_PROCESS
Definition: mmtypes.h:67
ULONG_PTR LockedInMemory
Definition: mmtypes.h:830
FORCEINLINE VOID MiReferenceProbedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1506
ULONG_PTR LockedInWs
Definition: mmtypes.h:829
#define MAP_SYSTEM
Definition: mmtypes.h:68
union _MMWSLE::@2498 u1

◆ MI_UNLOCK_VA()

FORCEINLINE VOID MI_UNLOCK_VA ( PMMPFN  Pfn1,
ULONG  LockType 
)

Definition at line 3190 of file virtual.c.

Referenced by MiUnlockVirtualMemory().

3193 {
3194  // HACK until we have proper WSLIST support
3195  PMMWSLE Wsle = &Pfn1->Wsle;
3196 
3197  if (LockType & MAP_PROCESS)
3198  Wsle->u1.e1.LockedInWs = 0;
3199  if (LockType & MAP_SYSTEM)
3200  Wsle->u1.e1.LockedInMemory = 0;
3201 
3202  if (!Wsle->u1.e1.LockedInWs &&
3203  !Wsle->u1.e1.LockedInMemory)
3204  {
3206  }
3207 }
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1434
MMWSLENTRY e1
Definition: mmtypes.h:844
MMWSLE Wsle
Definition: mm.h:364
#define MAP_PROCESS
Definition: mmtypes.h:67
ULONG_PTR LockedInMemory
Definition: mmtypes.h:830
ULONG_PTR LockedInWs
Definition: mmtypes.h:829
#define MAP_SYSTEM
Definition: mmtypes.h:68
union _MMWSLE::@2498 u1

◆ 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.

Referenced by NtFreeVirtualMemory().

46 {
47  PMMPTE PointerPte, LastPte;
48  PMMPDE PointerPde;
49  ULONG CommittedPages;
50 
51  /* Compute starting and ending PTE and PDE addresses */
52  PointerPde = MiAddressToPde(StartingAddress);
53  PointerPte = MiAddressToPte(StartingAddress);
54  LastPte = MiAddressToPte(EndingAddress);
55 
56  /* Handle commited pages first */
57  if (Vad->u.VadFlags.MemCommit == 1)
58  {
59  /* This is a committed VAD, so Assume the whole range is committed */
60  CommittedPages = (ULONG)BYTES_TO_PAGES(EndingAddress - StartingAddress);
61 
62  /* Is the PDE demand-zero? */
63  PointerPde = MiPteToPde(PointerPte);
64  if (PointerPde->u.Long != 0)
65  {
66  /* It is not. Is it valid? */
67  if (PointerPde->u.Hard.Valid == 0)
68  {
69  /* Fault it in */
70  PointerPte = MiPteToAddress(PointerPde);
71  MiMakeSystemAddressValid(PointerPte, Process);
72  }
73  }
74  else
75  {
76  /* It is, skip it and move to the next PDE, unless we're done */
77  PointerPde++;
78  PointerPte = MiPteToAddress(PointerPde);
79  if (PointerPte > LastPte) return CommittedPages;
80  }
81 
82  /* Now loop all the PTEs in the range */
83  while (PointerPte <= LastPte)
84  {
85  /* Have we crossed a PDE boundary? */
86  if (MiIsPteOnPdeBoundary(PointerPte))
87  {
88  /* Is this PDE demand zero? */
89  PointerPde = MiPteToPde(PointerPte);
90  if (PointerPde->u.Long != 0)
91  {
92  /* It isn't -- is it valid? */
93  if (PointerPde->u.Hard.Valid == 0)
94  {
95  /* Nope, fault it in */
96  PointerPte = MiPteToAddress(PointerPde);
97  MiMakeSystemAddressValid(PointerPte, Process);
98  }
99  }
100  else
101  {
102  /* It is, skip it and move to the next PDE */
103  PointerPde++;
104  PointerPte = MiPteToAddress(PointerPde);
105  continue;
106  }
107  }
108 
109  /* Is this PTE demand zero? */
110  if (PointerPte->u.Long != 0)
111  {
112  /* It isn't -- is it a decommited, invalid, or faulted PTE? */
113  if ((PointerPte->u.Soft.Protection == MM_DECOMMIT) &&
114  (PointerPte->u.Hard.Valid == 0) &&
115  ((PointerPte->u.Soft.Prototype == 0) ||
116  (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
117  {
118  /* It is, so remove it from the count of commited pages */
119  CommittedPages--;
120  }
121  }
122 
123  /* Move to the next PTE */
124  PointerPte++;
125  }
126 
127  /* Return how many committed pages there still are */
128  return CommittedPages;
129  }
130 
131  /* This is a non-commited VAD, so assume none of it is committed */
132  CommittedPages = 0;
133 
134  /* Is the PDE demand-zero? */
135  PointerPde = MiPteToPde(PointerPte);
136  if (PointerPde->u.Long != 0)
137  {
138  /* It isn't -- is it invalid? */
139  if (PointerPde->u.Hard.Valid == 0)
140  {
141  /* It is, so page it in */
142  PointerPte = MiPteToAddress(PointerPde);
143  MiMakeSystemAddressValid(PointerPte, Process);
144  }
145  }
146  else
147  {
148  /* It is, so skip it and move to the next PDE */
149  PointerPde++;
150  PointerPte = MiPteToAddress(PointerPde);
151  if (PointerPte > LastPte) return CommittedPages;
152  }
153 
154  /* Loop all the PTEs in this PDE */
155  while (PointerPte <= LastPte)
156  {
157  /* Have we crossed a PDE boundary? */
158  if (MiIsPteOnPdeBoundary(PointerPte))
159  {
160  /* Is this new PDE demand-zero? */
161  PointerPde = MiPteToPde(PointerPte);
162  if (PointerPde->u.Long != 0)
163  {
164  /* It isn't. Is it valid? */
165  if (PointerPde->u.Hard.Valid == 0)
166  {
167  /* It isn't, so make it valid */
168  PointerPte = MiPteToAddress(PointerPde);
169  MiMakeSystemAddressValid(PointerPte, Process);
170  }
171  }
172  else
173  {
174  /* It is, so skip it and move to the next one */
175  PointerPde++;
176  PointerPte = MiPteToAddress(PointerPde);
177  continue;
178  }
179  }
180 
181  /* Is this PTE demand-zero? */
182  if (PointerPte->u.Long != 0)
183  {
184  /* Nope. Is it a valid, non-decommited, non-paged out PTE? */
185  if ((PointerPte->u.Soft.Protection != MM_DECOMMIT) ||
186  (PointerPte->u.Hard.Valid == 1) ||
187  ((PointerPte->u.Soft.Prototype == 1) &&
188  (PointerPte->u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)))
189  {
190  /* It is! So we'll treat this as a committed page */
191  CommittedPages++;
192  }
193  }
194 
195  /* Move to the next PTE */
196  PointerPte++;
197  }
198 
199  /* Return how many committed pages we found in this VAD */
200  return CommittedPages;
201 }
ULONG NTAPI MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress, IN PEPROCESS CurrentProcess)
Definition: virtual.c:205
#define MiAddressToPde(x)
Definition: mmx86.c:20
#define MM_DECOMMIT
Definition: miarm.h:68
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:220
#define MiAddressToPte(x)
Definition: mmx86.c:19
PVOID FORCEINLINE MiPteToAddress(PMMPTE PointerPte)
Definition: mm.h:197
ULONG64 Protection
Definition: mmtypes.h:88
static const OBJECT_ATTRIBUTES const LARGE_INTEGER ULONG
Definition: virtual.c:34
ULONG64 Valid
Definition: mmtypes.h:150
#define BYTES_TO_PAGES(Size)
ULONG64 PageFileHigh
Definition: mmtypes.h:93
ULONG64 Prototype
Definition: mmtypes.h:89
ULONG_PTR Long
Definition: mmtypes.h:215
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define MiPteToPde(_Pte)
Definition: mm.h:232
#define MiIsPteOnPdeBoundary(PointerPte)
Definition: mm.h:236
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
unsigned int ULONG
Definition: retypes.h:1
union _MMPTE::@2228 u

◆ 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 3211 of file virtual.c.

Referenced by MiLockVirtualMemory(), and MiUnlockVirtualMemory().

3216 {
3217  PMMVAD Vad;
3218  PVOID CurrentVa;
3219 
3220  /* Get the base address and align the start address */
3221  *EndAddress = (PUCHAR)*BaseAddress + *RegionSize;
3222  *EndAddress = ALIGN_UP_POINTER_BY(*EndAddress, PAGE_SIZE);
3224 
3225  /* First loop and check all VADs */
3226  CurrentVa = *BaseAddress;
3227  while (CurrentVa < *EndAddress)
3228  {
3229  /* Get VAD */
3230  Vad = MiLocateAddress(CurrentVa);
3231  if (Vad == NULL)
3232  {
3234  return STATUS_ACCESS_VIOLATION;
3235  }
3236 
3237  /* Check VAD type */
3238  if ((Vad->u.VadFlags.VadType != VadNone) &&
3239  (Vad->u.VadFlags.VadType != VadImageMap) &&
3240  (Vad->u.VadFlags.VadType != VadWriteWatch))
3241  {
3242  *EndAddress = CurrentVa;
3243  *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3245  }
3246 
3247  CurrentVa = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
3248  }
3249 
3250  *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3251  return STATUS_SUCCESS;
3252 }
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
unsigned char * PUCHAR
Definition: retypes.h:3
union _MMVAD::@2488 u
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:735
ULONG_PTR EndingVpn
Definition: mmtypes.h:731
smooth NULL
Definition: ftsmooth.c:416
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
Definition: vadnode.c:48
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
#define ALIGN_UP_POINTER_BY(ptr, align)
Definition: umtypes.h:85
static PVOID
Definition: virtual.c:33
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
__kernel_entry _Inout_ _Inout_ PSIZE_T RegionSize
Definition: mmfuncs.h:172
return STATUS_SUCCESS
Definition: btrfs.c:2710
#define ALIGN_DOWN_POINTER_BY(ptr, align)
Definition: umtypes.h:82
#define STATUS_INCOMPATIBLE_FILE_MAP
Definition: ntstatus.h:299
ULONG_PTR VadType
Definition: mmtypes.h:695

◆ MiDecommitPages()

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

Definition at line 2502 of file virtual.c.

Referenced by NtFreeVirtualMemory().

2506 {
2507  PMMPTE PointerPte, CommitPte = NULL;
2508  PMMPDE PointerPde;
2509  ULONG CommitReduction = 0;
2510  PMMPTE ValidPteList[256];
2511  ULONG PteCount = 0;
2512  PMMPFN Pfn1;
2513  MMPTE PteContents;
2514  PETHREAD CurrentThread = PsGetCurrentThread();
2515 
2516  //
2517  // Get the PTE and PTE for the address, and lock the working set
2518  // If this was a VAD for a MEM_COMMIT allocation, also figure out where the
2519  // commited range ends so that we can do the right accounting.
2520  //
2521  PointerPde = MiAddressToPde(StartingAddress);
2522  PointerPte = MiAddressToPte(StartingAddress);
2523  if (Vad->u.VadFlags.MemCommit) CommitPte = MiAddressToPte(Vad->EndingVpn << PAGE_SHIFT);
2524  MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
2525 
2526  //
2527  // Make the PDE valid, and now loop through each page's worth of data
2528  //
2530  while (PointerPte <= EndingPte)
2531  {
2532  //
2533  // Check if we've crossed a PDE boundary
2534  //
2535  if (MiIsPteOnPdeBoundary(PointerPte))
2536  {
2537  //
2538  // Get the new PDE and flush the valid PTEs we had built up until
2539  // now. This helps reduce the amount of TLB flushing we have to do.
2540  // Note that Windows does a much better job using timestamps and
2541  // such, and does not flush the entire TLB all the time, but right
2542  // now we have bigger problems to worry about than TLB flushing.
2543  //
2544  PointerPde = MiAddressToPde(StartingAddress);
2545  if (PteCount)
2546  {
2547  MiProcessValidPteList(ValidPteList, PteCount);
2548  PteCount = 0;
2549  }
2550 
2551  //
2552  // Make this PDE valid
2553  //
2555  }
2556 
2557  //
2558  // Read this PTE. It might be active or still demand-zero.
2559  //
2560  PteContents = *PointerPte;
2561  if (PteContents.u.Long)
2562  {
2563  //
2564  // The PTE is active. It might be valid and in a working set, or
2565  // it might be a prototype PTE or paged out or even in transition.
2566  //
2567  if (PointerPte->u.Long == MmDecommittedPte.u.Long)
2568  {
2569  //
2570  // It's already decommited, so there's nothing for us to do here
2571  //
2572  CommitReduction++;
2573  }
2574  else
2575  {
2576  //
2577  // Remove it from the counters, and check if it was valid or not
2578  //
2579  //Process->NumberOfPrivatePages--;
2580  if (PteContents.u.Hard.Valid)
2581  {
2582  //
2583  // It's valid. At this point make sure that it is not a ROS
2584  // PFN. Also, we don't support ProtoPTEs in this code path.
2585  //
2586  Pfn1 = MiGetPfnEntry(PteContents.u.Hard.PageFrameNumber);
2587  ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
2588  ASSERT(Pfn1->u3.e1.PrototypePte == FALSE);
2589 
2590  //
2591  // Flush any pending PTEs that we had not yet flushed, if our
2592  // list has gotten too big, then add this PTE to the flush list.
2593  //
2594  if (PteCount == 256)
2595  {
2596  MiProcessValidPteList(ValidPteList, PteCount);
2597  PteCount = 0;
2598  }
2599  ValidPteList[PteCount++] = PointerPte;
2600  }
2601  else
2602  {
2603  //
2604  // We do not support any of these other scenarios at the moment
2605  //
2606  ASSERT(PteContents.u.Soft.Prototype == 0);
2607  ASSERT(PteContents.u.Soft.Transition == 0);
2608  ASSERT(PteContents.u.Soft.PageFileHigh == 0);
2609 
2610  //
2611  // So the only other possibility is that it is still a demand
2612  // zero PTE, in which case we undo the accounting we did
2613  // earlier and simply make the page decommitted.
2614  //
2615  //Process->NumberOfPrivatePages++;
2617  }
2618  }
2619  }
2620  else
2621  {
2622  //
2623  // This used to be a zero PTE and it no longer is, so we must add a
2624  // reference to the pagetable.
2625  //
2626  MiIncrementPageTableReferences(StartingAddress);
2627 
2628  //
2629  // Next, we account for decommitted PTEs and make the PTE as such
2630  //
2631  if (PointerPte > CommitPte) CommitReduction++;
2633  }
2634 
2635  //
2636  // Move to the next PTE and the next address
2637  //
2638  PointerPte++;
2639  StartingAddress = (PVOID)((ULONG_PTR)StartingAddress + PAGE_SIZE);
2640  }
2641 
2642  //
2643  // Flush any dangling PTEs from the loop in the last page table, and then
2644  // release the working set and return the commit reduction accounting.
2645  //
2646  if (PteCount) MiProcessValidPteList(ValidPteList, PteCount);
2647  MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread);
2648  return CommitReduction;
2649 }
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
FORCEINLINE VOID MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1179
#define MiAddressToPde(x)
Definition: mmx86.c:20
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
VOID NTAPI MiMakePdeExistAndMakeValid(IN PMMPDE PointerPde, IN PEPROCESS TargetProcess, IN KIRQL OldIrql)
Definition: virtual.c:2371
uint32_t ULONG_PTR
Definition: typedefs.h:63
USHORT PrototypePte
Definition: mm.h:295
MMPFNENTRY e1
Definition: mm.h:329
#define MiAddressToPte(x)
Definition: mmx86.c:19
smooth NULL
Definition: ftsmooth.c:416
VOID NTAPI MiProcessValidPteList(IN PMMPTE *ValidPteList, IN ULONG Count)
Definition: virtual.c:2450
union _MMPFN::@1722 u3
FORCEINLINE VOID MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1109
ULONG64 Valid
Definition: mmtypes.h:150
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
ULONG64 PageFileHigh
Definition: mmtypes.h:93
#define MM_NOIRQL
Definition: miarm.h:205
Definition: mm.h:305
static PVOID
Definition: virtual.c:33
ULONG64 Prototype
Definition: mmtypes.h:89
#define PAGE_SIZE
Definition: env_spec_w32.h:49
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:933
ULONG_PTR Long
Definition: mmtypes.h:215
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:945
#define MiIsPteOnPdeBoundary(PointerPte)
Definition: mm.h:236
ULONG64 Transition
Definition: mmtypes.h:90
#define MI_IS_ROS_PFN(x)
Definition: miarm.h:1043
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
FORCEINLINE VOID MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:1637
unsigned int ULONG
Definition: retypes.h:1
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
MMPTE MmDecommittedPte
Definition: init.c:46
union _MMPTE::@2228 u

◆ MiDeletePte()

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

Definition at line 391 of file virtual.c.

Referenced by MiBalancerThread(), MiDeleteVirtualAddresses(), MiQueryPageTableReferences(), MiResolveProtoPteFault(), MiUnmapLockedPagesInUserSpace(), MmArmAccessFault(), MmDeleteProcessAddressSpace(), and MmFreeMemoryArea().

395 {
396  PMMPFN Pfn1;
397  MMPTE TempPte;
398  PFN_NUMBER PageFrameIndex;
399  PMMPDE PointerPde;
400 
401  /* PFN lock must be held */
403 
404  /* Capture the PTE */
405  TempPte = *PointerPte;
406 
407  /* See if the PTE is valid */
408  if (TempPte.u.Hard.Valid == 0)
409  {
410  /* Prototype and paged out PTEs not supported yet */
411  ASSERT(TempPte.u.Soft.Prototype == 0);
412  ASSERT((TempPte.u.Soft.PageFileHigh == 0) || (TempPte.u.Soft.Transition == 1));
413 
414  if (TempPte.u.Soft.Transition)
415  {
416  /* Get the PFN entry */
417  PageFrameIndex = PFN_FROM_PTE(&TempPte);
418  Pfn1 = MiGetPfnEntry(PageFrameIndex);
419 
420  DPRINT("Pte %p is transitional!\n", PointerPte);
421 
422  /* Make sure the saved PTE address is valid */
423  ASSERT((PMMPTE)((ULONG_PTR)Pfn1->PteAddress & ~0x1) == PointerPte);
424 
425  /* Destroy the PTE */
426  MI_ERASE_PTE(PointerPte);
427 
428  /* Drop the reference on the page table. */
430 
431  ASSERT(Pfn1->u3.e1.PrototypePte == 0);
432 
433  /* Make the page free. For prototypes, it will be made free when deleting the section object */
434  if (Pfn1->u3.e2.ReferenceCount == 0)
435  {
436  /* And it should be in standby or modified list */
438 
439  /* Unlink it and set its reference count to one */
440  MiUnlinkPageFromList(Pfn1);
441  Pfn1->u3.e2.ReferenceCount++;
442 
443  /* This will put it back in free list and clean properly up */
444  MI_SET_PFN_DELETED(Pfn1);
445  MiDecrementReferenceCount(Pfn1, PageFrameIndex);
446  }
447  return;
448  }
449  }
450 
451  /* Get the PFN entry */
452  PageFrameIndex = PFN_FROM_PTE(&TempPte);
453  Pfn1 = MiGetPfnEntry(PageFrameIndex);
454 
455  /* Check if this is a valid, prototype PTE */
456  if (Pfn1->u3.e1.PrototypePte == 1)
457  {
458  /* Get the PDE and make sure it's faulted in */
459  PointerPde = MiPteToPde(PointerPte);
460  if (PointerPde->u.Hard.Valid == 0)
461  {
462 #if (_MI_PAGING_LEVELS == 2)
463  /* Could be paged pool access from a new process -- synchronize the page directories */
465  {
466 #endif
467  /* The PDE must be valid at this point */
468  KeBugCheckEx(MEMORY_MANAGEMENT,
469  0x61940,
470  (ULONG_PTR)PointerPte,
471  PointerPte->u.Long,
473  }
474 #if (_MI_PAGING_LEVELS == 2)
475  }
476 #endif
477  /* Drop the share count on the page table */
478  PointerPde = MiPteToPde(PointerPte);
480  PointerPde->u.Hard.PageFrameNumber);
481 
482  /* Drop the share count */
483  MiDecrementShareCount(Pfn1, PageFrameIndex);
484 
485  /* Either a fork, or this is the shared user data page */
486  if ((PointerPte <= MiHighestUserPte) && (PrototypePte != Pfn1->PteAddress))
487  {
488  /* If it's not the shared user page, then crash, since there's no fork() yet */
490  (MmHighestUserAddress <= (PVOID)USER_SHARED_DATA))
491  {
492  /* Must be some sort of memory corruption */
493  KeBugCheckEx(MEMORY_MANAGEMENT,
494  0x400,
495  (ULONG_PTR)PointerPte,
497  (ULONG_PTR)Pfn1->PteAddress);
498  }
499  }
500 
501  /* Erase it */
502  MI_ERASE_PTE(PointerPte);
503  }
504  else
505  {
506  /* Make sure the saved PTE address is valid */
507  if ((PMMPTE)((ULONG_PTR)Pfn1->PteAddress & ~0x1) != PointerPte)
508  {
509  /* The PFN entry is illegal, or invalid */
510  KeBugCheckEx(MEMORY_MANAGEMENT,
511  0x401,
512  (ULONG_PTR)PointerPte,
513  PointerPte->u.Long,
514  (ULONG_PTR)Pfn1->PteAddress);
515  }
516 
517  /* Erase the PTE */
518  MI_ERASE_PTE(PointerPte);
519 
520  /* There should only be 1 shared reference count */
521  ASSERT(Pfn1->u2.ShareCount == 1);
522 
523  /* Drop the reference on the page table. */
525 
526  /* Mark the PFN for deletion and dereference what should be the last ref */
527  MI_SET_PFN_DELETED(Pfn1);
528  MiDecrementShareCount(Pfn1, PageFrameIndex);
529 
530  /* We should eventually do this */
531  //CurrentProcess->NumberOfPrivatePages--;
532  }
533 
534  /* Flush the TLB */
536 }
struct _MMPFN::@1722::@1728 e2
FORCEINLINE VOID MI_ERASE_PTE(IN PMMPTE PointerPte)
Definition: miarm.h:959
MMPTE PrototypePte
Definition: init.c:42
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:929
VOID NTAPI MiUnlinkPageFromList(IN PMMPFN Pfn)
Definition: pfnlist.c:264
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
NTSTATUS FASTCALL MiCheckPdeForPagedPool(IN PVOID Address)
Definition: pagfault.c:475
USHORT PageLocation
Definition: mm.h:297
uint32_t ULONG_PTR
Definition: typedefs.h:63
USHORT PrototypePte
Definition: mm.h:295
MMPFNENTRY e1
Definition: mm.h:329
ULONG PFN_NUMBER
Definition: ke.h:8
ULONG_PTR ShareCount
Definition: mm.h:322
#define USER_SHARED_DATA
Definition: pstypes.h:51
void DPRINT(...)
Definition: polytest.cpp:61
VOID NTAPI MiDecrementShareCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1133
union _MMPFN::@1722 u3
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
ULONG64 Valid
Definition: mmtypes.h:150
#define PAGE_ALIGN(Va)
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:75
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
VOID NTAPI MiDecrementReferenceCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1222
ULONG64 PageFileHigh
Definition: mmtypes.h:93
Definition: mm.h:305
ULONG64 Prototype
Definition: mmtypes.h:89
_In_ ULONG _In_ BOOLEAN _Must_inspect_result_ PVOID * VirtualAddress
Definition: ndis.h:3773
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:933
union _MMPFN::@1721 u2
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define MI_SET_PFN_DELETED(x)
Definition: miarm.h:163
#define MiPteToPde(_Pte)
Definition: mm.h:232
ULONG_PTR PteFrame
Definition: mm.h:350
ULONG64 Transition
Definition: mmtypes.h:90
PMMPTE PteAddress
Definition: mm.h:318
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
PVOID MmHighestUserAddress
Definition: rtlcompat.c:29
union _MMPFN::@1725 u4
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
PMMPTE MiHighestUserPte
Definition: mminit.c:233
#define PFN_FROM_PTE(v)
Definition: mm.h:88
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:107
VOID NTAPI KeFlushCurrentTb(VOID)
Definition: cpu.c:322
union _MMPTE::@2228 u

◆ MiDeleteSystemPageableVm()

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

Definition at line 297 of file virtual.c.

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

301 {
302  PFN_COUNT ActualPages = 0;
303  PETHREAD CurrentThread = PsGetCurrentThread();
304  PMMPFN Pfn1, Pfn2;
305  PFN_NUMBER PageFrameIndex, PageTableIndex;
306  KIRQL OldIrql;
308 
309  /* Lock the system working set */
310  MiLockWorkingSet(CurrentThread, &MmSystemCacheWs);
311 
312  /* Loop all pages */
313  while (PageCount)
314  {
315  /* Make sure there's some data about the page */
316  if (PointerPte->u.Long)
317  {
318  /* As always, only handle current ARM3 scenarios */
319  ASSERT(PointerPte->u.Soft.Prototype == 0);
320  ASSERT(PointerPte->u.Soft.Transition == 0);
321 
322  /* Normally this is one possibility -- freeing a valid page */
323  if (PointerPte->u.Hard.Valid)
324  {
325  /* Get the page PFN */
326  PageFrameIndex = PFN_FROM_PTE(PointerPte);
327  Pfn1 = MiGetPfnEntry(PageFrameIndex);
328 
329  /* Should not have any working set data yet */
330  ASSERT(Pfn1->u1.WsIndex == 0);
331 
332  /* Actual valid, legitimate, pages */
333  if (ValidPages) (*ValidPages)++;
334 
335  /* Get the page table entry */
336  PageTableIndex = Pfn1->u4.PteFrame;
337  Pfn2 = MiGetPfnEntry(PageTableIndex);
338 
339  /* Lock the PFN database */
340  OldIrql = MiAcquirePfnLock();
341 
342  /* Delete it the page */
343  MI_SET_PFN_DELETED(Pfn1);
344  MiDecrementShareCount(Pfn1, PageFrameIndex);
345 
346  /* Decrement the page table too */
347  MiDecrementShareCount(Pfn2, PageTableIndex);
348 
349  /* Release the PFN database */
350  MiReleasePfnLock(OldIrql);
351 
352  /* Destroy the PTE */
353  MI_ERASE_PTE(PointerPte);
354  }
355  else
356  {
357  /*
358  * The only other ARM3 possibility is a demand zero page, which would
359  * mean freeing some of the paged pool pages that haven't even been
360  * touched yet, as part of a larger allocation.
361  *
362  * Right now, we shouldn't expect any page file information in the PTE
363  */
364  ASSERT(PointerPte->u.Soft.PageFileHigh == 0);
365 
366  /* Destroy the PTE */
367  MI_ERASE_PTE(PointerPte);
368  }
369 
370  /* Actual legitimate pages */
371  ActualPages++;
372  }
373 
374  /* Keep going */
375  PointerPte++;
376  PageCount--;
377  }
378 
379  /* Release the working set */
380  MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs);
381 
382  /* Flush the entire TLB */
384 
385  /* Done */
386  return ActualPages;
387 }
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
FORCEINLINE VOID MI_ERASE_PTE(IN PMMPTE PointerPte)
Definition: miarm.h:959
#define TRUE
Definition: types.h:120
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
ULONG PFN_COUNT
Definition: mmtypes.h:102
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:894
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:901
UCHAR KIRQL
Definition: env_spec_w32.h:591
ULONG PFN_NUMBER
Definition: ke.h:8
MMSUPPORT MmSystemCacheWs
Definition: init.c:55
VOID NTAPI MiDecrementShareCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1133
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1249
VOID NTAPI KeFlushEntireTb(IN BOOLEAN Invalid, IN BOOLEAN AllProcessors)
Definition: cpu.c:413
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
Definition: mm.h:305
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:933
#define MI_SET_PFN_DELETED(x)
Definition: miarm.h:163
ULONG_PTR PteFrame
Definition: mm.h:350
union _MMPFN::@1725 u4
ULONG WsIndex
Definition: mm.h:310
union _MMPFN::@1720 u1
FORCEINLINE VOID MiLockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1205
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define PFN_FROM_PTE(v)
Definition: mm.h:88

◆ MiDeleteVirtualAddresses()

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

Definition at line 540 of file virtual.c.

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

543 {
544  PMMPTE PointerPte, PrototypePte, LastPrototypePte;
545  PMMPDE PointerPde;
546  MMPTE TempPte;
548  KIRQL OldIrql;
549  BOOLEAN AddressGap = FALSE;
550  PSUBSECTION Subsection;
551 
552  /* Get out if this is a fake VAD, RosMm will free the marea pages */
553  if ((Vad) && (Vad->u.VadFlags.Spare == 1)) return;
554 
555  /* Grab the process and PTE/PDE for the address being deleted */
556  CurrentProcess = PsGetCurrentProcess();
557  PointerPde = MiAddressToPde(Va);
558  PointerPte = MiAddressToPte(Va);
559 
560  /* Check if this is a section VAD or a VM VAD */
561  if (!(Vad) || (Vad->u.VadFlags.PrivateMemory) || !(Vad->FirstPrototypePte))
562  {
563  /* Don't worry about prototypes */
564  PrototypePte = LastPrototypePte = NULL;
565  }
566  else
567  {
568  /* Get the prototype PTE */
569  PrototypePte = Vad->FirstPrototypePte;
570  LastPrototypePte = Vad->FirstPrototypePte + 1;
571  }
572 
573  /* In all cases, we don't support fork() yet */
574  ASSERT(CurrentProcess->CloneRoot == NULL);
575 
576  /* Loop the PTE for each VA */
577  while (TRUE)
578  {
579  /* First keep going until we find a valid PDE */
580  while (!PointerPde->u.Long)
581  {
582  /* There are gaps in the address space */
583  AddressGap = TRUE;
584 
585  /* Still no valid PDE, try the next 4MB (or whatever) */
586  PointerPde++;
587 
588  /* Update the PTE on this new boundary */
589  PointerPte = MiPteToAddress(PointerPde);
590 
591  /* Check if all the PDEs are invalid, so there's nothing to free */
592  Va = (ULONG_PTR)MiPteToAddress(PointerPte);
593  if (Va > EndingAddress) return;
594  }
595 
596  /* Now check if the PDE is mapped in */
597  if (!PointerPde->u.Hard.Valid)
598  {
599  /* It isn't, so map it in */
600  PointerPte = MiPteToAddress(PointerPde);
601  MiMakeSystemAddressValid(PointerPte, CurrentProcess);
602  }
603 
604  /* Now we should have a valid PDE, mapped in, and still have some VA */
605  ASSERT(PointerPde->u.Hard.Valid == 1);
606  ASSERT(Va <= EndingAddress);
607 
608  /* Check if this is a section VAD with gaps in it */
609  if ((AddressGap) && (LastPrototypePte))
610  {
611  /* We need to skip to the next correct prototype PTE */
612  PrototypePte = MI_GET_PROTOTYPE_PTE_FOR_VPN(Vad, Va >> PAGE_SHIFT);
613 
614  /* And we need the subsection to skip to the next last prototype PTE */
615  Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
616  if (Subsection)
617  {
618  /* Found it! */
619  LastPrototypePte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
620  }
621  else
622  {
623  /* No more subsections, we are done with prototype PTEs */
624  PrototypePte = NULL;
625  }
626  }
627 
628  /* Lock the PFN Database while we delete the PTEs */
629  OldIrql = MiAcquirePfnLock();
630  do
631  {
632  /* Capture the PDE and make sure it exists */
633  TempPte = *PointerPte;
634  if (TempPte.u.Long)
635  {
637 
638  /* Check if the PTE is actually mapped in */
639  if (MI_IS_MAPPED_PTE(&TempPte))
640  {
641  /* Are we dealing with section VAD? */
642  if ((LastPrototypePte) && (PrototypePte > LastPrototypePte))
643  {
644  /* We need to skip to the next correct prototype PTE */
645  PrototypePte = MI_GET_PROTOTYPE_PTE_FOR_VPN(Vad, Va >> PAGE_SHIFT);
646 
647  /* And we need the subsection to skip to the next last prototype PTE */
648  Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
649  if (Subsection)
650  {
651  /* Found it! */
652  LastPrototypePte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
653  }
654  else
655  {
656  /* No more subsections, we are done with prototype PTEs */
657  PrototypePte = NULL;
658  }
659  }
660 
661  /* Check for prototype PTE */
662  if ((TempPte.u.Hard.Valid == 0) &&
663  (TempPte.u.Soft.Prototype == 1))
664  {
665  /* Just nuke it */
666  MI_ERASE_PTE(PointerPte);
667  }
668  else
669  {
670  /* Delete the PTE proper */
671  MiDeletePte(PointerPte,
672  (PVOID)Va,
673  CurrentProcess,
674  PrototypePte);
675  }
676  }
677  else
678  {
679  /* The PTE was never mapped, just nuke it here */
680  MI_ERASE_PTE(PointerPte);
681  }
682  }
683 
684  /* Update the address and PTE for it */
685  Va += PAGE_SIZE;
686  PointerPte++;
687  PrototypePte++;
688 
689  /* Making sure the PDE is still valid */
690  ASSERT(PointerPde->u.Hard.Valid == 1);
691  }
692  while ((Va & (PDE_MAPPED_VA - 1)) && (Va <= EndingAddress));
693 
694  /* The PDE should still be valid at this point */
695  ASSERT(PointerPde->u.Hard.Valid == 1);
696 
697  /* Check remaining PTE count (go back 1 page due to above loop) */
698  if (MiQueryPageTableReferences((PVOID)(Va - PAGE_SIZE)) == 0)
699  {
700  if (PointerPde->u.Long != 0)
701  {
702  /* Delete the PTE proper */
703  MiDeletePte(PointerPde,
704  MiPteToAddress(PointerPde),
705  CurrentProcess,
706  NULL);
707  }
708  }
709 
710  /* Release the lock and get out if we're done */
711  MiReleasePfnLock(OldIrql);
712  if (Va > EndingAddress) return;
713 
714  /* Otherwise, we exited because we hit a new PDE boundary, so start over */
715  PointerPde = MiAddressToPde(Va);
716  AddressGap = FALSE;
717  }
718 }
ULONG NTAPI MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress, IN PEPROCESS CurrentProcess)
Definition: virtual.c:205
FORCEINLINE VOID MI_ERASE_PTE(IN PMMPTE PointerPte)
Definition: miarm.h:959
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
MMPTE PrototypePte
Definition: init.c:42
#define TRUE
Definition: types.h:120
#define MiAddressToPde(x)
Definition: mmx86.c:20
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:894
FORCEINLINE USHORT MiQueryPageTableReferences(IN PVOID Address)
Definition: miarm.h:1661
PVOID CloneRoot
Definition: pstypes.h:1230
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:901
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define PsGetCurrentProcess
Definition: psfuncs.h:17
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
PVOID FORCEINLINE MiPteToAddress(PMMPTE PointerPte)
Definition: mm.h:197
#define PDE_MAPPED_VA
Definition: miarm.h:22
FORCEINLINE VOID MiDecrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:1649
ULONG CurrentProcess
Definition: shell.c:125
ULONG64 Valid
Definition: mmtypes.h:150
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:75
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
ULONG64 Prototype
Definition: mmtypes.h:89
#define PAGE_SIZE
Definition: env_spec_w32.h:49
ULONG_PTR Long
Definition: mmtypes.h:215
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
PSUBSECTION NTAPI MiLocateSubsection(IN PMMVAD Vad, IN ULONG_PTR Vpn)
Definition: section.c:571
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
VOID NTAPI MiDeletePte(IN PMMPTE PointerPte, IN PVOID VirtualAddress, IN PEPROCESS CurrentProcess, IN PMMPTE PrototypePte)
Definition: virtual.c:391
FORCEINLINE BOOLEAN MI_IS_MAPPED_PTE(PMMPTE PointerPte)
Definition: mm.h:285
#define ULONG_PTR
Definition: config.h:101
PMMPTE SubsectionBase
Definition: mmtypes.h:571
FORCEINLINE PMMPTE MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad, IN ULONG_PTR Vpn)
Definition: miarm.h:1376
union _MMPTE::@2228 u
ULONG PtesInSubsection
Definition: mmtypes.h:573

◆ 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 766 of file virtual.c.

Referenced by MmCopyVirtualMemory().

773 {
774  PFN_NUMBER MdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
775  PMDL Mdl = (PMDL)MdlBuffer;
776  SIZE_T TotalSize, CurrentSize, RemainingSize;
777  volatile BOOLEAN FailedInProbe = FALSE;
778  volatile BOOLEAN PagesLocked = FALSE;
779  PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
780  volatile PVOID MdlAddress = NULL;
782  BOOLEAN HaveBadAddress;
783  ULONG_PTR BadAddress;
785  PAGED_CODE();
786 
787  //
788  // Calculate the maximum amount of data to move
789  //
790  TotalSize = MI_MAPPED_COPY_PAGES * PAGE_SIZE;
791  if (BufferSize <= TotalSize) TotalSize = BufferSize;
792  CurrentSize = TotalSize;
793  RemainingSize = BufferSize;
794 
795  //
796  // Loop as long as there is still data
797  //
798  while (RemainingSize > 0)
799  {
800  //
801  // Check if this transfer will finish everything off
802  //
803  if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
804 
805  //
806  // Attach to the source address space
807  //
808  KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
809 
810  //
811  // Check state for this pass
812  //
813  ASSERT(MdlAddress == NULL);
814  ASSERT(PagesLocked == FALSE);
815  ASSERT(FailedInProbe == FALSE);
816 
817  //
818  // Protect user-mode copy
819  //
820  _SEH2_TRY
821  {
822  //
823  // If this is our first time, probe the buffer
824  //
825  if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
826  {
827  //
828  // Catch a failure here
829  //
830  FailedInProbe = TRUE;
831 
832  //
833  // Do the probe
834  //
836 
837  //
838  // Passed
839  //
840  FailedInProbe = FALSE;
841  }
842 
843  //
844  // Initialize and probe and lock the MDL
845  //
846  MmInitializeMdl(Mdl, CurrentAddress, CurrentSize);
848  PagesLocked = TRUE;
849  }
851  {
852  Status = _SEH2_GetExceptionCode();
853  }
854  _SEH2_END
855 
856  /* Detach from source process */
857  KeUnstackDetachProcess(&ApcState);
858 
859  if (Status != STATUS_SUCCESS)
860  {
861  goto Exit;
862  }
863 
864  //
865  // Now map the pages
866  //
867  MdlAddress = MmMapLockedPagesSpecifyCache(Mdl,
868  KernelMode,
869  MmCached,
870  NULL,
871  FALSE,
873  if (!MdlAddress)
874  {
876  goto Exit;
877  }
878 
879  //
880  // Grab to the target process
881  //
882  KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
883 
884  _SEH2_TRY
885  {
886  //
887  // Check if this is our first time through
888  //
889  if ((CurrentTargetAddress == TargetAddress) && (PreviousMode != KernelMode))
890  {
891  //
892  // Catch a failure here
893  //
894  FailedInProbe = TRUE;
895 
896  //
897  // Do the probe
898  //
900 
901  //
902  // Passed
903  //
904  FailedInProbe = FALSE;
905  }
906 
907  //
908  // Now do the actual move
909  //
910  RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
911  }
913  &HaveBadAddress,
914  &BadAddress))
915  {
916  *ReturnSize = BufferSize - RemainingSize;
917  //
918  // Check if we failed during the probe
919  //
920  if (FailedInProbe)
921  {
922  //
923  // Exit
924  //
925  Status = _SEH2_GetExceptionCode();
926  }
927  else
928  {
929  //
930  // Othewise we failed during the move.
931  // Check if we know exactly where we stopped copying
932  //
933  if (HaveBadAddress)
934  {
935  //
936  // Return the exact number of bytes copied
937  //
938  *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
939  }
940  //
941  // Return partial copy
942  //
943  Status = STATUS_PARTIAL_COPY;
944  }
945  }
946  _SEH2_END;
947 
948  /* Detach from target process */
949  KeUnstackDetachProcess(&ApcState);
950 
951  //
952  // Check for SEH status
953  //
954  if (Status != STATUS_SUCCESS)
955  {
956  goto Exit;
957  }
958 
959  //
960  // Unmap and unlock
961  //
962  MmUnmapLockedPages(MdlAddress, Mdl);
963  MdlAddress = NULL;
964  MmUnlockPages(Mdl);
965  PagesLocked = FALSE;
966 
967  //
968  // Update location and size
969  //
970  RemainingSize -= CurrentSize;
971  CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
972  CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
973  }
974 
975 Exit:
976  if (MdlAddress != NULL)
977  MmUnmapLockedPages(MdlAddress, Mdl);
978  if (PagesLocked)
979  MmUnlockPages(Mdl);
980 
981  //
982  // All bytes read
983  //
984  if (Status == STATUS_SUCCESS)
985  *ReturnSize = BufferSize;
986  return Status;
987 }
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
KAPC_STATE
Definition: ketypes.h:1273
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define MmInitializeMdl(_MemoryDescriptorList, _BaseVa, _Length)
char CHAR
Definition: xmlstorage.h:175
LONG NTSTATUS
Definition: precomp.h:26
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1439
#define MI_MAPPED_COPY_PAGES
Definition: virtual.c:18
PVOID PMDL
Definition: usb.h:39
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define PAGED_CODE()
Definition: video.h:57
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER _Outptr_ PVOID * TargetAddress
Definition: iotypes.h:997
_SEH2_TRY
Definition: create.c:4250
uint32_t ULONG_PTR
Definition: typedefs.h:63
ULONG PFN_NUMBER
Definition: ke.h:8
VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState)
Definition: procobj.c:701
VOID NTAPI MmUnmapLockedPages(IN PVOID BaseAddress, IN PMDL Mdl)
Definition: mdlsup.c:841
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:11
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
static void Exit(void)
Definition: sock.c:1331
#define BufferSize
Definition: classpnp.h:419
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
MDL
Definition: mmtypes.h:117
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
static PVOID
Definition: virtual.c:33
#define PAGE_SIZE
Definition: env_spec_w32.h:49
Status
Definition: gdiplustypes.h:24
ULONG_PTR SIZE_T
Definition: typedefs.h:78
_SEH2_END
Definition: create.c:4424
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:935
PVOID NTAPI MmMapLockedPagesSpecifyCache(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN MEMORY_CACHING_TYPE CacheType, IN PVOID BaseAddress, IN ULONG BugCheckOnFailure, IN MM_PAGE_PRIORITY Priority)
Definition: mdlsup.c:664
VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
Definition: procobj.c:753
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1471
#define STATUS_PARTIAL_COPY
Definition: ntstatus.h:181
#define ULONG_PTR
Definition: config.h:101
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
return STATUS_SUCCESS
Definition: btrfs.c:2710
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS SourceAddress
Definition: iotypes.h:1089
LONG MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo, OUT PBOOLEAN HaveBadAddress, OUT PULONG_PTR BadAddress)
Definition: virtual.c:721

◆ 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 991 of file virtual.c.

Referenced by MmCopyVirtualMemory().

998 {
999  UCHAR StackBuffer[MI_POOL_COPY_BYTES];
1000  SIZE_T TotalSize, CurrentSize, RemainingSize;
1001  volatile BOOLEAN FailedInProbe = FALSE, HavePoolAddress = FALSE;
1002  PVOID CurrentAddress = SourceAddress, CurrentTargetAddress = TargetAddress;
1003  PVOID PoolAddress;
1005  BOOLEAN HaveBadAddress;
1006  ULONG_PTR BadAddress;
1008  PAGED_CODE();
1009 
1010  DPRINT("Copying %Iu bytes from process %p (address %p) to process %p (Address %p)\n",
1011  BufferSize, SourceProcess, SourceAddress, TargetProcess, TargetAddress);
1012 
1013  //
1014  // Calculate the maximum amount of data to move
1015  //
1016  TotalSize = MI_MAX_TRANSFER_SIZE;
1017  if (BufferSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
1018  CurrentSize = TotalSize;
1019  RemainingSize = BufferSize;
1020 
1021  //
1022  // Check if we can use the stack
1023  //
1025  {
1026  //
1027  // Use it
1028  //
1029  PoolAddress = (PVOID)StackBuffer;
1030  }
1031  else
1032  {
1033  //
1034  // Allocate pool
1035  //
1036  PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, 'VmRw');
1037  if (!PoolAddress) ASSERT(FALSE);
1038  HavePoolAddress = TRUE;
1039  }
1040 
1041  //
1042  // Loop as long as there is still data
1043  //
1044  while (RemainingSize > 0)
1045  {
1046  //
1047  // Check if this transfer will finish everything off
1048  //
1049  if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
1050 
1051  //
1052  // Attach to the source address space
1053  //
1054  KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
1055 
1056  /* Check that state is sane */
1057  ASSERT(FailedInProbe == FALSE);
1058  ASSERT(Status == STATUS_SUCCESS);
1059 
1060  //
1061  // Protect user-mode copy
1062  //
1063  _SEH2_TRY
1064  {
1065  //
1066  // If this is our first time, probe the buffer
1067  //
1068  if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
1069  {
1070  //
1071  // Catch a failure here
1072  //
1073  FailedInProbe = TRUE;
1074 
1075  //
1076  // Do the probe
1077  //
1079 
1080  //
1081  // Passed
1082  //
1083  FailedInProbe = FALSE;
1084  }
1085 
1086  //
1087  // Do the copy
1088  //
1089  RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
1090  }
1092  &HaveBadAddress,
1093  &BadAddress))
1094  {
1095  *ReturnSize = BufferSize - RemainingSize;
1096 
1097  //
1098  // Check if we failed during the probe
1099  //
1100  if (FailedInProbe)
1101  {
1102  //
1103  // Exit
1104  //
1105  Status = _SEH2_GetExceptionCode();
1106  }
1107  else
1108  {
1109  //
1110  // We failed during the move.
1111  // Check if we know exactly where we stopped copying
1112  //
1113  if (HaveBadAddress)
1114  {
1115  //
1116  // Return the exact number of bytes copied
1117  //
1118  *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
1119  }
1120  //
1121  // Return partial copy
1122  //
1123  Status = STATUS_PARTIAL_COPY;
1124  }
1125  }
1126  _SEH2_END
1127 
1128  /* Let go of the source */
1129  KeUnstackDetachProcess(&ApcState);
1130 
1131  if (Status != STATUS_SUCCESS)
1132  {
1133  goto Exit;
1134  }
1135 
1136  /* Grab the target process */
1137  KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
1138 
1139  _SEH2_TRY
1140  {
1141  //
1142  // Check if this is our first time through
1143  //
1144  if ((CurrentTargetAddress == TargetAddress) && (PreviousMode != KernelMode))
1145  {
1146  //
1147  // Catch a failure here
1148  //
1149  FailedInProbe = TRUE;
1150 
1151  //
1152  // Do the probe
1153  //
1155 
1156  //
1157  // Passed
1158  //
1159  FailedInProbe = FALSE;
1160  }
1161 
1162  //
1163  // Now do the actual move
1164  //
1165  RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
1166  }
1168  &HaveBadAddress,
1169  &BadAddress))
1170  {
1171  *ReturnSize = BufferSize - RemainingSize;
1172  //
1173  // Check if we failed during the probe
1174  //
1175  if (FailedInProbe)
1176  {
1177  //
1178  // Exit
1179  //
1180  Status = _SEH2_GetExceptionCode();
1181  }
1182  else
1183  {
1184  //
1185  // Otherwise we failed during the move.
1186  // Check if we know exactly where we stopped copying
1187  //
1188  if (HaveBadAddress)
1189  {
1190  //
1191  // Return the exact number of bytes copied
1192  //
1193  *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
1194  }
1195  //
1196  // Return partial copy
1197  //
1198  Status = STATUS_PARTIAL_COPY;
1199  }
1200  }
1201  _SEH2_END;
1202 
1203  //
1204  // Detach from target
1205  //
1206  KeUnstackDetachProcess(&ApcState);
1207 
1208  //
1209  // Check for SEH status
1210  //
1211  if (Status != STATUS_SUCCESS)
1212  {
1213  goto Exit;
1214  }
1215 
1216  //
1217  // Update location and size
1218  //
1219  RemainingSize -= CurrentSize;
1220  CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
1221  CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress +
1222  CurrentSize);
1223  }
1224 
1225 Exit:
1226  //
1227  // Check if we had allocated pool
1228  //
1229  if (HavePoolAddress)
1230  ExFreePoolWithTag(PoolAddress, 'VmRw');
1231 
1232  //
1233  // All bytes read
1234  //
1235  if (Status == STATUS_SUCCESS)
1236  *ReturnSize = BufferSize;
1237  return Status;
1238 }
#define MI_POOL_COPY_BYTES
Definition: virtual.c:19
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
KAPC_STATE
Definition: ketypes.h:1273
char CHAR
Definition: xmlstorage.h:175
LONG NTSTATUS
Definition: precomp.h:26
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define PAGED_CODE()
Definition: video.h:57
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER _Outptr_ PVOID * TargetAddress
Definition: iotypes.h:997
_SEH2_TRY
Definition: create.c:4250
uint32_t ULONG_PTR
Definition: typedefs.h:63
VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState)
Definition: procobj.c:701
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:11
unsigned char BOOLEAN
void DPRINT(...)
Definition: polytest.cpp:61
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
static void Exit(void)
Definition: sock.c:1331
#define BufferSize
Definition: classpnp.h:419
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
unsigned char UCHAR
Definition: xmlstorage.h:181
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
static PVOID
Definition: virtual.c:33
#define MI_MAX_TRANSFER_SIZE
Definition: virtual.c:20
Status
Definition: gdiplustypes.h:24
ULONG_PTR SIZE_T
Definition: typedefs.h:78
_SEH2_END
Definition: create.c:4424
VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
Definition: procobj.c:753
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1471
#define STATUS_PARTIAL_COPY
Definition: ntstatus.h:181
#define ULONG_PTR
Definition: config.h:101
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
return STATUS_SUCCESS
Definition: btrfs.c:2710
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS SourceAddress
Definition: iotypes.h:1089
LONG MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo, OUT PBOOLEAN HaveBadAddress, OUT PULONG_PTR BadAddress)
Definition: virtual.c:721

◆ MiFlushTbAndCapture()

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

Definition at line 1958 of file section.c.

Referenced by MiProtectVirtualMemory(), and MiSetProtectionOnSection().

1963 {
1964  MMPTE TempPte, PreviousPte;
1965  KIRQL OldIrql;
1966  BOOLEAN RebuildPte = FALSE;
1967 
1968  //
1969  // User for sanity checking later on
1970  //
1971  PreviousPte = *PointerPte;
1972 
1973  //
1974  // Build the PTE and acquire the PFN lock
1975  //
1976  MI_MAKE_HARDWARE_PTE_USER(&TempPte,
1977  PointerPte,
1978  ProtectionMask,
1979  PreviousPte.u.Hard.PageFrameNumber);
1980  OldIrql = MiAcquirePfnLock();
1981 
1982  //
1983  // We don't support I/O mappings in this path yet
1984  //
1985  ASSERT(Pfn1 != NULL);
1986  ASSERT(Pfn1->u3.e1.CacheAttribute != MiWriteCombined);
1987 
1988  //
1989  // Make sure new protection mask doesn't get in conflict and fix it if it does
1990  //
1991  if (Pfn1->u3.e1.CacheAttribute == MiCached)
1992  {
1993  //
1994  // This is a cached PFN
1995  //
1996  if (ProtectionMask & (MM_NOCACHE | MM_NOACCESS))
1997  {
1998  RebuildPte = TRUE;
1999  ProtectionMask &= ~(MM_NOCACHE | MM_NOACCESS);
2000  }
2001  }
2002  else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
2003  {
2004  //
2005  // This is a non-cached PFN
2006  //
2007  if ((ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) != MM_NOCACHE)
2008  {
2009  RebuildPte = TRUE;
2010  ProtectionMask &= ~MM_NOACCESS;
2011  ProtectionMask |= MM_NOCACHE;
2012  }
2013  }
2014 
2015  if (RebuildPte)
2016  {
2017  MI_MAKE_HARDWARE_PTE_USER(&TempPte,
2018  PointerPte,
2019  ProtectionMask,
2020  PreviousPte.u.Hard.PageFrameNumber);
2021  }
2022 
2023  //
2024  // Write the new PTE, making sure we are only changing the bits
2025  //
2026  MI_UPDATE_VALID_PTE(PointerPte, TempPte);
2027 
2028  //
2029  // Flush the TLB
2030  //
2031  ASSERT(PreviousPte.u.Hard.Valid == 1);
2032  KeFlushCurrentTb();
2033  ASSERT(PreviousPte.u.Hard.Valid == 1);
2034 
2035  //
2036  // Windows updates the relevant PFN1 information, we currently don't.
2037  //
2038  if (UpdateDirty && PreviousPte.u.Hard.Dirty)
2039  {
2040  if (!Pfn1->u3.e1.Modified)
2041  {
2042  DPRINT1("FIXME: Mark PFN as dirty\n");
2043  }
2044  }
2045 
2046  //
2047  // Not supported in ARM3
2048  //
2049  ASSERT(FoundVad->u.VadFlags.VadType != VadWriteWatch);
2050 
2051  //
2052  // Release the PFN lock, we are done
2053  //
2054  MiReleasePfnLock(OldIrql);
2055 }
#define TRUE
Definition: types.h:120
#define MM_NOACCESS
Definition: miarm.h:69
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:894
#define MM_NOCACHE
Definition: miarm.h:60
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:901
ULONG64 Dirty
Definition: mmtypes.h:164
UCHAR KIRQL
Definition: env_spec_w32.h:591
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
ULONG64 Valid
Definition: mmtypes.h:150
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:75
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:787
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define DPRINT1
Definition: precomp.h:8
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
FORCEINLINE VOID MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:930
VOID NTAPI KeFlushCurrentTb(VOID)
Definition: cpu.c:322
union _MMPTE::@2228 u

◆ MiGetExceptionInfo()

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

Definition at line 721 of file virtual.c.

Referenced by MiDoMappedCopy(), and MiDoPoolCopy().

724 {
725  PEXCEPTION_RECORD ExceptionRecord;
726  PAGED_CODE();
727 
728  //
729  // Assume default
730  //
731  *HaveBadAddress = FALSE;
732 
733  //
734  // Get the exception record
735  //
736  ExceptionRecord = ExceptionInfo->ExceptionRecord;
737 
738  //
739  // Look at the exception code
740  //
741  if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
742  (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
743  (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
744  {
745  //
746  // We can tell the address if we have more than one parameter
747  //
748  if (ExceptionRecord->NumberParameters > 1)
749  {
750  //
751  // Return the address
752  //
753  *HaveBadAddress = TRUE;
754  *BadAddress = ExceptionRecord->ExceptionInformation[1];
755  }
756  }
757 
758  //
759  // Continue executing the next handler
760  //
762 }
#define TRUE
Definition: types.h:120
#define STATUS_GUARD_PAGE_VIOLATION
Definition: ntstatus.h:170
#define PAGED_CODE()
Definition: video.h:57
DWORD ExceptionCode
Definition: compat.h:196
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]
Definition: compat.h:201
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:198
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:229
DWORD NumberParameters
Definition: compat.h:200

◆ MiGetPageProtection()

ULONG NTAPI MiGetPageProtection ( IN PMMPTE  PointerPte)

Definition at line 1329 of file virtual.c.

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

1330 {
1331  MMPTE TempPte;
1332  PMMPFN Pfn;
1334  PETHREAD CurrentThread;
1335  BOOLEAN WsSafe, WsShared;
1336  ULONG Protect;
1337  KIRQL OldIrql;
1338  PAGED_CODE();
1339 
1340  /* Copy this PTE's contents */
1341  TempPte = *PointerPte;
1342 
1343  /* Assure it's not totally zero */
1344  ASSERT(TempPte.u.Long);
1345 
1346  /* Check for a special prototype format */
1347  if ((TempPte.u.Soft.Valid == 0) &&
1348  (TempPte.u.Soft.Prototype == 1))
1349  {
1350  /* Check if the prototype PTE is not yet pointing to a PTE */
1351  if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
1352  {
1353  /* The prototype PTE contains the protection */
1354  return MmProtectToValue[TempPte.u.Soft.Protection];
1355  }
1356 
1357  /* Get a pointer to the underlying shared PTE */
1358  PointerPte = MiProtoPteToPte(&TempPte);
1359 
1360  /* Since the PTE we want to read can be paged out at any time, we need
1361  to release the working set lock first, so that it can be paged in */
1362  CurrentThread = PsGetCurrentThread();
1363  CurrentProcess = PsGetCurrentProcess();
1364  MiUnlockProcessWorkingSetForFault(CurrentProcess,
1365  CurrentThread,
1366  &WsSafe,
1367  &WsShared);
1368 
1369  /* Now read the PTE value */
1370  TempPte = *PointerPte;
1371 
1372  /* Check if that one is invalid */
1373  if (!TempPte.u.Hard.Valid)
1374  {
1375  /* We get the protection directly from this PTE */
1376  Protect = MmProtectToValue[TempPte.u.Soft.Protection];
1377  }
1378  else
1379  {
1380  /* The PTE is valid, so we might need to get the protection from
1381  the PFN. Lock the PFN database */
1382  OldIrql = MiAcquirePfnLock();
1383 
1384  /* Check if the PDE is still valid */
1385  if (MiAddressToPte(PointerPte)->u.Hard.Valid == 0)
1386  {
1387  /* It's not, make it valid */
1388  MiMakeSystemAddressValidPfn(PointerPte, OldIrql);
1389  }
1390 
1391  /* Now it's safe to read the PTE value again */
1392  TempPte = *PointerPte;
1393  ASSERT(TempPte.u.Long != 0);
1394 
1395  /* Check again if the PTE is invalid */
1396  if (!TempPte.u.Hard.Valid)
1397  {
1398  /* The PTE is not valid, so we can use it's protection field */
1399  Protect = MmProtectToValue[TempPte.u.Soft.Protection];
1400  }
1401  else
1402  {
1403  /* The PTE is valid, so we can find the protection in the
1404  OriginalPte field of the PFN */
1405  Pfn = MI_PFN_ELEMENT(TempPte.u.Hard.PageFrameNumber);
1406  Protect = MmProtectToValue[Pfn->OriginalPte.u.Soft.Protection];
1407  }
1408 
1409  /* Release the PFN database */
1410  MiReleasePfnLock(OldIrql);
1411  }
1412 
1413  /* Lock the working set again */
1414  MiLockProcessWorkingSetForFault(CurrentProcess,
1415  CurrentThread,
1416  WsSafe,
1417  WsShared);
1418 
1419  return Protect;
1420  }
1421 
1422  /* In the easy case of transition or demand zero PTE just return its protection */
1423  if (!TempPte.u.Hard.Valid) return MmProtectToValue[TempPte.u.Soft.Protection];
1424 
1425  /* If we get here, the PTE is valid, so look up the page in PFN database */
1426  Pfn = MiGetPfnEntry(TempPte.u.Hard.PageFrameNumber);
1427  if (!Pfn->u3.e1.PrototypePte)
1428  {
1429  /* Return protection of the original pte */
1430  ASSERT(Pfn->u4.AweAllocation == 0);
1432  }
1433 
1434  /* This is software PTE */
1435  DPRINT("Prototype PTE: %lx %p\n", TempPte.u.Hard.PageFrameNumber, Pfn);
1436  DPRINT("VA: %p\n", MiPteToAddress(&TempPte));
1437  DPRINT("Mask: %lx\n", TempPte.u.Soft.Protection);
1438  DPRINT("Mask2: %lx\n", Pfn->OriginalPte.u.Soft.Protection);
1439  return MmProtectToValue[TempPte.u.Soft.Protection];
1440 }
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
_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:214
ULONG_PTR AweAllocation
Definition: mm.h:353
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:220
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:894
GLenum GLclampf GLint GLenum GLuint GLenum GLenum GLsizei GLenum const GLvoid GLfloat GLfloat GLfloat GLfloat GLclampd GLint 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 GLboolean GLboolean GLboolean GLint GLenum GLsizei const GLvoid GLenum GLint GLenum GLint GLint GLsizei GLint GLenum GLint GLint GLint GLint GLsizei GLenum GLsizei const GLuint GLboolean GLenum GLenum GLint GLsizei GLenum GLsizei GLenum const GLvoid GLboolean const GLboolean GLenum const GLdouble * u
Definition: glfuncs.h:88
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:901
#define PAGED_CODE()
Definition: video.h:57
USHORT PrototypePte
Definition: mm.h:295
UCHAR KIRQL
Definition: env_spec_w32.h:591
MMPFNENTRY e1
Definition: mm.h:329
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define PsGetCurrentProcess
Definition: psfuncs.h:17
unsigned char BOOLEAN
PVOID FORCEINLINE MiPteToAddress(PMMPTE PointerPte)
Definition: mm.h:197
#define MiProtoPteToPte(x)
Definition: mm.h:246
void DPRINT(...)
Definition: polytest.cpp:61
ULONG64 Protection
Definition: mmtypes.h:88
union _MMPFN::@1722 u3
ULONG CurrentProcess
Definition: shell.c:125
FORCEINLINE VOID MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, OUT PBOOLEAN Safe, OUT PBOOLEAN Shared)
Definition: miarm.h:1287
ULONG64 Valid
Definition: mmtypes.h:150
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:75
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
FORCEINLINE PMMPFN MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
Definition: miarm.h:1393
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
ULONG64 PageFileHigh
Definition: mmtypes.h:93
Definition: mm.h:305
ULONG64 Prototype
Definition: mmtypes.h:89
ULONG64 Valid
Definition: mmtypes.h:86
const ULONG MmProtectToValue[32]
Definition: page.c:81
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:933
ULONG_PTR Long
Definition: mmtypes.h:215
FORCEINLINE VOID MiLockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, IN BOOLEAN Safe, IN BOOLEAN Shared)
Definition: miarm.h:1320
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
MMPTE OriginalPte
Definition: mm.h:339
union _MMPFN::@1725 u4
unsigned int ULONG
Definition: retypes.h:1
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
ULONG NTAPI MiMakeSystemAddressValidPfn(IN PVOID VirtualAddress, IN KIRQL OldIrql)
Definition: virtual.c:257
union _MMPTE::@2228 u

◆ MiIsEntireRangeCommitted()

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

Definition at line 1976 of file virtual.c.

Referenced by MiProtectVirtualMemory().

1980 {
1981  PMMPTE PointerPte, LastPte;
1982  PMMPDE PointerPde;
1983  BOOLEAN OnBoundary = TRUE;
1984  PAGED_CODE();
1985 
1986  /* Get the PDE and PTE addresses */
1987  PointerPde = MiAddressToPde(StartingAddress);
1988  PointerPte = MiAddressToPte(StartingAddress);
1989  LastPte = MiAddressToPte(EndingAddress);
1990 
1991  /* Loop all the PTEs */
1992  while (PointerPte <= LastPte)
1993  {
1994  /* Check if we've hit an new PDE boundary */
1995  if (OnBoundary)
1996  {
1997  /* Is this PDE demand zero? */
1998  PointerPde = MiPteToPde(PointerPte);
1999  if (PointerPde->u.Long != 0)
2000  {
2001  /* It isn't -- is it valid? */
2002  if (PointerPde->u.Hard.Valid == 0)
2003  {
2004  /* Nope, fault it in */
2005  MiMakeSystemAddressValid(PointerPte, Process);
2006  }
2007  }
2008  else
2009  {
2010  /* The PTE was already valid, so move to the next one */
2011  PointerPde++;
2012  PointerPte = MiPdeToPte(PointerPde);
2013 
2014  /* Is the entire VAD committed? If not, fail */
2015  if (!Vad->u.VadFlags.MemCommit) return FALSE;
2016 
2017  /* New loop iteration with our new, on-boundary PTE. */
2018  continue;
2019  }
2020  }
2021 
2022  /* Is the PTE demand zero? */
2023  if (PointerPte->u.Long == 0)
2024  {
2025  /* Is the entire VAD committed? If not, fail */
2026  if (!Vad->u.VadFlags.MemCommit) return FALSE;
2027  }
2028  else
2029  {
2030  /* It isn't -- is it a decommited, invalid, or faulted PTE? */
2031  if ((PointerPte->u.Soft.Protection == MM_DECOMMIT) &&
2032  (PointerPte->u.Hard.Valid == 0) &&
2033  ((PointerPte->u.Soft.Prototype == 0) ||
2034  (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
2035  {
2036  /* Then part of the range is decommitted, so fail */
2037  return FALSE;
2038  }
2039  }
2040 
2041  /* Move to the next PTE */
2042  PointerPte++;
2043  OnBoundary = MiIsPteOnPdeBoundary(PointerPte);
2044  }
2045 
2046  /* All PTEs seem valid, and no VAD checks failed, the range is okay */
2047  return TRUE;
2048 }
ULONG NTAPI MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress, IN PEPROCESS CurrentProcess)
Definition: virtual.c:205
#define TRUE
Definition: types.h:120
#define MiAddressToPde(x)
Definition: mmx86.c:20
#define MM_DECOMMIT
Definition: miarm.h:68
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:220
#define PAGED_CODE()
Definition: video.h:57
#define MiAddressToPte(x)
Definition: mmx86.c:19
unsigned char BOOLEAN
ULONG64 Protection
Definition: mmtypes.h:88
ULONG64 Valid
Definition: mmtypes.h:150
ULONG64 PageFileHigh
Definition: mmtypes.h:93
ULONG64 Prototype
Definition: mmtypes.h:89
ULONG_PTR Long
Definition: mmtypes.h:215
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define MiPteToPde(_Pte)
Definition: mm.h:232
#define MiPdeToPte(_Pde)
Definition: mm.h:231
#define MiIsPteOnPdeBoundary(PointerPte)
Definition: mm.h:236
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
union _MMPTE::@2228 u

◆ MiLockVirtualMemory()

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

Definition at line 3256 of file virtual.c.

Referenced by NtLockVirtualMemory(), and RunTest().

3260 {
3263  PVOID CurrentVa, EndAddress;
3264  PMMPTE PointerPte, LastPte;
3265  PMMPDE PointerPde;
3266 #if (_MI_PAGING_LEVELS >= 3)
3267  PMMPDE PointerPpe;
3268 #endif
3269 #if (_MI_PAGING_LEVELS == 4)
3270  PMMPDE PointerPxe;
3271 #endif
3272  PMMPFN Pfn1;
3273  NTSTATUS Status, TempStatus;
3274 
3275  /* Lock the address space */
3276  AddressSpace = MmGetCurrentAddressSpace();
3277  MmLockAddressSpace(AddressSpace);
3278 
3279  /* Make sure we still have an address space */
3280  CurrentProcess = PsGetCurrentProcess();
3281  if (CurrentProcess->VmDeleted)
3282  {
3284  goto Cleanup;
3285  }
3286 
3287  /* Check the VADs in the requested range */
3288  Status = MiCheckVadsForLockOperation(BaseAddress, RegionSize, &EndAddress);
3289  if (!NT_SUCCESS(Status))
3290  {
3291  goto Cleanup;
3292  }
3293 
3294  /* Enter SEH for probing */
3295  _SEH2_TRY
3296  {
3297  /* Loop all pages and probe them */
3298  CurrentVa = *BaseAddress;
3299  while (CurrentVa < EndAddress)
3300  {
3301  (void)(*(volatile CHAR*)CurrentVa);
3302  CurrentVa = (PUCHAR)CurrentVa + PAGE_SIZE;
3303  }
3304  }
3306  {
3307  Status = _SEH2_GetExceptionCode();
3308  goto Cleanup;
3309  }
3310  _SEH2_END;
3311 
3312  /* All pages were accessible, since we hold the address space lock, nothing
3313  can be de-committed. Assume success for now. */
3314  Status = STATUS_SUCCESS;
3315 
3316  /* Get the PTE and PDE */
3317  PointerPte = MiAddressToPte(*BaseAddress);
3318  PointerPde = MiAddressToPde(*BaseAddress);
3319 #if (_MI_PAGING_LEVELS >= 3)
3320  PointerPpe = MiAddressToPpe(*BaseAddress);
3321 #endif
3322 #if (_MI_PAGING_LEVELS == 4)
3323  PointerPxe = MiAddressToPxe(*BaseAddress);
3324 #endif
3325 
3326  /* Get the last PTE */
3327  LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3328 
3329  /* Lock the process working set */
3330  MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
3331 
3332  /* Loop the pages */
3333  do
3334  {
3335  /* Check for a page that is not accessible */
3336  while (
3337 #if (_MI_PAGING_LEVELS == 4)
3338  (PointerPxe->u.Hard.Valid == 0) ||
3339 #endif
3340 #if (_MI_PAGING_LEVELS >= 3)
3341  (PointerPpe->u.Hard.Valid == 0) ||
3342 #endif
3343  (PointerPde->u.Hard.Valid == 0) ||
3344  (PointerPte->u.Hard.Valid == 0))
3345  {
3346  /* Release process working set */
3347  MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
3348 
3349  /* Access the page */
3350  CurrentVa = MiPteToAddress(PointerPte);
3351 
3352  //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked
3353  TempStatus = MmAccessFault(TRUE, CurrentVa, KernelMode, (PVOID)(ULONG_PTR)0xBADBADA3BADBADA3ULL);
3354  if (!NT_SUCCESS(TempStatus))
3355  {
3356  // This should only happen, when remote backing storage is not accessible
3357  ASSERT(FALSE);
3358  Status = TempStatus;
3359  goto Cleanup;
3360  }
3361 
3362  /* Lock the process working set */
3363  MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
3364  }
3365 
3366  /* Get the PFN */
3367  Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3368  ASSERT(Pfn1 != NULL);
3369 
3370  /* Check the previous lock status */
3371  if (MI_IS_LOCKED_VA(Pfn1, MapType))
3372  {
3373  Status = STATUS_WAS_LOCKED;
3374  }
3375 
3376  /* Lock it */
3377  MI_LOCK_VA(Pfn1, MapType);
3378 
3379  /* Go to the next PTE */
3380  PointerPte++;
3381 
3382  /* Check if we're on a PDE boundary */
3383  if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3384 #if (_MI_PAGING_LEVELS >= 3)
3385  if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3386 #endif
3387 #if (_MI_PAGING_LEVELS == 4)
3388  if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3389 #endif
3390  } while (PointerPte <= LastPte);
3391 
3392  /* Release process working set */
3393  MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
3394 
3395 Cleanup:
3396  /* Unlock address space */
3397  MmUnlockAddressSpace(AddressSpace);
3398 
3399  return Status;
3400 }
#define _MI_PAGING_LEVELS
Definition: mm.h:6
#define TRUE
Definition: types.h:120
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:47
#define MiAddressToPde(x)
Definition: mmx86.c:20
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
NTSTATUS NTAPI MmAccessFault(IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
Definition: mmfault.c:204
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2268
unsigned char * PUCHAR
Definition: retypes.h:3
char CHAR
Definition: xmlstorage.h:175
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1410
LONG NTSTATUS
Definition: precomp.h:26
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1064
PMMPTE FORCEINLINE MiAddressToPpe(PVOID Address)
Definition: mm.h:150
_SEH2_TRY
Definition: create.c:4250
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define PsGetCurrentProcess
Definition: psfuncs.h:17
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
smooth NULL
Definition: ftsmooth.c:416
PVOID FORCEINLINE MiPteToAddress(PMMPTE PointerPte)
Definition: mm.h:197
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
ULONG VmDeleted
Definition: pstypes.h:1329
ULONG CurrentProcess
Definition: shell.c:125
static NTSTATUS MiCheckVadsForLockOperation(_Inout_ PVOID *BaseAddress, _Inout_ PSIZE_T RegionSize, _Inout_ PVOID *EndAddress)
Definition: virtual.c:3211
if(!(yy_init))
Definition: macro.lex.yy.c:717
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
ULONG64 Valid
Definition: mmtypes.h:150
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:488
#define MiIsPteOnPpeBoundary(PointerPte)
Definition: mm.h:238
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
Definition: mm.h:305
PMMPTE FORCEINLINE MiAddressToPxe(PVOID Address)
Definition: mm.h:160
#define PAGE_SIZE
Definition: env_spec_w32.h:49
static const WCHAR Cleanup[]
Definition: register.c:80
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:933
Status
Definition: gdiplustypes.h:24
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
_SEH2_END
Definition: create.c:4424
#define MiIsPteOnPdeBoundary(PointerPte)
Definition: mm.h:236
#define STATUS_WAS_LOCKED
Definition: ntstatus.h:139
__kernel_entry _Inout_ _Inout_ PSIZE_T RegionSize
Definition: mmfuncs.h:172
FORCEINLINE BOOLEAN MI_IS_LOCKED_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3152
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
return STATUS_SUCCESS
Definition: btrfs.c:2710
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1403
#define PFN_FROM_PTE(v)
Definition: mm.h:88
FORCEINLINE VOID MI_LOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3169
FORCEINLINE PMMSUPPORT MmGetCurrentAddressSpace(VOID)
Definition: mm.h:1425
#define MiIsPteOnPxeBoundary(PointerPte)
Definition: mm.h:240
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1134
union _MMPTE::@2228 u

◆ MiMakePdeExistAndMakeValid()

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

Definition at line 2371 of file virtual.c.

Referenced by MiDecommitPages(), MiMapLockedPagesInUserSpace(), MiProtectVirtualMemory(), MiQueryPageTableReferences(), MiSetProtectionOnSection(), and NtAllocateVirtualMemory().

2374 {
2375  PMMPTE PointerPte, PointerPpe, PointerPxe;
2376 
2377  //
2378  // Sanity checks. The latter is because we only use this function with the
2379  // PFN lock not held, so it may go away in the future.
2380  //
2382  ASSERT(OldIrql == MM_NOIRQL);
2383 
2384  //
2385  // Also get the PPE and PXE. This is okay not to #ifdef because they will
2386  // return the same address as the PDE on 2-level page table systems.
2387  //
2388  // If everything is already valid, there is nothing to do.
2389  //
2390  PointerPpe = MiAddressToPte(PointerPde);
2391  PointerPxe = MiAddressToPde(PointerPde);
2392  if ((PointerPxe->u.Hard.Valid) &&
2393  (PointerPpe->u.Hard.Valid) &&
2394  (PointerPde->u.Hard.Valid))
2395  {
2396  return;
2397  }
2398 
2399  //
2400  // At least something is invalid, so begin by getting the PTE for the PDE itself
2401  // and then lookup each additional level. We must do it in this precise order
2402  // because the pagfault.c code (as well as in Windows) depends that the next
2403  // level up (higher) must be valid when faulting a lower level
2404  //
2405  PointerPte = MiPteToAddress(PointerPde);
2406  do
2407  {
2408  //
2409  // Make sure APCs continued to be disabled
2410  //
2412 
2413  //
2414  // First, make the PXE valid if needed
2415  //
2416  if (!PointerPxe->u.Hard.Valid)
2417  {
2418  MiMakeSystemAddressValid(PointerPpe, TargetProcess);
2419  ASSERT(PointerPxe->u.Hard.Valid == 1);
2420  }
2421 
2422  //
2423  // Next, the PPE
2424  //
2425  if (!PointerPpe->u.Hard.Valid)
2426  {
2427  MiMakeSystemAddressValid(PointerPde, TargetProcess);
2428  ASSERT(PointerPpe->u.Hard.Valid == 1);
2429  }
2430 
2431  //
2432  // And finally, make the PDE itself valid.
2433  //
2434  MiMakeSystemAddressValid(PointerPte, TargetProcess);
2435 
2436  //
2437  // This should've worked the first time so the loop is really just for
2438  // show -- ASSERT that we're actually NOT going to be looping.
2439  //
2440  ASSERT(PointerPxe->u.Hard.Valid == 1);
2441  ASSERT(PointerPpe->u.Hard.Valid == 1);
2442  ASSERT(PointerPde->u.Hard.Valid == 1);
2443  } while (!(PointerPxe->u.Hard.Valid) ||
2444  !(PointerPpe->u.Hard.Valid) ||
2445  !(PointerPde->u.Hard.Valid));
2446 }
ULONG NTAPI MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress, IN PEPROCESS CurrentProcess)
Definition: virtual.c:205
#define TRUE
Definition: types.h:120
#define MiAddressToPde(x)
Definition: mmx86.c:20
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
#define MiAddressToPte(x)
Definition: mmx86.c:19
PVOID FORCEINLINE MiPteToAddress(PMMPTE PointerPte)
Definition: mm.h:197
ULONG64 Valid
Definition: mmtypes.h:150
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define MM_NOIRQL
Definition: miarm.h:205
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
union _MMPTE::@2228 u

◆ MiMakeSystemAddressValid()

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

Definition at line 205 of file virtual.c.

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

207 {
209  BOOLEAN WsShared = FALSE, WsSafe = FALSE, LockChange = FALSE;
210  PETHREAD CurrentThread = PsGetCurrentThread();
211 
212  /* Must be a non-pool page table, since those are double-mapped already */
213  ASSERT(PageTableVirtualAddress > MM_HIGHEST_USER_ADDRESS);
214  ASSERT((PageTableVirtualAddress < MmPagedPoolStart) ||
215  (PageTableVirtualAddress > MmPagedPoolEnd));
216 
217  /* Working set lock or PFN lock should be held */
219 
220  /* Check if the page table is valid */
221  while (!MmIsAddressValid(PageTableVirtualAddress))
222  {
223  /* Release the working set lock */
225  CurrentThread,
226  &WsSafe,
227  &WsShared);
228 
229  /* Fault it in */
230  Status = MmAccessFault(FALSE, PageTableVirtualAddress, KernelMode, NULL);
231  if (!NT_SUCCESS(Status))
232  {
233  /* This should not fail */
234  KeBugCheckEx(KERNEL_DATA_INPAGE_ERROR,
235  1,
236  Status,
238  (ULONG_PTR)PageTableVirtualAddress);
239  }
240 
241  /* Lock the working set again */
243  CurrentThread,
244  WsSafe,
245  WsShared);
246 
247  /* This flag will be useful later when we do better locking */
248  LockChange = TRUE;
249  }
250 
251  /* Let caller know what the lock state is */
252  return LockChange;
253 }
#define MM_HIGHEST_USER_ADDRESS
Definition: armddk.h:17
#define TRUE
Definition: types.h:120
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
NTSTATUS NTAPI MmAccessFault(IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
Definition: mmfault.c:204
LONG NTSTATUS
Definition: precomp.h:26
PVOID MmPagedPoolEnd
Definition: init.c:26
uint32_t ULONG_PTR
Definition: typedefs.h:63
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
ULONG CurrentProcess
Definition: shell.c:125
FORCEINLINE VOID MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, OUT PBOOLEAN Safe, OUT PBOOLEAN Shared)
Definition: miarm.h:1287
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
BOOLEAN NTAPI MmIsAddressValid(IN PVOID VirtualAddress)
Definition: mmsup.c:174
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
Status
Definition: gdiplustypes.h:24
PVOID MmPagedPoolStart
Definition: miarm.h:554
FORCEINLINE VOID MiLockProcessWorkingSetForFault(IN PEPROCESS Process, IN PETHREAD Thread, IN BOOLEAN Safe, IN BOOLEAN Shared)
Definition: miarm.h:1320
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:107

◆ MiMakeSystemAddressValidPfn()

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

Definition at line 257 of file virtual.c.

Referenced by MiGetPageProtection(), MiQueryPageTableReferences(), and MiSegmentDelete().

259 {
261  BOOLEAN LockChange = FALSE;
262 
263  /* Must be e kernel address */
265 
266  /* Check if the page is valid */
268  {
269  /* Release the PFN database */
271 
272  /* Fault it in */
274  if (!NT_SUCCESS(Status))
275  {
276  /* This should not fail */
277  KeBugCheckEx(KERNEL_DATA_INPAGE_ERROR,
278  3,
279  Status,
280  0,
282  }
283 
284  /* This flag will be useful later when we do better locking */
285  LockChange = TRUE;
286 
287  /* Lock the PFN database */
289  }
290 
291  /* Let caller know what the lock state is */
292  return LockChange;
293 }
#define MM_HIGHEST_USER_ADDRESS
Definition: armddk.h:17
#define TRUE
Definition: types.h:120
NTSTATUS NTAPI MmAccessFault(IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
Definition: mmfault.c:204
LONG NTSTATUS
Definition: precomp.h:26
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:894
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:901
uint32_t ULONG_PTR
Definition: typedefs.h:63
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
BOOLEAN NTAPI MmIsAddressValid(IN PVOID VirtualAddress)
Definition: mmsup.c:174
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
_In_ ULONG _In_ BOOLEAN _Must_inspect_result_ PVOID * VirtualAddress
Definition: ndis.h:3773
Status
Definition: gdiplustypes.h:24
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:107

◆ MiProcessValidPteList()

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

Definition at line 2450 of file virtual.c.

Referenced by MiDecommitPages().

2452 {
2453  KIRQL OldIrql;
2454  ULONG i;
2455  MMPTE TempPte;
2456  PFN_NUMBER PageFrameIndex;
2457  PMMPFN Pfn1, Pfn2;
2458 
2459  //
2460  // Acquire the PFN lock and loop all the PTEs in the list
2461  //
2462  OldIrql = MiAcquirePfnLock();
2463  for (i = 0; i != Count; i++)
2464  {
2465  //
2466  // The PTE must currently be valid
2467  //
2468  TempPte = *ValidPteList[i];
2469  ASSERT(TempPte.u.Hard.Valid == 1);
2470 
2471  //
2472  // Get the PFN entry for the page itself, and then for its page table
2473  //
2474  PageFrameIndex = PFN_FROM_PTE(&TempPte);
2475  Pfn1 = MiGetPfnEntry(PageFrameIndex);
2476  Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
2477 
2478  //
2479  // Decrement the share count on the page table, and then on the page
2480  // itself
2481  //
2482  MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
2483  MI_SET_PFN_DELETED(Pfn1);
2484  MiDecrementShareCount(Pfn1, PageFrameIndex);
2485 
2486  //
2487  // Make the page decommitted
2488  //
2489  MI_WRITE_INVALID_PTE(ValidPteList[i], MmDecommittedPte);
2490  }
2491 
2492  //
2493  // All the PTEs have been dereferenced and made invalid, flush the TLB now
2494  // and then release the PFN lock
2495  //
2496  KeFlushCurrentTb();
2497  MiReleasePfnLock(OldIrql);
2498 }
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:894
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:901
UCHAR KIRQL
Definition: env_spec_w32.h:591
GLenum GLclampf GLint i
Definition: glfuncs.h:14
ULONG PFN_NUMBER
Definition: ke.h:8
VOID NTAPI MiDecrementShareCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1133
ULONG64 Valid
Definition: mmtypes.h:150
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:75
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
Definition: mm.h:305
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:933
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define MI_SET_PFN_DELETED(x)
Definition: miarm.h:163
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:945
ULONG_PTR PteFrame
Definition: mm.h:350
union _MMPFN::@1725 u4
unsigned int ULONG
Definition: retypes.h:1
MMPTE MmDecommittedPte
Definition: init.c:46
#define PFN_FROM_PTE(v)
Definition: mm.h:88
VOID NTAPI KeFlushCurrentTb(VOID)
Definition: cpu.c:322
union _MMPTE::@2228 u

◆ 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 2092 of file virtual.c.

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

2097 {
2099  PMMVAD Vad;
2101  ULONG_PTR StartingAddress, EndingAddress;
2102  PMMPTE PointerPte, LastPte;
2103  PMMPDE PointerPde;
2104  MMPTE PteContents;
2105  PMMPFN Pfn1;
2106  ULONG ProtectionMask, OldProtect;
2107  BOOLEAN Committed;
2111 
2112  /* Calculate base address for the VAD */
2113  StartingAddress = (ULONG_PTR)PAGE_ALIGN((*BaseAddress));
2114  EndingAddress = (((ULONG_PTR)*BaseAddress + *NumberOfBytesToProtect - 1) | (PAGE_SIZE - 1));
2115 
2116  /* Calculate the protection mask and make sure it's valid */
2117  ProtectionMask = MiMakeProtectionMask(NewAccessProtection);
2118  if (ProtectionMask == MM_INVALID_PROTECTION)
2119  {
2120  DPRINT1("Invalid protection mask\n");
2122  }
2123 
2124  /* Check for ROS specific memory area */
2125  MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, *BaseAddress);
2126  if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3))
2127  {
2128  /* Evil hack */
2130  BaseAddress,
2131  NumberOfBytesToProtect,
2132  NewAccessProtection,
2133  OldAccessProtection);
2134  }
2135 
2136  /* Lock the address space and make sure the process isn't already dead */
2137  AddressSpace = MmGetCurrentAddressSpace();
2138  MmLockAddressSpace(AddressSpace);
2139  if (Process->VmDeleted)
2140  {
2141  DPRINT1("Process is dying\n");
2143  goto FailPath;
2144  }
2145 
2146  /* Get the VAD for this address range, and make sure it exists */
2147  Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
2148  EndingAddress >> PAGE_SHIFT,
2149  &Process->VadRoot,
2150  (PMMADDRESS_NODE*)&Vad);
2151  if (Result != TableFoundNode)
2152  {
2153  DPRINT("Could not find a VAD for this allocation\n");
2155  goto FailPath;
2156  }
2157 
2158  /* Make sure the address is within this VAD's boundaries */
2159  if ((((ULONG_PTR)StartingAddress >> PAGE_SHIFT) < Vad->StartingVpn) ||
2160  (((ULONG_PTR)EndingAddress >> PAGE_SHIFT) > Vad->EndingVpn))
2161  {
2163  goto FailPath;
2164  }
2165 
2166  /* These kinds of VADs are not supported atm */
2167  if ((Vad->u.VadFlags.VadType == VadAwe) ||
2169  (Vad->u.VadFlags.VadType == VadLargePages))
2170  {
2171  DPRINT1("Illegal VAD for attempting to set protection\n");
2173  goto FailPath;
2174  }
2175 
2176  /* Check for a VAD whose protection can't be changed */
2177  if (Vad->u.VadFlags.NoChange == 1)
2178  {
2179  DPRINT1("Trying to change protection of a NoChange VAD\n");
2181  goto FailPath;
2182  }
2183 
2184  /* Is this section, or private memory? */
2185  if (Vad->u.VadFlags.PrivateMemory == 0)
2186  {
2187  /* Not yet supported */
2188  if (Vad->u.VadFlags.VadType == VadLargePageSection)
2189  {
2190  DPRINT1("Illegal VAD for attempting to set protection\n");
2192  goto FailPath;
2193  }
2194 
2195  /* Rotate VADs are not yet supported */
2196  if (Vad->u.VadFlags.VadType == VadRotatePhysical)
2197  {
2198  DPRINT1("Illegal VAD for attempting to set protection\n");
2200  goto FailPath;
2201  }
2202 
2203  /* Not valid on section files */
2204  if (NewAccessProtection & (PAGE_NOCACHE | PAGE_WRITECOMBINE))
2205  {
2206  /* Fail */
2207  DPRINT1("Invalid protection flags for section\n");
2208  Status = STATUS_INVALID_PARAMETER_4;
2209  goto FailPath;
2210  }
2211 
2212  /* Check if data or page file mapping protection PTE is compatible */
2213  if (!Vad->ControlArea->u.Flags.Image)
2214  {
2215  /* Not yet */
2216  DPRINT1("Fixme: Not checking for valid protection\n");
2217  }
2218 
2219  /* This is a section, and this is not yet supported */
2220  DPRINT1("Section protection not yet supported\n");
2221  OldProtect = 0;
2222  }
2223  else
2224  {
2225  /* Private memory, check protection flags */
2226  if ((NewAccessProtection & PAGE_WRITECOPY) ||
2227  (NewAccessProtection & PAGE_EXECUTE_WRITECOPY))
2228  {
2229  DPRINT1("Invalid protection flags for private memory\n");
2230  Status = STATUS_INVALID_PARAMETER_4;
2231  goto FailPath;
2232  }
2233 
2234  /* Lock the working set */
2236 
2237  /* Check if all pages in this range are committed */
2238  Committed = MiIsEntireRangeCommitted(StartingAddress,
2239  EndingAddress,
2240  Vad,
2241  Process);
2242  if (!Committed)
2243  {
2244  /* Fail */
2245  DPRINT1("The entire range is not committed\n");
2246  Status = STATUS_NOT_COMMITTED;
2248  goto FailPath;
2249  }
2250 
2251  /* Compute starting and ending PTE and PDE addresses */
2252  PointerPde = MiAddressToPde(StartingAddress);
2253  PointerPte = MiAddressToPte(StartingAddress);
2254  LastPte = MiAddressToPte(EndingAddress);
2255 
2256  /* Make this PDE valid */
2258 
2259  /* Save protection of the first page */
2260  if (PointerPte->u.Long != 0)
2261  {
2262  /* Capture the page protection and make the PDE valid */
2263  OldProtect = MiGetPageProtection(PointerPte);
2265  }
2266  else
2267  {
2268  /* Grab the old protection from the VAD itself */
2269  OldProtect = MmProtectToValue[Vad->u.VadFlags.Protection];
2270  }
2271 
2272  /* Loop all the PTEs now */
2273  while (PointerPte <= LastPte)
2274  {
2275  /* Check if we've crossed a PDE boundary and make the new PDE valid too */
2276  if (MiIsPteOnPdeBoundary(PointerPte))
2277  {
2278  PointerPde = MiPteToPde(PointerPte);
2280  }
2281 
2282  /* Capture the PTE and check if it was empty */
2283  PteContents = *PointerPte;
2284  if (PteContents.u.Long == 0)
2285  {
2286  /* This used to be a zero PTE and it no longer is, so we must add a
2287  reference to the pagetable. */
2289  }
2290 
2291  /* Check what kind of PTE we are dealing with */
2292  if (PteContents.u.Hard.Valid == 1)
2293  {
2294  /* Get the PFN entry */
2295  Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
2296 
2297  /* We don't support this yet */
2298  ASSERT(Pfn1->u3.e1.PrototypePte == 0);
2299 
2300  /* Check if the page should not be accessible at all */
2301  if ((NewAccessProtection & PAGE_NOACCESS) ||
2302  (NewAccessProtection & PAGE_GUARD))
2303  {
2305 
2306  /* Mark the PTE as transition and change its protection */
2307  PteContents.u.Hard.Valid = 0;
2308  PteContents.u.Soft.Transition = 1;
2309  PteContents.u.Trans.Protection = ProtectionMask;
2310  /* Decrease PFN share count and write the PTE */
2311  MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
2312  // FIXME: remove the page from the WS
2313  MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2314 #ifdef CONFIG_SMP
2315  // FIXME: Should invalidate entry in every CPU TLB
2316  ASSERT(FALSE);
2317 #endif
2318  KeInvalidateTlbEntry(MiPteToAddress(PointerPte));
2319 
2320  /* We are done for this PTE */
2321  MiReleasePfnLock(OldIrql);
2322  }
2323  else
2324  {
2325  /* Write the protection mask and write it with a TLB flush */
2326  Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
2327  MiFlushTbAndCapture(Vad,
2328  PointerPte,
2329  ProtectionMask,
2330  Pfn1,
2331  TRUE);
2332  }
2333  }
2334  else
2335  {
2336  /* We don't support these cases yet */
2337  ASSERT(PteContents.u.Soft.Prototype == 0);
2338  //ASSERT(PteContents.u.Soft.Transition == 0);
2339 
2340  /* The PTE is already demand-zero, just update the protection mask */
2341  PteContents.u.Soft.Protection = ProtectionMask;
2342  MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2343  ASSERT(PointerPte->u.Long != 0);
2344  }
2345 
2346  /* Move to the next PTE */
2347  PointerPte++;
2348  }
2349 
2350  /* Unlock the working set */
2352  }
2353 
2354  /* Unlock the address space */
2355  MmUnlockAddressSpace(AddressSpace);
2356 
2357  /* Return parameters and success */
2358  *NumberOfBytesToProtect = EndingAddress - StartingAddress + 1;
2359  *BaseAddress = (PVOID)StartingAddress;
2360  *OldAccessProtection = OldProtect;
2361  return STATUS_SUCCESS;
2362 
2363 FailPath:
2364  /* Unlock the address space and return the failure code */
2365  MmUnlockAddressSpace(AddressSpace);
2366  return Status;
2367 }
#define PAGE_NOCACHE
Definition: nt_native.h:1311
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define MM_INVALID_PROTECTION
Definition: miarm.h:71
#define TRUE
Definition: types.h:120
ULONG Type
Definition: mm.h:214
FORCEINLINE VOID MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1179
#define MiAddressToPde(x)
Definition: mmx86.c:20
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define PAGE_GUARD
Definition: nt_native.h:1310
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2268
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1410
enum _TABLE_SEARCH_RESULT TABLE_SEARCH_RESULT
LONG NTSTATUS
Definition: precomp.h:26
FORCEINLINE KIRQL MiAcquirePfnLock(VOID)
Definition: mm.h:894
union _MMVAD::@2488 u
ULONG_PTR Protection
Definition: mmtypes.h:697
PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress(PMMSUPPORT AddressSpace, PVOID Address)
Definition: marea.c:60
ULONG NTAPI MiGetPageProtection(IN PMMPTE PointerPte)
Definition: virtual.c:1329
ULONG_PTR NoChange
Definition: mmtypes.h:694
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:735
FORCEINLINE VOID MiReleasePfnLock(_In_ KIRQL OldIrql)
Definition: mm.h:901
VOID NTAPI MiMakePdeExistAndMakeValid(IN PMMPDE PointerPde, IN PEPROCESS TargetProcess, IN KIRQL OldIrql)
Definition: virtual.c:2371
uint32_t ULONG_PTR
Definition: typedefs.h:63
USHORT PrototypePte
Definition: mm.h:295
UCHAR KIRQL
Definition: env_spec_w32.h:591
MMPFNENTRY e1
Definition: mm.h:329
ULONG_PTR EndingVpn
Definition: mmtypes.h:731
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define PAGE_EXECUTE_WRITECOPY
Definition: nt_native.h:1309
#define MEMORY_AREA_OWNED_BY_ARM3
Definition: mm.h:73
PCONTROL_AREA ControlArea
Definition: mmtypes.h:737
#define PAGE_NOACCESS
Definition: nt_native.h:1302
unsigned char BOOLEAN
PVOID FORCEINLINE MiPteToAddress(PMMPTE PointerPte)
Definition: mm.h:197
_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:426
void DPRINT(...)
Definition: polytest.cpp:61
VOID NTAPI MiDecrementShareCount(IN PMMPFN Pfn1, IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:1133
ULONG64 Protection
Definition: mmtypes.h:88
ULONG_PTR StartingVpn
Definition: mmtypes.h:730
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:78
BOOLEAN NTAPI MiIsEntireRangeCommitted(IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
Definition: virtual.c:1976
union _MMPFN::@1722 u3
FORCEINLINE VOID MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1109
FORCEINLINE VOID KeInvalidateTlbEntry(IN PVOID Address)
Definition: ke.h:201
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
ULONG_PTR PrivateMemory
Definition: mmtypes.h:699
MMPTE_TRANSITION Trans
Definition: mmtypes.h:220
ULONG64 Valid
Definition: mmtypes.h:150
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:488
#define PAGE_ALIGN(Va)
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
VOID NTAPI MiFlushTbAndCapture(IN PMMVAD FoundVad, IN PMMPTE PointerPte, IN ULONG ProtectionMask, IN PMMPFN Pfn1, IN BOOLEAN CaptureDirtyBit)
Definition: section.c:1958
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define MM_NOIRQL
Definition: miarm.h:205
ULONG NTAPI MiMakeProtectionMask(IN ULONG Protect)
Definition: section.c:159
Definition: mm.h:305
static PVOID
Definition: virtual.c:33
ULONG64 Prototype
Definition: mmtypes.h:89
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define STATUS_INVALID_PAGE_PROTECTION
Definition: ntstatus.h:291
const ULONG MmProtectToValue[32]
Definition: page.c:81
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:933
Status
Definition: gdiplustypes.h:24
ULONG_PTR Long
Definition: mmtypes.h:215
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define MiPteToPde(_Pte)
Definition: mm.h:232
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:945
#define PAGE_WRITECOMBINE
Definition: mmtypes.h:78
#define MiIsPteOnPdeBoundary(PointerPte)
Definition: mm.h:236
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:2052
ULONG64 Transition
Definition: mmtypes.h:90
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
MMPTE OriginalPte
Definition: mm.h:339
#define PAGE_WRITECOPY
Definition: nt_native.h:1305
#define STATUS_NOT_COMMITTED
Definition: ntstatus.h:268
#define DPRINT1
Definition: precomp.h:8
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
FORCEINLINE VOID MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:1637
MMSECTION_FLAGS Flags
Definition: mmtypes.h:523
unsigned int ULONG
Definition: retypes.h:1
#define ULONG_PTR
Definition: config.h:101
union _CONTROL_AREA::@2481 u
#define STATUS_INVALID_PARAMETER_4
Definition: ntstatus.h:464
#define STATUS_CONFLICTING_ADDRESSES
Definition: ntstatus.h:247
return STATUS_SUCCESS
Definition: btrfs.c:2710
struct _MEMORY_AREA * MemoryArea
Definition: newmm.h:65
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1403
#define PFN_FROM_PTE(v)
Definition: mm.h:88
ULONG64 Protection
Definition: mmtypes.h:103
ULONG_PTR VadType
Definition: mmtypes.h:695
FORCEINLINE PMMSUPPORT MmGetCurrentAddressSpace(VOID)
Definition: mm.h:1425
union _MMPTE::@2228 u

◆ MiQueryAddressState()

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

Definition at line 1444 of file virtual.c.

Referenced by MiQueryMemoryBasicInformation().

1449 {
1450 
1451  PMMPTE PointerPte, ProtoPte;
1452  PMMPDE PointerPde;
1453 #if (_MI_PAGING_LEVELS >= 3)
1454  PMMPPE PointerPpe;
1455 #endif
1456 #if (_MI_PAGING_LEVELS >= 4)
1457  PMMPXE PointerPxe;
1458 #endif
1459  MMPTE TempPte, TempProtoPte;
1460  BOOLEAN DemandZeroPte = TRUE, ValidPte = FALSE;
1461  ULONG State = MEM_RESERVE, Protect = 0;
1462  ASSERT((Vad->StartingVpn <= ((ULONG_PTR)Va >> PAGE_SHIFT)) &&
1463  (Vad->EndingVpn >= ((ULONG_PTR)Va >> PAGE_SHIFT)));
1464 
1465  /* Only normal VADs supported */
1466  ASSERT(Vad->u.VadFlags.VadType == VadNone);
1467 
1468  /* Get the PDE and PTE for the address */
1469  PointerPde = MiAddressToPde(Va);
1470  PointerPte = MiAddressToPte(Va);
1471 #if (_MI_PAGING_LEVELS >= 3)
1472  PointerPpe = MiAddressToPpe(Va);
1473 #endif
1474 #if (_MI_PAGING_LEVELS >= 4)
1475  PointerPxe = MiAddressToPxe(Va);
1476 #endif
1477 
1478  /* Return the next range */
1479  *NextVa = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
1480 
1481  do
1482  {
1483 #if (_MI_PAGING_LEVELS >= 4)
1484  /* Does the PXE exist? */
1485  if (PointerPxe->u.Long == 0)
1486  {
1487  /* It does not, next range starts at the next PXE */
1488  *NextVa = MiPxeToAddress(PointerPxe + 1);
1489  break;
1490  }
1491 
1492  /* Is the PXE valid? */
1493  if (PointerPxe->u.Hard.Valid == 0)
1494  {
1495  /* Is isn't, fault it in (make the PPE accessible) */
1496  MiMakeSystemAddressValid(PointerPpe, TargetProcess);
1497  }
1498 #endif
1499 #if (_MI_PAGING_LEVELS >= 3)
1500  /* Does the PPE exist? */
1501  if (PointerPpe->u.Long == 0)
1502  {
1503  /* It does not, next range starts at the next PPE */
1504  *NextVa = MiPpeToAddress(PointerPpe + 1);
1505  break;
1506  }
1507 
1508  /* Is the PPE valid? */
1509  if (PointerPpe->u.Hard.Valid == 0)
1510  {
1511  /* Is isn't, fault it in (make the PDE accessible) */
1512  MiMakeSystemAddressValid(PointerPde, TargetProcess);
1513  }
1514 #endif
1515 
1516  /* Does the PDE exist? */
1517  if (PointerPde->u.Long == 0)
1518  {
1519  /* It does not, next range starts at the next PDE */
1520  *NextVa = MiPdeToAddress(PointerPde + 1);
1521  break;
1522  }
1523 
1524  /* Is the PDE valid? */
1525  if (PointerPde->u.Hard.Valid == 0)
1526  {
1527  /* Is isn't, fault it in (make the PTE accessible) */
1528  MiMakeSystemAddressValid(PointerPte, TargetProcess);
1529  }
1530 
1531  /* We have a PTE that we can access now! */
1532  ValidPte = TRUE;
1533 
1534  } while (FALSE);
1535 
1536  /* Is it safe to try reading the PTE? */
1537  if (ValidPte)
1538  {
1539  /* FIXME: watch out for large pages */
1540  ASSERT(PointerPde->u.Hard.LargePage == FALSE);
1541 
1542  /* Capture the PTE */
1543  TempPte = *PointerPte;
1544  if (TempPte.u.Long != 0)
1545  {
1546  /* The PTE is valid, so it's not zeroed out */
1547  DemandZeroPte = FALSE;
1548 
1549  /* Is it a decommited, invalid, or faulted PTE? */
1550  if ((TempPte.u.Soft.Protection == MM_DECOMMIT) &&
1551  (TempPte.u.Hard.Valid == 0) &&
1552  ((TempPte.u.Soft.Prototype == 0) ||
1553  (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
1554  {
1555  /* Otherwise our defaults should hold */
1556  ASSERT(Protect == 0);
1557  ASSERT(State == MEM_RESERVE);
1558  }
1559  else
1560  {
1561  /* This means it's committed */
1562  State = MEM_COMMIT;
1563 
1564  /* We don't support these */
1565  ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
1566  ASSERT(Vad->u.VadFlags.VadType != VadRotatePhysical);
1567  ASSERT(Vad->u.VadFlags.VadType != VadAwe);
1568 
1569  /* Get protection state of this page */
1570  Protect = MiGetPageProtection(PointerPte);
1571 
1572  /* Check if this is an image-backed VAD */
1573  if ((TempPte.u.Soft.Valid == 0) &&
1574  (TempPte.u.Soft.Prototype == 1) &&
1575  (Vad->u.VadFlags.PrivateMemory == 0) &&
1576  (Vad->ControlArea))
1577  {
1578  DPRINT1("Not supported\n");
1579  ASSERT(FALSE);
1580  }
1581  }
1582  }
1583  }
1584 
1585  /* Check if this was a demand-zero PTE, since we need to find the state */
1586  if (DemandZeroPte)
1587  {
1588  /* Not yet handled */
1589  ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
1590  ASSERT(Vad->u.VadFlags.VadType != VadAwe);
1591 
1592  /* Check if this is private commited memory, or an section-backed VAD */
1593  if ((Vad->u.VadFlags.PrivateMemory == 0) && (Vad->ControlArea))
1594  {
1595  /* Tell caller about the next range */
1596  *NextVa = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
1597 
1598  /* Get the prototype PTE for this VAD */
1599  ProtoPte = MI_GET_PROTOTYPE_PTE_FOR_VPN(Vad,
1600  (ULONG_PTR)Va >> PAGE_SHIFT);
1601  if (ProtoPte)
1602  {
1603  /* We should unlock the working set, but it's not being held! */
1604 
1605  /* Is the prototype PTE actually valid (committed)? */
1606  TempProtoPte = *ProtoPte;
1607  if (TempProtoPte.u.Long)
1608  {
1609  /* Unless this is a memory-mapped file, handle it like private VAD */
1610  State = MEM_COMMIT;
1611  ASSERT(Vad->u.VadFlags.VadType != VadImageMap);
1612  Protect = MmProtectToValue[Vad->u.VadFlags.Protection];
1613  }
1614 
1615  /* We should re-lock the working set */
1616  }
1617  }
1618  else if (Vad->u.VadFlags.MemCommit)
1619  {
1620  /* This is committed memory */
1621  State = MEM_COMMIT;
1622 
1623  /* Convert the protection */
1624  Protect = MmProtectToValue[Vad->u.VadFlags.Protection];
1625  }
1626  }
1627 
1628  /* Return the protection code */
1629  *ReturnedProtect = Protect;
1630  return State;
1631 }
ULONG NTAPI MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress, IN PEPROCESS CurrentProcess)
Definition: virtual.c:205
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define TRUE
Definition: types.h:120
#define MiAddressToPde(x)
Definition: mmx86.c:20
_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:214
#define MM_DECOMMIT
Definition: miarm.h:68
PVOID FORCEINLINE MiPpeToAddress(PMMPTE PointerPpe)
Definition: mm.h:215
PVOID FORCEINLINE MiPxeToAddress(PMMPTE PointerPxe)
Definition: mm.h:224
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:220
PMMPTE FORCEINLINE MiAddressToPpe(PVOID Address)
Definition: mm.h:150
ULONG NTAPI MiGetPageProtection(IN PMMPTE PointerPte)
Definition: virtual.c:1329
#define MEM_COMMIT
Definition: nt_native.h:1313
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define MEM_RESERVE
Definition: nt_native.h:1314
unsigned char BOOLEAN
ULONG64 Protection
Definition: mmtypes.h:88
PVOID FORCEINLINE MiPdeToAddress(PMMPTE PointerPde)
Definition: mm.h:206
ULONG64 Valid
Definition: mmtypes.h:150
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:75
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
ULONG64 PageFileHigh
Definition: mmtypes.h:93
static PVOID
Definition: virtual.c:33
PMMPTE FORCEINLINE MiAddressToPxe(PVOID Address)
Definition: mm.h:160
ULONG64 Prototype
Definition: mmtypes.h:89
#define PAGE_SIZE
Definition: env_spec_w32.h:49
ULONG64 Valid
Definition: mmtypes.h:86
const ULONG MmProtectToValue[32]
Definition: page.c:81
ULONG_PTR Long
Definition: mmtypes.h:215
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
enum State_ State
Definition: pofuncs.h:54
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
ULONG64 LargePage
Definition: mmtypes.h:165
MMPTE DemandZeroPte
Definition: init.c:39
FORCEINLINE PMMPTE MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad, IN ULONG_PTR Vpn)
Definition: miarm.h:1376
union _MMPTE::@2228 u

◆ MiQueryMemoryBasicInformation()

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

Definition at line 1635 of file virtual.c.

Referenced by NtQueryVirtualMemory().

1640 {
1641  PEPROCESS TargetProcess;
1643  PMMVAD Vad = NULL;
1644  PVOID Address, NextAddress;
1645  BOOLEAN Found = FALSE;
1646  ULONG NewProtect, NewState;
1647  ULONG_PTR BaseVpn;
1648  MEMORY_BASIC_INFORMATION MemoryInfo;
1653 
1654  /* Check for illegal addresses in user-space, or the shared memory area */
1657  {
1658  Address = PAGE_ALIGN(BaseAddress);
1659 
1660  /* Make up an info structure describing this range */
1661  MemoryInfo.BaseAddress = Address;
1662  MemoryInfo.AllocationProtect = PAGE_READONLY;
1663  MemoryInfo.Type = MEM_PRIVATE;
1664 
1665  /* Special case for shared data */
1666  if (Address == (PVOID)MM_SHARED_USER_DATA_VA)
1667  {
1668  MemoryInfo.AllocationBase = (PVOID)MM_SHARED_USER_DATA_VA;
1669  MemoryInfo.State = MEM_COMMIT;
1670  MemoryInfo.Protect = PAGE_READONLY;
1671  MemoryInfo.RegionSize = PAGE_SIZE;
1672  }
1673  else
1674  {
1675  MemoryInfo.AllocationBase = (PCHAR)MM_HIGHEST_VAD_ADDRESS + 1;
1676  MemoryInfo.State = MEM_RESERVE;
1677  MemoryInfo.Protect = PAGE_NOACCESS;
1679  }
1680 
1681  /* Return the data, NtQueryInformation already probed it*/
1682  if (PreviousMode != KernelMode)
1683  {
1684  _SEH2_TRY
1685  {
1686  *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1688  }
1690  {
1691  Status = _SEH2_GetExceptionCode();
1692  }
1693  _SEH2_END;
1694  }
1695  else
1696  {
1697  *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1699  }
1700 
1701  return Status;
1702  }
1703 
1704  /* Check if this is for a local or remote process */
1706  {
1707  TargetProcess = PsGetCurrentProcess();
1708  }
1709  else
1710  {
1711  /* Reference the target process */
1714  PsProcessType,
1716  (PVOID*)&TargetProcess,
1717  NULL);
1718  if (!NT_SUCCESS(Status)) return Status;
1719 
1720  /* Attach to it now */
1721  KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
1722  }
1723 
1724  /* Lock the address space and make sure the process isn't already dead */
1725  MmLockAddressSpace(&TargetProcess->Vm);
1726  if (TargetProcess->VmDeleted)
1727  {
1728  /* Unlock the address space of the process */
1729  MmUnlockAddressSpace(&TargetProcess->Vm);
1730 
1731  /* Check if we were attached */
1733  {
1734  /* Detach and dereference the process */
1735  KeUnstackDetachProcess(&ApcState);
1736  ObDereferenceObject(TargetProcess);
1737  }
1738 
1739  /* Bail out */
1740  DPRINT1("Process is dying\n");
1742  }
1743 
1744  /* Loop the VADs */
1745  ASSERT(TargetProcess->VadRoot.NumberGenericTableElements);
1746  if (TargetProcess->VadRoot.NumberGenericTableElements)
1747  {
1748  /* Scan on the right */
1749  Vad = (PMMVAD)TargetProcess->VadRoot.BalancedRoot.RightChild;
1750  BaseVpn = (ULONG_PTR)BaseAddress >> PAGE_SHIFT;
1751  while (Vad)
1752  {
1753  /* Check if this VAD covers the allocation range */
1754  if ((BaseVpn >= Vad->StartingVpn) &&
1755  (BaseVpn <= Vad->EndingVpn))
1756  {
1757  /* We're done */
1758  Found = TRUE;
1759  break;
1760  }
1761 
1762  /* Check if this VAD is too high */
1763  if (BaseVpn < Vad->StartingVpn)
1764  {
1765  /* Stop if there is no left child */
1766  if (!Vad->LeftChild) break;
1767 
1768  /* Search on the left next */
1769  Vad = Vad->LeftChild;
1770  }
1771  else
1772  {
1773  /* Then this VAD is too low, keep searching on the right */
1774  ASSERT(BaseVpn > Vad->EndingVpn);
1775 
1776  /* Stop if there is no right child */
1777  if (!Vad->RightChild) break;
1778 
1779  /* Search on the right next */
1780  Vad = Vad->RightChild;
1781  }
1782  }
1783  }
1784 
1785  /* Was a VAD found? */
1786  if (!Found)
1787  {
1788  Address = PAGE_ALIGN(BaseAddress);
1789 
1790  /* Calculate region size */
1791  if (Vad)
1792  {
1793  if (Vad->StartingVpn >= BaseVpn)
1794  {
1795  /* Region size is the free space till the start of that VAD */
1796  MemoryInfo.RegionSize = (ULONG_PTR)(Vad->StartingVpn << PAGE_SHIFT) - (ULONG_PTR)Address;
1797  }
1798  else
1799  {
1800  /* Get the next VAD */
1801  Vad = (PMMVAD)MiGetNextNode((PMMADDRESS_NODE)Vad);
1802  if (Vad)
1803  {
1804  /* Region size is the free space till the start of that VAD */
1805  MemoryInfo.RegionSize = (ULONG_PTR)(Vad->StartingVpn << PAGE_SHIFT) - (ULONG_PTR)Address;
1806  }
1807  else
1808  {
1809  /* Maximum possible region size with that base address */
1810  MemoryInfo.RegionSize = (PCHAR)MM_HIGHEST_VAD_ADDRESS + 1 - (PCHAR)Address;
1811  }
1812  }
1813  }
1814  else
1815  {
1816  /* Maximum possible region size with that base address */
1817  MemoryInfo.RegionSize = (PCHAR)MM_HIGHEST_VAD_ADDRESS + 1 - (PCHAR)Address;
1818  }
1819 
1820  /* Unlock the address space of the process */
1821  MmUnlockAddressSpace(&TargetProcess->Vm);
1822 
1823  /* Check if we were attached */
1825  {
1826  /* Detach and derefernece the process */
1827  KeUnstackDetachProcess(&ApcState);
1828  ObDereferenceObject(TargetProcess);
1829  }
1830 
1831  /* Build the rest of the initial information block */
1832  MemoryInfo.BaseAddress = Address;
1833  MemoryInfo.AllocationBase = NULL;
1834  MemoryInfo.AllocationProtect = 0;
1835  MemoryInfo.State = MEM_FREE;
1836  MemoryInfo.Protect = PAGE_NOACCESS;
1837  MemoryInfo.Type = 0;
1838 
1839  /* Return the data, NtQueryInformation already probed it*/
1840  if (PreviousMode != KernelMode)
1841  {
1842  _SEH2_TRY
1843  {
1844  *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1846  }
1848  {
1849  Status = _SEH2_GetExceptionCode();
1850  }
1851  _SEH2_END;
1852  }
1853  else
1854  {
1855  *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1857  }
1858 
1859  return Status;
1860  }
1861 
1862  /* Set the correct memory type based on what kind of VAD this is */
1863  if ((Vad->u.VadFlags.PrivateMemory) ||
1864  (Vad->u.VadFlags.VadType == VadRotatePhysical))
1865  {
1866  MemoryInfo.Type = MEM_PRIVATE;
1867  }
1868  else if (Vad->u.VadFlags.VadType == VadImageMap)
1869  {
1870  MemoryInfo.Type = MEM_IMAGE;
1871  }
1872  else
1873  {
1874  MemoryInfo.Type = MEM_MAPPED;
1875  }
1876 
1877  /* Find the memory area the specified address belongs to */
1878  MemoryArea = MmLocateMemoryAreaByAddress(&TargetProcess->Vm, BaseAddress);
1879  ASSERT(MemoryArea != NULL);
1880 
1881  /* Determine information dependent on the memory area type */
1882  if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
1883  {
1884  Status = MmQuerySectionView(MemoryArea, BaseAddress, &MemoryInfo, &ResultLength);
1885  if (!NT_SUCCESS(Status))
1886  {
1887  DPRINT1("MmQuerySectionView failed. MemoryArea=%p (%p-%p), BaseAddress=%p\n",
1888  MemoryArea, MA_GetStartingAddress(MemoryArea), MA_GetEndingAddress(MemoryArea), BaseAddress);
1889  ASSERT(NT_SUCCESS(Status));
1890  }
1891  }
1892  else
1893  {
1894  /* Build the initial information block */
1895  Address = PAGE_ALIGN(BaseAddress);
1896  MemoryInfo.BaseAddress = Address;
1897  MemoryInfo.AllocationBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
1899  MemoryInfo.Type = MEM_PRIVATE;
1900 
1901  /* Acquire the working set lock (shared is enough) */
1903 
1904  /* Find the largest chunk of memory which has the same state and protection mask */
1905  MemoryInfo.State = MiQueryAddressState(Address,
1906  Vad,
1907  TargetProcess,
1908  &MemoryInfo.Protect,
1909  &NextAddress);
1910  Address = NextAddress;
1911  while (((ULONG_PTR)Address >> PAGE_SHIFT) <= Vad->EndingVpn)
1912  {
1913  /* Keep going unless the state or protection mask changed */
1914  NewState = MiQueryAddressState(Address, Vad, TargetProcess, &NewProtect, &NextAddress);
1915  if ((NewState != MemoryInfo.State) || (NewProtect != MemoryInfo.Protect)) break;
1916  Address = NextAddress;
1917  }
1918 
1919  /* Release the working set lock */
1921 
1922  /* Check if we went outside of the VAD */
1923  if (((ULONG_PTR)Address >> PAGE_SHIFT) > Vad->EndingVpn)
1924  {
1925  /* Set the end of the VAD as the end address */
1926  Address = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
1927  }
1928 
1929  /* Now that we know the last VA address, calculate the region size */
1930  MemoryInfo.RegionSize = ((ULONG_PTR)Address - (ULONG_PTR)MemoryInfo.BaseAddress);
1931  }
1932 
1933  /* Unlock the address space of the process */
1934  MmUnlockAddressSpace(&TargetProcess->Vm);
1935 
1936  /* Check if we were attached */
1938  {
1939  /* Detach and derefernece the process */
1940  KeUnstackDetachProcess(&ApcState);
1941  ObDereferenceObject(TargetProcess);
1942  }
1943 
1944  /* Return the data, NtQueryInformation already probed it */
1945  if (PreviousMode != KernelMode)
1946  {
1947  _SEH2_TRY
1948  {
1949  *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1951  }
1953  {
1954  Status = _SEH2_GetExceptionCode();
1955  }
1956  _SEH2_END;
1957  }
1958  else
1959  {
1960  *(PMEMORY_BASIC_INFORMATION)MemoryInformation = MemoryInfo;
1962  }
1963 
1964  /* All went well */
1965  DPRINT("Base: %p AllocBase: %p AllocProtect: %lx Protect: %lx "
1966  "State: %lx Type: %lx Size: %lx\n",
1967  MemoryInfo.BaseAddress, MemoryInfo.AllocationBase,
1968  MemoryInfo.AllocationProtect, MemoryInfo.Protect,
1969  MemoryInfo.State, MemoryInfo.Type, MemoryInfo.RegionSize);
1970 
1971  return Status;
1972 }
IN CINT OUT PVOID IN ULONG OUT PULONG ResultLength
Definition: conport.c:47
signed char * PCHAR
Definition: retypes.h:7
#define MM_HIGHEST_USER_ADDRESS
Definition: armddk.h:17
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define TRUE
Definition: types.h:120
#define MEM_IMAGE
Definition: mmtypes.h:88
KAPC_STATE
Definition: ketypes.h:1273
ULONG Type
Definition: mm.h:214
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:158
struct _MEMORY_BASIC_INFORMATION MEMORY_BASIC_INFORMATION
FORCEINLINE VOID MiUnlockProcessWorkingSetShared(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1155
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1410
LONG NTSTATUS
Definition: precomp.h:26
ULONG_PTR NumberGenericTableElements
Definition: mmtypes.h:669
union _MMVAD::@2488 u
KPROCESSOR_MODE NTAPI ExGetPreviousMode(VOID)
Definition: sysinfo.c:2964
ULONG_PTR Protection
Definition: mmtypes.h:697
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
#define MM_SHARED_USER_DATA_VA
Definition: mmtypes.h:48
PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress(PMMSUPPORT AddressSpace, PVOID Address)
Definition: marea.c:60
#define MEM_COMMIT
Definition: nt_native.h:1313
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:735
MMADDRESS_NODE BalancedRoot
Definition: mmtypes.h:663
_SEH2_TRY
Definition: create.c:4250
uint32_t ULONG_PTR
Definition: typedefs.h:63
ULONG_PTR EndingVpn
Definition: mmtypes.h:731
NTSTATUS NTAPI MmQuerySectionView(PMEMORY_AREA MemoryArea, PVOID Address, PMEMORY_BASIC_INFORMATION Info, PSIZE_T ResultLength)
Definition: section.c:2558
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:496
VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState)
Definition: procobj.c:701
struct _MMVAD * LeftChild
Definition: mmtypes.h:728
#define MEM_RESERVE
Definition: nt_native.h:1314
#define PsGetCurrentProcess
Definition: psfuncs.h:17
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define PAGE_NOACCESS
Definition: nt_native.h:1302
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
static WCHAR Address[46]
Definition: ping.c:68
void DPRINT(...)
Definition: polytest.cpp:61
return Found
Definition: dirsup.c:1270
ULONG_PTR StartingVpn
Definition: mmtypes.h:730
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:71
#define NtCurrentProcess()
Definition: nt_native.h:1657
#define PCHAR
Definition: match.c:90
#define MEM_FREE
Definition: nt_native.h:1317
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
ULONG VmDeleted
Definition: pstypes.h:1329
ULONG_PTR PrivateMemory
Definition: mmtypes.h:699
#define MEM_PRIVATE
Definition: nt_native.h:1318
struct _MEMORY_BASIC_INFORMATION * PMEMORY_BASIC_INFORMATION
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:488
#define PAGE_ALIGN(Va)
#define MA_GetEndingAddress(_MemoryArea)
Definition: mm.h:208
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
PMMADDRESS_NODE NTAPI MiGetNextNode(IN PMMADDRESS_NODE Node)
Definition: vadnode.c:467
struct _MMADDRESS_NODE * RightChild
Definition: mmtypes.h:653
FORCEINLINE VOID MiLockProcessWorkingSetShared(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1086
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
struct _MMVAD * RightChild
Definition: mmtypes.h:729
static PVOID
Definition: virtual.c:33
#define PAGE_SIZE
Definition: env_spec_w32.h:49
KPROCESS Pcb
Definition: pstypes.h:1193
const ULONG MmProtectToValue[32]
Definition: page.c:81
#define MA_GetStartingAddress(_MemoryArea)
Definition: mm.h:207
MMSUPPORT Vm
Definition: pstypes.h:1287
Status
Definition: gdiplustypes.h:24
ULONG NTAPI MiQueryAddressState(IN PVOID Va, IN PMMVAD Vad, IN PEPROCESS TargetProcess, OUT PULONG ReturnedProtect, OUT PVOID *NextVa)
Definition: virtual.c:1444
ULONG_PTR SIZE_T
Definition: typedefs.h:78
_SEH2_END
Definition: create.c:4424
VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
Definition: procobj.c:753
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1471
_Must_inspect_result_ _In_ ULONG NewProtect
Definition: mmfuncs.h:683
#define PAGE_READONLY
Definition: compat.h:127
#define MEM_MAPPED
Definition: nt_native.h:1319
#define DPRINT1
Definition: precomp.h:8
#define MM_HIGHEST_VAD_ADDRESS
Definition: mm.h:42
unsigned int ULONG
Definition: retypes.h:1
#define ULONG_PTR
Definition: config.h:101
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
_In_ HANDLE ProcessHandle
Definition: mmfuncs.h:403
return STATUS_SUCCESS
Definition: btrfs.c:2710
MM_AVL_TABLE VadRoot
Definition: pstypes.h:1384
struct _MEMORY_AREA * MemoryArea
Definition: newmm.h:65
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1403
struct _MMVAD * PMMVAD
POBJECT_TYPE PsProcessType
Definition: process.c:20
ULONG_PTR VadType
Definition: mmtypes.h:695

◆ 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 2052 of file virtual.c.

Referenced by MiProtectVirtualMemory(), and MiQueryPageTableReferences().

2057 {
2060  ULONG OldAccessProtection_;
2061  NTSTATUS Status;
2062 
2063  *NumberOfBytesToProtect = PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - PAGE_ROUND_DOWN(*BaseAddress);
2065 
2066  AddressSpace = &Process->Vm;
2067  MmLockAddressSpace(AddressSpace);
2068  MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
2069  if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
2070  {
2071  MmUnlockAddressSpace(AddressSpace);
2072  return STATUS_UNSUCCESSFUL;
2073  }
2074 
2075  if (OldAccessProtection == NULL) OldAccessProtection = &OldAccessProtection_;
2076 
2077  ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW);
2078  Status = MmProtectSectionView(AddressSpace,
2079  MemoryArea,
2080  *BaseAddress,
2081  *NumberOfBytesToProtect,
2082  NewAccessProtection,
2083  OldAccessProtection);
2084 
2085  MmUnlockAddressSpace(AddressSpace);
2086 
2087  return Status;
2088 }
ULONG Type
Definition: mm.h:214
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2268
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1410
LONG NTSTATUS
Definition: precomp.h:26
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress(PMMSUPPORT AddressSpace, PVOID Address)
Definition: marea.c:60
#define PAGE_ROUND_UP(x)
Definition: scsiport_int.h:13
uint32_t ULONG_PTR
Definition: typedefs.h:63
smooth NULL
Definition: ftsmooth.c:416
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:71
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
BOOLEAN DeleteInProgress
Definition: mm.h:217
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
static PVOID
Definition: virtual.c:33
Status
Definition: gdiplustypes.h:24
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
NTSTATUS NTAPI MmProtectSectionView(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PVOID BaseAddress, SIZE_T Length, ULONG Protect, PULONG OldProtect)
Definition: section.c:2522
unsigned int ULONG
Definition: retypes.h:1
struct _MEMORY_AREA * MemoryArea
Definition: newmm.h:65
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1403

◆ MiUnlockVirtualMemory()

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

Definition at line 3575 of file virtual.c.

Referenced by NtUnlockVirtualMemory().

3579 {
3582  PVOID EndAddress;
3583  PMMPTE PointerPte, LastPte;
3584  PMMPDE PointerPde;
3585 #if (_MI_PAGING_LEVELS >= 3)
3586  PMMPDE PointerPpe;
3587 #endif
3588 #if (_MI_PAGING_LEVELS == 4)
3589  PMMPDE PointerPxe;
3590 #endif
3591  PMMPFN Pfn1;
3592  NTSTATUS Status;
3593 
3594  /* Lock the address space */
3595  AddressSpace = MmGetCurrentAddressSpace();
3596  MmLockAddressSpace(AddressSpace);
3597 
3598  /* Make sure we still have an address space */
3599  CurrentProcess = PsGetCurrentProcess();
3600  if (CurrentProcess->VmDeleted)
3601  {
3603  goto Cleanup;
3604  }
3605 
3606  /* Check the VADs in the requested range */
3607  Status = MiCheckVadsForLockOperation(BaseAddress, RegionSize, &EndAddress);
3608 
3609  /* Note: only bail out, if we hit an area without a VAD. If we hit an
3610  incompatible VAD we continue, like Windows does */
3611  if (Status == STATUS_ACCESS_VIOLATION)
3612  {
3613  Status = STATUS_NOT_LOCKED;
3614  goto Cleanup;
3615  }
3616 
3617  /* Get the PTE and PDE */
3618  PointerPte = MiAddressToPte(*BaseAddress);
3619  PointerPde = MiAddressToPde(*BaseAddress);
3620 #if (_MI_PAGING_LEVELS >= 3)
3621  PointerPpe = MiAddressToPpe(*BaseAddress);
3622 #endif
3623 #if (_MI_PAGING_LEVELS == 4)
3624  PointerPxe = MiAddressToPxe(*BaseAddress);
3625 #endif
3626 
3627  /* Get the last PTE */
3628  LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3629 
3630  /* Lock the process working set */
3631  MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
3632 
3633  /* Loop the pages */
3634  do
3635  {
3636  /* Check for a page that is not present */
3637  if (
3638 #if (_MI_PAGING_LEVELS == 4)
3639  (PointerPxe->u.Hard.Valid == 0) ||
3640 #endif
3641 #if (_MI_PAGING_LEVELS >= 3)
3642  (PointerPpe->u.Hard.Valid == 0) ||
3643 #endif
3644  (PointerPde->u.Hard.Valid == 0) ||
3645  (PointerPte->u.Hard.Valid == 0))
3646  {
3647  /* Remember it, but keep going */
3648  Status = STATUS_NOT_LOCKED;
3649  }
3650  else
3651  {
3652  /* Get the PFN */
3653  Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3654  ASSERT(Pfn1 != NULL);
3655 
3656  /* Check if all of the requested locks are present */
3657  if (((MapType & MAP_SYSTEM) && !MI_IS_LOCKED_VA(Pfn1, MAP_SYSTEM)) ||
3658  ((MapType & MAP_PROCESS) && !MI_IS_LOCKED_VA(Pfn1, MAP_PROCESS)))
3659  {
3660  /* Remember it, but keep going */
3661  Status = STATUS_NOT_LOCKED;
3662 
3663  /* Check if no lock is present */
3664  if (!MI_IS_LOCKED_VA(Pfn1, MAP_PROCESS | MAP_SYSTEM))
3665  {
3666  DPRINT1("FIXME: Should remove the page from WS\n");
3667  }
3668  }
3669  }
3670 
3671  /* Go to the next PTE */
3672  PointerPte++;
3673 
3674  /* Check if we're on a PDE boundary */
3675  if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3676 #if (_MI_PAGING_LEVELS >= 3)
3677  if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3678 #endif
3679 #if (_MI_PAGING_LEVELS == 4)
3680  if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3681 #endif
3682  } while (PointerPte <= LastPte);
3683 
3684  /* Check if we hit a page that was not locked */
3685  if (Status == STATUS_NOT_LOCKED)
3686  {
3687  goto CleanupWithWsLock;
3688  }
3689 
3690  /* All pages in the region were locked, so unlock them all */
3691 
3692  /* Get the PTE and PDE */
3693  PointerPte = MiAddressToPte(*BaseAddress);
3694  PointerPde = MiAddressToPde(*BaseAddress);
3695 #if (_MI_PAGING_LEVELS >= 3)
3696  PointerPpe = MiAddressToPpe(*BaseAddress);
3697 #endif
3698 #if (_MI_PAGING_LEVELS == 4)
3699  PointerPxe = MiAddressToPxe(*BaseAddress);
3700 #endif
3701 
3702  /* Loop the pages */
3703  do
3704  {
3705  /* Unlock it */
3706  Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3707  MI_UNLOCK_VA(Pfn1, MapType);
3708 
3709  /* Go to the next PTE */
3710  PointerPte++;
3711 
3712  /* Check if we're on a PDE boundary */
3713  if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3714 #if (_MI_PAGING_LEVELS >= 3)
3715  if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3716 #endif
3717 #if (_MI_PAGING_LEVELS == 4)
3718  if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3719 #endif
3720  } while (PointerPte <= LastPte);
3721 
3722  /* Everything is done */
3723  Status = STATUS_SUCCESS;
3724 
3725 CleanupWithWsLock:
3726 
3727  /* Release process working set */
3728  MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
3729 
3730 Cleanup:
3731  /* Unlock address space */
3732  MmUnlockAddressSpace(AddressSpace);
3733 
3734  return Status;
3735 }
#define _MI_PAGING_LEVELS
Definition: mm.h:6
#define MiAddressToPde(x)
Definition: mmx86.c:20
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2268
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1410
LONG NTSTATUS
Definition: precomp.h:26
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1064
PMMPTE FORCEINLINE MiAddressToPpe(PVOID Address)
Definition: mm.h:150
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define PsGetCurrentProcess
Definition: psfuncs.h:17
smooth NULL
Definition: ftsmooth.c:416
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
ULONG VmDeleted
Definition: pstypes.h:1329
ULONG CurrentProcess
Definition: shell.c:125
static NTSTATUS MiCheckVadsForLockOperation(_Inout_ PVOID *BaseAddress, _Inout_ PSIZE_T RegionSize, _Inout_ PVOID *EndAddress)
Definition: virtual.c:3211
if(!(yy_init))
Definition: macro.lex.yy.c:717
ULONG64 Valid
Definition: mmtypes.h:150
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:488
#define MiIsPteOnPpeBoundary(PointerPte)
Definition: mm.h:238
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
Definition: mm.h:305
PMMPTE FORCEINLINE MiAddressToPxe(PVOID Address)
Definition: mm.h:160
static const WCHAR Cleanup[]
Definition: register.c:80
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:933
FORCEINLINE VOID MI_UNLOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3190
Status
Definition: gdiplustypes.h:24
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
#define MAP_PROCESS
Definition: mmtypes.h:67
#define MiIsPteOnPdeBoundary(PointerPte)
Definition: mm.h:236
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
__kernel_entry _Inout_ _Inout_ PSIZE_T RegionSize
Definition: mmfuncs.h:172
#define DPRINT1
Definition: precomp.h:8
FORCEINLINE BOOLEAN MI_IS_LOCKED_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3152
#define STATUS_NOT_LOCKED
Definition: ntstatus.h:265
return STATUS_SUCCESS
Definition: btrfs.c:2710
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1403
#define MAP_SYSTEM
Definition: mmtypes.h:68
#define PFN_FROM_PTE(v)
Definition: mm.h:88
FORCEINLINE PMMSUPPORT MmGetCurrentAddressSpace(VOID)
Definition: mm.h:1425
#define MiIsPteOnPxeBoundary(PointerPte)
Definition: mm.h:240
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1134
union _MMPTE::@2228 u

◆ 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 1242 of file virtual.c.

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

1249 {
1250  NTSTATUS Status;
1251  PEPROCESS Process = SourceProcess;
1252 
1253  //
1254  // Don't accept zero-sized buffers
1255  //
1256  if (!BufferSize) return STATUS_SUCCESS;
1257 
1258  //
1259  // If we are copying from ourselves, lock the target instead
1260  //
1261  if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess;
1262 
1263  //
1264  // Acquire rundown protection
1265  //
1266