ReactOS 0.4.17-dev-684-ga6524ef
pagfault.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
#include <mm/ARM3/miarm.h>
Include dependency graph for pagfault.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define MODULE_INVOLVED_IN_ARM3
 
#define HYDRA_PROCESS   (PEPROCESS)1
 
#define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7)
 

Functions

VOID NTAPI MmRebalanceMemoryConsumersAndWait (VOID)
 
static NTSTATUS NTAPI MiCheckForUserStackOverflow (IN PVOID Address, IN PVOID TrapInformation)
 
FORCEINLINE BOOLEAN MiIsAccessAllowed (_In_ ULONG ProtectionMask, _In_ BOOLEAN Write, _In_ BOOLEAN Execute)
 
static NTSTATUS NTAPI MiAccessCheck (IN PMMPTE PointerPte, IN BOOLEAN StoreInstruction, IN KPROCESSOR_MODE PreviousMode, IN ULONG_PTR ProtectionMask, IN PVOID TrapFrame, IN BOOLEAN LockHeld)
 
static PMMPTE NTAPI MiCheckVirtualAddress (IN PVOID VirtualAddress, OUT PULONG ProtectCode, OUT PMMVAD *ProtoVad)
 
NTSTATUS FASTCALL MiCheckPdeForPagedPool (IN PVOID Address)
 
VOID NTAPI MiZeroPfn (IN PFN_NUMBER PageFrameNumber)
 
VOID NTAPI MiCopyPfn (_In_ PFN_NUMBER DestPage, _In_ PFN_NUMBER SrcPage)
 
static NTSTATUS NTAPI MiResolveDemandZeroFault (IN PVOID Address, IN PMMPTE PointerPte, IN ULONG Protection, IN PEPROCESS Process, IN KIRQL OldIrql)
 
static NTSTATUS NTAPI MiCompleteProtoPteFault (IN BOOLEAN StoreInstruction, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN KIRQL OldIrql, IN PMMPFN *LockedProtoPfn)
 
static NTSTATUS NTAPI MiResolvePageFileFault (_In_ BOOLEAN StoreInstruction, _In_ PVOID FaultingAddress, _In_ PMMPTE PointerPte, _In_ PEPROCESS CurrentProcess, _Inout_ KIRQL *OldIrql)
 
static NTSTATUS NTAPI MiResolveTransitionFault (IN BOOLEAN StoreInstruction, IN PVOID FaultingAddress, IN PMMPTE PointerPte, IN PEPROCESS CurrentProcess, IN KIRQL OldIrql, OUT PKEVENT **InPageBlock)
 
static NTSTATUS NTAPI MiResolveProtoPteFault (IN BOOLEAN StoreInstruction, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN OUT PMMPFN *OutPfn, OUT PVOID *PageFileData, OUT PMMPTE PteValue, IN PEPROCESS Process, IN KIRQL OldIrql, IN PVOID TrapInformation)
 
NTSTATUS NTAPI MiDispatchFault (IN ULONG FaultCode, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN BOOLEAN Recursive, IN PEPROCESS Process, IN PVOID TrapInformation, IN PMMVAD Vad)
 
NTSTATUS NTAPI MmArmAccessFault (IN ULONG FaultCode, IN PVOID Address, IN KPROCESSOR_MODE Mode, IN PVOID TrapInformation)
 
NTSTATUS NTAPI MmGetExecuteOptions (IN PULONG ExecuteOptions)
 
NTSTATUS NTAPI MmSetExecuteOptions (IN ULONG ExecuteOptions)
 

Macro Definition Documentation

◆ _BYTE_MASK

#define _BYTE_MASK (   Bit0,
  Bit1,
  Bit2,
  Bit3,
  Bit4,
  Bit5,
  Bit6,
  Bit7 
)
Value:
(Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \
((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7)

◆ HYDRA_PROCESS

#define HYDRA_PROCESS   (PEPROCESS)1

Definition at line 24 of file pagfault.c.

◆ MODULE_INVOLVED_IN_ARM3

#define MODULE_INVOLVED_IN_ARM3

Definition at line 15 of file pagfault.c.

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file pagfault.c.

Function Documentation

◆ MiAccessCheck()

static NTSTATUS NTAPI MiAccessCheck ( IN PMMPTE  PointerPte,
IN BOOLEAN  StoreInstruction,
IN KPROCESSOR_MODE  PreviousMode,
IN ULONG_PTR  ProtectionMask,
IN PVOID  TrapFrame,
IN BOOLEAN  LockHeld 
)
static

Definition at line 188 of file pagfault.c.

194{
196
197 /* Check for invalid user-mode access */
198 if ((PreviousMode == UserMode) && (PointerPte > MiHighestUserPte))
199 {
201 }
202
203 /* Capture the PTE -- is it valid? */
204 TempPte = *PointerPte;
205 if (TempPte.u.Hard.Valid)
206 {
207 /* Was someone trying to write to it? */
208 if (StoreInstruction)
209 {
210 /* Is it writable?*/
213 {
214 /* Then there's nothing to worry about */
215 return STATUS_SUCCESS;
216 }
217
218 /* Oops! This isn't allowed */
220 }
221
222 /* Someone was trying to read from a valid PTE, that's fine too */
223 return STATUS_SUCCESS;
224 }
225
226 /* Check if the protection on the page allows what is being attempted */
227 if (!MiIsAccessAllowed(ProtectionMask, StoreInstruction, FALSE))
228 {
230 }
231
232 /* Check if this is a guard page */
233 if ((ProtectionMask & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
234 {
235 ASSERT(ProtectionMask != MM_DECOMMIT);
236
237 /* Attached processes can't expand their stack */
239
240 /* No support for prototype PTEs yet */
241 ASSERT(TempPte.u.Soft.Prototype == 0);
242
243 /* Remove the guard page bit, and return a guard page violation */
244 TempPte.u.Soft.Protection = ProtectionMask & ~MM_GUARDPAGE;
245 ASSERT(TempPte.u.Long != 0);
246 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
248 }
249
250 /* Nothing to do */
251 return STATUS_SUCCESS;
252}
_In_ PVOID _In_ ULONG _Out_ PVOID _In_ ULONG _Inout_ PULONG _In_ KPROCESSOR_MODE PreviousMode
HARDWARE_PTE_ARMV6 TempPte
Definition: winldr.c:76
#define FALSE
Definition: types.h:117
#define STATUS_ACCESS_VIOLATION
PMMPTE MiHighestUserPte
Definition: mminit.c:234
#define MM_GUARDPAGE
Definition: miarm.h:57
#define MM_DECOMMIT
Definition: miarm.h:64
FORCEINLINE VOID MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte, IN MMPTE InvalidPte)
Definition: miarm.h:1000
#define MM_PROTECT_SPECIAL
Definition: miarm.h:59
#define ASSERT(a)
Definition: mode.c:44
#define UserMode
Definition: asm.h:39
#define MI_IS_PAGE_COPY_ON_WRITE(x)
Definition: mm.h:110
#define MI_IS_PAGE_WRITEABLE(x)
Definition: mm.h:106
#define STATUS_GUARD_PAGE_VIOLATION
Definition: ntstatus.h:262
FORCEINLINE BOOLEAN MiIsAccessAllowed(_In_ ULONG ProtectionMask, _In_ BOOLEAN Write, _In_ BOOLEAN Execute)
Definition: pagfault.c:158
BOOLEAN NTAPI KeIsAttachedProcess(VOID)
Definition: procobj.c:693
#define STATUS_SUCCESS
Definition: shellext.h:65

Referenced by MiResolveProtoPteFault(), and MmArmAccessFault().

◆ MiCheckForUserStackOverflow()

static NTSTATUS NTAPI MiCheckForUserStackOverflow ( IN PVOID  Address,
IN PVOID  TrapInformation 
)
static

Definition at line 34 of file pagfault.c.

36{
37 PETHREAD CurrentThread = PsGetCurrentThread();
38 PTEB Teb = CurrentThread->Tcb.Teb;
39 PVOID StackBase, DeallocationStack, NextStackAddress;
40 SIZE_T GuaranteedSize;
42
43 /* Do we own the address space lock? */
44 if (CurrentThread->AddressSpaceOwner == 1)
45 {
46 /* This isn't valid */
47 DPRINT1("Process owns address space lock\n");
50 }
51
52 /* Are we attached? */
54 {
55 /* This isn't valid */
56 DPRINT1("Process is attached\n");
58 }
59
60 /* Read the current settings */
61 StackBase = Teb->NtTib.StackBase;
62 DeallocationStack = Teb->DeallocationStack;
63 GuaranteedSize = Teb->GuaranteedStackBytes;
64 DPRINT("Handling guard page fault with Stacks Addresses 0x%p and 0x%p, guarantee: %lx\n",
65 StackBase, DeallocationStack, GuaranteedSize);
66
67 /* Guarantees make this code harder, for now, assume there aren't any */
68 ASSERT(GuaranteedSize == 0);
69
70 /* So allocate only the minimum guard page size */
71 GuaranteedSize = PAGE_SIZE;
72
73 /* Does this faulting stack address actually exist in the stack? */
74 if ((Address >= StackBase) || (Address < DeallocationStack))
75 {
76 /* That's odd... */
77 DPRINT1("Faulting address outside of stack bounds. Address=%p, StackBase=%p, DeallocationStack=%p\n",
78 Address, StackBase, DeallocationStack);
80 }
81
82 /* This is where the stack will start now */
83 NextStackAddress = (PVOID)((ULONG_PTR)PAGE_ALIGN(Address) - GuaranteedSize);
84
85 /* Do we have at least one page between here and the end of the stack? */
86 if (((ULONG_PTR)NextStackAddress - PAGE_SIZE) <= (ULONG_PTR)DeallocationStack)
87 {
88 /* We don't -- Trying to make this guard page valid now */
89 DPRINT1("Close to our death...\n");
90
91 /* Calculate the next memory address */
92 NextStackAddress = (PVOID)((ULONG_PTR)PAGE_ALIGN(DeallocationStack) + GuaranteedSize);
93
94 /* Allocate the memory */
95 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
96 &NextStackAddress,
97 0,
98 &GuaranteedSize,
101 if (NT_SUCCESS(Status))
102 {
103 /* Success! */
104 Teb->NtTib.StackLimit = NextStackAddress;
105
106#if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
107 /* Update WOW64 32-bit TEB stack limit */
108 if (CurrentThread->ThreadsProcess->Wow64Process != NULL)
109 {
110 PS_GET_TEB32_FROM_TEB(Teb)->NtTib.StackLimit = PtrToUlong(Teb->NtTib.StackLimit);
111 }
112#endif
113 }
114 else
115 {
116 DPRINT1("Failed to allocate memory\n");
117 }
118
120 }
121
122 /* Don't handle this flag yet */
124
125 /* Update the stack limit */
126 Teb->NtTib.StackLimit = (PVOID)((ULONG_PTR)NextStackAddress + GuaranteedSize);
127
128#if defined(_WIN64) && defined(BUILD_WOW64_ENABLED)
129 /* Update WOW64 32-bit TEB stack limit */
130 if (CurrentThread->ThreadsProcess->Wow64Process != NULL)
131 {
132 PS_GET_TEB32_FROM_TEB(Teb)->NtTib.StackLimit = PtrToUlong(Teb->NtTib.StackLimit);
133 }
134#endif
135
136 /* Now move the guard page to the next page */
137 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
138 &NextStackAddress,
139 0,
140 &GuaranteedSize,
144 {
145 /* We did it! */
146 DPRINT("Guard page handled successfully for %p\n", Address);
148 }
149
150 /* Fail, we couldn't move the guard page */
151 DPRINT1("Guard page failure: %lx\n", Status);
152 ASSERT(FALSE);
154}
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
PPEB Peb
Definition: dllmain.c:27
#define ULONG_PTR
Definition: config.h:101
#define PtrToUlong(u)
Definition: config.h:107
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define PAGE_SIZE
Definition: env_spec_w32.h:49
Status
Definition: gdiplustypes.h:24
#define FLG_DISABLE_STACK_EXTENSION
Definition: pstypes.h:66
#define PAGE_READWRITE
Definition: nt_native.h:1307
#define NtCurrentProcess()
Definition: nt_native.h:1660
#define MEM_COMMIT
Definition: nt_native.h:1316
#define PAGE_GUARD
Definition: nt_native.h:1313
BOOLEAN NTAPI KeAreAllApcsDisabled(VOID)
Definition: apc.c:985
#define STATUS_PAGE_FAULT_GUARD_PAGE
Definition: ntstatus.h:150
#define STATUS_ALREADY_COMMITTED
Definition: ntstatus.h:363
#define STATUS_STACK_OVERFLOW
Definition: ntstatus.h:583
static WCHAR Address[46]
Definition: ping.c:68
#define DPRINT
Definition: sndvol32.h:73
KTHREAD Tcb
Definition: pstypes.h:1198
PVOID Teb
Definition: ketypes.h:1954
PVOID StackLimit
Definition: compat.h:713
PVOID StackBase
Definition: compat.h:712
ULONG NtGlobalFlag
Definition: ntddk_ex.h:270
Definition: compat.h:836
NT_TIB NtTib
Definition: ntddk_ex.h:332
ULONG GuaranteedStackBytes
Definition: winternl.h:668
PVOID DeallocationStack
Definition: compat.h:878
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define PAGE_ALIGN(Va)
#define PsGetCurrentProcess
Definition: psfuncs.h:17

Referenced by MmArmAccessFault().

◆ MiCheckPdeForPagedPool()

NTSTATUS FASTCALL MiCheckPdeForPagedPool ( IN PVOID  Address)

Definition at line 495 of file pagfault.c.

496{
498}

Referenced by MiDeletePte(), MiInitializePfn(), MiInitializePfnAndMakePteValid(), and MmArmAccessFault().

◆ MiCheckVirtualAddress()

static PMMPTE NTAPI MiCheckVirtualAddress ( IN PVOID  VirtualAddress,
OUT PULONG  ProtectCode,
OUT PMMVAD ProtoVad 
)
static

Definition at line 257 of file pagfault.c.

260{
261 PMMVAD Vad;
262 PMMPTE PointerPte;
263
264 /* No prototype/section support for now */
265 *ProtoVad = NULL;
266
267 /* User or kernel fault? */
269 {
270 /* Special case for shared data */
272 {
273 /* It's a read-only page */
274 *ProtectCode = MM_READONLY;
275 return MmSharedUserDataPte;
276 }
277
278 /* Find the VAD, it might not exist if the address is bogus */
280 if (!Vad)
281 {
282 /* Bogus virtual address */
283 *ProtectCode = MM_NOACCESS;
284 return NULL;
285 }
286
287 /* ReactOS does not handle physical memory VADs yet */
289
290 /* Check if it's a section, or just an allocation */
291 if (Vad->u.VadFlags.PrivateMemory)
292 {
293 /* ReactOS does not handle AWE VADs yet */
294 ASSERT(Vad->u.VadFlags.VadType != VadAwe);
295
296 /* This must be a TEB/PEB VAD */
297 if (Vad->u.VadFlags.MemCommit)
298 {
299 /* It's committed, so return the VAD protection */
300 *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
301 }
302 else
303 {
304 /* It has not yet been committed, so return no access */
305 *ProtectCode = MM_NOACCESS;
306 }
307
308 /* In both cases, return no PTE */
309 return NULL;
310 }
311 else
312 {
313 /* ReactOS does not supoprt these VADs yet */
316
317 /* Return the proto VAD */
318 *ProtoVad = Vad;
319
320 /* Get the prototype PTE for this page */
321 PointerPte = (((ULONG_PTR)VirtualAddress >> PAGE_SHIFT) - Vad->StartingVpn) + Vad->FirstPrototypePte;
322 ASSERT(PointerPte != NULL);
323 ASSERT(PointerPte <= Vad->LastContiguousPte);
324
325 /* Return the Prototype PTE and the protection for the page mapping */
326 *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
327 return PointerPte;
328 }
329 }
331 {
332 /* This should never happen, as these addresses are handled by the double-maping */
335 {
336 /* Fail such access */
337 *ProtectCode = MM_NOACCESS;
338 return NULL;
339 }
340
341 /* Return full access rights */
342 *ProtectCode = MM_EXECUTE_READWRITE;
343 return NULL;
344 }
346 {
347 /* ReactOS does not have an image list yet, so bail out to failure case */
349 }
350
351 /* Default case -- failure */
352 *ProtectCode = MM_NOACCESS;
353 return NULL;
354}
#define MM_HIGHEST_USER_ADDRESS
Definition: armddk.h:17
#define MM_READONLY
Definition: bootanim.c:18
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
PMMVAD NTAPI MiLocateAddress(IN PVOID VirtualAddress)
PMMPTE MmSharedUserDataPte
Definition: mminit.c:26
PVOID MmPagedPoolStart
Definition: miarm.h:579
PMM_SESSION_SPACE MmSessionSpace
Definition: session.c:21
#define MI_IS_SESSION_ADDRESS(Address)
Definition: miarm.h:185
#define MM_EXECUTE_READWRITE
Definition: miarm.h:49
MM_PAGED_POOL_INFO MmPagedPoolInfo
Definition: pool.c:25
#define MI_IS_PAGE_TABLE_ADDRESS(Address)
Definition: miarm.h:191
#define MM_NOACCESS
Definition: miarm.h:65
struct _MMPTE * PMMPTE
#define MM_SHARED_USER_DATA_VA
Definition: mmtypes.h:48
@ VadAwe
Definition: mmtypes.h:207
@ VadDevicePhysicalMemory
Definition: mmtypes.h:205
@ VadImageMap
Definition: mmtypes.h:206
#define MiAddressToPte(x)
Definition: mm.h:145
ULONG ExtendableFile
Definition: mmtypes.h:712
ULONG_PTR MemCommit
Definition: mmtypes.h:695
ULONG_PTR Protection
Definition: mmtypes.h:696
ULONG_PTR VadType
Definition: mmtypes.h:694
ULONG_PTR PrivateMemory
Definition: mmtypes.h:698
union _MMVAD::@2880 u
union _MMVAD::@2881 u2
ULONG_PTR StartingVpn
Definition: mmtypes.h:729
MMVAD_FLAGS2 VadFlags2
Definition: mmtypes.h:742
MMVAD_FLAGS VadFlags
Definition: mmtypes.h:734
PMMPTE FirstPrototypePte
Definition: mmtypes.h:737
PMMPTE LastPteForPagedPool
Definition: mm.h:508
LIST_ENTRY ImageList
Definition: miarm.h:493
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDMATRANSACTION _In_ PFN_WDF_PROGRAM_DMA _In_ WDF_DMA_DIRECTION _In_ PMDL _In_ PVOID VirtualAddress

Referenced by MmArmAccessFault().

◆ MiCompleteProtoPteFault()

static NTSTATUS NTAPI MiCompleteProtoPteFault ( IN BOOLEAN  StoreInstruction,
IN PVOID  Address,
IN PMMPTE  PointerPte,
IN PMMPTE  PointerProtoPte,
IN KIRQL  OldIrql,
IN PMMPFN LockedProtoPfn 
)
static

Definition at line 791 of file pagfault.c.

797{
799 PMMPTE OriginalPte, PageTablePte;
800 ULONG_PTR Protection;
801 PFN_NUMBER PageFrameIndex;
802 PMMPFN Pfn1, Pfn2;
803 BOOLEAN OriginalProtection, DirtyPage;
804
805 /* Must be called with an valid prototype PTE, with the PFN lock held */
807 ASSERT(PointerProtoPte->u.Hard.Valid == 1);
808
809 /* Get the page */
810 PageFrameIndex = PFN_FROM_PTE(PointerProtoPte);
811
812 /* Get the PFN entry and set it as a prototype PTE */
813 Pfn1 = MiGetPfnEntry(PageFrameIndex);
814 Pfn1->u3.e1.PrototypePte = 1;
815
816 /* Increment the share count for the page table */
817 PageTablePte = MiAddressToPte(PointerPte);
818 Pfn2 = MiGetPfnEntry(PageTablePte->u.Hard.PageFrameNumber);
819 Pfn2->u2.ShareCount++;
820
821 /* Check where we should be getting the protection information from */
822 if (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
823 {
824 /* Get the protection from the PTE, there's no real Proto PTE data */
825 Protection = PointerPte->u.Soft.Protection;
826
827 /* Remember that we did not use the proto protection */
828 OriginalProtection = FALSE;
829 }
830 else
831 {
832 /* Get the protection from the original PTE link */
833 OriginalPte = &Pfn1->OriginalPte;
834 Protection = OriginalPte->u.Soft.Protection;
835
836 /* Remember that we used the original protection */
837 OriginalProtection = TRUE;
838
839 /* Check if this was a write on a read only proto */
840 if ((StoreInstruction) && !(Protection & MM_READWRITE))
841 {
842 /* Clear the flag */
843 StoreInstruction = 0;
844 }
845 }
846
847 /* Check if this was a write on a non-COW page */
848 DirtyPage = FALSE;
849 if ((StoreInstruction) && ((Protection & MM_WRITECOPY) != MM_WRITECOPY))
850 {
851 /* Then the page should be marked dirty */
852 DirtyPage = TRUE;
853
854 /* ReactOS check */
855 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype != 0);
856 }
857
858 /* Did we get a locked incoming PFN? */
859 if (*LockedProtoPfn)
860 {
861 /* Drop a reference */
862 ASSERT((*LockedProtoPfn)->u3.e2.ReferenceCount >= 1);
863 MiDereferencePfnAndDropLockCount(*LockedProtoPfn);
864 *LockedProtoPfn = NULL;
865 }
866
867 /* Release the PFN lock */
868 MiReleasePfnLock(OldIrql);
869
870 /* Remove special/caching bits */
871 Protection &= ~MM_PROTECT_SPECIAL;
872
873 /* Setup caching */
874 if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
875 {
876 /* Write combining, no caching */
879 }
880 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
881 {
882 /* Write through, no caching */
885 }
886
887 /* Check if this is a kernel or user address */
889 {
890 /* Build the user PTE */
891 MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, Protection, PageFrameIndex);
892 }
893 else
894 {
895 /* Build the kernel PTE */
896 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, PageFrameIndex);
897 }
898
899 /* Set the dirty flag if needed */
900 if (DirtyPage) MI_MAKE_DIRTY_PAGE(&TempPte);
901
902 /* Write the PTE */
903 MI_WRITE_VALID_PTE(PointerPte, TempPte);
904
905 /* Reset the protection if needed */
906 if (OriginalProtection) Protection = MM_ZERO_ACCESS;
907
908 /* Return success */
909 ASSERT(PointerPte == MiAddressToPte(Address));
910 return STATUS_SUCCESS;
911}
ULONG_PTR PFN_NUMBER
unsigned char BOOLEAN
Definition: actypes.h:127
#define MM_READWRITE
Definition: bootanim.c:19
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:834
@ MiWriteCombined
Definition: miarm.h:416
@ MiNonCached
Definition: miarm.h:414
FORCEINLINE VOID MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1622
#define MM_ZERO_ACCESS
Definition: miarm.h:43
FORCEINLINE VOID MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte, IN PMMPTE MappingPte, IN ULONG_PTR ProtectionMask, IN PFN_NUMBER PageFrameNumber)
Definition: miarm.h:813
#define MI_PTE_LOOKUP_NEEDED
Definition: miarm.h:245
FORCEINLINE VOID MI_WRITE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:967
#define MM_WRITECOPY
Definition: miarm.h:48
#define MI_PAGE_WRITE_COMBINED(x)
Definition: mm.h:103
#define MI_PAGE_DISABLE_CACHE(x)
Definition: mm.h:101
#define MmSystemRangeStart
Definition: mm.h:32
#define MI_PAGE_WRITE_THROUGH(x)
Definition: mm.h:102
#define MI_MAKE_DIRTY_PAGE(x)
Definition: mm.h:98
#define PFN_FROM_PTE(v)
Definition: mm.h:92
FORCEINLINE PMMPFN MiGetPfnEntry(IN PFN_NUMBER Pfn)
Definition: mm.h:1046
#define MI_ASSERT_PFN_LOCK_HELD()
Definition: mm.h:1042
USHORT CacheAttribute
Definition: mm.h:377
USHORT PrototypePte
Definition: mm.h:373
Definition: mm.h:390
union _MMPFN::@1980 u3
MMPTE OriginalPte
Definition: mm.h:426
union _MMPFN::@1979 u2
MMPFNENTRY e1
Definition: mm.h:413
ULONG_PTR ShareCount
Definition: mm.h:406
ULONG64 PageFrameNumber
Definition: mmtypes.h:171
ULONG64 Protection
Definition: mmtypes.h:88
ULONG64 Prototype
Definition: mmtypes.h:89
MMPTE_SOFTWARE Soft
Definition: mmtypes.h:219
union _MMPTE::@2559 u
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

Referenced by MiDispatchFault(), and MiResolveProtoPteFault().

◆ MiCopyPfn()

VOID NTAPI MiCopyPfn ( _In_ PFN_NUMBER  DestPage,
_In_ PFN_NUMBER  SrcPage 
)

Definition at line 549 of file pagfault.c.

552{
553 PMMPTE SysPtes;
555 PMMPFN DestPfn, SrcPfn;
556 PVOID DestAddress;
557 const VOID* SrcAddress;
558
559 /* Get the PFNs */
560 DestPfn = MiGetPfnEntry(DestPage);
561 ASSERT(DestPfn);
562 SrcPfn = MiGetPfnEntry(SrcPage);
563 ASSERT(SrcPfn);
564
565 /* Grab 2 system PTEs */
567 ASSERT(SysPtes);
568
569 /* Initialize the destination PTE */
571 TempPte.u.Hard.PageFrameNumber = DestPage;
572
573 /* Setup caching */
574 if (DestPfn->u3.e1.CacheAttribute == MiWriteCombined)
575 {
576 /* Write combining, no caching */
579 }
580 else if (DestPfn->u3.e1.CacheAttribute == MiNonCached)
581 {
582 /* Write through, no caching */
585 }
586
587 /* Make the system PTE valid with our PFN */
588 MI_WRITE_VALID_PTE(&SysPtes[0], TempPte);
589
590 /* Initialize the source PTE */
592 TempPte.u.Hard.PageFrameNumber = SrcPage;
593
594 /* Setup caching */
595 if (SrcPfn->u3.e1.CacheAttribute == MiNonCached)
596 {
598 }
599
600 /* Make the system PTE valid with our PFN */
601 MI_WRITE_VALID_PTE(&SysPtes[1], TempPte);
602
603 /* Get the addresses and perform the copy */
604 DestAddress = MiPteToAddress(&SysPtes[0]);
605 SrcAddress = MiPteToAddress(&SysPtes[1]);
606 RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
607
608 /* Now get rid of it */
610}
@ SystemPteSpace
Definition: miarm.h:407
VOID NTAPI MiReleaseSystemPtes(IN PMMPTE StartingPte, IN ULONG NumberOfPtes, IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType)
Definition: syspte.c:264
PMMPTE NTAPI MiReserveSystemPtes(IN ULONG NumberOfPtes, IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType)
Definition: syspte.c:246
#define MiPteToAddress(_Pte)
Definition: mm.h:116
MMPTE ValidKernelPte
Definition: init.c:29
ULONG PageFrameNumber
Definition: mmtypes.h:109
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263

Referenced by MiResolveProtoPteFault(), and MmArmAccessFault().

◆ MiDispatchFault()

NTSTATUS NTAPI MiDispatchFault ( IN ULONG  FaultCode,
IN PVOID  Address,
IN PMMPTE  PointerPte,
IN PMMPTE  PointerProtoPte,
IN BOOLEAN  Recursive,
IN PEPROCESS  Process,
IN PVOID  TrapInformation,
IN PMMVAD  Vad 
)

Definition at line 1354 of file pagfault.c.

1362{
1363 MMPTE TempPte;
1364 KIRQL OldIrql, LockIrql;
1366 PMMPTE SuperProtoPte;
1367 PMMPFN Pfn1, OutPfn = NULL;
1368 PFN_NUMBER PageFrameIndex;
1369 PFN_COUNT PteCount, ProcessedPtes;
1370 DPRINT("ARM3 Page Fault Dispatcher for address: %p in process: %p\n",
1371 Address,
1372 Process);
1373
1374 /* Make sure the addresses are ok */
1375 ASSERT(PointerPte == MiAddressToPte(Address));
1376
1377 //
1378 // Make sure APCs are off and we're not at dispatch
1379 //
1383
1384 //
1385 // Grab a copy of the PTE
1386 //
1387 TempPte = *PointerPte;
1388
1389 /* Do we have a prototype PTE? */
1390 if (PointerProtoPte)
1391 {
1392 /* This should never happen */
1393 ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
1394
1395 /* Check if this is a kernel-mode address */
1396 SuperProtoPte = MiAddressToPte(PointerProtoPte);
1398 {
1399 /* Lock the PFN database */
1400 LockIrql = MiAcquirePfnLock();
1401
1402 /* Has the PTE been made valid yet? */
1403 if (!SuperProtoPte->u.Hard.Valid)
1404 {
1405 ASSERT(FALSE);
1406 }
1407 else if (PointerPte->u.Hard.Valid == 1)
1408 {
1409 ASSERT(FALSE);
1410 }
1411
1412 /* Resolve the fault -- this will release the PFN lock */
1414 Address,
1415 PointerPte,
1416 PointerProtoPte,
1417 &OutPfn,
1418 NULL,
1419 NULL,
1420 Process,
1421 LockIrql,
1422 TrapInformation);
1424
1425 /* Complete this as a transition fault */
1429 return Status;
1430 }
1431 else
1432 {
1433 /* We only handle the lookup path */
1434 ASSERT(PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
1435
1436 /* Is there a non-image VAD? */
1437 if ((Vad) &&
1438 (Vad->u.VadFlags.VadType != VadImageMap) &&
1439 !(Vad->u2.VadFlags2.ExtendableFile))
1440 {
1441 /* One day, ReactOS will cluster faults */
1443 DPRINT("Should cluster fault, but won't\n");
1444 }
1445
1446 /* Only one PTE to handle for now */
1447 PteCount = 1;
1448 ProcessedPtes = 0;
1449
1450 /* Lock the PFN database */
1451 LockIrql = MiAcquirePfnLock();
1452
1453 /* We only handle the valid path */
1454 ASSERT(SuperProtoPte->u.Hard.Valid == 1);
1455
1456 /* Capture the PTE */
1457 TempPte = *PointerProtoPte;
1458
1459 /* Loop to handle future case of clustered faults */
1460 while (TRUE)
1461 {
1462 /* For our current usage, this should be true */
1463 if (TempPte.u.Hard.Valid == 1)
1464 {
1465 /* Bump the share count on the PTE */
1466 PageFrameIndex = PFN_FROM_PTE(&TempPte);
1467 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1468 Pfn1->u2.ShareCount++;
1469 }
1470 else if ((TempPte.u.Soft.Prototype == 0) &&
1471 (TempPte.u.Soft.Transition == 1))
1472 {
1473 /* This is a standby page, bring it back from the cache */
1474 PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1475 DPRINT("oooh, shiny, a soft fault! 0x%lx\n", PageFrameIndex);
1476 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1478
1479 /* Should not yet happen in ReactOS */
1480 ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
1481 ASSERT(Pfn1->u4.InPageError == 0);
1482
1483 /* Get the page */
1485
1486 /* Bump its reference count */
1487 ASSERT(Pfn1->u2.ShareCount == 0);
1488 InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1489 Pfn1->u2.ShareCount++;
1490
1491 /* Make it valid again */
1492 /* This looks like another macro.... */
1494 ASSERT(PointerProtoPte->u.Hard.Valid == 0);
1495 ASSERT(PointerProtoPte->u.Trans.Prototype == 0);
1496 ASSERT(PointerProtoPte->u.Trans.Transition == 1);
1497 TempPte.u.Long = (PointerProtoPte->u.Long & ~0xFFF) |
1498 MmProtectToPteMask[PointerProtoPte->u.Trans.Protection];
1499 TempPte.u.Hard.Valid = 1;
1501
1502 /* Is the PTE writeable? */
1503 if ((Pfn1->u3.e1.Modified) &&
1506 {
1507 /* Make it dirty */
1509 }
1510 else
1511 {
1512 /* Make it clean */
1514 }
1515
1516 /* Write the valid PTE */
1517 MI_WRITE_VALID_PTE(PointerProtoPte, TempPte);
1518 ASSERT(PointerPte->u.Hard.Valid == 0);
1519 }
1520 else
1521 {
1522 /* Page is invalid, get out of the loop */
1523 break;
1524 }
1525
1526 /* One more done, was it the last? */
1527 if (++ProcessedPtes == PteCount)
1528 {
1529 /* Complete the fault */
1531 Address,
1532 PointerPte,
1533 PointerProtoPte,
1534 LockIrql,
1535 &OutPfn);
1536
1537 /* THIS RELEASES THE PFN LOCK! */
1538 break;
1539 }
1540
1541 /* No clustered faults yet */
1542 ASSERT(FALSE);
1543 }
1544
1545 /* Did we resolve the fault? */
1546 if (ProcessedPtes)
1547 {
1548 /* Bump the transition count */
1549 InterlockedExchangeAddSizeT(&KeGetCurrentPrcb()->MmTransitionCount, ProcessedPtes);
1550 ProcessedPtes--;
1551
1552 /* Loop all the processing we did */
1553 ASSERT(ProcessedPtes == 0);
1554
1555 /* Complete this as a transition fault */
1560 }
1561
1562 /* We did not -- PFN lock is still held, prepare to resolve prototype PTE fault */
1563 OutPfn = MI_PFN_ELEMENT(SuperProtoPte->u.Hard.PageFrameNumber);
1565 ASSERT(OutPfn->u3.e2.ReferenceCount > 1);
1566 ASSERT(PointerPte->u.Hard.Valid == 0);
1567
1568 /* Resolve the fault -- this will release the PFN lock */
1570 Address,
1571 PointerPte,
1572 PointerProtoPte,
1573 &OutPfn,
1574 NULL,
1575 NULL,
1576 Process,
1577 LockIrql,
1578 TrapInformation);
1579 //ASSERT(Status != STATUS_ISSUE_PAGING_IO);
1580 //ASSERT(Status != STATUS_REFAULT);
1581 //ASSERT(Status != STATUS_PTE_CHANGED);
1582
1583 /* Did the routine clean out the PFN or should we? */
1584 if (OutPfn)
1585 {
1586 /* We had a locked PFN, so acquire the PFN lock to dereference it */
1587 ASSERT(PointerProtoPte != NULL);
1588 OldIrql = MiAcquirePfnLock();
1589
1590 /* Dereference the locked PFN */
1592 ASSERT(OutPfn->u3.e2.ReferenceCount >= 1);
1593
1594 /* And now release the lock */
1595 MiReleasePfnLock(OldIrql);
1596 }
1597
1598 /* Complete this as a transition fault */
1602 return Status;
1603 }
1604 }
1605
1606 /* Is this a transition PTE */
1607 if (TempPte.u.Soft.Transition)
1608 {
1609 PKEVENT* InPageBlock = NULL;
1610 PKEVENT PreviousPageEvent;
1611 KEVENT CurrentPageEvent;
1612
1613 /* Lock the PFN database */
1614 LockIrql = MiAcquirePfnLock();
1615
1616 /* Resolve */
1617 Status = MiResolveTransitionFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, LockIrql, &InPageBlock);
1618
1620
1621 if (InPageBlock != NULL)
1622 {
1623 /* Another thread is reading or writing this page. Put us into the waiting queue. */
1624 KeInitializeEvent(&CurrentPageEvent, NotificationEvent, FALSE);
1625 PreviousPageEvent = *InPageBlock;
1626 *InPageBlock = &CurrentPageEvent;
1627 }
1628
1629 /* And now release the lock and leave*/
1630 MiReleasePfnLock(LockIrql);
1631
1632 if (InPageBlock != NULL)
1633 {
1634 KeWaitForSingleObject(&CurrentPageEvent, WrPageIn, KernelMode, FALSE, NULL);
1635
1636 /* Let's the chain go on */
1637 if (PreviousPageEvent)
1638 {
1639 KeSetEvent(PreviousPageEvent, IO_NO_INCREMENT, FALSE);
1640 }
1641 }
1642
1646 return Status;
1647 }
1648
1649 /* Should we page the data back in ? */
1650 if (TempPte.u.Soft.PageFileHigh != 0)
1651 {
1652 /* Lock the PFN database */
1653 LockIrql = MiAcquirePfnLock();
1654
1655 /* Resolve */
1656 Status = MiResolvePageFileFault(!MI_IS_NOT_PRESENT_FAULT(FaultCode), Address, PointerPte, Process, &LockIrql);
1657
1658 /* And now release the lock and leave*/
1659 MiReleasePfnLock(LockIrql);
1660
1664 return Status;
1665 }
1666
1667 //
1668 // The PTE must be invalid but not completely empty. It must also not be a
1669 // prototype a transition or a paged-out PTE as those scenarii should've been handled above.
1670 // These are all Windows checks
1671 //
1672 ASSERT(TempPte.u.Hard.Valid == 0);
1673 ASSERT(TempPte.u.Soft.Prototype == 0);
1674 ASSERT(TempPte.u.Soft.Transition == 0);
1675 ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1676 ASSERT(TempPte.u.Long != 0);
1677
1678 //
1679 // If we got this far, the PTE can only be a demand zero PTE, which is what
1680 // we want. Go handle it!
1681 //
1683 PointerPte,
1684 (ULONG)TempPte.u.Soft.Protection,
1685 Process,
1686 MM_NOIRQL);
1688 if (NT_SUCCESS(Status))
1689 {
1690#if MI_TRACE_PFNS
1691 /* Update debug info */
1692 if (TrapInformation)
1693 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
1694 else
1695 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
1696#endif
1697
1698 //
1699 // Make sure we're returning in a sane state and pass the status down
1700 //
1703 return Status;
1704 }
1705
1706 //
1707 // Return status
1708 //
1709 return Status;
1710}
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
#define InterlockedIncrement16
Definition: interlocked.h:221
#define InterlockedExchangeAddSizeT(a, b)
Definition: interlocked.h:211
#define _ReturnAddress()
Definition: intrin_arm.h:35
FORCEINLINE BOOLEAN MI_IS_PHYSICAL_ADDRESS(IN PVOID Address)
Definition: miarm.h:953
FORCEINLINE VOID MiReferenceUsedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1749
VOID NTAPI MiUnlinkPageFromList(IN PMMPFN Pfn)
Definition: pfnlist.c:265
FORCEINLINE PMMPFN MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
Definition: miarm.h:1581
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1197
#define KernelMode
Definition: asm.h:38
@ ActiveAndValid
Definition: mmtypes.h:159
@ NotificationEvent
#define MI_IS_NOT_PRESENT_FAULT(FaultCode)
Definition: mm.h:121
#define MI_MAKE_ACCESSED_PAGE(x)
Definition: mm.h:100
#define MI_MAKE_CLEAN_PAGE(x)
Definition: mm.h:99
#define MM_NOIRQL
Definition: mm.h:70
const ULONG MmProtectToPteMask[32]
Definition: page.c:22
#define STATUS_PAGE_FAULT_TRANSITION
Definition: ntstatus.h:147
static NTSTATUS NTAPI MiResolveDemandZeroFault(IN PVOID Address, IN PMMPTE PointerPte, IN ULONG Protection, IN PEPROCESS Process, IN KIRQL OldIrql)
Definition: pagfault.c:615
static NTSTATUS NTAPI MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN KIRQL OldIrql, IN PMMPFN *LockedProtoPfn)
Definition: pagfault.c:791
static NTSTATUS NTAPI MiResolveTransitionFault(IN BOOLEAN StoreInstruction, IN PVOID FaultingAddress, IN PMMPTE PointerPte, IN PEPROCESS CurrentProcess, IN KIRQL OldIrql, OUT PKEVENT **InPageBlock)
Definition: pagfault.c:1008
static NTSTATUS NTAPI MiResolvePageFileFault(_In_ BOOLEAN StoreInstruction, _In_ PVOID FaultingAddress, _In_ PMMPTE PointerPte, _In_ PEPROCESS CurrentProcess, _Inout_ KIRQL *OldIrql)
Definition: pagfault.c:916
static NTSTATUS NTAPI MiResolveProtoPteFault(IN BOOLEAN StoreInstruction, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN OUT PMMPFN *OutPfn, OUT PVOID *PageFileData, OUT PMMPTE PteValue, IN PEPROCESS Process, IN KIRQL OldIrql, IN PVOID TrapInformation)
Definition: pagfault.c:1140
USHORT Modified
Definition: mm.h:370
USHORT ReadInProgress
Definition: mm.h:371
USHORT PageLocation
Definition: mm.h:375
union _MMPFN::@1983 u4
ULONG_PTR InPageError
Definition: mm.h:438
struct _MMPFN::@1980::@1986 e2
ULONG64 Valid
Definition: mmtypes.h:150
int16_t * PSHORT
Definition: typedefs.h:55
#define IO_NO_INCREMENT
Definition: iotypes.h:598
@ WrPageIn
Definition: ketypes.h:476
ULONG PFN_COUNT
Definition: mmtypes.h:102

Referenced by MmArmAccessFault().

◆ MiIsAccessAllowed()

FORCEINLINE BOOLEAN MiIsAccessAllowed ( _In_ ULONG  ProtectionMask,
_In_ BOOLEAN  Write,
_In_ BOOLEAN  Execute 
)

Definition at line 158 of file pagfault.c.

162{
163 #define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7) \
164 (Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \
165 ((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7)
166 static const UCHAR AccessAllowedMask[2][2] =
167 {
168 { // Protect 0 1 2 3 4 5 6 7
169 _BYTE_MASK(0, 1, 1, 1, 1, 1, 1, 1), // READ
170 _BYTE_MASK(0, 0, 1, 1, 0, 0, 1, 1), // EXECUTE READ
171 },
172 {
173 _BYTE_MASK(0, 0, 0, 0, 1, 1, 1, 1), // WRITE
174 _BYTE_MASK(0, 0, 0, 0, 0, 0, 1, 1), // EXECUTE WRITE
175 }
176 };
177
178 /* We want only the lower access bits */
179 ProtectionMask &= MM_PROTECT_ACCESS;
180
181 /* Look it up in the table */
182 return (AccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1;
183}
static INT Execute(LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
Definition: cmd.c:345
#define MM_PROTECT_ACCESS
Definition: miarm.h:51
#define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7)
unsigned char UCHAR
Definition: typedefs.h:53
static BOOL Write(PBYTE Address, PBYTE Data, SIZE_T Size)
Definition: vmhorizon.c:15

Referenced by MiAccessCheck().

◆ MiResolveDemandZeroFault()

static NTSTATUS NTAPI MiResolveDemandZeroFault ( IN PVOID  Address,
IN PMMPTE  PointerPte,
IN ULONG  Protection,
IN PEPROCESS  Process,
IN KIRQL  OldIrql 
)
static

Definition at line 615 of file pagfault.c.

620{
621 PFN_NUMBER PageFrameNumber = 0;
623 BOOLEAN NeedZero = FALSE, HaveLock = FALSE;
624 ULONG Color;
625 PMMPFN Pfn1;
626 DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
627 Address,
628 Process);
629
630 /* Must currently only be called by paging path */
631 if ((Process > HYDRA_PROCESS) && (OldIrql == MM_NOIRQL))
632 {
633 /* Sanity check */
634 ASSERT(MI_IS_PAGE_TABLE_ADDRESS(PointerPte));
635
636 /* No forking yet */
637 ASSERT(Process->ForkInProgress == NULL);
638
639 /* Get process color */
641 ASSERT(Color != 0xFFFFFFFF);
642
643 /* We'll need a zero page */
644 NeedZero = TRUE;
645 }
646 else
647 {
648 /* Check if we need a zero page */
649 NeedZero = (OldIrql != MM_NOIRQL);
650
651 /* Session-backed image views must be zeroed */
652 if ((Process == HYDRA_PROCESS) &&
655 {
656 NeedZero = TRUE;
657 }
658
659 /* Hardcode unknown color */
660 Color = 0xFFFFFFFF;
661 }
662
663 /* Check if the PFN database should be acquired */
664 if (OldIrql == MM_NOIRQL)
665 {
666 /* Acquire it and remember we should release it after */
667 OldIrql = MiAcquirePfnLock();
668 HaveLock = TRUE;
669 }
670
671 /* We either manually locked the PFN DB, or already came with it locked */
673 ASSERT(PointerPte->u.Hard.Valid == 0);
674
675 /* Assert we have enough pages */
676 //ASSERT(MmAvailablePages >= 32);
677
678#if MI_TRACE_PFNS
679 if (UserPdeFault) MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
680 if (!UserPdeFault) MI_SET_USAGE(MI_USAGE_DEMAND_ZERO);
681#endif
682 if (Process == HYDRA_PROCESS) MI_SET_PROCESS2("Hydra");
683 else if (Process) MI_SET_PROCESS2(Process->ImageFileName);
684 else MI_SET_PROCESS2("Kernel Demand 0");
685
686 /* Do we need a zero page? */
687 if (Color != 0xFFFFFFFF)
688 {
689 /* Try to get one, if we couldn't grab a free page and zero it */
690 PageFrameNumber = MiRemoveZeroPageSafe(Color);
691 if (!PageFrameNumber)
692 {
693 /* We'll need a free page and zero it manually */
694 PageFrameNumber = MiRemoveAnyPage(Color);
695 NeedZero = TRUE;
696 }
697 else
698 {
699 /* Page guaranteed to be zero-filled */
700 NeedZero = FALSE;
701 }
702 }
703 else
704 {
705 /* Get a color, and see if we should grab a zero or non-zero page */
707 if (!NeedZero)
708 {
709 /* Process or system doesn't want a zero page, grab anything */
710 PageFrameNumber = MiRemoveAnyPage(Color);
711 }
712 else
713 {
714 /* System wants a zero page, obtain one */
715 PageFrameNumber = MiRemoveZeroPage(Color);
716 /* No need to zero-fill it */
717 NeedZero = FALSE;
718 }
719 }
720
721 if (PageFrameNumber == 0)
722 {
723 MiReleasePfnLock(OldIrql);
724 return STATUS_NO_MEMORY;
725 }
726
727 /* Initialize it */
728 MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
729
730 /* Increment demand zero faults */
731 KeGetCurrentPrcb()->MmDemandZeroCount++;
732
733 /* Do we have the lock? */
734 if (HaveLock)
735 {
736 /* Release it */
737 MiReleasePfnLock(OldIrql);
738
739 /* Update performance counters */
740 if (Process > HYDRA_PROCESS) Process->NumberOfPrivatePages++;
741 }
742
743 /* Zero the page if need be */
744 if (NeedZero) MiZeroPfn(PageFrameNumber);
745
746 /* Fault on user PDE, or fault on user PTE? */
747 if (PointerPte <= MiHighestUserPte)
748 {
749 /* User fault, build a user PTE */
751 PointerPte,
752 Protection,
753 PageFrameNumber);
754 }
755 else
756 {
757 /* This is a user-mode PDE, create a kernel PTE for it */
759 PointerPte,
760 Protection,
761 PageFrameNumber);
762 }
763
764 /* Set it dirty if it's a writable page */
766
767 /* Write it */
768 MI_WRITE_VALID_PTE(PointerPte, TempPte);
769
770 /* Did we manually acquire the lock */
771 if (HaveLock)
772 {
773 /* Get the PFN entry */
774 Pfn1 = MI_PFN_ELEMENT(PageFrameNumber);
775
776 /* Windows does these sanity checks */
777 ASSERT(Pfn1->u1.Event == 0);
778 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
779 }
780
781 //
782 // It's all good now
783 //
784 DPRINT("Demand zero page has now been paged in\n");
786}
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
PFN_NUMBER NTAPI MiRemoveZeroPage(IN ULONG Color)
Definition: pfnlist.c:537
#define MI_IS_SESSION_IMAGE_ADDRESS(Address)
Definition: miarm.h:182
#define MI_GET_NEXT_COLOR()
Definition: miarm.h:236
PFN_NUMBER NTAPI MiRemoveAnyPage(IN ULONG Color)
Definition: pfnlist.c:477
VOID NTAPI MiInitializePfn(IN PFN_NUMBER PageFrameIndex, IN PMMPTE PointerPte, IN BOOLEAN Modified)
Definition: pfnlist.c:970
#define MI_GET_NEXT_PROCESS_COLOR(x)
Definition: miarm.h:237
PVOID MiSessionSpaceWs
Definition: mminit.c:131
FORCEINLINE PFN_NUMBER MiRemoveZeroPageSafe(IN ULONG Color)
Definition: miarm.h:2413
#define MI_SET_PROCESS2(x)
Definition: mm.h:329
@ MI_USAGE_PAGE_TABLE
Definition: mm.h:344
@ MI_USAGE_DEMAND_ZERO
Definition: mm.h:350
#define MI_SET_USAGE(x)
Definition: mm.h:327
PVOID MiSessionViewStart
Definition: init.c:30
#define STATUS_PAGE_FAULT_DEMAND_ZERO
Definition: ntstatus.h:148
VOID NTAPI MiZeroPfn(IN PFN_NUMBER PageFrameNumber)
Definition: pagfault.c:503
#define HYDRA_PROCESS
Definition: pagfault.c:24
union _MMPFN::@1978 u1
PKEVENT Event
Definition: mm.h:395

Referenced by MiDispatchFault(), MiResolveProtoPteFault(), and MmArmAccessFault().

◆ MiResolvePageFileFault()

static NTSTATUS NTAPI MiResolvePageFileFault ( _In_ BOOLEAN  StoreInstruction,
_In_ PVOID  FaultingAddress,
_In_ PMMPTE  PointerPte,
_In_ PEPROCESS  CurrentProcess,
_Inout_ KIRQL OldIrql 
)
static

Definition at line 916 of file pagfault.c.

921{
922 ULONG Color;
925 MMPTE TempPte = *PointerPte;
926 PMMPFN Pfn1;
927 ULONG PageFileIndex = TempPte.u.Soft.PageFileLow;
928 ULONG_PTR PageFileOffset = TempPte.u.Soft.PageFileHigh;
929 ULONG Protection = TempPte.u.Soft.Protection;
930
931 /* Things we don't support yet */
932 ASSERT(CurrentProcess > HYDRA_PROCESS);
934
936 MI_SET_PROCESS(CurrentProcess);
937
938 /* We must hold the PFN lock */
940
941 /* Some sanity checks */
942 ASSERT(TempPte.u.Hard.Valid == 0);
943 ASSERT(TempPte.u.Soft.PageFileHigh != 0);
944 ASSERT(TempPte.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED);
945
946 /* Get any page, it will be overwritten */
947 Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
949 if (Page == 0)
950 {
951 return STATUS_NO_MEMORY;
952 }
953
954 /* Initialize this PFN */
955 MiInitializePfn(Page, PointerPte, StoreInstruction);
956
957 /* Sets the PFN as being in IO operation */
958 Pfn1 = MI_PFN_ELEMENT(Page);
959 ASSERT(Pfn1->u1.Event == NULL);
960 ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
961 ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
962 Pfn1->u3.e1.ReadInProgress = 1;
963
964 /* We must write the PTE now as the PFN lock will be released while performing the IO operation */
965 MI_MAKE_TRANSITION_PTE(&TempPte, Page, Protection);
966
967 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
968
969 /* Release the PFN lock while we proceed */
970 MiReleasePfnLock(*OldIrql);
971
972 /* Do the paging IO */
973 Status = MiReadPageFile(Page, PageFileIndex, PageFileOffset);
974
975 /* Lock the PFN database again */
976 *OldIrql = MiAcquirePfnLock();
977
978 /* Nobody should have changed that while we were not looking */
979 ASSERT(Pfn1->u3.e1.ReadInProgress == 1);
980 ASSERT(Pfn1->u3.e1.WriteInProgress == 0);
981
982 if (!NT_SUCCESS(Status))
983 {
984 /* Malheur! */
985 ASSERT(FALSE);
986 Pfn1->u4.InPageError = 1;
987 Pfn1->u1.ReadStatus = Status;
988 }
989
990 /* And the PTE can finally be valid */
991 MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, Page);
992 MI_WRITE_VALID_PTE(PointerPte, TempPte);
993
994 Pfn1->u3.e1.ReadInProgress = 0;
995 /* Did someone start to wait on us while we proceeded ? */
996 if (Pfn1->u1.Event)
997 {
998 /* Tell them we're done */
1000 }
1001
1002 return Status;
1003}
FORCEINLINE VOID MI_MAKE_TRANSITION_PTE(_Out_ PMMPTE NewPte, _In_ PFN_NUMBER Page, _In_ ULONG Protection)
Definition: miarm.h:937
@ MI_USAGE_PAGE_FILE
Definition: mm.h:356
NTSTATUS NTAPI MiReadPageFile(_In_ PFN_NUMBER Page, _In_ ULONG PageFileIndex, _In_ ULONG_PTR PageFileOffset)
Definition: pagefile.c:211
_In_ PVOID _Out_opt_ BOOLEAN _Out_opt_ PPFN_NUMBER Page
Definition: mm.h:1305
#define MI_SET_PROCESS(x)
Definition: mm.h:328
USHORT WriteInProgress
Definition: mm.h:372
NTSTATUS ReadStatus
Definition: mm.h:396

Referenced by MiDispatchFault().

◆ MiResolveProtoPteFault()

static NTSTATUS NTAPI MiResolveProtoPteFault ( IN BOOLEAN  StoreInstruction,
IN PVOID  Address,
IN PMMPTE  PointerPte,
IN PMMPTE  PointerProtoPte,
IN OUT PMMPFN OutPfn,
OUT PVOID PageFileData,
OUT PMMPTE  PteValue,
IN PEPROCESS  Process,
IN KIRQL  OldIrql,
IN PVOID  TrapInformation 
)
static

Definition at line 1140 of file pagfault.c.

1150{
1151 MMPTE TempPte, PteContents;
1152 PMMPFN Pfn1;
1153 PFN_NUMBER PageFrameIndex;
1155 PKEVENT* InPageBlock = NULL;
1156 ULONG Protection;
1157
1158 /* Must be called with an invalid, prototype PTE, with the PFN lock held */
1160 ASSERT(PointerPte->u.Hard.Valid == 0);
1161 ASSERT(PointerPte->u.Soft.Prototype == 1);
1162
1163 /* Read the prototype PTE and check if it's valid */
1164 TempPte = *PointerProtoPte;
1165 if (TempPte.u.Hard.Valid == 1)
1166 {
1167 /* One more user of this mapped page */
1168 PageFrameIndex = PFN_FROM_PTE(&TempPte);
1169 Pfn1 = MiGetPfnEntry(PageFrameIndex);
1170 Pfn1->u2.ShareCount++;
1171
1172 /* Call it a transition */
1173 InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1174
1175 /* Complete the prototype PTE fault -- this will release the PFN lock */
1176 return MiCompleteProtoPteFault(StoreInstruction,
1177 Address,
1178 PointerPte,
1179 PointerProtoPte,
1180 OldIrql,
1181 OutPfn);
1182 }
1183
1184 /* Make sure there's some protection mask */
1185 if (TempPte.u.Long == 0)
1186 {
1187 /* Release the lock */
1188 DPRINT1("Access on reserved section?\n");
1189 MiReleasePfnLock(OldIrql);
1191 }
1192
1193 /* There is no such thing as a decommitted prototype PTE */
1195
1196 /* Check for access rights on the PTE proper */
1197 PteContents = *PointerPte;
1198 if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)
1199 {
1200 if (!PteContents.u.Proto.ReadOnly)
1201 {
1202 Protection = TempPte.u.Soft.Protection;
1203 }
1204 else
1205 {
1206 Protection = MM_READONLY;
1207 }
1208 /* Check for page acess in software */
1209 Status = MiAccessCheck(PointerProtoPte,
1210 StoreInstruction,
1211 KernelMode,
1212 TempPte.u.Soft.Protection,
1213 TrapInformation,
1214 TRUE);
1216 }
1217 else
1218 {
1219 Protection = PteContents.u.Soft.Protection;
1220 }
1221
1222 /* Check for writing copy on write page */
1223 if (((Protection & MM_WRITECOPY) == MM_WRITECOPY) && StoreInstruction)
1224 {
1225 PFN_NUMBER PageFrameIndex, ProtoPageFrameIndex;
1226 ULONG Color;
1227
1228 /* Resolve the proto fault as if it was a read operation */
1230 Address,
1231 PointerPte,
1232 PointerProtoPte,
1233 OutPfn,
1234 PageFileData,
1235 PteValue,
1236 Process,
1237 OldIrql,
1238 TrapInformation);
1239
1240 if (!NT_SUCCESS(Status))
1241 {
1242 return Status;
1243 }
1244
1245 /* Lock again the PFN lock, MiResolveProtoPteFault unlocked it */
1246 OldIrql = MiAcquirePfnLock();
1247
1248 /* And re-read the proto PTE */
1249 TempPte = *PointerProtoPte;
1250 ASSERT(TempPte.u.Hard.Valid == 1);
1251 ProtoPageFrameIndex = PFN_FROM_PTE(&TempPte);
1252
1255
1256 /* Get a new page for the private copy */
1257 if (Process > HYDRA_PROCESS)
1259 else
1261
1262 PageFrameIndex = MiRemoveAnyPage(Color);
1263 if (PageFrameIndex == 0)
1264 {
1265 MiReleasePfnLock(OldIrql);
1266 return STATUS_NO_MEMORY;
1267 }
1268
1269 /* Perform the copy */
1270 MiCopyPfn(PageFrameIndex, ProtoPageFrameIndex);
1271
1272 /* This will drop everything MiResolveProtoPteFault referenced */
1273 MiDeletePte(PointerPte, Address, Process, PointerProtoPte);
1274
1275 /* Because now we use this */
1276 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1277 MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
1278
1279 /* Fix the protection */
1280 Protection &= ~MM_WRITECOPY;
1281 Protection |= MM_READWRITE;
1283 {
1284 /* Build the user PTE */
1285 MI_MAKE_HARDWARE_PTE_USER(&PteContents, PointerPte, Protection, PageFrameIndex);
1286 }
1287 else
1288 {
1289 /* Build the kernel PTE */
1290 MI_MAKE_HARDWARE_PTE(&PteContents, PointerPte, Protection, PageFrameIndex);
1291 }
1292
1293 /* And finally, write the valid PTE */
1294 MI_WRITE_VALID_PTE(PointerPte, PteContents);
1295
1296 /* The caller expects us to release the PFN lock */
1297 MiReleasePfnLock(OldIrql);
1298 return Status;
1299 }
1300
1301 /* Check for clone PTEs */
1302 if (PointerPte <= MiHighestUserPte) ASSERT(Process->CloneRoot == NULL);
1303
1304 /* We don't support mapped files yet */
1305 ASSERT(TempPte.u.Soft.Prototype == 0);
1306
1307 /* We might however have transition PTEs */
1308 if (TempPte.u.Soft.Transition == 1)
1309 {
1310 /* Resolve the transition fault */
1312 Status = MiResolveTransitionFault(StoreInstruction,
1313 Address,
1314 PointerProtoPte,
1315 Process,
1316 OldIrql,
1317 &InPageBlock);
1319 }
1320 else
1321 {
1322 /* We also don't support paged out pages */
1323 ASSERT(TempPte.u.Soft.PageFileHigh == 0);
1324
1325 /* Resolve the demand zero fault */
1327 PointerProtoPte,
1328 (ULONG)TempPte.u.Soft.Protection,
1329 Process,
1330 OldIrql);
1331#if MI_TRACE_PFNS
1332 /* Update debug info */
1333 if (TrapInformation)
1334 MiGetPfnEntry(PointerProtoPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
1335 else
1336 MiGetPfnEntry(PointerProtoPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
1337#endif
1338
1340 }
1341
1342 /* Complete the prototype PTE fault -- this will release the PFN lock */
1343 ASSERT(PointerPte->u.Hard.Valid == 0);
1344 return MiCompleteProtoPteFault(StoreInstruction,
1345 Address,
1346 PointerPte,
1347 PointerProtoPte,
1348 OldIrql,
1349 OutPfn);
1350}
#define InterlockedIncrement
Definition: armddk.h:53
VOID NTAPI MiDeletePte(IN PMMPTE PointerPte, IN PVOID VirtualAddress, IN PEPROCESS CurrentProcess, IN PMMPTE PrototypePte)
Definition: virtual.c:369
@ MI_USAGE_COW
Definition: mm.h:357
MMPTE MmDecommittedPte
Definition: init.c:44
VOID NTAPI MiCopyPfn(_In_ PFN_NUMBER DestPage, _In_ PFN_NUMBER SrcPage)
Definition: pagfault.c:549
static NTSTATUS NTAPI MiAccessCheck(IN PMMPTE PointerPte, IN BOOLEAN StoreInstruction, IN KPROCESSOR_MODE PreviousMode, IN ULONG_PTR ProtectionMask, IN PVOID TrapFrame, IN BOOLEAN LockHeld)
Definition: pagfault.c:188
ULONG64 ReadOnly
Definition: mmtypes.h:119
ULONG64 PageFileHigh
Definition: mmtypes.h:93
MMPTE_PROTOTYPE Proto
Definition: mmtypes.h:218
ULONG_PTR Long
Definition: mmtypes.h:215

Referenced by MiDispatchFault(), and MiResolveProtoPteFault().

◆ MiResolveTransitionFault()

static NTSTATUS NTAPI MiResolveTransitionFault ( IN BOOLEAN  StoreInstruction,
IN PVOID  FaultingAddress,
IN PMMPTE  PointerPte,
IN PEPROCESS  CurrentProcess,
IN KIRQL  OldIrql,
OUT PKEVENT **  InPageBlock 
)
static

Definition at line 1008 of file pagfault.c.

1014{
1015 PFN_NUMBER PageFrameIndex;
1016 PMMPFN Pfn1;
1017 MMPTE TempPte;
1018 PMMPTE PointerToPteForProtoPage;
1019 DPRINT("Transition fault on 0x%p with PTE 0x%p in process %s\n",
1020 FaultingAddress, PointerPte, CurrentProcess->ImageFileName);
1021
1022 /* Windowss does this check */
1023 ASSERT(*InPageBlock == NULL);
1024
1025 /* ARM3 doesn't support this path */
1027
1028 /* Capture the PTE and make sure it's in transition format */
1029 TempPte = *PointerPte;
1030 ASSERT((TempPte.u.Soft.Valid == 0) &&
1031 (TempPte.u.Soft.Prototype == 0) &&
1032 (TempPte.u.Soft.Transition == 1));
1033
1034 /* Get the PFN and the PFN entry */
1035 PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
1036 DPRINT("Transition PFN: %lx\n", PageFrameIndex);
1037 Pfn1 = MiGetPfnEntry(PageFrameIndex);
1038
1039 /* One more transition fault! */
1040 InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
1041
1042 /* This is from ARM3 -- Windows normally handles this here */
1043 ASSERT(Pfn1->u4.InPageError == 0);
1044
1045 /* See if we should wait before terminating the fault */
1046 if ((Pfn1->u3.e1.ReadInProgress == 1)
1047 || ((Pfn1->u3.e1.WriteInProgress == 1) && StoreInstruction))
1048 {
1049 DPRINT1("The page is currently in a page transition !\n");
1050 *InPageBlock = &Pfn1->u1.Event;
1051 if (PointerPte == Pfn1->PteAddress)
1052 {
1053 DPRINT1("And this if for this particular PTE.\n");
1054 /* The PTE will be made valid by the thread serving the fault */
1055 return STATUS_SUCCESS; // FIXME: Maybe something more descriptive
1056 }
1057 }
1058
1059 /* Windows checks there's some free pages and this isn't an in-page error */
1061 ASSERT(Pfn1->u4.InPageError == 0);
1062
1063 /* ReactOS checks for this */
1065
1066 /* Was this a transition page in the valid list, or free/zero list? */
1067 if (Pfn1->u3.e1.PageLocation == ActiveAndValid)
1068 {
1069 /* All Windows does here is a bunch of sanity checks */
1070 DPRINT("Transition in active list\n");
1073 ASSERT(Pfn1->u2.ShareCount != 0);
1074 ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1075 }
1076 else
1077 {
1078 /* Otherwise, the page is removed from its list */
1079 DPRINT("Transition page in free/zero list\n");
1082 }
1083
1084 /* At this point, there should no longer be any in-page errors */
1085 ASSERT(Pfn1->u4.InPageError == 0);
1086
1087 /* Check if this was a PFN with no more share references */
1088 if (Pfn1->u2.ShareCount == 0) MiDropLockCount(Pfn1);
1089
1090 /* Bump the share count and make the page valid */
1091 Pfn1->u2.ShareCount++;
1093
1094 /* Prototype PTEs are in paged pool, which itself might be in transition */
1095 if (FaultingAddress >= MmSystemRangeStart)
1096 {
1097 /* Check if this is a paged pool PTE in transition state */
1098 PointerToPteForProtoPage = MiAddressToPte(PointerPte);
1099 TempPte = *PointerToPteForProtoPage;
1100 if ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Transition == 1))
1101 {
1102 /* This isn't yet supported */
1103 DPRINT1("Double transition fault not yet supported\n");
1104 ASSERT(FALSE);
1105 }
1106 }
1107
1108 /* Build the final PTE */
1109 ASSERT(PointerPte->u.Hard.Valid == 0);
1110 ASSERT(PointerPte->u.Trans.Prototype == 0);
1111 ASSERT(PointerPte->u.Trans.Transition == 1);
1112 TempPte.u.Long = (PointerPte->u.Long & ~0xFFF) |
1113 (MmProtectToPteMask[PointerPte->u.Trans.Protection]) |
1114 MiDetermineUserGlobalPteMask(PointerPte);
1115
1116 /* Is the PTE writeable? */
1117 if ((Pfn1->u3.e1.Modified) &&
1120 {
1121 /* Make it dirty */
1123 }
1124 else
1125 {
1126 /* Make it clean */
1128 }
1129
1130 /* Write the valid PTE */
1131 MI_WRITE_VALID_PTE(PointerPte, TempPte);
1132
1133 /* Return success */
1135}
FORCEINLINE VOID MiReferenceUnusedPageAndBumpLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1794
FORCEINLINE VOID MiDropLockCount(IN PMMPFN Pfn1)
Definition: miarm.h:1592
FORCEINLINE ULONG_PTR MiDetermineUserGlobalPteMask(IN PVOID PointerPte)
Definition: miarm.h:741
PFN_NUMBER MmAvailablePages
Definition: freelist.c:26
PVOID MmPagedPoolEnd
Definition: init.c:26
PMMPTE PteAddress
Definition: mm.h:402

Referenced by MiDispatchFault(), and MiResolveProtoPteFault().

◆ MiZeroPfn()

VOID NTAPI MiZeroPfn ( IN PFN_NUMBER  PageFrameNumber)

Definition at line 503 of file pagfault.c.

504{
505 PMMPTE ZeroPte;
507 PMMPFN Pfn1;
508 PVOID ZeroAddress;
509
510 /* Get the PFN for this page */
511 Pfn1 = MiGetPfnEntry(PageFrameNumber);
512 ASSERT(Pfn1);
513
514 /* Grab a system PTE we can use to zero the page */
516 ASSERT(ZeroPte);
517
518 /* Initialize the PTE for it */
520 TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
521
522 /* Setup caching */
523 if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
524 {
525 /* Write combining, no caching */
528 }
529 else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
530 {
531 /* Write through, no caching */
534 }
535
536 /* Make the system PTE valid with our PFN */
537 MI_WRITE_VALID_PTE(ZeroPte, TempPte);
538
539 /* Get the address it maps to, and zero it out */
540 ZeroAddress = MiPteToAddress(ZeroPte);
541 KeZeroPages(ZeroAddress, PAGE_SIZE);
542
543 /* Now get rid of it */
545}
VOID FASTCALL KeZeroPages(IN PVOID Address, IN ULONG Size)
Definition: cpu.c:56

Referenced by MiResolveDemandZeroFault(), and MmArmAccessFault().

◆ MmArmAccessFault()

NTSTATUS NTAPI MmArmAccessFault ( IN ULONG  FaultCode,
IN PVOID  Address,
IN KPROCESSOR_MODE  Mode,
IN PVOID  TrapInformation 
)

Definition at line 1714 of file pagfault.c.

1718{
1719 KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
1720 PMMPTE ProtoPte = NULL;
1721 PMMPTE PointerPte = MiAddressToPte(Address);
1722 PMMPDE PointerPde = MiAddressToPde(Address);
1723#if (_MI_PAGING_LEVELS >= 3)
1724 PMMPDE PointerPpe = MiAddressToPpe(Address);
1725#if (_MI_PAGING_LEVELS == 4)
1726 PMMPDE PointerPxe = MiAddressToPxe(Address);
1727#endif
1728#endif
1729 MMPTE TempPte;
1730 PETHREAD CurrentThread;
1731 PEPROCESS CurrentProcess;
1733 PMMSUPPORT WorkingSet;
1734 ULONG ProtectionCode;
1735 PMMVAD Vad = NULL;
1736 PFN_NUMBER PageFrameIndex;
1737 ULONG Color;
1738 BOOLEAN IsSessionAddress;
1739 PMMPFN Pfn1;
1740 DPRINT("ARM3 FAULT AT: %p\n", Address);
1741
1742 /* Check for page fault on high IRQL */
1743 if (OldIrql > APC_LEVEL)
1744 {
1745#if (_MI_PAGING_LEVELS < 3)
1746 /* Could be a page table for paged pool, which we'll allow */
1747 if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1749#endif
1750 /* Check if any of the top-level pages are invalid */
1751 if (
1752#if (_MI_PAGING_LEVELS == 4)
1753 (PointerPxe->u.Hard.Valid == 0) ||
1754#endif
1755#if (_MI_PAGING_LEVELS >= 3)
1756 (PointerPpe->u.Hard.Valid == 0) ||
1757#endif
1758 (PointerPde->u.Hard.Valid == 0) ||
1759 (PointerPte->u.Hard.Valid == 0))
1760 {
1761 /* This fault is not valid, print out some debugging help */
1762 DbgPrint("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
1763 Address,
1764 OldIrql);
1765 if (TrapInformation)
1766 {
1767 PKTRAP_FRAME TrapFrame = TrapInformation;
1768#ifdef _M_IX86
1769 DbgPrint("MM:***EIP %p, EFL %p\n", TrapFrame->Eip, TrapFrame->EFlags);
1770 DbgPrint("MM:***EAX %p, ECX %p EDX %p\n", TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1771 DbgPrint("MM:***EBX %p, ESI %p EDI %p\n", TrapFrame->Ebx, TrapFrame->Esi, TrapFrame->Edi);
1772#elif defined(_M_AMD64)
1773 DbgPrint("MM:***RIP %p, EFL %p\n", TrapFrame->Rip, TrapFrame->EFlags);
1774 DbgPrint("MM:***RAX %p, RCX %p RDX %p\n", TrapFrame->Rax, TrapFrame->Rcx, TrapFrame->Rdx);
1775 DbgPrint("MM:***RBX %p, RSI %p RDI %p\n", TrapFrame->Rbx, TrapFrame->Rsi, TrapFrame->Rdi);
1776#elif defined(_M_ARM)
1777 DbgPrint("MM:***PC %p\n", TrapFrame->Pc);
1778 DbgPrint("MM:***R0 %p, R1 %p R2 %p, R3 %p\n", TrapFrame->R0, TrapFrame->R1, TrapFrame->R2, TrapFrame->R3);
1779 DbgPrint("MM:***R11 %p, R12 %p SP %p, LR %p\n", TrapFrame->R11, TrapFrame->R12, TrapFrame->Sp, TrapFrame->Lr);
1780#endif
1781 }
1782
1783 /* Tell the trap handler to fail */
1784 return STATUS_IN_PAGE_ERROR | 0x10000000;
1785 }
1786
1787 /* Not yet implemented in ReactOS */
1788 ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
1789 ASSERT((!MI_IS_NOT_PRESENT_FAULT(FaultCode) && MI_IS_PAGE_COPY_ON_WRITE(PointerPte)) == FALSE);
1790
1791 /* Check if this was a write */
1792 if (MI_IS_WRITE_ACCESS(FaultCode))
1793 {
1794 /* Was it to a read-only page? */
1795 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1796 if (!(PointerPte->u.Long & PTE_READWRITE) &&
1798 {
1799 /* Crash with distinguished bugcheck code */
1800 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1802 PointerPte->u.Long,
1803 (ULONG_PTR)TrapInformation,
1804 10);
1805 }
1806 }
1807
1808 /* Nothing is actually wrong */
1809 DPRINT1("Fault at IRQL %u is ok (%p)\n", OldIrql, Address);
1810 return STATUS_SUCCESS;
1811 }
1812
1813 /* Check for kernel fault address */
1815 {
1816 /* Bail out, if the fault came from user mode */
1817 if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
1818
1819#if (_MI_PAGING_LEVELS == 2)
1820 if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
1822#endif
1823
1824 /* Check if the higher page table entries are invalid */
1825 if (
1826#if (_MI_PAGING_LEVELS == 4)
1827 /* AMD64 system, check if PXE is invalid */
1828 (PointerPxe->u.Hard.Valid == 0) ||
1829#endif
1830#if (_MI_PAGING_LEVELS >= 3)
1831 /* PAE/AMD64 system, check if PPE is invalid */
1832 (PointerPpe->u.Hard.Valid == 0) ||
1833#endif
1834 /* Always check if the PDE is valid */
1835 (PointerPde->u.Hard.Valid == 0))
1836 {
1837 /* PXE/PPE/PDE (still) not valid, kill the system */
1838 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1840 FaultCode,
1841 (ULONG_PTR)TrapInformation,
1842 2);
1843 }
1844
1845 /* Not handling session faults yet */
1846 IsSessionAddress = MI_IS_SESSION_ADDRESS(Address);
1847
1848 /* The PDE is valid, so read the PTE */
1849 TempPte = *PointerPte;
1850 if (TempPte.u.Hard.Valid == 1)
1851 {
1852 /* Check if this was system space or session space */
1853 if (!IsSessionAddress)
1854 {
1855 /* Check if the PTE is still valid under PFN lock */
1856 OldIrql = MiAcquirePfnLock();
1857 TempPte = *PointerPte;
1858 if (TempPte.u.Hard.Valid)
1859 {
1860 /* Check if this was a write */
1861 if (MI_IS_WRITE_ACCESS(FaultCode))
1862 {
1863 /* Was it to a read-only page? */
1864 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1865 if (!(PointerPte->u.Long & PTE_READWRITE) &&
1867 {
1868 /* Crash with distinguished bugcheck code */
1869 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1871 PointerPte->u.Long,
1872 (ULONG_PTR)TrapInformation,
1873 11);
1874 }
1875 }
1876
1877 /* Check for execution of non-executable memory */
1878 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1880 {
1881 KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1883 (ULONG_PTR)TempPte.u.Long,
1884 (ULONG_PTR)TrapInformation,
1885 1);
1886 }
1887 }
1888
1889 /* Release PFN lock and return all good */
1890 MiReleasePfnLock(OldIrql);
1891 return STATUS_SUCCESS;
1892 }
1893 }
1894#if (_MI_PAGING_LEVELS == 2)
1895 /* Check if this was a session PTE that needs to remap the session PDE */
1897 {
1898 /* Do the remapping */
1899 Status = MiCheckPdeForSessionSpace(Address);
1900 if (!NT_SUCCESS(Status))
1901 {
1902 /* It failed, this address is invalid */
1903 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
1905 FaultCode,
1906 (ULONG_PTR)TrapInformation,
1907 6);
1908 }
1909 }
1910#else
1911
1912_WARN("Session space stuff is not implemented yet!")
1913
1914#endif
1915
1916 /* Check for a fault on the page table or hyperspace */
1918 {
1919#if (_MI_PAGING_LEVELS < 3)
1920 /* Windows does this check but I don't understand why -- it's done above! */
1922#endif
1923 /* Handle this as a user mode fault */
1924 goto UserFault;
1925 }
1926
1927 /* Get the current thread */
1928 CurrentThread = PsGetCurrentThread();
1929
1930 /* What kind of address is this */
1931 if (!IsSessionAddress)
1932 {
1933 /* Use the system working set */
1934 WorkingSet = &MmSystemCacheWs;
1935 CurrentProcess = NULL;
1936
1937 /* Make sure we don't have a recursive working set lock */
1938 if ((CurrentThread->OwnsProcessWorkingSetExclusive) ||
1939 (CurrentThread->OwnsProcessWorkingSetShared) ||
1940 (CurrentThread->OwnsSystemWorkingSetExclusive) ||
1941 (CurrentThread->OwnsSystemWorkingSetShared) ||
1942 (CurrentThread->OwnsSessionWorkingSetExclusive) ||
1943 (CurrentThread->OwnsSessionWorkingSetShared))
1944 {
1945 /* Fail */
1946 return STATUS_IN_PAGE_ERROR | 0x10000000;
1947 }
1948 }
1949 else
1950 {
1951 /* Use the session process and working set */
1952 CurrentProcess = HYDRA_PROCESS;
1953 WorkingSet = &MmSessionSpace->GlobalVirtualAddress->Vm;
1954
1955 /* Make sure we don't have a recursive working set lock */
1956 if ((CurrentThread->OwnsSessionWorkingSetExclusive) ||
1957 (CurrentThread->OwnsSessionWorkingSetShared))
1958 {
1959 /* Fail */
1960 return STATUS_IN_PAGE_ERROR | 0x10000000;
1961 }
1962 }
1963RetryKernel:
1964 /* Acquire the working set lock */
1965 KeRaiseIrql(APC_LEVEL, &LockIrql);
1966 MiLockWorkingSet(CurrentThread, WorkingSet);
1967
1968 /* Re-read PTE now that we own the lock */
1969 TempPte = *PointerPte;
1970 if (TempPte.u.Hard.Valid == 1)
1971 {
1972 /* Check if this was a write */
1973 if (MI_IS_WRITE_ACCESS(FaultCode))
1974 {
1975 /* Was it to a read-only page that is not copy on write? */
1976 Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
1977 if (!(TempPte.u.Long & PTE_READWRITE) &&
1980 {
1981 /* Case not yet handled */
1982 ASSERT(!IsSessionAddress);
1983
1984 /* Crash with distinguished bugcheck code */
1985 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
1987 TempPte.u.Long,
1988 (ULONG_PTR)TrapInformation,
1989 12);
1990 }
1991 }
1992
1993 /* Check for execution of non-executable memory */
1994 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
1996 {
1997 KeBugCheckEx(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY,
1999 (ULONG_PTR)TempPte.u.Long,
2000 (ULONG_PTR)TrapInformation,
2001 2);
2002 }
2003
2004 /* Check for read-only write in session space */
2005 if ((IsSessionAddress) &&
2006 MI_IS_WRITE_ACCESS(FaultCode) &&
2008 {
2009 /* Sanity check */
2011
2012 /* Was this COW? */
2014 {
2015 /* Then this is not allowed */
2016 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
2018 (ULONG_PTR)TempPte.u.Long,
2019 (ULONG_PTR)TrapInformation,
2020 13);
2021 }
2022
2023 /* Otherwise, handle COW */
2024 ASSERT(FALSE);
2025 }
2026
2027 /* Release the working set */
2028 MiUnlockWorkingSet(CurrentThread, WorkingSet);
2029 KeLowerIrql(LockIrql);
2030
2031 /* Otherwise, the PDE was probably invalid, and all is good now */
2032 return STATUS_SUCCESS;
2033 }
2034
2035 /* Check one kind of prototype PTE */
2036 if (TempPte.u.Soft.Prototype)
2037 {
2038 /* Make sure protected pool is on, and that this is a pool address */
2045 {
2046 /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
2047 KeBugCheckEx(DRIVER_CAUGHT_MODIFYING_FREED_POOL,
2049 FaultCode,
2050 Mode,
2051 4);
2052 }
2053
2054 /* Get the prototype PTE! */
2055 ProtoPte = MiProtoPteToPte(&TempPte);
2056
2057 /* Do we need to locate the prototype PTE in session space? */
2058 if ((IsSessionAddress) &&
2059 (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED))
2060 {
2061 /* Yep, go find it as well as the VAD for it */
2062 ProtoPte = MiCheckVirtualAddress(Address,
2063 &ProtectionCode,
2064 &Vad);
2065 ASSERT(ProtoPte != NULL);
2066 }
2067 }
2068 else
2069 {
2070 /* We don't implement transition PTEs */
2071 ASSERT(TempPte.u.Soft.Transition == 0);
2072
2073 /* Check for no-access PTE */
2074 if (TempPte.u.Soft.Protection == MM_NOACCESS)
2075 {
2076 /* Bugcheck the system! */
2077 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2079 FaultCode,
2080 (ULONG_PTR)TrapInformation,
2081 1);
2082 }
2083
2084 /* Check for no protecton at all */
2085 if (TempPte.u.Soft.Protection == MM_ZERO_ACCESS)
2086 {
2087 /* Bugcheck the system! */
2088 KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
2090 FaultCode,
2091 (ULONG_PTR)TrapInformation,
2092 0);
2093 }
2094 }
2095
2096 /* Check for demand page */
2097 if (MI_IS_WRITE_ACCESS(FaultCode) &&
2098 !(ProtoPte) &&
2099 !(IsSessionAddress) &&
2100 !(TempPte.u.Hard.Valid))
2101 {
2102 /* Get the protection code */
2103 ASSERT(TempPte.u.Soft.Transition == 0);
2104 if (!(TempPte.u.Soft.Protection & MM_READWRITE))
2105 {
2106 /* Bugcheck the system! */
2107 KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
2109 TempPte.u.Long,
2110 (ULONG_PTR)TrapInformation,
2111 14);
2112 }
2113 }
2114
2115 /* Now do the real fault handling */
2116 Status = MiDispatchFault(FaultCode,
2117 Address,
2118 PointerPte,
2119 ProtoPte,
2120 FALSE,
2121 CurrentProcess,
2122 TrapInformation,
2123 NULL);
2124
2125 /* Release the working set */
2127 MiUnlockWorkingSet(CurrentThread, WorkingSet);
2128 KeLowerIrql(LockIrql);
2129
2130 if (Status == STATUS_NO_MEMORY)
2131 {
2133 goto RetryKernel;
2134 }
2135
2136 /* We are done! */
2137 DPRINT("Fault resolved with status: %lx\n", Status);
2138 return Status;
2139 }
2140
2141 /* This is a user fault */
2142UserFault:
2143 CurrentThread = PsGetCurrentThread();
2144 CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
2145
2146 /* Lock the working set */
2147 MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
2148
2149 ProtectionCode = MM_INVALID_PROTECTION;
2150
2151#if (_MI_PAGING_LEVELS == 4)
2152 /* Check if the PXE is valid */
2153 if (PointerPxe->u.Hard.Valid == 0)
2154 {
2155 /* Right now, we only handle scenarios where the PXE is totally empty */
2156 ASSERT(PointerPxe->u.Long == 0);
2157
2158 /* This is only possible for user mode addresses! */
2159 ASSERT(PointerPte <= MiHighestUserPte);
2160
2161 /* Check if we have a VAD */
2162 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2163 if (ProtectionCode == MM_NOACCESS)
2164 {
2165 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2167 }
2168
2169 /* Resolve a demand zero fault */
2170 Status = MiResolveDemandZeroFault(PointerPpe,
2171 PointerPxe,
2173 CurrentProcess,
2174 MM_NOIRQL);
2175 if (!NT_SUCCESS(Status))
2176 {
2177 goto ExitUser;
2178 }
2179
2180 /* We should come back with a valid PXE */
2181 ASSERT(PointerPxe->u.Hard.Valid == 1);
2182 }
2183#endif
2184
2185#if (_MI_PAGING_LEVELS >= 3)
2186 /* Check if the PPE is valid */
2187 if (PointerPpe->u.Hard.Valid == 0)
2188 {
2189 /* Right now, we only handle scenarios where the PPE is totally empty */
2190 ASSERT(PointerPpe->u.Long == 0);
2191
2192 /* This is only possible for user mode addresses! */
2193 ASSERT(PointerPte <= MiHighestUserPte);
2194
2195 /* Check if we have a VAD, unless we did this already */
2196 if (ProtectionCode == MM_INVALID_PROTECTION)
2197 {
2198 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2199 }
2200
2201 if (ProtectionCode == MM_NOACCESS)
2202 {
2203 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2205 }
2206
2207 /* Resolve a demand zero fault */
2208 Status = MiResolveDemandZeroFault(PointerPde,
2209 PointerPpe,
2211 CurrentProcess,
2212 MM_NOIRQL);
2213 if (!NT_SUCCESS(Status))
2214 {
2215 goto ExitUser;
2216 }
2217
2218 /* We should come back with a valid PPE */
2219 ASSERT(PointerPpe->u.Hard.Valid == 1);
2221 }
2222#endif
2223
2224 /* Check if the PDE is invalid */
2225 if (PointerPde->u.Hard.Valid == 0)
2226 {
2227 /* Right now, we only handle scenarios where the PDE is totally empty */
2228 ASSERT(PointerPde->u.Long == 0);
2229
2230 /* And go dispatch the fault on the PDE. This should handle the demand-zero */
2231#if MI_TRACE_PFNS
2232 UserPdeFault = TRUE;
2233#endif
2234 /* Check if we have a VAD, unless we did this already */
2235 if (ProtectionCode == MM_INVALID_PROTECTION)
2236 {
2237 MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2238 }
2239
2240 if (ProtectionCode == MM_NOACCESS)
2241 {
2242#if (_MI_PAGING_LEVELS == 2)
2243 /* Could be a page table for paged pool */
2245#endif
2246 /* Has the code above changed anything -- is this now a valid PTE? */
2247 Status = (PointerPde->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2248
2249 /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2250 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2251 return Status;
2252 }
2253
2254 /* Resolve a demand zero fault */
2255 Status = MiResolveDemandZeroFault(PointerPte,
2256 PointerPde,
2258 CurrentProcess,
2259 MM_NOIRQL);
2260 if (!NT_SUCCESS(Status))
2261 {
2262 goto ExitUser;
2263 }
2264
2265#if _MI_PAGING_LEVELS >= 3
2267#endif
2268
2269#if MI_TRACE_PFNS
2270 UserPdeFault = FALSE;
2271 /* Update debug info */
2272 if (TrapInformation)
2273 MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
2274 else
2275 MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
2276#endif
2277 /* We should come back with APCs enabled, and with a valid PDE */
2279 ASSERT(PointerPde->u.Hard.Valid == 1);
2280 }
2281 else
2282 {
2283 /* Not yet implemented in ReactOS */
2284 ASSERT(MI_IS_PAGE_LARGE(PointerPde) == FALSE);
2285 }
2286
2287 /* Now capture the PTE. */
2288 TempPte = *PointerPte;
2289
2290 /* Check if the PTE is valid */
2291 if (TempPte.u.Hard.Valid)
2292 {
2293 /* Check if this is a write on a readonly PTE */
2294 if (MI_IS_WRITE_ACCESS(FaultCode))
2295 {
2296 /* Is this a copy on write PTE? */
2298 {
2299 PFN_NUMBER PageFrameIndex, OldPageFrameIndex;
2300 PMMPFN Pfn1;
2301
2302 LockIrql = MiAcquirePfnLock();
2303
2305
2307 MI_SET_PROCESS(CurrentProcess);
2308
2309 /* Allocate a new page and copy it */
2310 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(CurrentProcess));
2311 if (PageFrameIndex == 0)
2312 {
2313 MiReleasePfnLock(LockIrql);
2315 goto ExitUser;
2316 }
2317 OldPageFrameIndex = PFN_FROM_PTE(&TempPte);
2318
2319 MiCopyPfn(PageFrameIndex, OldPageFrameIndex);
2320
2321 /* Dereference whatever this PTE is referencing */
2322 Pfn1 = MI_PFN_ELEMENT(OldPageFrameIndex);
2323 ASSERT(Pfn1->u3.e1.PrototypePte == 1);
2324 ASSERT(!MI_IS_PFN_DELETED(Pfn1));
2325 ProtoPte = Pfn1->PteAddress;
2326 MiDeletePte(PointerPte, Address, CurrentProcess, ProtoPte);
2327
2328 /* And make a new shiny one with our page */
2329 MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
2330 TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
2331 TempPte.u.Hard.Write = 1;
2332 TempPte.u.Hard.CopyOnWrite = 0;
2333
2334 MI_WRITE_VALID_PTE(PointerPte, TempPte);
2335
2336 MiReleasePfnLock(LockIrql);
2337
2338 /* Return the status */
2339 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2341 }
2342
2343 /* Is this a read-only PTE? */
2345 {
2346 /* Return the status */
2347 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2349 }
2350 }
2351
2352#if _MI_HAS_NO_EXECUTE
2353 /* Check for execution of non-executable memory */
2354 if (MI_IS_INSTRUCTION_FETCH(FaultCode) &&
2356 {
2357 /* Check if execute enable was set */
2358 if (CurrentProcess->Pcb.Flags.ExecuteEnable)
2359 {
2360 /* Fix up the PTE to be executable */
2361 TempPte.u.Hard.NoExecute = 0;
2362 MI_UPDATE_VALID_PTE(PointerPte, TempPte);
2363 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2364 return STATUS_SUCCESS;
2365 }
2366
2367 /* Return the status */
2368 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2370 }
2371#endif
2372
2373 /* The fault has already been resolved by a different thread */
2374 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2375 return STATUS_SUCCESS;
2376 }
2377
2378 /* Quick check for demand-zero */
2381 {
2382 /* Resolve the fault */
2384 PointerPte,
2385 TempPte.u.Soft.Protection,
2386 CurrentProcess,
2387 MM_NOIRQL);
2388 if (!NT_SUCCESS(Status))
2389 {
2390 goto ExitUser;
2391 }
2392
2393#if MI_TRACE_PFNS
2394 /* Update debug info */
2395 if (TrapInformation)
2396 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = (PVOID)((PKTRAP_FRAME)TrapInformation)->Eip;
2397 else
2398 MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber)->CallSite = _ReturnAddress();
2399#endif
2400
2401 /* Return the status */
2402 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2404 }
2405
2406 /* Check for zero PTE */
2407 if (TempPte.u.Long == 0)
2408 {
2409 /* Check if this address range belongs to a valid allocation (VAD) */
2410 ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
2411 if (ProtectionCode == MM_NOACCESS)
2412 {
2413#if (_MI_PAGING_LEVELS == 2)
2414 /* Could be a page table for paged pool */
2416#endif
2417 /* Has the code above changed anything -- is this now a valid PTE? */
2418 Status = (PointerPte->u.Hard.Valid == 1) ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION;
2419
2420 /* Either this was a bogus VA or we've fixed up a paged pool PDE */
2421 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2422 return Status;
2423 }
2424
2425 /*
2426 * Check if this is a real user-mode address or actually a kernel-mode
2427 * page table for a user mode address
2428 */
2430#if _MI_PAGING_LEVELS >= 3
2432#if _MI_PAGING_LEVELS == 4
2434#endif
2435#endif
2436 )
2437 {
2438 /* Add an additional page table reference */
2440 }
2441
2442 /* Is this a guard page? */
2443 if ((ProtectionCode & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
2444 {
2445 /* The VAD protection cannot be MM_DECOMMIT! */
2446 ASSERT(ProtectionCode != MM_DECOMMIT);
2447
2448 /* Remove the bit */
2449 TempPte.u.Soft.Protection = ProtectionCode & ~MM_GUARDPAGE;
2450 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2451
2452 /* Not supported */
2453 ASSERT(ProtoPte == NULL);
2454 ASSERT(CurrentThread->ApcNeeded == 0);
2455
2456 /* Drop the working set lock */
2457 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2459
2460 /* Handle stack expansion */
2461 return MiCheckForUserStackOverflow(Address, TrapInformation);
2462 }
2463
2464 /* Did we get a prototype PTE back? */
2465 if (!ProtoPte)
2466 {
2467 /* Is this PTE actually part of the PDE-PTE self-mapping directory? */
2468 if (PointerPde == MiAddressToPde(PTE_BASE))
2469 {
2470 /* Then it's really a demand-zero PDE (on behalf of user-mode) */
2471#ifdef _M_ARM
2472 _WARN("This is probably completely broken!");
2474#else
2476#endif
2477 }
2478 else
2479 {
2480 /* No, create a new PTE. First, write the protection */
2481 TempPte.u.Soft.Protection = ProtectionCode;
2482 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2483 }
2484
2485 /* Lock the PFN database since we're going to grab a page */
2486 OldIrql = MiAcquirePfnLock();
2487
2488 /* Make sure we have enough pages */
2489 //ASSERT(MmAvailablePages >= 32);
2490
2491 /* Try to get a zero page */
2493 MI_SET_PROCESS2(CurrentProcess->ImageFileName);
2494 Color = MI_GET_NEXT_PROCESS_COLOR(CurrentProcess);
2495 PageFrameIndex = MiRemoveZeroPageSafe(Color);
2496 if (!PageFrameIndex)
2497 {
2498 /* Grab a page out of there. Later we should grab a colored zero page */
2499 PageFrameIndex = MiRemoveAnyPage(Color);
2500
2501 /* Release the lock since we need to do some zeroing */
2502 MiReleasePfnLock(OldIrql);
2503
2504 if (PageFrameIndex == 0)
2505 {
2507 goto ExitUser;
2508 }
2509
2510 /* Zero out the page, since it's for user-mode */
2511 MiZeroPfn(PageFrameIndex);
2512
2513 /* Grab the lock again so we can initialize the PFN entry */
2514 OldIrql = MiAcquirePfnLock();
2515 }
2516
2517 /* Initialize the PFN entry now */
2518 MiInitializePfn(PageFrameIndex, PointerPte, 1);
2519
2520 /* Increment the count of pages in the process */
2521 CurrentProcess->NumberOfPrivatePages++;
2522
2523 /* One more demand-zero fault */
2524 KeGetCurrentPrcb()->MmDemandZeroCount++;
2525
2526 /* And we're done with the lock */
2527 MiReleasePfnLock(OldIrql);
2528
2529 /* Fault on user PDE, or fault on user PTE? */
2530 if (PointerPte <= MiHighestUserPte)
2531 {
2532 /* User fault, build a user PTE */
2534 PointerPte,
2535 PointerPte->u.Soft.Protection,
2536 PageFrameIndex);
2537 }
2538 else
2539 {
2540 /* This is a user-mode PDE, create a kernel PTE for it */
2542 PointerPte,
2543 PointerPte->u.Soft.Protection,
2544 PageFrameIndex);
2545 }
2546
2547 /* Write the dirty bit for writeable pages */
2549
2550 /* And now write down the PTE, making the address valid */
2551 MI_WRITE_VALID_PTE(PointerPte, TempPte);
2552 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
2553 ASSERT(Pfn1->u1.Event == NULL);
2554
2555 /* Demand zero */
2557 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2559 }
2560
2561 /* We should have a valid protection here */
2562 ASSERT(ProtectionCode != 0x100);
2563
2564 /* Write the prototype PTE */
2566 TempPte.u.Soft.Protection = ProtectionCode;
2567 ASSERT(TempPte.u.Long != 0);
2568 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
2569 }
2570 else
2571 {
2572 /* Get the protection code and check if this is a proto PTE */
2573 ProtectionCode = (ULONG)TempPte.u.Soft.Protection;
2574 if (TempPte.u.Soft.Prototype)
2575 {
2576 /* Do we need to go find the real PTE? */
2577 if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
2578 {
2579 /* Get the prototype pte and VAD for it */
2580 ProtoPte = MiCheckVirtualAddress(Address,
2581 &ProtectionCode,
2582 &Vad);
2583 if (!ProtoPte)
2584 {
2586 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2588 }
2589 }
2590 else
2591 {
2592 /* Get the prototype PTE! */
2593 ProtoPte = MiProtoPteToPte(&TempPte);
2594
2595 /* Is it read-only */
2596 if (TempPte.u.Proto.ReadOnly)
2597 {
2598 /* Set read-only code */
2599 ProtectionCode = MM_READONLY;
2600 }
2601 else
2602 {
2603 /* Set unknown protection */
2604 ProtectionCode = 0x100;
2605 ASSERT(CurrentProcess->CloneRoot != NULL);
2606 }
2607 }
2608 }
2609 }
2610
2611 /* Do we have a valid protection code? */
2612 if (ProtectionCode != 0x100)
2613 {
2614 /* Run a software access check first, including to detect guard pages */
2615 Status = MiAccessCheck(PointerPte,
2616 !MI_IS_NOT_PRESENT_FAULT(FaultCode),
2617 Mode,
2618 ProtectionCode,
2619 TrapInformation,
2620 FALSE);
2621 if (Status != STATUS_SUCCESS)
2622 {
2623 /* Not supported */
2624 ASSERT(CurrentThread->ApcNeeded == 0);
2625
2626 /* Drop the working set lock */
2627 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2629
2630 /* Did we hit a guard page? */
2632 {
2633 /* Handle stack expansion */
2634 return MiCheckForUserStackOverflow(Address, TrapInformation);
2635 }
2636
2637 /* Otherwise, fail back to the caller directly */
2638 return Status;
2639 }
2640 }
2641
2642 /* Dispatch the fault */
2643 Status = MiDispatchFault(FaultCode,
2644 Address,
2645 PointerPte,
2646 ProtoPte,
2647 FALSE,
2648 CurrentProcess,
2649 TrapInformation,
2650 Vad);
2651
2652ExitUser:
2653
2654 /* Return the status */
2656 MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
2657
2658 if (Status == STATUS_NO_MEMORY)
2659 {
2661 goto UserFault;
2662 }
2663
2664 return Status;
2665}
#define PTE_BASE
Definition: winldr.c:20
#define _WARN(msg)
Definition: debug.h:135
DECLSPEC_NORETURN VOID NTAPI KeBugCheckEx(IN ULONG BugCheckCode, IN ULONG_PTR BugCheckParameter1, IN ULONG_PTR BugCheckParameter2, IN ULONG_PTR BugCheckParameter3, IN ULONG_PTR BugCheckParameter4)
Definition: debug.c:485
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define DbgPrint
Definition: hal.h:12
_In_ ULONG Mode
Definition: hubbusif.h:303
if(dx< 0)
Definition: linetemp.h:194
#define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)
Definition: miarm.h:194
FORCEINLINE VOID MiLockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1272
PVOID MmNonPagedPoolEnd
Definition: mminit.c:100
BOOLEAN MmProtectFreedNonPagedPool
Definition: pool.c:31
FORCEINLINE BOOLEAN MiIsUserPte(PVOID Address)
Definition: miarm.h:730
#define MI_IS_SESSION_PTE(Pte)
Definition: miarm.h:188
#define MM_INVALID_PROTECTION
Definition: miarm.h:67
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1201
FORCEINLINE VOID MiUnlockWorkingSet(IN PETHREAD Thread, IN PMMSUPPORT WorkingSet)
Definition: miarm.h:1358
FORCEINLINE VOID MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde, IN MMPDE InvalidPde)
Definition: miarm.h:1042
FORCEINLINE BOOLEAN MiIsUserPde(PVOID Address)
Definition: miarm.h:722
FORCEINLINE VOID MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte, IN MMPTE TempPte)
Definition: miarm.h:985
#define MI_IS_PFN_DELETED(x)
Definition: miarm.h:209
#define MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address)
Definition: miarm.h:197
FORCEINLINE USHORT MiIncrementPageTableReferences(IN PVOID Address)
Definition: miarm.h:2479
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1131
struct _EPROCESS * PEPROCESS
Definition: nt_native.h:30
#define MI_IS_PAGE_EXECUTABLE(x)
Definition: mm.h:111
#define MI_IS_WRITE_ACCESS(FaultCode)
Definition: mm.h:122
#define MM_PTE_SOFTWARE_PROTECTION_BITS
Definition: mm.h:75
#define MI_IS_INSTRUCTION_FETCH(FaultCode)
Definition: mm.h:125
#define _MI_PAGING_LEVELS
Definition: mm.h:6
FORCEINLINE PMMPTE MiAddressToPpe(PVOID Address)
Definition: mm.h:161
#define MiProtoPteToPte(x)
Definition: mm.h:316
FORCEINLINE PMMPTE MiAddressToPxe(PVOID Address)
Definition: mm.h:171
#define MI_IS_PAGE_LARGE(x)
Definition: mm.h:104
#define MiAddressToPde(x)
Definition: mm.h:156
@ MI_USAGE_PEB_TEB
Definition: mm.h:342
ULONG MmSizeOfNonPagedPoolInBytes
Definition: init.c:21
PVOID MmNonPagedPoolExpansionStart
Definition: init.c:25
MMSUPPORT MmSystemCacheWs
Definition: init.c:55
PVOID MmNonPagedPoolStart
Definition: init.c:24
MMPDE DemandZeroPde
Definition: init.c:36
MMPTE PrototypePte
Definition: init.c:40
#define STATUS_WAIT_1
Definition: ntstatus.h:123
#define STATUS_PAGE_FAULT_COPY_ON_WRITE
Definition: ntstatus.h:149
#define STATUS_IN_PAGE_ERROR
Definition: ntstatus.h:336
static PMMPTE NTAPI MiCheckVirtualAddress(IN PVOID VirtualAddress, OUT PULONG ProtectCode, OUT PMMVAD *ProtoVad)
Definition: pagfault.c:257
VOID NTAPI MmRebalanceMemoryConsumersAndWait(VOID)
Definition: balance.c:300
NTSTATUS FASTCALL MiCheckPdeForPagedPool(IN PVOID Address)
Definition: pagfault.c:495
static NTSTATUS NTAPI MiCheckForUserStackOverflow(IN PVOID Address, IN PVOID TrapInformation)
Definition: pagfault.c:34
NTSTATUS NTAPI MiDispatchFault(IN ULONG FaultCode, IN PVOID Address, IN PMMPTE PointerPte, IN PMMPTE PointerProtoPte, IN BOOLEAN Recursive, IN PEPROCESS Process, IN PVOID TrapInformation, IN PMMVAD Vad)
Definition: pagfault.c:1354
PFN_NUMBER NumberOfPrivatePages
Definition: pstypes.h:1407
KPROCESS Pcb
Definition: pstypes.h:1369
PVOID CloneRoot
Definition: pstypes.h:1406
CHAR ImageFileName[16]
Definition: pstypes.h:1433
ULONG OwnsSessionWorkingSetExclusive
Definition: pstypes.h:1320
ULONG OwnsSessionWorkingSetShared
Definition: pstypes.h:1321
ULONG OwnsSystemWorkingSetShared
Definition: pstypes.h:1319
ULONG OwnsProcessWorkingSetShared
Definition: pstypes.h:1317
ULONG OwnsProcessWorkingSetExclusive
Definition: pstypes.h:1316
ULONG OwnsSystemWorkingSetExclusive
Definition: pstypes.h:1318
UCHAR ExecuteEnable
Definition: ketypes.h:1132
KEXECUTE_OPTIONS Flags
Definition: ketypes.h:2277
KAPC_STATE ApcState
Definition: ketypes.h:1925
ULONG R3
Definition: ketypes.h:370
UINT64 Rdi
Definition: ketypes.h:475
ULONG Sp
Definition: ketypes.h:372
ULONG Pc
Definition: ketypes.h:375
ULONG Edi
Definition: ketypes.h:316
UINT64 Rsi
Definition: ketypes.h:476
UINT64 Rdx
Definition: ketypes.h:425
ULONG Lr
Definition: ketypes.h:373
ULONG EFlags
Definition: ketypes.h:489
ULONG R0
Definition: ketypes.h:367
ULONG Ebx
Definition: ketypes.h:318
ULONG Ecx
Definition: ketypes.h:311
UINT64 Rbx
Definition: ketypes.h:474
ULONG Eip
Definition: ketypes.h:321
UINT64 Rax
Definition: ketypes.h:423
UINT64 Rip
Definition: ketypes.h:484
ULONG R2
Definition: ketypes.h:369
ULONG R1
Definition: ketypes.h:368
ULONG Eax
Definition: ketypes.h:312
UINT64 Rcx
Definition: ketypes.h:424
ULONG Esi
Definition: ketypes.h:317
ULONG Edx
Definition: ketypes.h:310
UINT64 R11
Definition: ketypes.h:429
ULONG R12
Definition: ketypes.h:371
struct _MM_SESSION_SPACE * GlobalVirtualAddress
Definition: miarm.h:474

Referenced by MmAccessFault().

◆ MmGetExecuteOptions()

NTSTATUS NTAPI MmGetExecuteOptions ( IN PULONG  ExecuteOptions)

Definition at line 2669 of file pagfault.c.

2670{
2671 PKPROCESS CurrentProcess = &PsGetCurrentProcess()->Pcb;
2673
2674 *ExecuteOptions = 0;
2675
2676 if (CurrentProcess->Flags.ExecuteDisable)
2677 {
2678 *ExecuteOptions |= MEM_EXECUTE_OPTION_DISABLE;
2679 }
2680
2681 if (CurrentProcess->Flags.ExecuteEnable)
2682 {
2683 *ExecuteOptions |= MEM_EXECUTE_OPTION_ENABLE;
2684 }
2685
2686 if (CurrentProcess->Flags.DisableThunkEmulation)
2687 {
2689 }
2690
2691 if (CurrentProcess->Flags.Permanent)
2692 {
2693 *ExecuteOptions |= MEM_EXECUTE_OPTION_PERMANENT;
2694 }
2695
2696 if (CurrentProcess->Flags.ExecuteDispatchEnable)
2697 {
2699 }
2700
2701 if (CurrentProcess->Flags.ImageDispatchEnable)
2702 {
2704 }
2705
2706 return STATUS_SUCCESS;
2707}
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define MEM_EXECUTE_OPTION_DISABLE
Definition: mmtypes.h:73
#define MEM_EXECUTE_OPTION_PERMANENT
Definition: mmtypes.h:76
#define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE
Definition: mmtypes.h:77
#define MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE
Definition: mmtypes.h:78
#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION
Definition: mmtypes.h:75
#define MEM_EXECUTE_OPTION_ENABLE
Definition: mmtypes.h:74
UCHAR DisableThunkEmulation
Definition: ketypes.h:1133
UCHAR ExecuteDisable
Definition: ketypes.h:1131
UCHAR ExecuteDispatchEnable
Definition: ketypes.h:1135
UCHAR ImageDispatchEnable
Definition: ketypes.h:1136

Referenced by NtQueryInformationProcess().

◆ MmRebalanceMemoryConsumersAndWait()

VOID NTAPI MmRebalanceMemoryConsumersAndWait ( VOID  )

Definition at line 300 of file balance.c.

301{
302 ASSERT(PsGetCurrentProcess()->AddressCreationLock.Owner != KeGetCurrentThread());
305
309}
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
LONG NTAPI KeResetEvent(IN PKEVENT Event)
Definition: eventobj.c:134
#define KeGetCurrentThread
Definition: hal.h:55
FORCEINLINE BOOLEAN MM_ANY_WS_LOCK_HELD(IN PETHREAD Thread)
Definition: miarm.h:1059
static KEVENT MiBalancerDoneEvent
Definition: balance.c:34
VOID NTAPI MmRebalanceMemoryConsumers(VOID)
Definition: balance.c:290
@ Executive
Definition: ketypes.h:467

Referenced by MmArmAccessFault().

◆ MmSetExecuteOptions()

NTSTATUS NTAPI MmSetExecuteOptions ( IN ULONG  ExecuteOptions)

Definition at line 2711 of file pagfault.c.

2712{
2713 PKPROCESS CurrentProcess = &PsGetCurrentProcess()->Pcb;
2714 KLOCK_QUEUE_HANDLE ProcessLock;
2717
2718 /* Only accept valid flags */
2719 if (ExecuteOptions & ~MEM_EXECUTE_OPTION_VALID_FLAGS)
2720 {
2721 /* Fail */
2722 DPRINT1("Invalid no-execute options\n");
2724 }
2725
2726 /* Change the NX state in the process lock */
2727 KiAcquireProcessLockRaiseToSynch(CurrentProcess, &ProcessLock);
2728
2729 /* Don't change anything if the permanent flag was set */
2730 if (!CurrentProcess->Flags.Permanent)
2731 {
2732 /* Start by assuming it's not disabled */
2733 CurrentProcess->Flags.ExecuteDisable = FALSE;
2734
2735 /* Now process each flag and turn the equivalent bit on */
2736 if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE)
2737 {
2738 CurrentProcess->Flags.ExecuteDisable = TRUE;
2739 }
2740 if (ExecuteOptions & MEM_EXECUTE_OPTION_ENABLE)
2741 {
2742 CurrentProcess->Flags.ExecuteEnable = TRUE;
2743 }
2744 if (ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
2745 {
2746 CurrentProcess->Flags.DisableThunkEmulation = TRUE;
2747 }
2748 if (ExecuteOptions & MEM_EXECUTE_OPTION_PERMANENT)
2749 {
2750 CurrentProcess->Flags.Permanent = TRUE;
2751 }
2752 if (ExecuteOptions & MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE)
2753 {
2754 CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2755 }
2756 if (ExecuteOptions & MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE)
2757 {
2758 CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2759 }
2760
2761 /* These are turned on by default if no-execution is also enabled */
2762 if (CurrentProcess->Flags.ExecuteEnable)
2763 {
2764 CurrentProcess->Flags.ExecuteDispatchEnable = TRUE;
2765 CurrentProcess->Flags.ImageDispatchEnable = TRUE;
2766 }
2767
2768 /* All good */
2770 }
2771
2772 /* Release the lock and return status */
2773 KiReleaseProcessLock(&ProcessLock);
2774 return Status;
2775}
FORCEINLINE VOID KiReleaseProcessLock(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:660
FORCEINLINE VOID KiAcquireProcessLockRaiseToSynch(IN PKPROCESS Process, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:651
#define MEM_EXECUTE_OPTION_VALID_FLAGS
Definition: mmtypes.h:79
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135

Referenced by NtSetInformationProcess().