ReactOS 0.4.16-dev-1007-g2e85425
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_opt_ 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)
 
VOID NTAPI MiMakePdeExistAndMakeValid (IN PMMPDE PointerPde, IN PEPROCESS TargetProcess, IN KIRQL OldIrql)
 
VOID NTAPI MiProcessValidPteList (IN PMMPTE *ValidPteList, IN ULONG Count)
 
ULONG NTAPI MiDecommitPages (IN PVOID StartingAddress, IN PMMPTE EndingPte, IN PEPROCESS Process, IN PMMVAD Vad)
 
PVOID NTAPI MmGetVirtualForPhysical (IN PHYSICAL_ADDRESS PhysicalAddress)
 
PVOID NTAPI MmSecureVirtualMemory (IN PVOID Address, IN SIZE_T Length, IN ULONG Mode)
 
VOID NTAPI MmUnsecureVirtualMemory (IN PVOID SecureMem)
 
NTSTATUS NTAPI NtReadVirtualMemory (IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN SIZE_T NumberOfBytesToRead, OUT PSIZE_T NumberOfBytesRead OPTIONAL)
 
NTSTATUS NTAPI NtWriteVirtualMemory (IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN PVOID Buffer, IN SIZE_T NumberOfBytesToWrite, OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
 
NTSTATUS NTAPI NtFlushInstructionCache (_In_ HANDLE ProcessHandle, _In_opt_ PVOID BaseAddress, _In_ SIZE_T FlushSize)
 
NTSTATUS NTAPI NtProtectVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *UnsafeBaseAddress, IN OUT SIZE_T *UnsafeNumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG UnsafeOldAccessProtection)
 
FORCEINLINE BOOLEAN MI_IS_LOCKED_VA (PMMPFN Pfn1, ULONG LockType)
 
FORCEINLINE VOID MI_LOCK_VA (PMMPFN Pfn1, ULONG LockType)
 
FORCEINLINE VOID MI_UNLOCK_VA (PMMPFN Pfn1, ULONG LockType)
 
static NTSTATUS MiCheckVadsForLockOperation (_Inout_ PVOID *BaseAddress, _Inout_ PSIZE_T RegionSize, _Inout_ PVOID *EndAddress)
 
static NTSTATUS MiLockVirtualMemory (IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
 
NTSTATUS NTAPI NtLockVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToLock, IN ULONG MapType)
 
static NTSTATUS MiUnlockVirtualMemory (IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
 
NTSTATUS NTAPI NtUnlockVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToUnlock, IN ULONG MapType)
 
NTSTATUS NTAPI NtFlushVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToFlush, OUT PIO_STATUS_BLOCK IoStatusBlock)
 
NTSTATUS NTAPI NtGetWriteWatch (IN HANDLE ProcessHandle, IN ULONG Flags, IN PVOID BaseAddress, IN SIZE_T RegionSize, IN PVOID *UserAddressArray, OUT PULONG_PTR EntriesInUserAddressArray, OUT PULONG Granularity)
 
NTSTATUS NTAPI NtResetWriteWatch (IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN SIZE_T RegionSize)
 
NTSTATUS NTAPI NtQueryVirtualMemory (IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN MEMORY_INFORMATION_CLASS MemoryInformationClass, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
 
NTSTATUS NTAPI NtAllocateVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *UBaseAddress, IN ULONG_PTR ZeroBits, IN OUT PSIZE_T URegionSize, IN ULONG AllocationType, IN ULONG Protect)
 
NTSTATUS NTAPI NtFreeVirtualMemory (IN HANDLE ProcessHandle, IN PVOID *UBaseAddress, IN PSIZE_T URegionSize, IN ULONG FreeType)
 
PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress (PVOID Address)
 

Macro Definition Documentation

◆ MI_MAPPED_COPY_PAGES

#define MI_MAPPED_COPY_PAGES   14

Definition at line 18 of file virtual.c.

◆ MI_MAX_TRANSFER_SIZE

#define MI_MAX_TRANSFER_SIZE   64 * 1024

Definition at line 20 of file virtual.c.

◆ MI_POOL_COPY_BYTES

#define MI_POOL_COPY_BYTES   512

Definition at line 19 of file virtual.c.

◆ MODULE_INVOLVED_IN_ARM3

#define MODULE_INVOLVED_IN_ARM3

Definition at line 15 of file virtual.c.

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file virtual.c.

Function Documentation

◆ MI_IS_LOCKED_VA()

FORCEINLINE BOOLEAN MI_IS_LOCKED_VA ( PMMPFN  Pfn1,
ULONG  LockType 
)

Definition at line 3237 of file virtual.c.

3240{
3241 // HACK until we have proper WSLIST support
3242 PMMWSLE Wsle = &Pfn1->Wsle;
3243
3244 if ((LockType & MAP_PROCESS) && (Wsle->u1.e1.LockedInWs))
3245 return TRUE;
3246 if ((LockType & MAP_SYSTEM) && (Wsle->u1.e1.LockedInMemory))
3247 return TRUE;
3248
3249 return FALSE;
3250}
_In_ WDFREQUEST _In_ MEDIA_LOCK_TYPE LockType
Definition: cdrom.h:1335
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define MAP_PROCESS
Definition: mmtypes.h:67
#define MAP_SYSTEM
Definition: mmtypes.h:68
MMWSLE Wsle
Definition: mm.h:445
ULONG_PTR LockedInMemory
Definition: mmtypes.h:829
ULONG_PTR LockedInWs
Definition: mmtypes.h:828
union _MMWSLE::@2713 u1
MMWSLENTRY e1
Definition: mmtypes.h:858

Referenced by MiLockVirtualMemory(), and MiUnlockVirtualMemory().

◆ MI_LOCK_VA()

FORCEINLINE VOID MI_LOCK_VA ( PMMPFN  Pfn1,
ULONG  LockType 
)

Definition at line 3254 of file virtual.c.

3257{
3258 // HACK until we have proper WSLIST support
3259 PMMWSLE Wsle = &Pfn1->Wsle;
3260
3261 if (!Wsle->u1.e1.LockedInWs &&
3262 !Wsle->u1.e1.LockedInMemory)
3263 {
3265 }
3266
3267 if (LockType & MAP_PROCESS)
3268 Wsle->u1.e1.LockedInWs = 1;
3269 if (LockType & MAP_SYSTEM)
3270 Wsle->u1.e1.LockedInMemory = 1;
3271}
FORCEINLINE VOID MiReferenceProbedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1700

Referenced by MiLockVirtualMemory().

◆ MI_UNLOCK_VA()

FORCEINLINE VOID MI_UNLOCK_VA ( PMMPFN  Pfn1,
ULONG  LockType 
)

Definition at line 3275 of file virtual.c.

3278{
3279 // HACK until we have proper WSLIST support
3280 PMMWSLE Wsle = &Pfn1->Wsle;
3281
3282 if (LockType & MAP_PROCESS)
3283 Wsle->u1.e1.LockedInWs = 0;
3284 if (LockType & MAP_SYSTEM)
3285 Wsle->u1.e1.LockedInMemory = 0;
3286
3287 if (!Wsle->u1.e1.LockedInWs &&
3288 !Wsle->u1.e1.LockedInMemory)
3289 {
3291 }
3292}
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1628

Referenced by MiUnlockVirtualMemory().

◆ MiCalculatePageCommitment()

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

Definition at line 42 of file virtual.c.

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

Referenced by NtFreeVirtualMemory().

◆ MiCheckVadsForLockOperation()

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

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

Definition at line 3296 of file virtual.c.

3301{
3302 PMMVAD Vad;
3303 PVOID CurrentVa;
3304
3305 /* Get the base address and align the start address */
3306 *EndAddress = (PUCHAR)*BaseAddress + *RegionSize;
3307 *EndAddress = ALIGN_UP_POINTER_BY(*EndAddress, PAGE_SIZE);
3309
3310 /* First loop and check all VADs */
3311 CurrentVa = *BaseAddress;
3312 while (CurrentVa < *EndAddress)
3313 {
3314 /* Get VAD */
3315 Vad = MiLocateAddress(CurrentVa);
3316 if (Vad == NULL)
3317 {
3320 }
3321
3322 /* Check VAD type */
3323 if ((Vad->u.VadFlags.VadType != VadNone) &&
3324 (Vad->u.VadFlags.VadType != VadImageMap) &&
3325 (Vad->u.VadFlags.VadType != VadWriteWatch))
3326 {
3327 *EndAddress = CurrentVa;
3328 *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3330 }
3331
3332 CurrentVa = (PVOID)((Vad->EndingVpn + 1) << PAGE_SHIFT);
3333 }
3334
3335 *RegionSize = (PUCHAR)*EndAddress - (PUCHAR)*BaseAddress;
3336 return STATUS_SUCCESS;
3337}
#define NULL
Definition: types.h:112
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
__kernel_entry _Inout_ _Inout_ PSIZE_T RegionSize
Definition: mmfuncs.h:172
@ VadWriteWatch
Definition: mmtypes.h:208
@ VadImageMap
Definition: mmtypes.h:206
@ VadNone
Definition: mmtypes.h:204
#define STATUS_INCOMPATIBLE_FILE_MAP
Definition: ntstatus.h:313
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
#define STATUS_SUCCESS
Definition: shellext.h:65
ULONG_PTR VadType
Definition: mmtypes.h:694
ULONG_PTR EndingVpn
Definition: mmtypes.h:730
union _MMVAD::@2703 u
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:734
void * PVOID
Definition: typedefs.h:50
unsigned char * PUCHAR
Definition: typedefs.h:53
#define ALIGN_UP_POINTER_BY(ptr, align)
Definition: umtypes.h:85
#define ALIGN_DOWN_POINTER_BY(ptr, align)
Definition: umtypes.h:82

Referenced by MiLockVirtualMemory(), and MiUnlockVirtualMemory().

◆ MiDecommitPages()

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

Definition at line 2587 of file virtual.c.

2591{
2592 PMMPTE PointerPte, CommitPte = NULL;
2593 PMMPDE PointerPde;
2594 ULONG CommitReduction = 0;
2595 PMMPTE ValidPteList[256];
2596 ULONG PteCount = 0;
2597 PMMPFN Pfn1;
2598 MMPTE PteContents;
2599 PETHREAD CurrentThread = PsGetCurrentThread();
2600
2601 //
2602 // Get the PTE and PTE for the address, and lock the working set
2603 // If this was a VAD for a MEM_COMMIT allocation, also figure out where the
2604 // commited range ends so that we can do the right accounting.
2605 //
2606 PointerPde = MiAddressToPde(StartingAddress);
2607 PointerPte = MiAddressToPte(StartingAddress);
2608 if (Vad->u.VadFlags.MemCommit) CommitPte = MiAddressToPte(Vad->EndingVpn << PAGE_SHIFT);
2609 MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
2610
2611 //
2612 // Make the PDE valid, and now loop through each page's worth of data
2613 //
2615 while (PointerPte <= EndingPte)
2616 {
2617 //
2618 // Check if we've crossed a PDE boundary
2619 //
2620 if (MiIsPteOnPdeBoundary(PointerPte))
2621 {
2622 //
2623 // Get the new PDE and flush the valid PTEs we had built up until
2624 // now. This helps reduce the amount of TLB flushing we have to do.
2625 // Note that Windows does a much better job using timestamps and
2626 // such, and does not flush the entire TLB all the time, but right
2627 // now we have bigger problems to worry about than TLB flushing.
2628 //
2629 PointerPde = MiAddressToPde(StartingAddress);
2630 if (PteCount)
2631 {
2632 MiProcessValidPteList(ValidPteList, PteCount);
2633 PteCount = 0;
2634 }
2635
2636 //
2637 // Make this PDE valid
2638 //
2640 }
2641
2642 //
2643 // Read this PTE. It might be active or still demand-zero.
2644 //
2645 PteContents = *PointerPte;
2646 if (PteContents.u.Long)
2647 {
2648 //
2649 // The PTE is active. It might be valid and in a working set, or
2650 // it might be a prototype PTE or paged out or even in transition.
2651 //
2652 if (PointerPte->u.Long == MmDecommittedPte.u.Long)
2653 {
2654 //
2655 // It's already decommited, so there's nothing for us to do here
2656 //
2657 CommitReduction++;
2658 }
2659 else
2660 {
2661 //
2662 // Remove it from the counters, and check if it was valid or not
2663 //
2664 //Process->NumberOfPrivatePages--;
2665 if (PteContents.u.Hard.Valid)
2666 {
2667 //
2668 // It's valid. At this point make sure that it is not a ROS
2669 // PFN. Also, we don't support ProtoPTEs in this code path.
2670 //
2671 Pfn1 = MiGetPfnEntry(PteContents.u.Hard.PageFrameNumber);
2672 ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
2673 ASSERT(Pfn1->u3.e1.PrototypePte == FALSE);
2674
2675 //
2676 // Flush any pending PTEs that we had not yet flushed, if our
2677 // list has gotten too big, then add this PTE to the flush list.
2678 //
2679 if (PteCount == 256)
2680 {
2681 MiProcessValidPteList(ValidPteList, PteCount);
2682 PteCount = 0;
2683 }
2684 ValidPteList[PteCount++] = PointerPte;
2685 }
2686 else
2687 {
2688 //
2689 // We do not support any of these other scenarios at the moment
2690 //
2691 ASSERT(PteContents.u.Soft.Prototype == 0);
2692 ASSERT(PteContents.u.Soft.Transition == 0);
2693 ASSERT(PteContents.u.Soft.PageFileHigh == 0);
2694
2695 //
2696 // So the only other possibility is that it is still a demand
2697 // zero PTE, in which case we undo the accounting we did
2698 // earlier and simply make the page decommitted.
2699 //
2700 //Process->NumberOfPrivatePages++;
2702 }
2703 }
2704 }
2705 else
2706 {
2707 //
2708 // This used to be a zero PTE and it no longer is, so we must add a
2709 // reference to the pagetable.
2710 //
2711 MiIncrementPageTableReferences(StartingAddress);
2712
2713 //
2714 // Next, we account for decommitted PTEs and make the PTE as such
2715 //
2716 if (PointerPte > CommitPte) CommitReduction++;
2718 }
2719
2720 //
2721 // Move to the next PTE and the next address
2722 //
2723 PointerPte++;
2724 StartingAddress = (PVOID)((ULONG_PTR)StartingAddress + PAGE_SIZE);
2725 }
2726
2727 //
2728 // Flush any dangling PTEs from the loop in the last page table, and then
2729 // release the working set and return the commit reduction accounting.
2730 //
2731 if (PteCount) MiProcessValidPteList(ValidPteList, PteCount);
2733 return CommitReduction;
2734}
#define MI_IS_ROS_PFN(x)
Definition: miarm.h:1116
FORCEINLINE VOID MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1252
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:1006
FORCEINLINE USHORT MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2485
FORCEINLINE VOID MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1182
#define MiAddressToPde(x)
Definition: mmx86.c:20
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:1038
#define MM_NOIRQL
Definition: mm.h:70
VOID NTAPI MiProcessValidPteList(IN PMMPTE *ValidPteList, IN ULONG Count)
Definition: virtual.c:2535
VOID NTAPI MiMakePdeExistAndMakeValid(IN PMMPDE PointerPde, IN PEPROCESS TargetProcess, IN KIRQL OldIrql)
Definition: virtual.c:2441
MMPTE MmDecommittedPte
Definition: init.c:44
USHORT PrototypePte
Definition: mm.h:374
Definition: mm.h:385
union _MMPFN::@1835 u3
MMPFNENTRY e1
Definition: mm.h:408
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
ULONG64 Transition
Definition: mmtypes.h:90
uint32_t ULONG
Definition: typedefs.h:59

Referenced by NtFreeVirtualMemory().

◆ MiDeletePte()

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

Definition at line 369 of file virtual.c.

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

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

◆ MiDeleteSystemPageableVm()

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

Definition at line 275 of file virtual.c.

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

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

◆ MiDeleteVirtualAddresses()

VOID NTAPI MiDeleteVirtualAddresses ( _In_ ULONG_PTR  Va,
_In_ ULONG_PTR  EndingAddress,
_In_opt_ PMMVAD  Vad 
)

Definition at line 530 of file virtual.c.

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

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

◆ MiDoMappedCopy()

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

Definition at line 795 of file virtual.c.

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

Referenced by MmCopyVirtualMemory().

◆ MiDoPoolCopy()

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

Definition at line 1020 of file virtual.c.

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

Referenced by MmCopyVirtualMemory().

◆ MiFlushTbAndCapture()

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

Definition at line 1821 of file section.c.

1826{
1827 MMPTE TempPte, PreviousPte;
1828 KIRQL OldIrql;
1829 BOOLEAN RebuildPte = FALSE;
1830
1831 //
1832 // User for sanity checking later on
1833 //
1834 PreviousPte = *PointerPte;
1835
1836 //
1837 // Build the PTE and acquire the PFN lock
1838 //
1840 PointerPte,
1841 ProtectionMask,
1842 PreviousPte.u.Hard.PageFrameNumber);
1843 OldIrql = MiAcquirePfnLock();
1844
1845 //
1846 // We don't support I/O mappings in this path yet
1847 //
1848 ASSERT(Pfn1 != NULL);
1849 ASSERT(Pfn1->u3.e1.CacheAttribute != MiWriteCombined);
1850
1851 //
1852 // Make sure new protection mask doesn't get in conflict and fix it if it does
1853 //
1854 if (Pfn1->u3.e1.CacheAttribute == MiCached)
1855 {
1856 //
1857 // This is a cached PFN
1858 //
1859 if (ProtectionMask & (MM_NOCACHE | MM_NOACCESS))
1860 {
1861 RebuildPte = TRUE;
1862 ProtectionMask &= ~(MM_NOCACHE | MM_NOACCESS);
1863 }
1864 }
1865 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
1866 {
1867 //
1868 // This is a non-cached PFN
1869 //
1870 if ((ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) != MM_NOCACHE)
1871 {
1872 RebuildPte = TRUE;
1873 ProtectionMask &= ~MM_NOACCESS;
1874 ProtectionMask |= MM_NOCACHE;
1875 }
1876 }
1877
1878 if (RebuildPte)
1879 {
1881 PointerPte,
1882 ProtectionMask,
1883 PreviousPte.u.Hard.PageFrameNumber);
1884 }
1885
1886 //
1887 // Write the new PTE, making sure we are only changing the bits
1888 //
1889 MI_UPDATE_VALID_PTE(PointerPte, TempPte);
1890
1891 //
1892 // Flush the TLB
1893 //
1894 ASSERT(PreviousPte.u.Hard.Valid == 1);
1896 ASSERT(PreviousPte.u.Hard.Valid == 1);
1897
1898 //
1899 // Windows updates the relevant PFN1 information, we currently don't.
1900 //
1901 if (UpdateDirty && PreviousPte.u.Hard.Dirty)
1902 {
1903 if (!Pfn1->u3.e1.Modified)
1904 {
1905 DPRINT1("FIXME: Mark PFN as dirty\n");
1906 }
1907 }
1908
1909 //
1910 // Not supported in ARM3
1911 //
1912 ASSERT(FoundVad->u.VadFlags.VadType != VadWriteWatch);
1913
1914 //
1915 // Release the PFN lock, we are done
1916 //
1917 MiReleasePfnLock(OldIrql);
1918}
#define DPRINT1
Definition: precomp.h:8
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:841
#define MM_NOCACHE
Definition: miarm.h:56
@ MiWriteCombined
Definition: miarm.h:426
@ MiCached
Definition: miarm.h:425
@ MiNonCached
Definition: miarm.h:424
#define MM_NOACCESS
Definition: miarm.h:65
FORCEINLINE VOID MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:991
ULONG64 Dirty
Definition: mmtypes.h:164

Referenced by MiProtectVirtualMemory().

◆ MiGetExceptionInfo()

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

Definition at line 750 of file virtual.c.

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

Referenced by MiDoMappedCopy(), and MiDoPoolCopy().

◆ MiGetPageProtection()

ULONG NTAPI MiGetPageProtection ( IN PMMPTE  PointerPte)

Definition at line 1356 of file virtual.c.

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

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

◆ MiIsEntireRangeCommitted()

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

Definition at line 1999 of file virtual.c.

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

Referenced by MiProtectVirtualMemory().

◆ MiLockVirtualMemory()

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

Definition at line 3341 of file virtual.c.

3345{
3346 PEPROCESS CurrentProcess;
3348 PVOID CurrentVa, EndAddress;
3349 PMMPTE PointerPte, LastPte;
3350 PMMPDE PointerPde;
3351#if (_MI_PAGING_LEVELS >= 3)
3352 PMMPDE PointerPpe;
3353#endif
3354#if (_MI_PAGING_LEVELS == 4)
3355 PMMPDE PointerPxe;
3356#endif
3357 PMMPFN Pfn1;
3358 NTSTATUS Status, TempStatus;
3359
3360 /* Lock the address space */
3363
3364 /* Make sure we still have an address space */
3365 CurrentProcess = PsGetCurrentProcess();
3366 if (CurrentProcess->VmDeleted)
3367 {
3369 goto Cleanup;
3370 }
3371
3372 /* Check the VADs in the requested range */
3374 if (!NT_SUCCESS(Status))
3375 {
3376 goto Cleanup;
3377 }
3378
3379 /* Enter SEH for probing */
3380 _SEH2_TRY
3381 {
3382 /* Loop all pages and probe them */
3383 CurrentVa = *BaseAddress;
3384 while (CurrentVa < EndAddress)
3385 {
3386 (void)(*(volatile CHAR*)CurrentVa);
3387 CurrentVa = (PUCHAR)CurrentVa + PAGE_SIZE;
3388 }
3389 }
3391 {
3393 goto Cleanup;
3394 }
3395 _SEH2_END;
3396
3397 /* All pages were accessible, since we hold the address space lock, nothing
3398 can be de-committed. Assume success for now. */
3400
3401 /* Get the PTE and PDE */
3402 PointerPte = MiAddressToPte(*BaseAddress);
3403 PointerPde = MiAddressToPde(*BaseAddress);
3404#if (_MI_PAGING_LEVELS >= 3)
3405 PointerPpe = MiAddressToPpe(*BaseAddress);
3406#endif
3407#if (_MI_PAGING_LEVELS == 4)
3408 PointerPxe = MiAddressToPxe(*BaseAddress);
3409#endif
3410
3411 /* Get the last PTE */
3412 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3413
3414 /* Lock the process working set */
3416
3417 /* Loop the pages */
3418 do
3419 {
3420 /* Check for a page that is not accessible */
3421 while (
3422#if (_MI_PAGING_LEVELS == 4)
3423 (PointerPxe->u.Hard.Valid == 0) ||
3424#endif
3425#if (_MI_PAGING_LEVELS >= 3)
3426 (PointerPpe->u.Hard.Valid == 0) ||
3427#endif
3428 (PointerPde->u.Hard.Valid == 0) ||
3429 (PointerPte->u.Hard.Valid == 0))
3430 {
3431 /* Release process working set */
3433
3434 /* Access the page */
3435 CurrentVa = MiPteToAddress(PointerPte);
3436
3437 //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked
3438 TempStatus = MmAccessFault(TRUE, CurrentVa, KernelMode, (PVOID)(ULONG_PTR)0xBADBADA3BADBADA3ULL);
3439 if (!NT_SUCCESS(TempStatus))
3440 {
3441 // This should only happen, when remote backing storage is not accessible
3442 ASSERT(FALSE);
3443 Status = TempStatus;
3444 goto Cleanup;
3445 }
3446
3447 /* Lock the process working set */
3449 }
3450
3451 /* Get the PFN */
3452 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3453 ASSERT(Pfn1 != NULL);
3454
3455 /* Check the previous lock status */
3456 if (MI_IS_LOCKED_VA(Pfn1, MapType))
3457 {
3459 }
3460
3461 /* Lock it */
3462 MI_LOCK_VA(Pfn1, MapType);
3463
3464 /* Go to the next PTE */
3465 PointerPte++;
3466
3467 /* Check if we're on a PDE boundary */
3468 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3469#if (_MI_PAGING_LEVELS >= 3)
3470 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3471#endif
3472#if (_MI_PAGING_LEVELS == 4)
3473 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3474#endif
3475 } while (PointerPte <= LastPte);
3476
3477 /* Release process working set */
3479
3480Cleanup:
3481 /* Unlock address space */
3483
3484 return Status;
3485}
static const WCHAR Cleanup[]
Definition: register.c:80
if(dx< 0)
Definition: linetemp.h:194
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1207
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1137
#define _MI_PAGING_LEVELS
Definition: mm.h:6
FORCEINLINE PMMSUPPORT MmGetCurrentAddressSpace(VOID)
Definition: mm.h:1715
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1687
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1700
NTSTATUS NTAPI MmAccessFault(IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
Definition: mmfault.c:220
FORCEINLINE VOID MI_LOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3254
static NTSTATUS MiCheckVadsForLockOperation(_Inout_ PVOID *BaseAddress, _Inout_ PSIZE_T RegionSize, _Inout_ PVOID *EndAddress)
Definition: virtual.c:3296
FORCEINLINE BOOLEAN MI_IS_LOCKED_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3237
#define STATUS_WAS_LOCKED
Definition: ntstatus.h:139
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
ULONG VmDeleted
Definition: pstypes.h:1399
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2274

Referenced by NtLockVirtualMemory(), and RunTest().

◆ MiMakePdeExistAndMakeValid()

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

Definition at line 2441 of file virtual.c.

2444{
2445 PMMPTE PointerPte;
2446#if _MI_PAGING_LEVELS >= 3
2447 PMMPPE PointerPpe = MiPdeToPpe(PointerPde);
2448#if _MI_PAGING_LEVELS == 4
2449 PMMPXE PointerPxe = MiPdeToPxe(PointerPde);
2450#endif
2451#endif
2452
2453 //
2454 // Sanity checks. The latter is because we only use this function with the
2455 // PFN lock not held, so it may go away in the future.
2456 //
2459
2460 //
2461 // If everything is already valid, there is nothing to do.
2462 //
2463 if (
2464#if _MI_PAGING_LEVELS == 4
2465 (PointerPxe->u.Hard.Valid) &&
2466#endif
2467#if _MI_PAGING_LEVELS >= 3
2468 (PointerPpe->u.Hard.Valid) &&
2469#endif
2470 (PointerPde->u.Hard.Valid))
2471 {
2472 return;
2473 }
2474
2475 //
2476 // At least something is invalid, so begin by getting the PTE for the PDE itself
2477 // and then lookup each additional level. We must do it in this precise order
2478 // because the pagfault.c code (as well as in Windows) depends that the next
2479 // level up (higher) must be valid when faulting a lower level
2480 //
2481 PointerPte = MiPteToAddress(PointerPde);
2482 do
2483 {
2484 //
2485 // Make sure APCs continued to be disabled
2486 //
2488
2489#if _MI_PAGING_LEVELS == 4
2490 //
2491 // First, make the PXE valid if needed
2492 //
2493 if (!PointerPxe->u.Hard.Valid)
2494 {
2495 MiMakeSystemAddressValid(PointerPpe, TargetProcess);
2496 ASSERT(PointerPxe->u.Hard.Valid == 1);
2497 }
2498#endif
2499
2500#if _MI_PAGING_LEVELS >= 3
2501 //
2502 // Next, the PPE
2503 //
2504 if (!PointerPpe->u.Hard.Valid)
2505 {
2506 MiMakeSystemAddressValid(PointerPde, TargetProcess);
2507 ASSERT(PointerPpe->u.Hard.Valid == 1);
2508 }
2509#endif
2510
2511 //
2512 // And finally, make the PDE itself valid.
2513 //
2514 MiMakeSystemAddressValid(PointerPte, TargetProcess);
2515
2516 /* Do not increment Page table refcount here for the PDE, this must be managed by caller */
2517
2518 //
2519 // This should've worked the first time so the loop is really just for
2520 // show -- ASSERT that we're actually NOT going to be looping.
2521 //
2522 ASSERT(PointerPde->u.Hard.Valid == 1);
2523 } while (
2524#if _MI_PAGING_LEVELS == 4
2525 !PointerPxe->u.Hard.Valid ||
2526#endif
2527#if _MI_PAGING_LEVELS >= 3
2528 !PointerPpe->u.Hard.Valid ||
2529#endif
2530 !PointerPde->u.Hard.Valid);
2531}
FORCEINLINE PMMPXE MiPdeToPxe(PMMPDE PointerPde)
Definition: mm.h:300
FORCEINLINE PMMPDE MiPdeToPpe(PMMPDE PointerPde)
Definition: mm.h:292
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985

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

◆ MiMakeSystemAddressValid()

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

Definition at line 183 of file virtual.c.

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

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

◆ MiMakeSystemAddressValidPfn()

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

Definition at line 235 of file virtual.c.

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

Referenced by MiGetPageProtection(), and MiSegmentDelete().

◆ MiProcessValidPteList()

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

Definition at line 2535 of file virtual.c.

2537{
2538 KIRQL OldIrql;
2539 ULONG i;
2540 MMPTE TempPte;
2541 PFN_NUMBER PageFrameIndex;
2542 PMMPFN Pfn1, Pfn2;
2543
2544 //
2545 // Acquire the PFN lock and loop all the PTEs in the list
2546 //
2547 OldIrql = MiAcquirePfnLock();
2548 for (i = 0; i != Count; i++)
2549 {
2550 //
2551 // The PTE must currently be valid
2552 //
2553 TempPte = *ValidPteList[i];
2554 ASSERT(TempPte.u.Hard.Valid == 1);
2555
2556 //
2557 // Get the PFN entry for the page itself, and then for its page table
2558 //
2559 PageFrameIndex = PFN_FROM_PTE(&TempPte);
2560 Pfn1 = MiGetPfnEntry(PageFrameIndex);
2561 Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame);
2562
2563 //
2564 // Decrement the share count on the page table, and then on the page
2565 // itself
2566 //
2567 MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame);
2568 MI_SET_PFN_DELETED(Pfn1);
2569 MiDecrementShareCount(Pfn1, PageFrameIndex);
2570
2571 //
2572 // Make the page decommitted
2573 //
2574 MI_WRITE_INVALID_PTE(ValidPteList[i], MmDecommittedPte);
2575 }
2576
2577 //
2578 // All the PTEs have been dereferenced and made invalid, flush the TLB now
2579 // and then release the PFN lock
2580 //
2582 MiReleasePfnLock(OldIrql);
2583}
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
int Count
Definition: noreturn.cpp:7

Referenced by MiDecommitPages().

◆ MiProtectVirtualMemory()

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

Definition at line 2155 of file virtual.c.

2160{
2161 PMMVAD Vad;
2163 ULONG_PTR StartingAddress, EndingAddress;
2164 PMMPTE PointerPte, LastPte;
2165 PMMPDE PointerPde;
2166 MMPTE PteContents;
2167 PMMPFN Pfn1;
2168 ULONG ProtectionMask, OldProtect;
2169 BOOLEAN Committed;
2173
2174 /* We must be attached */
2176
2177 /* Calculate base address for the VAD */
2178 StartingAddress = (ULONG_PTR)PAGE_ALIGN((*BaseAddress));
2179 EndingAddress = (((ULONG_PTR)*BaseAddress + *NumberOfBytesToProtect - 1) | (PAGE_SIZE - 1));
2180
2181 /* Calculate the protection mask and make sure it's valid */
2182 ProtectionMask = MiMakeProtectionMask(NewAccessProtection);
2183 if (ProtectionMask == MM_INVALID_PROTECTION)
2184 {
2185 DPRINT1("Invalid protection mask\n");
2187 }
2188
2189 /* Lock the address space and make sure the process isn't already dead */
2192 if (Process->VmDeleted)
2193 {
2194 DPRINT1("Process is dying\n");
2196 goto FailPath;
2197 }
2198
2199 /* Get the VAD for this address range, and make sure it exists */
2200 Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
2201 EndingAddress >> PAGE_SHIFT,
2202 &Process->VadRoot,
2203 (PMMADDRESS_NODE*)&Vad);
2204 if (Result != TableFoundNode)
2205 {
2206 DPRINT("Could not find a VAD for this allocation\n");
2208 goto FailPath;
2209 }
2210
2211 /* Check if this is a ROSMM VAD */
2212 if (MI_IS_ROSMM_VAD(Vad))
2213 {
2214 /* Not too shabby hack */
2216 *NumberOfBytesToProtect = PAGE_ROUND_UP((ULONG_PTR)(*BaseAddress) + (*NumberOfBytesToProtect)) - PAGE_ROUND_DOWN(*BaseAddress);
2219 (PMEMORY_AREA)Vad,
2220 *BaseAddress,
2221 *NumberOfBytesToProtect,
2222 NewAccessProtection,
2223 OldAccessProtection);
2225 return Status;
2226 }
2227
2228 /* Make sure the address is within this VAD's boundaries */
2229 if ((((ULONG_PTR)StartingAddress >> PAGE_SHIFT) < Vad->StartingVpn) ||
2230 (((ULONG_PTR)EndingAddress >> PAGE_SHIFT) > Vad->EndingVpn))
2231 {
2233 goto FailPath;
2234 }
2235
2236 /* These kinds of VADs are not supported atm */
2237 if ((Vad->u.VadFlags.VadType == VadAwe) ||
2239 (Vad->u.VadFlags.VadType == VadLargePages))
2240 {
2241 DPRINT1("Illegal VAD for attempting to set protection\n");
2243 goto FailPath;
2244 }
2245
2246 /* Check for a VAD whose protection can't be changed */
2247 if (Vad->u.VadFlags.NoChange == 1)
2248 {
2249 DPRINT1("Trying to change protection of a NoChange VAD\n");
2251 goto FailPath;
2252 }
2253
2254 /* Is this section, or private memory? */
2255 if (Vad->u.VadFlags.PrivateMemory == 0)
2256 {
2257 /* Not yet supported */
2259 {
2260 DPRINT1("Illegal VAD for attempting to set protection\n");
2262 goto FailPath;
2263 }
2264
2265 /* Rotate VADs are not yet supported */
2266 if (Vad->u.VadFlags.VadType == VadRotatePhysical)
2267 {
2268 DPRINT1("Illegal VAD for attempting to set protection\n");
2270 goto FailPath;
2271 }
2272
2273 /* Not valid on section files */
2274 if (NewAccessProtection & (PAGE_NOCACHE | PAGE_WRITECOMBINE))
2275 {
2276 /* Fail */
2277 DPRINT1("Invalid protection flags for section\n");
2279 goto FailPath;
2280 }
2281
2282 /* Check if data or page file mapping protection PTE is compatible */
2283 if (!Vad->ControlArea->u.Flags.Image)
2284 {
2285 /* Not yet */
2286 DPRINT1("Fixme: Not checking for valid protection\n");
2287 }
2288
2289 /* This is a section, and this is not yet supported */
2290 DPRINT1("Section protection not yet supported\n");
2291 OldProtect = 0;
2292 }
2293 else
2294 {
2295 /* Private memory, check protection flags */
2296 if ((NewAccessProtection & PAGE_WRITECOPY) ||
2297 (NewAccessProtection & PAGE_EXECUTE_WRITECOPY))
2298 {
2299 DPRINT1("Invalid protection flags for private memory\n");
2301 goto FailPath;
2302 }
2303
2304 /* Lock the working set */
2306
2307 /* Check if all pages in this range are committed */
2308 Committed = MiIsEntireRangeCommitted(StartingAddress,
2309 EndingAddress,
2310 Vad,
2311 Process);
2312 if (!Committed)
2313 {
2314 /* Fail */
2315 DPRINT1("The entire range is not committed\n");
2318 goto FailPath;
2319 }
2320
2321 /* Compute starting and ending PTE and PDE addresses */
2322 PointerPde = MiAddressToPde(StartingAddress);
2323 PointerPte = MiAddressToPte(StartingAddress);
2324 LastPte = MiAddressToPte(EndingAddress);
2325
2326 /* Make this PDE valid */
2328
2329 /* Save protection of the first page */
2330 if (PointerPte->u.Long != 0)
2331 {
2332 /* Capture the page protection and make the PDE valid */
2333 OldProtect = MiGetPageProtection(PointerPte);
2335 }
2336 else
2337 {
2338 /* Grab the old protection from the VAD itself */
2339 OldProtect = MmProtectToValue[Vad->u.VadFlags.Protection];
2340 }
2341
2342 /* Loop all the PTEs now */
2343 while (PointerPte <= LastPte)
2344 {
2345 /* Check if we've crossed a PDE boundary and make the new PDE valid too */
2346 if (MiIsPteOnPdeBoundary(PointerPte))
2347 {
2348 PointerPde = MiPteToPde(PointerPte);
2350 }
2351
2352 /* Capture the PTE and check if it was empty */
2353 PteContents = *PointerPte;
2354 if (PteContents.u.Long == 0)
2355 {
2356 /* This used to be a zero PTE and it no longer is, so we must add a
2357 reference to the pagetable. */
2359 }
2360
2361 /* Check what kind of PTE we are dealing with */
2362 if (PteContents.u.Hard.Valid == 1)
2363 {
2364 /* Get the PFN entry */
2365 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
2366
2367 /* We don't support this yet */
2368 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
2369
2370 /* Check if the page should not be accessible at all */
2371 if ((NewAccessProtection & PAGE_NOACCESS) ||
2372 (NewAccessProtection & PAGE_GUARD))
2373 {
2374 KIRQL OldIrql = MiAcquirePfnLock();
2375
2376 /* Mark the PTE as transition and change its protection */
2377 PteContents.u.Hard.Valid = 0;
2378 PteContents.u.Soft.Transition = 1;
2379 PteContents.u.Trans.Protection = ProtectionMask;
2380 /* Decrease PFN share count and write the PTE */
2381 MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
2382 // FIXME: remove the page from the WS
2383 MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2384#ifdef CONFIG_SMP
2385 // FIXME: Should invalidate entry in every CPU TLB
2387#endif
2389
2390 /* We are done for this PTE */
2391 MiReleasePfnLock(OldIrql);
2392 }
2393 else
2394 {
2395 /* Write the protection mask and write it with a TLB flush */
2396 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
2398 PointerPte,
2399 ProtectionMask,
2400 Pfn1,
2401 TRUE);
2402 }
2403 }
2404 else
2405 {
2406 /* We don't support these cases yet */
2407 ASSERT(PteContents.u.Soft.Prototype == 0);
2408 //ASSERT(PteContents.u.Soft.Transition == 0);
2409
2410 /* The PTE is already demand-zero, just update the protection mask */
2411 PteContents.u.Soft.Protection = ProtectionMask;
2412 MI_WRITE_INVALID_PTE(PointerPte, PteContents);
2413 ASSERT(PointerPte->u.Long != 0);
2414 }
2415
2416 /* Move to the next PTE */
2417 PointerPte++;
2418 }
2419
2420 /* Unlock the working set */
2422 }
2423
2424 /* Unlock the address space */
2426
2427 /* Return parameters and success */
2428 *NumberOfBytesToProtect = EndingAddress - StartingAddress + 1;
2429 *BaseAddress = (PVOID)StartingAddress;
2430 *OldAccessProtection = OldProtect;
2431 return STATUS_SUCCESS;
2432
2433FailPath:
2434 /* Unlock the address space and return the failure code */
2436 return Status;
2437}
Type
Definition: Type.h:7
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
#define MM_INVALID_PROTECTION
Definition: miarm.h:67
TABLE_SEARCH_RESULT NTAPI MiCheckForConflictingNode(IN ULONG_PTR StartVpn, IN ULONG_PTR EndVpn, IN PMM_AVL_TABLE Table, OUT PMMADDRESS_NODE *NodeOrParent)
Definition: vadnode.c:157
ULONG NTAPI MiMakeProtectionMask(IN ULONG Protect)
Definition: section.c:140
#define PAGE_ROUND_UP(x)
Definition: mmtypes.h:38
@ VadAwe
Definition: mmtypes.h:207
@ VadLargePageSection
Definition: mmtypes.h:211
@ VadLargePages
Definition: mmtypes.h:209
@ VadRotatePhysical
Definition: mmtypes.h:210
@ VadDevicePhysicalMemory
Definition: mmtypes.h:205
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
#define PAGE_WRITECOPY
Definition: nt_native.h:1305
#define PAGE_NOCACHE
Definition: nt_native.h:1311
#define PAGE_EXECUTE_WRITECOPY
Definition: nt_native.h:1309
#define PAGE_NOACCESS
Definition: nt_native.h:1302
#define PAGE_GUARD
Definition: nt_native.h:1310
FORCEINLINE VOID KeInvalidateTlbEntry(IN PVOID Address)
Definition: ke.h:264
NTSTATUS NTAPI MmProtectSectionView(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PVOID BaseAddress, SIZE_T Length, ULONG Protect, PULONG OldProtect)
Definition: section.c:2068
#define MI_IS_ROSMM_VAD(Vad)
Definition: mm.h:274
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:93
CCHAR KeNumberProcessors
Definition: processor.c:19
ULONG NTAPI MiGetPageProtection(IN PMMPTE PointerPte)
Definition: virtual.c:1356
VOID NTAPI MiFlushTbAndCapture(IN PMMVAD FoundVad, IN PMMPTE PointerPte, IN ULONG ProtectionMask, IN PMMPFN Pfn1, IN BOOLEAN CaptureDirtyBit)
Definition: section.c:1821
BOOLEAN NTAPI MiIsEntireRangeCommitted(IN ULONG_PTR StartingAddress, IN ULONG_PTR EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
Definition: virtual.c:1999
#define STATUS_INVALID_PARAMETER_4
Definition: ntstatus.h:478
#define STATUS_CONFLICTING_ADDRESSES
Definition: ntstatus.h:261
#define STATUS_INVALID_PAGE_PROTECTION
Definition: ntstatus.h:305
#define STATUS_NOT_COMMITTED
Definition: ntstatus.h:282
union _CONTROL_AREA::@2696 u
MMSECTION_FLAGS Flags
Definition: mmtypes.h:531
ULONG64 Protection
Definition: mmtypes.h:103
MMPTE_TRANSITION Trans
Definition: mmtypes.h:220
ULONG_PTR NoChange
Definition: mmtypes.h:693
ULONG_PTR Protection
Definition: mmtypes.h:696
ULONG_PTR PrivateMemory
Definition: mmtypes.h:698
PCONTROL_AREA ControlArea
Definition: mmtypes.h:736
ULONG_PTR StartingVpn
Definition: mmtypes.h:729
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
#define PAGE_WRITECOMBINE
Definition: mmtypes.h:78
TABLE_SEARCH_RESULT
Definition: rtltypes.h:386

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

◆ MiQueryAddressState()

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

Definition at line 1471 of file virtual.c.

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

Referenced by MiQueryMemoryBasicInformation().

◆ MiQueryMemoryBasicInformation()

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

Definition at line 1662 of file virtual.c.

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

Referenced by NtQueryVirtualMemory().

◆ MiUnlockVirtualMemory()

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

Definition at line 3660 of file virtual.c.

3664{
3665 PEPROCESS CurrentProcess;
3667 PVOID EndAddress;
3668 PMMPTE PointerPte, LastPte;
3669 PMMPDE PointerPde;
3670#if (_MI_PAGING_LEVELS >= 3)
3671 PMMPDE PointerPpe;
3672#endif
3673#if (_MI_PAGING_LEVELS == 4)
3674 PMMPDE PointerPxe;
3675#endif
3676 PMMPFN Pfn1;
3678
3679 /* Lock the address space */
3682
3683 /* Make sure we still have an address space */
3684 CurrentProcess = PsGetCurrentProcess();
3685 if (CurrentProcess->VmDeleted)
3686 {
3688 goto Cleanup;
3689 }
3690
3691 /* Check the VADs in the requested range */
3693
3694 /* Note: only bail out, if we hit an area without a VAD. If we hit an
3695 incompatible VAD we continue, like Windows does */
3697 {
3699 goto Cleanup;
3700 }
3701
3702 /* Get the PTE and PDE */
3703 PointerPte = MiAddressToPte(*BaseAddress);
3704 PointerPde = MiAddressToPde(*BaseAddress);
3705#if (_MI_PAGING_LEVELS >= 3)
3706 PointerPpe = MiAddressToPpe(*BaseAddress);
3707#endif
3708#if (_MI_PAGING_LEVELS == 4)
3709 PointerPxe = MiAddressToPxe(*BaseAddress);
3710#endif
3711
3712 /* Get the last PTE */
3713 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)EndAddress - 1));
3714
3715 /* Lock the process working set */
3717
3718 /* Loop the pages */
3719 do
3720 {
3721 /* Check for a page that is not present */
3722 if (
3723#if (_MI_PAGING_LEVELS == 4)
3724 (PointerPxe->u.Hard.Valid == 0) ||
3725#endif
3726#if (_MI_PAGING_LEVELS >= 3)
3727 (PointerPpe->u.Hard.Valid == 0) ||
3728#endif
3729 (PointerPde->u.Hard.Valid == 0) ||
3730 (PointerPte->u.Hard.Valid == 0))
3731 {
3732 /* Remember it, but keep going */
3734 }
3735 else
3736 {
3737 /* Get the PFN */
3738 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3739 ASSERT(Pfn1 != NULL);
3740
3741 /* Check if all of the requested locks are present */
3742 if (((MapType & MAP_SYSTEM) && !MI_IS_LOCKED_VA(Pfn1, MAP_SYSTEM)) ||
3743 ((MapType & MAP_PROCESS) && !MI_IS_LOCKED_VA(Pfn1, MAP_PROCESS)))
3744 {
3745 /* Remember it, but keep going */
3747
3748 /* Check if no lock is present */
3750 {
3751 DPRINT1("FIXME: Should remove the page from WS\n");
3752 }
3753 }
3754 }
3755
3756 /* Go to the next PTE */
3757 PointerPte++;
3758
3759 /* Check if we're on a PDE boundary */
3760 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3761#if (_MI_PAGING_LEVELS >= 3)
3762 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3763#endif
3764#if (_MI_PAGING_LEVELS == 4)
3765 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3766#endif
3767 } while (PointerPte <= LastPte);
3768
3769 /* Check if we hit a page that was not locked */
3771 {
3772 goto CleanupWithWsLock;
3773 }
3774
3775 /* All pages in the region were locked, so unlock them all */
3776
3777 /* Get the PTE and PDE */
3778 PointerPte = MiAddressToPte(*BaseAddress);
3779 PointerPde = MiAddressToPde(*BaseAddress);
3780#if (_MI_PAGING_LEVELS >= 3)
3781 PointerPpe = MiAddressToPpe(*BaseAddress);
3782#endif
3783#if (_MI_PAGING_LEVELS == 4)
3784 PointerPxe = MiAddressToPxe(*BaseAddress);
3785#endif
3786
3787 /* Loop the pages */
3788 do
3789 {
3790 /* Unlock it */
3791 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
3792 MI_UNLOCK_VA(Pfn1, MapType);
3793
3794 /* Go to the next PTE */
3795 PointerPte++;
3796
3797 /* Check if we're on a PDE boundary */
3798 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
3799#if (_MI_PAGING_LEVELS >= 3)
3800 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
3801#endif
3802#if (_MI_PAGING_LEVELS == 4)
3803 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
3804#endif
3805 } while (PointerPte <= LastPte);
3806
3807 /* Everything is done */
3809
3810CleanupWithWsLock:
3811
3812 /* Release process working set */
3814
3815Cleanup:
3816 /* Unlock address space */
3818
3819 return Status;
3820}
FORCEINLINE VOID MI_UNLOCK_VA(PMMPFN Pfn1, ULONG LockType)
Definition: virtual.c:3275
#define STATUS_NOT_LOCKED
Definition: ntstatus.h:279

Referenced by NtUnlockVirtualMemory().

◆ MmCopyVirtualMemory()

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

Definition at line 1271 of file virtual.c.

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

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

◆ MmFlushVirtualMemory()

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

Definition at line 1342 of file virtual.c.

1346{
1347 PAGED_CODE();
1348
1350
1352}
#define UNIMPLEMENTED
Definition: ntoskrnl.c:15
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42

Referenced by NtFlushVirtualMemory().

◆ MmGetPhysicalAddress()

PHYSICAL_ADDRESS NTAPI MmGetPhysicalAddress ( PVOID  Address)

Definition at line 5671 of file virtual.c.

5672{
5674 MMPDE TempPde;
5675 MMPTE TempPte;
5676
5677 /* Check if the PXE/PPE/PDE is valid */
5678 if (
5679#if (_MI_PAGING_LEVELS == 4)
5680 (MiAddressToPxe(Address)->u.Hard.Valid) &&
5681#endif
5682#if (_MI_PAGING_LEVELS >= 3)
5683 (MiAddressToPpe(Address)->u.Hard.Valid) &&
5684#endif
5685 (MiAddressToPde(Address)->u.Hard.Valid))
5686 {
5687 /* Check for large pages */
5689 if (TempPde.u.Hard.LargePage)
5690 {
5691 /* Physical address is base page + large page offset */
5694 return PhysicalAddress;
5695 }
5696
5697 /* Check if the PTE is valid */
5699 if (TempPte.u.Hard.Valid)
5700 {
5701 /* Physical address is base page + page offset */
5704 return PhysicalAddress;
5705 }
5706 }
5707
5709 DPRINT1("MM:MmGetPhysicalAddressFailed base address was %p\n", Address);
5711 return PhysicalAddress;
5712}
HARDWARE_PDE_ARMV6 TempPde
Definition: winldr.c:78
#define KeRosDumpStackFrames(Frames, Count)
Definition: gdidebug.h:11
unsigned __int64 ULONG64
Definition: imports.h:198
#define PTE_PER_PAGE
Definition: mm.h:20
ULONG PageFrameNumber
Definition: mmtypes.h:74
LONGLONG QuadPart
Definition: typedefs.h:114
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS PhysicalAddress
Definition: iotypes.h:1098

◆ MmGetVirtualForPhysical()

PVOID NTAPI MmGetVirtualForPhysical ( IN PHYSICAL_ADDRESS  PhysicalAddress)

Definition at line 2743 of file virtual.c.

2744{
2746 return 0;
2747}

◆ MmSecureVirtualMemory()

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

Definition at line 2754 of file virtual.c.

2757{
2758 static ULONG Warn; if (!Warn++) UNIMPLEMENTED;
2759 return Address;
2760}
@ Warn
Definition: video.h:589

Referenced by EngSecureMem(), and EngSecureMemForRead().

◆ MmUnsecureVirtualMemory()

VOID NTAPI MmUnsecureVirtualMemory ( IN PVOID  SecureMem)

Definition at line 2767 of file virtual.c.

2768{
2769 static ULONG Warn; if (!Warn++) UNIMPLEMENTED;
2770}

Referenced by EngUnsecureMem().

◆ NtAllocateVirtualMemory()

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

Definition at line 4452 of file virtual.c.

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

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

◆ NtFlushInstructionCache()

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

Definition at line 3004 of file virtual.c.

3007{
3011 PAGED_CODE();
3012
3013 /* Is a base address given? */
3014 if (BaseAddress != NULL)
3015 {
3016 /* If the requested size is 0, there is nothing to do */
3017 if (FlushSize == 0)
3018 {
3019 return STATUS_SUCCESS;
3020 }
3021
3022 /* Is this a user mode call? */
3024 {
3025 /* Make sure the base address is in user space */
3027 {
3028 DPRINT1("Invalid BaseAddress 0x%p\n", BaseAddress);
3030 }
3031 }
3032 }
3033
3034 /* Is another process requested? */
3036 {
3037 /* Reference the process */
3042 (PVOID*)&Process,
3043 NULL);
3044 if (!NT_SUCCESS(Status))
3045 {
3046 DPRINT1("Failed to reference the process %p\n", ProcessHandle);
3047 return Status;
3048 }
3049
3050 /* Attach to the process */
3052 }
3053
3054 /* Forward to Ke */
3055 KeSweepICache(BaseAddress, FlushSize);
3056
3057 /* Check if we attached */
3059 {
3060 /* Detach from the process and dereference it */
3063 }
3064
3065 /* All done, return to caller */
3066 return STATUS_SUCCESS;
3067}
#define PROCESS_VM_WRITE
Definition: pstypes.h:163
FORCEINLINE VOID KeSweepICache(IN PVOID BaseAddress, IN SIZE_T FlushSize)
Definition: ke.h:280

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

◆ NtFlushVirtualMemory()

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

Definition at line 3995 of file virtual.c.

3999{
4003 PVOID CapturedBaseAddress;
4004 SIZE_T CapturedBytesToFlush;
4005 IO_STATUS_BLOCK LocalStatusBlock;
4006 PAGED_CODE();
4007
4008 //
4009 // Check if we came from user mode
4010 //
4011 if (PreviousMode != KernelMode)
4012 {
4013 //
4014 // Enter SEH for probing
4015 //
4016 _SEH2_TRY
4017 {
4018 //
4019 // Validate all outputs
4020 //
4022 ProbeForWriteSize_t(NumberOfBytesToFlush);
4024
4025 //
4026 // Capture them
4027 //
4028 CapturedBaseAddress = *BaseAddress;
4029 CapturedBytesToFlush = *NumberOfBytesToFlush;
4030 }
4032 {
4033 //
4034 // Get exception code
4035 //
4037 }
4038 _SEH2_END;
4039 }
4040 else
4041 {
4042 //
4043 // Capture directly
4044 //
4045 CapturedBaseAddress = *BaseAddress;
4046 CapturedBytesToFlush = *NumberOfBytesToFlush;
4047 }
4048
4049 //
4050 // Catch illegal base address
4051 //
4052 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
4053
4054 //
4055 // Catch illegal region size
4056 //
4057 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToFlush)
4058 {
4059 //
4060 // Fail
4061 //
4063 }
4064
4065 //
4066 // Get a reference to the process
4067 //
4072 (PVOID*)(&Process),
4073 NULL);
4074 if (!NT_SUCCESS(Status)) return Status;
4075
4076 //
4077 // Do it
4078 //
4080 &CapturedBaseAddress,
4081 &CapturedBytesToFlush,
4082 &LocalStatusBlock);
4083
4084 //
4085 // Release reference
4086 //
4088
4089 //
4090 // Enter SEH to return data
4091 //
4092 _SEH2_TRY
4093 {
4094 //
4095 // Return data to user
4096 //
4097 *BaseAddress = PAGE_ALIGN(CapturedBaseAddress);
4098 *NumberOfBytesToFlush = 0;
4099 *IoStatusBlock = LocalStatusBlock;
4100 }
4102 {
4103 }
4104 _SEH2_END;
4105
4106 //
4107 // Return status
4108 //
4109 return Status;
4110}
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
ULONG MmUserProbeAddress
Definition: init.c:50
NTSTATUS NTAPI MmFlushVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, OUT PIO_STATUS_BLOCK IoStatusBlock)
Definition: virtual.c:1342
#define ProbeForWriteIoStatusBlock(Ptr)
Definition: probe.h:52

Referenced by FlushViewOfFile(), and Test_ImageSection().

◆ NtFreeVirtualMemory()

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

Definition at line 5187 of file virtual.c.

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

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

◆ NtGetWriteWatch()

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

Definition at line 4117 of file virtual.c.

4124{
4127 PVOID EndAddress;
4129 ULONG_PTR CapturedEntryCount;
4130 PAGED_CODE();
4131
4132 //
4133 // Check if we came from user mode
4134 //
4135 if (PreviousMode != KernelMode)
4136 {
4137 //
4138 // Enter SEH for probing
4139 //
4140 _SEH2_TRY
4141 {
4142 //
4143 // Catch illegal base address
4144 //
4146
4147 //
4148 // Catch illegal region size
4149 //
4151 {
4152 //
4153 // Fail
4154 //
4156 }
4157
4158 //
4159 // Validate all data
4160 //
4161 ProbeForWriteSize_t(EntriesInUserAddressArray);
4162 ProbeForWriteUlong(Granularity);
4163
4164 //
4165 // Capture them
4166 //
4167 CapturedEntryCount = *EntriesInUserAddressArray;
4168
4169 //
4170 // Must have a count
4171 //
4172 if (CapturedEntryCount == 0) _SEH2_YIELD(return STATUS_INVALID_PARAMETER_5);
4173
4174 //
4175 // Can't be larger than the maximum
4176 //
4177 if (CapturedEntryCount > (MAXULONG_PTR / sizeof(ULONG_PTR)))
4178 {
4179 //
4180 // Fail
4181 //
4183 }
4184
4185 //
4186 // Probe the actual array
4187 //
4188 ProbeForWrite(UserAddressArray,
4189 CapturedEntryCount * sizeof(PVOID),
4190 sizeof(PVOID));
4191 }
4193 {
4194 //
4195 // Get exception code
4196 //
4198 }
4199 _SEH2_END;
4200 }
4201 else
4202 {
4203 //
4204 // Capture directly
4205 //
4206 CapturedEntryCount = *EntriesInUserAddressArray;
4207 ASSERT(CapturedEntryCount != 0);
4208 }
4209
4210 //
4211 // Check if this is a local request
4212 //
4214 {
4215 //
4216 // No need to reference the process
4217 //
4219 }
4220 else
4221 {
4222 //
4223 // Reference the target
4224 //
4229 (PVOID *)&Process,
4230 NULL);
4231 if (!NT_SUCCESS(Status)) return Status;
4232 }
4233
4234 //
4235 // Compute the last address and validate it
4236 //
4237 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
4238 if (BaseAddress > EndAddress)
4239 {
4240 //
4241 // Fail
4242 //
4245 }
4246
4247 //
4248 // Oops :(
4249 //
4251
4252 //
4253 // Dereference if needed
4254 //
4256
4257 //
4258 // Enter SEH to return data
4259 //
4260 _SEH2_TRY
4261 {
4262 //
4263 // Return data to user
4264 //
4265 *EntriesInUserAddressArray = 0;
4266 *Granularity = PAGE_SIZE;
4267 }
4269 {
4270 //
4271 // Get exception code
4272 //
4274 }
4275 _SEH2_END;
4276
4277 //
4278 // Return success
4279 //
4280 return STATUS_SUCCESS;
4281}

Referenced by GetWriteWatch().

◆ NtLockVirtualMemory()

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

Definition at line 3489 of file virtual.c.

3493{
3495 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3500 PVOID CapturedBaseAddress;
3501 SIZE_T CapturedBytesToLock;
3502 PAGED_CODE();
3503
3504 //
3505 // Validate flags
3506 //
3507 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
3508 {
3509 //
3510 // Invalid set of flags
3511 //
3513 }
3514
3515 //
3516 // At least one flag must be specified
3517 //
3518 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
3519 {
3520 //
3521 // No flag given
3522 //
3524 }
3525
3526 //
3527 // Enter SEH for probing
3528 //
3529 _SEH2_TRY
3530 {
3531 //
3532 // Validate output data
3533 //
3535 ProbeForWriteSize_t(NumberOfBytesToLock);
3536
3537 //
3538 // Capture it
3539 //
3540 CapturedBaseAddress = *BaseAddress;
3541 CapturedBytesToLock = *NumberOfBytesToLock;
3542 }
3544 {
3545 //
3546 // Get exception code
3547 //
3549 }
3550 _SEH2_END;
3551
3552 //
3553 // Catch illegal base address
3554 //
3555 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
3556
3557 //
3558 // Catch illegal region size
3559 //
3560 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToLock)
3561 {
3562 //
3563 // Fail
3564 //
3566 }
3567
3568 //
3569 // 0 is also illegal
3570 //
3571 if (!CapturedBytesToLock) return STATUS_INVALID_PARAMETER;
3572
3573 //
3574 // Get a reference to the process
3575 //
3580 (PVOID*)(&Process),
3581 NULL);
3582 if (!NT_SUCCESS(Status)) return Status;
3583
3584 //
3585 // Check if this is is system-mapped
3586 //
3587 if (MapType & MAP_SYSTEM)
3588 {
3589 //
3590 // Check for required privilege
3591 //
3593 {
3594 //
3595 // Fail: Don't have it
3596 //
3599 }
3600 }
3601
3602 //
3603 // Check if we should attach
3604 //
3605 if (CurrentProcess != Process)
3606 {
3607 //
3608 // Do it
3609 //
3611 Attached = TRUE;
3612 }
3613
3614 //
3615 // Call the internal function
3616 //
3617 Status = MiLockVirtualMemory(&CapturedBaseAddress,
3618 &CapturedBytesToLock,
3619 MapType);
3620
3621 //
3622 // Detach if needed
3623 //
3625
3626 //
3627 // Release reference
3628 //
3630
3631 //
3632 // Enter SEH to return data
3633 //
3634 _SEH2_TRY
3635 {
3636 //
3637 // Return data to user
3638 //
3639 *BaseAddress = CapturedBaseAddress;
3640 *NumberOfBytesToLock = CapturedBytesToLock;
3641 }
3643 {
3644 //
3645 // Get exception code
3646 //
3648 }
3649 _SEH2_END;
3650
3651 //
3652 // Return status
3653 //
3654 return Status;
3655}
static NTSTATUS MiLockVirtualMemory(IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
Definition: virtual.c:3341

Referenced by VirtualLock().

◆ NtProtectVirtualMemory()

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

Definition at line 3071 of file virtual.c.

3076{
3078 ULONG OldAccessProtection;
3079 ULONG Protection;
3080 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3082 SIZE_T NumberOfBytesToProtect = 0;
3087 PAGED_CODE();
3088
3089 //
3090 // Check for valid protection flags
3091 //
3092 Protection = NewAccessProtection & ~(PAGE_GUARD|PAGE_NOCACHE);
3093 if (Protection != PAGE_NOACCESS &&
3094 Protection != PAGE_READONLY &&
3095 Protection != PAGE_READWRITE &&
3096 Protection != PAGE_WRITECOPY &&
3097 Protection != PAGE_EXECUTE &&
3098 Protection != PAGE_EXECUTE_READ &&
3099 Protection != PAGE_EXECUTE_READWRITE &&
3100 Protection != PAGE_EXECUTE_WRITECOPY)
3101 {
3102 //
3103 // Fail
3104 //
3106 }
3107
3108 //
3109 // Check if we came from user mode
3110 //
3111 if (PreviousMode != KernelMode)
3112 {
3113 //
3114 // Enter SEH for probing
3115 //
3116 _SEH2_TRY
3117 {
3118 //
3119 // Validate all outputs
3120 //
3121 ProbeForWritePointer(UnsafeBaseAddress);
3122 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);
3123 ProbeForWriteUlong(UnsafeOldAccessProtection);
3124
3125 //
3126 // Capture them
3127 //
3128 BaseAddress = *UnsafeBaseAddress;
3129 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
3130 }
3132 {
3133 //
3134 // Get exception code
3135 //
3137 }
3138 _SEH2_END;
3139 }
3140 else
3141 {
3142 //
3143 // Capture directly
3144 //
3145 BaseAddress = *UnsafeBaseAddress;
3146 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
3147 }
3148
3149 //
3150 // Catch illegal base address
3151 //
3153
3154 //
3155 // Catch illegal region size
3156 //
3157 if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect)
3158 {
3159 //
3160 // Fail
3161 //
3163 }
3164
3165 //
3166 // 0 is also illegal
3167 //
3168 if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3;
3169
3170 //
3171 // Get a reference to the process
3172 //
3177 (PVOID*)(&Process),
3178 NULL);
3179 if (!NT_SUCCESS(Status)) return Status;
3180
3181 //
3182 // Check if we should attach
3183 //
3184 if (CurrentProcess != Process)
3185 {
3186 //
3187 // Do it
3188 //
3190 Attached = TRUE;
3191 }
3192
3193 //
3194 // Do the actual work
3195 //
3197 &BaseAddress,
3198 &NumberOfBytesToProtect,
3199 NewAccessProtection,
3200 &OldAccessProtection);
3201
3202 //
3203 // Detach if needed
3204 //
3206
3207 //
3208 // Release reference
3209 //
3211
3212 //
3213 // Enter SEH to return data
3214 //
3215 _SEH2_TRY
3216 {
3217 //
3218 // Return data to user
3219 //
3220 *UnsafeOldAccessProtection = OldAccessProtection;
3221 *UnsafeBaseAddress = BaseAddress;
3222 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
3223 }
3225 {
3226 }
3227 _SEH2_END;
3228
3229 //
3230 // Return status
3231 //
3232 return Status;
3233}
#define PAGE_EXECUTE_READ
Definition: nt_native.h:1307
#define PAGE_EXECUTE
Definition: nt_native.h:1306
#define PAGE_EXECUTE_READWRITE
Definition: nt_native.h:1308

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

◆ NtQueryVirtualMemory()

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

Definition at line 4369 of file virtual.c.

4375{
4378
4379 DPRINT("Querying class %d about address: %p\n", MemoryInformationClass, BaseAddress);
4380
4381 /* Bail out if the address is invalid */
4383
4384 /* Probe return buffer */
4386 if (PreviousMode != KernelMode)
4387 {
4388 _SEH2_TRY
4389 {
4390 ProbeForWrite(MemoryInformation,
4391 MemoryInformationLength,
4392 sizeof(ULONG_PTR));
4393
4395 }
4397 {
4399 }
4400 _SEH2_END;
4401
4402 if (!NT_SUCCESS(Status))
4403 {
4404 return Status;
4405 }
4406 }
4407
4408 switch(MemoryInformationClass)
4409 {
4411 /* Validate the size information of the class */
4412 if (MemoryInformationLength < sizeof(MEMORY_BASIC_INFORMATION))
4413 {
4414 /* The size is invalid */
4416 }
4419 MemoryInformation,
4420 MemoryInformationLength,
4421 ReturnLength);
4422 break;
4423
4424 case MemorySectionName:
4425 /* Validate the size information of the class */
4426 if (MemoryInformationLength < sizeof(MEMORY_SECTION_NAME))
4427 {
4428 /* The size is invalid */
4430 }
4433 MemoryInformation,
4434 MemoryInformationLength,
4435 ReturnLength);
4436 break;
4439 default:
4440 DPRINT1("Unhandled memory information class %d\n", MemoryInformationClass);
4441 break;
4442 }
4443
4444 return Status;
4445}
NTSTATUS NTAPI MiQueryMemorySectionName(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: section.c:1754
@ MemoryBasicInformation
Definition: mmtypes.h:183
@ MemorySectionName
Definition: mmtypes.h:185
@ MemoryWorkingSetList
Definition: mmtypes.h:184
@ MemoryBasicVlmInformation
Definition: mmtypes.h:186
NTSTATUS NTAPI MiQueryMemoryBasicInformation(IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength)
Definition: virtual.c:1662
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133

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

◆ NtReadVirtualMemory()

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

Definition at line 2776 of file virtual.c.

2781{
2785 SIZE_T BytesRead = 0;
2786 PAGED_CODE();
2787
2788 //
2789 // Check if we came from user mode
2790 //
2791 if (PreviousMode != KernelMode)
2792 {
2793 //
2794 // Validate the read addresses
2795 //
2796 if ((((ULONG_PTR)BaseAddress + NumberOfBytesToRead) < (ULONG_PTR)BaseAddress) ||
2797 (((ULONG_PTR)Buffer + NumberOfBytesToRead) < (ULONG_PTR)Buffer) ||
2798 (((ULONG_PTR)BaseAddress + NumberOfBytesToRead) > MmUserProbeAddress) ||
2799 (((ULONG_PTR)Buffer + NumberOfBytesToRead) > MmUserProbeAddress))
2800 {
2801 //
2802 // Don't allow to write into kernel space
2803 //
2805 }
2806
2807 //
2808 // Enter SEH for probe
2809 //
2810 _SEH2_TRY
2811 {
2812 //
2813 // Probe the output value
2814 //
2815 if (NumberOfBytesRead) ProbeForWriteSize_t(NumberOfBytesRead);
2816 }
2818 {
2819 //
2820 // Get exception code
2821 //
2823 }
2824 _SEH2_END;
2825 }
2826
2827 //
2828 // Don't do zero-byte transfers
2829 //
2830 if (NumberOfBytesToRead)
2831 {
2832 //
2833 // Reference the process
2834 //
2839 (PVOID*)(&Process),
2840 NULL);
2841 if (NT_SUCCESS(Status))
2842 {
2843 //
2844 // Do the copy
2845 //
2849 Buffer,
2850 NumberOfBytesToRead,
2852 &BytesRead);
2853
2854 //
2855 // Dereference the process
2856 //
2858 }
2859 }
2860
2861 //
2862 // Check if the caller sent this parameter
2863 //
2864 if (NumberOfBytesRead)
2865 {
2866 //
2867 // Enter SEH to guard write
2868 //
2869 _SEH2_TRY
2870 {
2871 //
2872 // Return the number of bytes read
2873 //
2874 *NumberOfBytesRead = BytesRead;
2875 }
2877 {
2878 }
2879 _SEH2_END;
2880 }
2881
2882 //
2883 // Return status
2884 //
2885 return Status;
2886}
Definition: bufpool.h:45
#define PROCESS_VM_READ
Definition: pstypes.h:162
NTSTATUS NTAPI MmCopyVirtualMemory(IN PEPROCESS SourceProcess, IN PVOID SourceAddress, IN PEPROCESS TargetProcess, OUT PVOID TargetAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T ReturnSize)
Definition: virtual.c:1271
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870

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

◆ NtResetWriteWatch()

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

Definition at line 4288 of file virtual.c.

4291{
4292 PVOID EndAddress;
4297
4298 //
4299 // Catch illegal base address
4300 //
4302
4303 //
4304 // Catch illegal region size
4305 //
4307 {
4308 //
4309 // Fail
4310 //
4312 }
4313
4314 //
4315 // Check if this is a local request
4316 //
4318 {
4319 //
4320 // No need to reference the process
4321 //
4323 }
4324 else
4325 {
4326 //
4327 // Reference the target
4328 //
4333 (PVOID *)&Process,
4334 NULL);
4335 if (!NT_SUCCESS(Status)) return Status;
4336 }
4337
4338 //
4339 // Compute the last address and validate it
4340 //
4341 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
4342 if (BaseAddress > EndAddress)
4343 {
4344 //
4345 // Fail
4346 //
4349 }
4350
4351 //
4352 // Oops :(
4353 //
4355
4356 //
4357 // Dereference if needed
4358 //
4360
4361 //
4362 // Return success
4363 //
4364 return STATUS_SUCCESS;
4365}
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693

Referenced by ResetWriteWatch().

◆ NtUnlockVirtualMemory()

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

Definition at line 3825 of file virtual.c.

3829{
3831 PEPROCESS CurrentProcess = PsGetCurrentProcess();
3836 PVOID CapturedBaseAddress;
3837 SIZE_T CapturedBytesToUnlock;
3838 PAGED_CODE();
3839
3840 //
3841 // Validate flags
3842 //
3843 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
3844 {
3845 //
3846 // Invalid set of flags
3847 //
3849 }
3850
3851 //
3852 // At least one flag must be specified
3853 //
3854 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
3855 {
3856 //
3857 // No flag given
3858 //
3860 }
3861
3862 //
3863 // Enter SEH for probing
3864 //
3865 _SEH2_TRY
3866 {
3867 //
3868 // Validate output data
3869 //
3871 ProbeForWriteSize_t(NumberOfBytesToUnlock);
3872
3873 //
3874 // Capture it
3875 //
3876 CapturedBaseAddress = *BaseAddress;
3877 CapturedBytesToUnlock = *NumberOfBytesToUnlock;
3878 }
3880 {
3881 //
3882 // Get exception code
3883 //
3885 }
3886 _SEH2_END;
3887
3888 //
3889 // Catch illegal base address
3890 //
3891 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
3892
3893 //
3894 // Catch illegal region size
3895 //
3896 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToUnlock)
3897 {
3898 //
3899 // Fail
3900 //
3902 }
3903
3904 //
3905 // 0 is also illegal
3906 //
3907 if (!CapturedBytesToUnlock) return STATUS_INVALID_PARAMETER;
3908
3909 //
3910 // Get a reference to the process
3911 //
3916 (PVOID*)(&Process),
3917 NULL);
3918 if (!NT_SUCCESS(Status)) return Status;
3919
3920 //
3921 // Check if this is is system-mapped
3922 //
3923 if (MapType & MAP_SYSTEM)
3924 {
3925 //
3926 // Check for required privilege
3927 //
3929 {
3930 //
3931 // Fail: Don't have it
3932 //
3935 }
3936 }
3937
3938 //
3939 // Check if we should attach
3940 //
3941 if (CurrentProcess != Process)
3942 {
3943 //
3944 // Do it
3945 //
3947 Attached = TRUE;
3948 }
3949
3950 //
3951 // Call the internal function
3952 //
3953 Status = MiUnlockVirtualMemory(&CapturedBaseAddress,
3954 &CapturedBytesToUnlock,
3955 MapType);
3956
3957 //
3958 // Detach if needed
3959 //
3961
3962 //
3963 // Release reference
3964 //
3966
3967 //
3968 // Enter SEH to return data
3969 //
3970 _SEH2_TRY
3971 {
3972 //
3973 // Return data to user
3974 //
3975 *BaseAddress = CapturedBaseAddress;
3976 *NumberOfBytesToUnlock = CapturedBytesToUnlock;
3977 }
3979 {
3980 //
3981 // Get exception code
3982 //
3984 }
3985 _SEH2_END;
3986
3987 //
3988 // Return status
3989 //
3990 return STATUS_SUCCESS;
3991}
static NTSTATUS MiUnlockVirtualMemory(IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
Definition: virtual.c:3660

Referenced by VirtualUnlock().

◆ NtWriteVirtualMemory()

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

Definition at line 2890 of file virtual.c.

2895{
2899 SIZE_T BytesWritten = 0;
2900 PAGED_CODE();
2901
2902 //
2903 // Check if we came from user mode
2904 //
2905 if (PreviousMode != KernelMode)
2906 {
2907 //
2908 // Validate the read addresses
2909 //
2910 if ((((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) < (ULONG_PTR)BaseAddress) ||
2911 (((ULONG_PTR)Buffer + NumberOfBytesToWrite) < (ULONG_PTR)Buffer) ||
2912 (((ULONG_PTR)BaseAddress + NumberOfBytesToWrite) > MmUserProbeAddress) ||
2913 (((ULONG_PTR)Buffer + NumberOfBytesToWrite) > MmUserProbeAddress))
2914 {
2915 //
2916 // Don't allow to write into kernel space
2917 //
2919 }
2920
2921 //
2922 // Enter SEH for probe
2923 //
2924 _SEH2_TRY
2925 {
2926 //
2927 // Probe the output value
2928 //
2929 if (NumberOfBytesWritten) ProbeForWriteSize_t(NumberOfBytesWritten);
2930 }
2932 {
2933 //
2934 // Get exception code
2935 //
2937 }
2938 _SEH2_END;
2939 }
2940
2941 //
2942 // Don't do zero-byte transfers
2943 //
2944 if (NumberOfBytesToWrite)
2945 {
2946 //
2947 // Reference the process
2948 //
2953 (PVOID*)&Process,
2954 NULL);
2955 if (NT_SUCCESS(Status))
2956 {
2957 //
2958 // Do the copy
2959 //
2961 Buffer,
2962 Process,
2964 NumberOfBytesToWrite,
2966 &BytesWritten);
2967
2968 //
2969 // Dereference the process
2970 //
2972 }
2973 }
2974
2975 //
2976 // Check if the caller sent this parameter
2977 //
2978 if (NumberOfBytesWritten)
2979 {
2980 //
2981 // Enter SEH to guard write
2982 //
2983 _SEH2_TRY
2984 {
2985 //
2986 // Return the number of bytes written
2987 //
2988 *NumberOfBytesWritten = BytesWritten;
2989 }
2991 {
2992 }
2993 _SEH2_END;
2994 }
2995
2996 //
2997 // Return status
2998 //
2999 return Status;
3000}
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:960

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